@charset "UTF-8";

/* ==================================================================
 * style.css — per-block (BEM) styles
 *
 *  header / menu / kv / message / figure / manifest /
 *  funclub / live / release / footer / more / scribble / side-label
 *  (the loader lives in base.css - it must be styled before this file lands)
 *
 * Positions and sizes come from the comps
 * (PC 2560px = 1280px @2x / SP 786px = 393px @2x), in % and rem (1rem = 10px).
 * ================================================================== */

/* ================================================================ Header
 * Icons are white SVGs used as masks, so one --ui variable drives the color.
 * ================================================================ */
.header {
  position: fixed;
  top: 2.4rem;
  right: 2.8rem;
  z-index: var(--z-header);
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 0.5rem;
  /* Flips white/black in sync with the KV slide theme. */
  --ui: #1b1b1b;
  color: var(--ui);
  transition: color 0.6s var(--ease-out);
}

.header--light {
  --ui: #fff;
}

/* Always white while the menu overlays the page. */
.header.is-open {
  --ui: #fff;
}

.header__mark {
  display: block;
  width: 5rem;
  aspect-ratio: 40.47 / 40.69;
  margin-left: -0.3rem;
  background: currentColor;
  -webkit-mask: url("../images/common/logo-cat.svg") center / contain no-repeat;
  mask: url("../images/common/logo-cat.svg") center / contain no-repeat;
  transition: opacity 0.4s var(--ease-out);
}

.header__home {
  display: block;
}

.header__toggle {
  display: block;
  padding: 0.6rem 0;
}

.header__toggle-icon {
  display: block;
  width: 4.98rem;
  aspect-ratio: 49.78 / 27.47;
  background: currentColor;
  -webkit-mask: url("../images/common/icon-ham.svg") center / contain no-repeat;
  mask: url("../images/common/icon-ham.svg") center / contain no-repeat;
  /* Same duration as .header__home so the cat and the bars fade together. */
  transition: opacity 0.4s var(--ease-out);
}

/* Swap to the X icon while open. */
.header.is-open .header__toggle-icon {
  aspect-ratio: 49.41 / 25.47;
  -webkit-mask-image: url("../images/common/icon-ham-close.svg");
  mask-image: url("../images/common/icon-ham-close.svg");
}

/* The cat and the bars act as one unit: hovering either (anywhere on the
   header column) dims both together. */
.header:hover .header__mark,
.header:hover .header__toggle-icon {
  opacity: 0.6;
}

/* ================================================================ Menu */
.menu {
  position: fixed;
  inset: 0;
  z-index: var(--z-menu);
  visibility: hidden;
  /* No opacity here: a semi-transparent ancestor becomes the backdrop
     root, so the backdrop-filter below would see nothing to blur while
     fading (the blur pops in only when opacity hits 1). Fading is done
     per-child instead; 0.55s covers the slowest closing child below
     (closing is quicker than the 0.8s staggered opening on purpose —
     dismissal should feel immediate). */
  transition: visibility 0.55s;
}

.menu.is-open {
  visibility: visible;
  /* Do not raise z-index here: it would sit above the header (95)
     and hide the cat mark and close button. */
}

/* No solid background: blur the page behind and lay #121a1a at 80% on top
   (per the design spec). The backdrop-filter sits below the header
   (--z-menu 90 < --z-header 95) so the header stays sharp.
   Browsers without backdrop-filter just get the 80% black.
   The blur radius stays constant; fading the element's own opacity fades
   the filtered result with it, which reads as the blur ramping in but is
   far cheaper than animating backdrop-filter itself. */
.menu__backdrop {
  position: absolute;
  inset: 0;
  background: rgba(18, 26, 26, 0.8);
  -webkit-backdrop-filter: blur(2.4rem);
  backdrop-filter: blur(2.4rem);
  opacity: 0;
  /* Base duration = closing; opening restores the slower fade below. */
  transition: opacity 0.45s var(--ease-out);
}

.menu.is-open .menu__backdrop {
  opacity: 1;
  transition-duration: 0.7s;
}

.menu__list {
  position: relative;
  height: 100%;
}

.menu__item {
  position: absolute;
  opacity: 0;
  /* Slightly tilted, straightening as it appears (hand-placed feel). */
  transform: translate3d(0, 2rem, 0) rotate(1.4deg);
  /* Base duration = closing (quick); opening slows down below. */
  transition:
    opacity 0.45s var(--ease-out),
    transform 0.45s var(--ease-out);
}

.menu.is-open .menu__item {
  opacity: 1;
  transform: none;
  transition-duration: 0.8s, 0.8s;
}

.menu.is-open .menu__item:nth-child(1) { transition-delay: 0.08s; }
.menu.is-open .menu__item:nth-child(2) { transition-delay: 0.16s; }
.menu.is-open .menu__item:nth-child(3) { transition-delay: 0.24s; }
.menu.is-open .menu__item:nth-child(4) { transition-delay: 0.32s; }
.menu.is-open .menu__item:nth-child(5) { transition-delay: 0.40s; }

/* Hand-scattered layout, measured from the comp. */
.menu__item--top      { top: 11%;    left: 32.2%; width: 10%; }
.menu__item--manifest { top: 25.1%;  left: 46.3%; width: 27.2%; }
.menu__item--funclub  { top: 44.5%;  left: 23.3%; width: 25.7%; }
.menu__item--live     { top: 58.65%; left: 57%;   width: 18.9%; }
.menu__item--release  { top: 76.05%; left: 21.1%; width: 25.7%; }

/* TOP's asset tilts less than the comp (comp 16.4deg / asset 10.4deg);
   add the difference in CSS. */
.menu__item--top .menu__link {
  transform: rotate(6deg);
  transform-origin: left center;
}

/* RELEASE's asset already carries the comp tilt (comp -7.3deg / asset -7.2deg),
   so no CSS rotation on PC. */

.menu__link {
  position: relative;
  display: block;
  color: #fff;
}

/* Inlined SVG. Claw strikes appear on hover / current. */
.menu__logo {
  display: block;
}

.menu__logo svg {
  display: block;
  width: 100%;
  height: auto;
  overflow: visible;
}

.menu__logo-text {
  transition: opacity 0.4s var(--ease-out);
}

.menu__logo-strike {
  opacity: 0;
  transition: opacity 0.05s linear;
}

/* The 3 strikes scratch in one by one; they vanish together
   (delays live only on the appearing selectors). */
.menu__logo-strike > * {
  opacity: 0;
  transition: opacity 0.05s linear;
}

.menu__link:hover .menu__logo-strike,
.menu__link:focus-visible .menu__logo-strike,
.menu.is-open .menu__item.is-current .menu__logo-strike {
  opacity: 1;
}

.menu__link:hover .menu__logo-strike > *,
.menu__link:focus-visible .menu__logo-strike > *,
.menu.is-open .menu__item.is-current .menu__logo-strike > * {
  opacity: 1;
}

/* Hover scratches immediately. */
.menu__link:hover .menu__logo-strike > :nth-child(2),
.menu__link:focus-visible .menu__logo-strike > :nth-child(2) {
  transition-delay: 0.11s;
}

.menu__link:hover .menu__logo-strike > :nth-child(3),
.menu__link:focus-visible .menu__logo-strike > :nth-child(3) {
  transition-delay: 0.24s;
}

/* The current item scratches after the items settle. .menu.is-open always
   transitions 0 -> 1, so it replays every time the menu opens. */
.menu.is-open .menu__item.is-current .menu__logo-strike > :nth-child(1) { transition-delay: 0.6s; }
.menu.is-open .menu__item.is-current .menu__logo-strike > :nth-child(2) { transition-delay: 0.74s; }
.menu.is-open .menu__item.is-current .menu__logo-strike > :nth-child(3) { transition-delay: 0.9s; }

.menu__link:hover .menu__logo-text,
.menu__link:focus-visible .menu__logo-text {
  opacity: 0.75;
}

/* NEW badge at the upper-right end of a word. The <img> sits in every
   item; only a <li class="... has-new"> shows it, so a badge is switched
   on / off by that class alone (no markup change).
   width is a share of the item, and the items differ in width, so each
   item gets its own value below to keep the badge the same size on
   screen (RELEASE's 19.3% of 25.7% = 4.96% of the menu is the reference).
   top is a share of the word's height, which also differs per asset. */
.menu__badge {
  display: none;
  position: absolute;
  top: -40%;
  left: 102%;
  width: 19.3%;
  height: auto;
}

.menu__item.has-new .menu__badge {
  display: block;
}

.menu__item--manifest .menu__badge {
  top: -34%;
  width: 18.2%;
}

.menu__item--live .menu__badge {
  top: 10%;
  width: 26.2%;
  transform: rotate(9deg);
}

/* ================================================================ KV */
/* The KV + message stage. KV and the message are NOT stacked: they flow
   normally (KV one viewport tall, the message below it), and the copy
   types in when it enters the viewport — same behavior on PC and SP. */
.stage {
  position: relative;
}

.kv {
  cursor: pointer;
  position: relative;
  z-index: var(--z-kv);
  width: 100%;
  height: 100vh; /* fallback where svh is unsupported */
  height: 100svh;
  /* Flat colour only. The photo fallback below is attached by main.js
     (.is-nogl) when WebGL actually fails - if it lived here it would decode
     and paint during loading and could flash before the loader covers. */
  background: #7fa8c4;
  overflow: hidden;
  overflow: clip;
  user-select: none;
  -webkit-user-select: none;
  --ui: #1b1b1b;
}

/* WebGL failed (or its context was lost and not returned): fall back to
   the still photo so the KV is never blank. The canvas is hidden as well -
   a dead context can leave a stale or black buffer on it. */
.kv.is-nogl {
  background: #7fa8c4 url("../images/kv/kv-01.webp") center bottom / cover no-repeat;
}

.kv.is-nogl .kv__canvas {
  visibility: hidden;
}

/* The KV always fits within the viewport (100svh, no aspect-ratio
   growth). What each slide shows inside that crop is the per-slide
   focus — the object-position equivalent — set in main.js (KV_SLIDES)
   and applied by the cover math in kv-slider.js.
   PC only: keep a usable height on very short browser windows.
   SP only: a just-in-case cap for unusually tall portrait screens
   (ordinary phones never reach it). */
@media (min-width: 769px) {
  .kv {
    min-height: 48rem;
  }
}

@media (max-width: 768px) {
  .kv {
    max-height: 120rem;
  }
}

.kv[data-theme="white"] {
  --ui: #fff;
}

.kv__canvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  /* No touch-action restriction: every gesture is left to the browser so
     its native pinch zoom works on the whole page, KV included. The
     slides advance on autoplay alone (no tap/swipe navigation). */
  touch-action: auto;
}

.kv__catch {
  position: absolute;
  top: 13%;
  left: 11.5%;
  /* z-index: 2; */
  width: 74%;
  max-width: 140rem;
  pointer-events: none;
}

.kv__catch-image {
  display: block;
  width: 100%;
  transition: filter 0.6s var(--ease-out);
}

.kv__catch-image svg {
  display: block;
  width: 100%;
  height: auto;
}

.kv[data-theme="white"] .kv__catch-image {
  filter: brightness(0) invert(1);
}

.kv__catch-image--sp {
  display: none;
}

.kv__scroll {
  position: absolute;
  right: 4.6rem;
  bottom: 3rem;
  z-index: 2;
  display: flex;
  flex-direction: row-reverse;
  align-items: normal;
  gap: 1.4rem;
  color: var(--ui);
  transition: color 0.6s var(--ease-out), opacity 0.4s var(--ease-out);
  cursor: pointer;
}

.kv__scroll:hover {
  opacity: 0.6;
}

.kv__scroll-label {
  font-family: var(--font-serif);
  font-size: 1.3rem;
  letter-spacing: 0.1em;
  line-height: 1;
  writing-mode: vertical-rl;
}

/* Scroll arrow (hand-drawn SVG as a mask, following --ui). */
.kv__scroll-arrow {
  display: block;
  width: 0.7rem;
  height: 8.4rem;
  background: currentColor;
  -webkit-mask: url("../images/common/scroll-arw.svg") bottom center / 100% auto no-repeat;
  mask: url("../images/common/scroll-arw.svg") bottom center / 100% auto no-repeat;
}

/* One sweep flowing top to bottom. */
.kv__scroll-arrow::after {
  content: "";
  display: block;
  height: 100%;
  background: linear-gradient(to bottom, transparent 0%, rgba(0, 0, 0, 0.55) 45%, transparent 100%);
  animation: kvScroll 2.6s var(--ease-inout) infinite;
}

@keyframes kvScroll {
  0%        { transform: translateY(-100%); }
  60%, 100% { transform: translateY(100%); }
}

/* ================================================================ Message */
/* Flows below the KV; the copy types in on enter.
   Driven by initStage() in main.js. */
.message {
  position: relative;
  z-index: 2;
  /* Comp(SP準拠): copy starts below the KV, with space before the
     costume photo. */
  padding: 12.5rem 0 13.5rem;
  background: var(--c-bg);
}

.message__inner {
  width: min(64rem, 84%);
  margin-inline: auto;
}

/* The letter, swept in top to bottom as if it were being written: a soft
   edged gradient mask whose stop travels down the image. The two stops are
   kept 18% apart so the edge is a fade and not a wipe line, and the sweep
   runs to 118% so the last stretch of the paper ends fully opaque rather
   than under the tail of the fade.
   The mask only exists once initStage has armed it (.is-armed): without JS
   the letter must still be on the page, not masked out of it. */
@property --letter-sweep {
  syntax: "<percentage>";
  initial-value: 0%;
  inherits: false;
}

.message__letter img {
  display: block;
  width: 100%;
  height: auto;
}

.message__letter.is-armed {
  --letter-sweep: 0%;
  -webkit-mask-image: linear-gradient(#000 calc(var(--letter-sweep) - 18%), rgba(0, 0, 0, 0) var(--letter-sweep));
  mask-image: linear-gradient(#000 calc(var(--letter-sweep) - 18%), rgba(0, 0, 0, 0) var(--letter-sweep));
}

.message__letter.is-armed.is-written {
  --letter-sweep: 118%;
  transition: --letter-sweep 2s var(--ease-spread);
}

/* Under the letter now, not pulled up over the copy: the image runs to its
   own date line and has no room left inside it. */
.message__sign {
  width: 25.5rem;
  margin: 1.4rem 0 0 auto;
}

.message__sign img {
  width: 100%;
}

/* ================================================================ Figure
 * Photos keep their intrinsic ratio; modifiers only place them.
 * ================================================================ */
.figure {
  position: relative;
}

.figure__image {
  width: 100%;
  height: auto;
}

/* After the message: costume close-up (left-aligned, bleeding off). */
.figure--costume {
  /* Comp: narrower than the raw 70.2% crop; 60% sits closest. */
  width: 48%;
  margin-right: auto;
}

/* Below MANIFEST: cliff (right-aligned, bleeding off). */
.figure--cliff {
  width: 62.5%;
  margin: 5.4rem 0 0 auto;
}

/* The light and sky cuts are placed in the Light block
   (.figure--light / --sky). */

/* Full-width band. The box is the photo's own 2560x1040 made 10% shorter
   (2816 = 2560 x 1.1), so the photo covers the full width uncropped and the
   only crop it takes is real height - 5% off the top and 5% off the bottom -
   rather than an upscale that would eat into the sides.
   10% is the ceiling here: the figure spans ~80% of the frame from the banner
   tip to her feet, so a deeper crop leaves too little window to hold her.
   The photo used to drift inside that surplus (data-parallax); it now enters
   like the rest of the page's photos instead (data-gl-reveal, see
   index.html), with data-gl-scale="1" so the entrance does not shrink it away
   from the band's clipped edges. */
.figure--band {
  width: 100%;
  aspect-ratio: 2816 / 1040;
  overflow: clip;
}

.figure--band .figure__image {
  position: absolute;
  inset: -5% 0;
  width: 100%;
  height: 110%;
  object-fit: cover;
}

/* ================================================================ Title rows (shared)
 * A thin "| LABEL ------" rule with the handwritten title sitting on it.
 * Rule inset: 10.9% each side (comp: 140px of 1280).
 * ================================================================ */
.title-row {
  position: relative;
  margin-inline: 10.9%;
  /* currentColor, not var(--c-text): every row on the top page inherits that
     same colour from body, and it lets the sub pages put the row on blue
     just by setting a colour on the section. */
  border-bottom: 1px solid currentColor;
}

/* Leading "|" and the letterspaced label
   (comp: M-T spans 265px; nearly as large as the handwritten title). */
.title-row__label {
  position: absolute;
  bottom: 0;
  left: 0;
  padding: 0 0 0.6rem 1.8rem;
  border-left: 1px solid currentColor;
  font-family: var(--font-serif);
  font-size: 1.4rem;
  letter-spacing: 2em;
  line-height: 1;
}

/* Handwritten title on the rule (JS trims the svg viewBox to the ink). */
.title-row__art {
  display: block;
  margin-bottom: -1.5rem; /* bite slightly into the rule, as in the comp */
}

/* Centered; widths chosen so the ink height matches across titles
   (ink boxes: manifest 464x100 / funclub 377x100 / live 291x100 /
   release 373x100 -> width ∝ ink width for equal height). */
.title-row__art--manifest { width: 40.8%; margin-inline: auto; }
.title-row__art--funclub  { width: 38.2%; margin-inline: auto; }
.title-row__art--live     { width: 25.6%; margin-inline: auto; }
.title-row__art--release  { width: 37.8%; margin-inline: auto; }

.title__art {
  display: block;
}

.title__art svg {
  display: block;
  width: 100%;
  height: auto;
}

/* ================================================================ Manifest */
.manifest {
  /* Comp: title top is 176px below the costume photo. */
  padding: 28rem 0 0;
}

.manifest__list {
  margin-top: 7rem;
  margin-inline: 10.9%;
}

.manifest__item + .manifest__item {
  margin-top: 5.5rem;
}

.manifest__link {
  display: block;
  transition: opacity 0.4s var(--ease-out), transform 0.6s var(--ease-out);
}

.manifest__link:hover {
  transform: translateX(0.5rem);
  opacity: 0.6;
}

/* The "|1/ F A N C L U B ------" row. */
.manifest__head {
  position: relative;
  display: block;
  padding: 0 0 0.7rem 8rem;
  border-bottom: 1px solid var(--c-text);
}

/* Leading "|". */
.manifest__head::before {
  content: "";
  position: absolute;
  bottom: 0;
  left: 0;
  width: 1px;
  height: 2.6rem;
  background: var(--c-text);
}

.manifest__num {
  position: absolute;
  bottom: 0.4rem;
  left: 1.8rem;
  font-family: var(--font-serif);
  font-style: normal;
  font-size: 1.9rem;
  line-height: 1;
}

/* Hand-drawn diagonal across the number
   (comp: extends 23px above and 28px below the rule). */
.manifest__head::after {
  content: "";
  position: absolute;
  bottom: -2.8rem;
  left: 0;
  width: 4.7rem;
  height: 5.1rem;
  background: url("../images/common/diagonal-line01.svg") center / contain no-repeat;
}

.manifest__item:nth-child(2) .manifest__head::after {
  background-image: url("../images/common/diagonal-line02.svg");
}

.manifest__item:nth-child(3) .manifest__head::after {
  background-image: url("../images/common/diagonal-line03.svg");
}

.manifest__name {
  display: block;
  font-family: var(--font-serif);
  font-size: 2rem;
  letter-spacing: 0.7em;
  line-height: 1;
}

.manifest__lead {
  margin: 1.3rem 0 0 8rem;
  font-family: var(--font-serif);
  font-size: 2rem;
  letter-spacing: 0.02em;
  line-height: 1.5;
}

.manifest__lead .scribble {
  margin-left: 1.2rem;
}

.manifest__masked {
  margin: 0.6rem 0 0 8rem;
}

/* ================================================================ Fan club */
.funclub {
  position: relative;
  /* Comp: 102px from the cliff photo to the handwritten FAN CLUB. */
  padding-top: 10.2rem;
  margin-bottom: 16.5rem;
}

.funclub__title {
  /* Comp: 71px from the rule to the paper. */
  margin-bottom: 7.1rem;
}

/* Flat single-color paper, full width, straight edges (artboard 1). */
.funclub__paper {
  position: relative;
  padding: 10.7rem 0 10.5rem;
  background: var(--c-paper);
}

/* Tail + NEW OPEN! peeking from the paper's top-left edge. */
.funclub__newopen {
  position: absolute;
  top: 4.8rem;
  left: 0;
  z-index: 2;
  width: 28rem;
  height: auto;
  pointer-events: none;
}

.funclub__inner {
  position: relative;
  z-index: 2;
  width: min(100rem, 84%);
  margin-inline: auto;
  color: var(--c-paper-ink);
  text-align: center;
}

.funclub__logo {
  width: 21.5rem;
  margin-inline: auto;
}

.funclub__logo img {
  width: 100%;
}

/* Ornamental divider under the logo (artboard 1: 172px wide, right below). */
.funclub__divider {
  width: 23rem;
  margin: 0.7rem auto 0;
}

/* Underlined heading. Underline = border.svg (a 2px + 1px line pair in
   #6d5531, 6px tall) stretched to the text width; preserveAspectRatio="none"
   in the asset lets it stretch. 0.7rem gap + 0.6rem for the lines. */
.funclub__heading {
  width: fit-content;
  margin: 2.5rem auto 0;
  padding-bottom: 0.8rem;
  background: url("../images/funclub/border.svg") left bottom / 100% 0.6rem no-repeat;
  /* Slight thickening: the larger size renders optically thinner than the
     body copy, and the webfont has no medium weight to reach for. */
  -webkit-text-stroke: 0.03rem currentColor;
  font-family: var(--font-mincho);
  font-size: 1.9rem;
  letter-spacing: 0.1em;
  line-height: 1.5;
}

.funclub__body {
  /* Lines run right up to the inner width (64rem), so widen by 5rem
     each side to avoid wraps. Text is centered so nothing moves visually.
     Negative margins, not transform: data-reveal overwrites transform. */
  margin-top: 1.6rem;
  margin-inline: -5rem;
}

.funclub__text {
  font-size: 1.4rem;
  letter-spacing: 0.06em;
  line-height: 2.2;
}

.funclub__text + .funclub__text {
  margin-top: 1.8em;
}

/* Small ruby over "NIGHT OWLS". */
.funclub__ruby {
  position: relative;
  white-space: nowrap;
}

.funclub__ruby i {
  position: absolute;
  top: -1.15em;
  left: 50%;
  transform: translateX(-50%);
  font-style: normal;
  font-size: 0.6em;
  letter-spacing: 0.22em;
  white-space: nowrap;
}

/* ---------------- Benefits ---------------- */
.funclub__benefits {
  margin-top: 6.4rem;
}

/* Benefits title with ornaments, one SVG (artboard 1: 215px wide). */
.funclub__benefits-title {
  width: 30rem;
  margin-inline: auto;
}

.funclub__benefits-title img {
  display: block;
  width: 100%;
  height: auto;
}

/* 3 columns, centred on the middle one so it shares an axis with the benefits
   title above it (artboard 1: column centres 294 / 640 / 985 @1280, i.e. the
   middle sits on the inner's centre).

   The outer two are one `1fr` track each, so the grid always makes them the
   same width; that symmetry is what puts the middle track's centre on the row's
   centre, whatever the copy says. `width: max-content` then sizes every track
   to its own longest line, so nothing has to wrap or overflow. The row comes
   out wider than the inner, so auto margins cannot centre it (they resolve to
   0 and it just overflows right) - left/transform does.

   This used to be a flex row sized to each column's text, nudged into place
   with a hand-tuned `margin-left: 4.6rem`. That only cancelled out for one
   exact set of strings - rewriting a benefit moved the middle label off the
   title's axis again (67px off, with the current copy). */
.funclub__benefit-list {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: start;
  gap: 5rem;
  position: relative;
  width: max-content;
  max-width: 92vw;
  margin: 2.8rem 0 0;
  left: 50%;
  transform: translateX(-50%);
}

.funclub__benefit {
  min-width: 0;
}

/* The outer two hug the middle column, so the space either side of it is the
   gap and nothing else. Centred in their (equal) tracks instead, the short
   first column sat 107px clear of the middle while the long third one sat 40px
   clear - the first one read as drifting off on its own. */
.funclub__benefit:first-child {
  justify-self: end;
}

.funclub__benefit:last-child {
  justify-self: start;
}

/* Benefit label: live text with an ornament either side of it, so the frame
   grows and shrinks with whatever the label says and the text stays centred
   in it.
   It used to be one 150x22.33 SVG sitting behind a fixed 15rem box, with the
   text floated over the middle of it - which only lined up while every label
   was exactly 4 characters, and left the text drifting off the brackets as
   soon as one was not. benefit-frame-left/-right.svg are that same drawing
   split at the brackets (the original's 4 paths, 2 and 2): the left half ends
   on the opening bracket, the right half starts on the closing one. */
.funclub__benefit-label {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.1rem;
  width: fit-content;
  height: 2.2rem;
  margin-inline: auto;
}

/* 48.04 and 47.1 wide against the shared 22.33 height, so each keeps its drawn
   proportions off the label's height alone. */
.funclub__benefit-label::before,
.funclub__benefit-label::after {
  content: "";
  flex: none;
  /* Explicit, not 100%: the SP label below grows to two lines, and a
     percentage against that auto height would resolve to auto - which is 0
     for an empty pseudo-element. */
  height: 2.2rem;
  background-position: center;
  background-size: contain;
  background-repeat: no-repeat;
}

.funclub__benefit-label::before {
  width: calc(2.2rem * 48.04 / 22.33);
  background-image: url("../images/funclub/benefit-frame-left.svg");
}

.funclub__benefit-label::after {
  width: calc(2.2rem * 47.1 / 22.33);
  background-image: url("../images/funclub/benefit-frame-right.svg");
}

.funclub__benefit-label-text {
  color: #6d5531;
  font-family: "Noto Sans JP", sans-serif;
  font-weight: 700;
  font-size: 1.5rem;
  letter-spacing: 0.02em;
  line-height: 1;
  /* Optical centring. The glyphs' ink is asymmetric about the baseline (.853em
     up, .091em down), so a line box centred in the frame still leaves the ink
     ~0.5px low against the brackets. The line box centre sits .4231em above the
     baseline and the ink centre .381em, hence the .042em difference. Moves the
     ink only - transform applies here because a flex item is blockified. */
  transform: translateY(-0.042em);
}

/* Condition line under a tag. Kept out of the bracket frame: inside it, the
   note stretched that tag to 380px against the other two at 148 and 268 - the
   brackets are meant to hold a short tag - and set the condition in the same
   1.3rem bold as the tag itself, so the two read as equally important. Out
   here it is quieter than the tag and quieter than the benefits it qualifies,
   which is the order it should be read in.

   Comp: a hairline pill around the words, set in the same gothic as the tag
   above it (the benefits it qualifies stay in the mincho). It used to be an
   underline in that mincho, bolded. inline-block so the pill wraps the
   sentence and not the column - the same reason the underline replaced a
   ruled ::before. */
.funclub__benefit-note {
  /* Takes the slot the first line of benefits would have had, so this column
     still starts level with the other two. */
  display: inline-block;
  margin-top: 0;
  padding: 0.1rem 0.85em 0.1rem;
  border: 1px solid currentColor;
  border-radius: 0.8rem;
  font-family: "Noto Sans JP", sans-serif;
  /* Numeric, not `lighter`: that resolves one step down from the inherited
     400, i.e. 100, and the kit carries no face that light - the match then
     fell back up to 700 and the note stayed bold. 400 is loaded for this
     (see the Google Fonts href in the head). */
  font-weight: 400;
  font-size: 1.2rem;
  letter-spacing: 0.06em;
  line-height: 1.5;
}

/* The note reads as the heading of the benefits under it, so nothing between
   them - the space above the note is the one that separates it from the tag. */
.funclub__benefit-note + .funclub__benefit-text {
  margin-top: 1rem;
}

.funclub__benefit-text + .funclub__benefit-text{
  margin-top: 1rem;
}

.funclub__benefit-text {
  margin-top: 1.6rem;
  font-size: 1.5rem;
  letter-spacing: 0.06em;
  line-height: 1.9;
}

.funclub__benefit-text small {
  font-size: 1rem;
  display: block;
  line-height: 1.2;
}


.funclub__benefit-text span.small {
  font-size: 1rem;
  line-height: 1.2;
}

/* 「…and more!」 as the designer drew it. Sized in em off the benefits it
   closes, so it keeps its weight against them on SP as well; the file's ink
   is already --c-paper-ink. */
.funclub__benefit-more {
  margin-top: 0.8rem;
  font-size: 1.4rem;
}

.funclub__benefit-more img {
  display: block;
  width: 5.2em;
  height: auto;
  margin-inline: auto;
}

/* The row's own breakpoint, well ahead of the page's 768px one. Side by side
   the three columns want ~1080px (the middle one alone wants ~380px), and the
   92vw cap starts biting into that at about 1175px - past there they can only
   fit by squeezing each other and breaking lines mid-word. Everything else on
   the paper still reads fine at those widths, so only this row stacks. */
@media (max-width: 1200px) {
  .funclub__benefit-list {
    display: block;
    width: auto;
    max-width: none;
    /* Centring is the block's own margins again once it is not over-wide. */
    left: auto;
    transform: none;
  }

  /* justify-self applies to plain block boxes too, so the grid's hug rules
     would shove these two out to the far left and right once stacked. */
  .funclub__benefit:first-child,
  .funclub__benefit:last-child {
    justify-self: auto;
  }

  .funclub__benefit + .funclub__benefit {
    margin-top: 3.5rem;
  }
}

/* ---------------- Button ---------------- */
.funclub__action {
  margin-top: 7.5rem;
}

/* Two pills stacked: the dark "詳細はこちら" and the outlined
   "NIGHT OWLS TOP" (--sub). Pill, text (outlined font), and on SP the
   arrow are baked into the images; the alt text carries the label. */
.funclub__btn {
  position: relative;
  display: block;
  width: fit-content;
  margin-inline: auto;
  transition: opacity 0.4s var(--ease-out);
}

/* Comp: 62px between the two pills. */
.funclub__btn + .funclub__btn {
  margin-top: 2.5rem;
}

.funclub__btn:hover {
  opacity: 0.75;
}

/* Live text on a CSS pill (replaces the baked PNG faces).
   Spec: Noto Sans JP ExtraBold, 14px PC / 13px SP, #6c5531 x #f0d9bc. */
.funclub__btn-face {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 63rem; /* 1260px @2x */
  height: 5rem;
  border-radius: 999px;
  background: #6c5531;
  color: #f0d9bc;
  font-family: "Noto Sans JP", sans-serif;
  font-weight: 800;
  font-size: 1.4rem;
  letter-spacing: 0.02em;
  line-height: 1;
  white-space: nowrap;
}

.funclub__btn--sub .funclub__btn-face {
  background: #f0d9bc;
  border: 0.2rem solid #6c5531;
  color: #6c5531;
}

/* Overlaid on the pill's empty right end so it can slide. Masked so each
   button tints it (cream on the dark pill, ink on the light one).
   Aspect ratio follows the SVG viewBox (40.79 x 13.2). */
.funclub__btn-arrow {
  position: absolute;
  top: 50%;
  right: 4.2rem;
  width: 4rem;
  aspect-ratio: 40.79 / 13.2;
  background: #f0d9bc;
  -webkit-mask: url("../images/funclub/arrow.svg") center / contain no-repeat;
  mask: url("../images/funclub/arrow.svg") center / contain no-repeat;
  translate: 0 -50%;
  transition: transform 0.55s var(--ease-out);
}

.funclub__btn--sub .funclub__btn-arrow {
  background: #6c5531;
}

.funclub__btn:hover .funclub__btn-arrow {
  transform: translateX(0.8rem);
}

/* ---------------- Props on the paper ---------------- */
.funclub__deco {
  position: absolute;
  z-index: 2;
  height: auto;
  pointer-events: none;
}

/* PC: horizontals anchor to the text column (.funclub__inner = centered
   min(100rem, 84%)), not the paper edges, so the props keep their distance
   from the copy at any screen width. calc(50% - min(50rem, 42%)) is the
   inner's edge reproduced in paper coordinates; the trailing rem is the
   offset from that edge (values match the previous look at 1280px). */
.funclub__deco--glasses {
  top: 37.5%;
  left: calc(45% - min(50rem, 42%) + 1rem);
  width: 12.5rem;
}

.funclub__deco--lantern {
  top: 60%;
  left: calc(45% - min(60rem, 42%) + 1rem);
  width: 9.5rem;
}

.funclub__deco--key {
  top: 42%;
  right: calc(45% - min(50rem, 42%) + 1.2rem);
  width: 12rem;
}

.funclub__deco--paw {
  right: calc(45% - min(50rem, 42%) - 3.1rem);
  bottom: 19%;
  width: 5.7rem;
}

@media (max-width: 1200px) {
  .funclub__deco--key{
    top: 46%;
    right: calc(45% - min(50rem, 42%) + 1.2rem);
    width: 12rem;
  }

  .funclub__deco--lantern {
    top: 60%;
    left: calc(45% - min(60rem, 42%) + 1rem);
    width: 7.5rem;
  }
}

/* Lantern: warm breathing glow + a slight hanging sway. Animates filter
   and the separate rotate property only, so it never fights the
   data-reveal opacity/transform transition (same for the props below —
   and the tail's GSAP entrance writes transform, which composes with
   the rotate property instead of clashing). The paw stays still: it is
   a stamped print, not an object. */
@media (prefers-reduced-motion: no-preference) {
  .funclub__deco--lantern {
    transform-origin: 50% 6%; /* swing from the handle */
    animation: lanternGlow 5.2s ease-in-out infinite;
  }

  .funclub__newopen {
    transform-origin: 12% 60%; /* wag from the tail base */
    animation: propSway 6.4s ease-in-out infinite;
  }

  .funclub__deco--glasses {
    animation: propTilt 7s ease-in-out infinite 1.2s;
  }

  .funclub__deco--key {
    transform-origin: 72% 40%; /* rock around the key's head */
    animation: propSway 5.6s ease-in-out infinite 0.7s;
  }
}

@keyframes propSway {
  0%, 100% { rotate: -2deg; }
  50%      { rotate: 1.6deg; }
}

@keyframes propTilt {
  0%, 100% { rotate: -1.3deg; }
  50%      { rotate: 1.1deg; }
}

@keyframes lanternGlow {
  0%, 100% {
    rotate: -1.2deg;
    filter:
      drop-shadow(0 0 1rem rgba(255, 198, 96, 0.35))
      drop-shadow(0 0 2.8rem rgba(255, 180, 70, 0.16));
  }
  50% {
    rotate: 1.2deg;
    filter:
      drop-shadow(0 0 1.6rem rgba(255, 208, 110, 0.6))
      drop-shadow(0 0 3.6rem rgba(255, 186, 80, 0.3));
  }
}

/* ================================================================ Light
 * Between FUN CLUB and LIVE: the light cut (with the side labels hanging
 * beside it) and the sky cut.
 * ================================================================ */
.light {
  /* Comp: 163px from the paper to the light photo. */
  margin-top: 16.3rem;
}

/* Light and hand (small, left-aligned cut). The side labels are positioned
   against this box. */
.light__inner {
  position: relative;
}

.figure--light {
  width: 26.5%;
  margin-left: 18%;
}

/* Sky cut (one tall image). */
.figure--sky {
  width: 39%;
  margin-top: 6.6rem;
  margin-left: 50%;
}

/* ================================================================ Live */
.live {
  position: relative;
}

/* Comp: 98px from the sky photos to the handwritten LIVE. */
.live__title {
  margin-top: 9.8rem;
}

/* Full-bleed blue-sky photo behind the announcement copy (comp: live.png).
   White text throughout; the photo is a smooth gradient so any crop reads fine. */
.live__info {
  margin-top: 5rem;
  padding: 9rem 5% 9rem;
  background: #1e6ea8 url("../images/live/live-bg-pc.webp?20260827") center / cover no-repeat;
  color: #fff;
  text-align: center;
  font-family: var(--font-serif);
  margin-bottom: 14rem;
}

/* Reveal name -> copy -> link one by one
   (the container itself never fades). */
.live__info[data-reveal] {
  opacity: 1;
  transform: none;
}

.live__info[data-reveal] > * {
  opacity: 0;
  transform: translate3d(0, 2.4rem, 0);
  transition: opacity 1.1s var(--ease-out), transform 1.1s var(--ease-out);
}

.live__info[data-reveal].is-shown > * {
  opacity: 1;
  transform: none;
}

.live__info[data-reveal].is-shown > :nth-child(2) { transition-delay: 0.12s; }
.live__info[data-reveal].is-shown > :nth-child(3) { transition-delay: 0.24s; }
.live__info[data-reveal].is-shown > :nth-child(4) { transition-delay: 0.36s; }

/* Name/title lockup (Aimer / Premium Concert 2026 / Sing like a Stray Cat
   / -hiss-) plus the hand-drawn leaf outline are all baked into live-logo
   (comp: live.png) — the real text stays for accessibility only. */
.live__name-mark {
  display: block;
  width: min(58rem, 78%);
  margin: 0 auto;
  height: auto;
}

/* Description (mincho, small). Two paragraphs: the intro copy, then the
   FC line with a blank-line gap above it (comp: live.png). */
.live__desc {
  margin-top: 4.6rem;
  font-family: var(--font-mincho);
  font-size: 1.6rem;
  letter-spacing: 0.06em;
  line-height: 2.5;
}

.live__desc--fc {
  margin-top: 2.4rem;
}

.live__desc-em {
  text-decoration: underline;
  text-underline-offset: 0.3em;
  transition: opacity 0.4s var(--ease-out);
}

.live__desc-em:hover {
  opacity: 0.75;
}

/* Right edge lines up with .title-row's own margin (10.9%), not
   .live__info's padding (5%). Both are % of .live__info's own content
   width, so the gap = (10.9 - 5) / (100 - 2*5) * 100 = 6.56%. */
.live__action {
  margin-top: 4.6rem;
  text-align: right;
  margin-right: 6.56%;
}

/* ================================================================ Release */
.release {
  /* Comp: 102px from the sand photo to the handwritten RELEASE. */
  padding-top: 10.2rem;
}

.release__title {
  margin-bottom: 8rem;
}

.release__panel {
  position: relative;
  /* Creates its own stacking context: the body needs z-index above the
     photo, but without this it would also stack above the header. */
  z-index: 0;
  /* Align with the title rule (10.9% each side). */
  width: 70%;
  margin-left: 15%;
}

.release__image {
  width: 100%;
  height: auto;
}

.release__body {
  position: absolute;
  /* Comp: album name around 33% of the panel height. */
  top: 20%;
  left: 0;
  width: 100%;
  text-align: center;
  color: #fff;
  z-index: 2;
}

.release__album {
  font-family: var(--font-serif);
  font-size: 2rem;
  letter-spacing: 0.14em;
  line-height: 1.6;
}

.release__soon {
  margin-top: 2rem;
  font-family: var(--font-serif);
  font-size: 1.5rem;
  letter-spacing: 0;
}

/* ---------------- Credit ---------------- */
.release__credit {
  margin: 4rem 10.9% 0;
  font-family: var(--font-serif);
}

/* inline-flex + no width: the hit area hugs the label instead of
   stretching across the whole row. */
.release__credit-title {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  font: inherit;
  font-size: 1rem;
  letter-spacing: 0.12em;
  text-align: left;
  cursor: pointer;
}

/* Chevron mask that flips 180deg when the panel is open. */
.release__credit-icon {
  display: block;
  width: 1rem;
  aspect-ratio: 6 / 3;
  flex: none;
  background: currentColor;
  -webkit-mask: url("../images/common/credit-arw.svg") center / contain no-repeat;
  mask: url("../images/common/credit-arw.svg") center / contain no-repeat;
  transition: transform 0.5s var(--ease-out);
  transform: rotate(180deg);
}

.release__credit-title[aria-expanded="true"] .release__credit-icon {
  transform: rotate(0deg);
}

/* Height is animated by JS (main.js: initCreditAccordion), which measures
   the content and tweens with GSAP — a CSS-only grid-rows transition can't
   resolve an intrinsic (auto) end height reliably. Starts open so content
   stays reachable with JS disabled; JS collapses it on init. */
.release__credit-collapse {
  overflow: hidden;
  margin-top: 2.4rem;
}

.release__credit-item + .release__credit-item {
  margin-top: 2.4rem;
}

.release__credit-item dt {
  font-size: 0.9rem;
  letter-spacing: 0.14em;
  line-height: 1.6;
  opacity: 0.85;
}

.release__credit-item dd {
  margin-top: 0.3rem;
  font-size: 1rem;
  letter-spacing: 0.06em;
  line-height: 1.5;
}

/* ================================================================ Sub pages
 * Hero shared by the second-level pages (comp: LIVE, 1280 base).
 * The blue sky the top page's LIVE block already uses, with the site logo in
 * the top-left corner and the page's own title row beneath it.
 * ================================================================ */
.sub-hero {
  /* Comp: 32px from the top of the page to the logo. */
  padding: 3.2rem 0 12rem;
  /* Same sky, same fallback colour as .live__info on the top page. */
  background: #1e6ea8 url("../images/live/live-bg-pc.webp?20260827") center / cover no-repeat;
  color: #fff;
}

/* Comp: the asset at 1:1 (282x69) sitting 38px in from the left edge.
   Fluid below the comp width so it never crowds a narrow window, capped at
   its natural size above it - the header mark it sits opposite is a fixed
   size too, and a logo that grows with the viewport would dwarf it. */
.sub-hero__logo {
  width: 22%;
  max-width: 28.2rem;
  margin-left: 3.8rem;
}

/* The logo is the way back to the top page. */
.sub-hero__logo-link {
  display: block;
  transition: opacity 0.4s var(--ease-out);
}

.sub-hero__logo-link:hover {
  opacity: 0.75;
}

.sub-hero__logo-image {
  display: block;
}

.sub-hero__logo-image svg {
  display: block;
  width: 100%;
  height: auto;
}

/* Comp: the rule sits 217px down the page, i.e. 116px below the logo. */
.sub-hero__title {
  margin-top: 12rem;
}

/* ================================================================ Footer */
.footer {
  padding: 10rem 10.9% 8.8rem;
  font-family: var(--font-serif);
  font-size: 1.2rem;
  letter-spacing: 0.04em;
  line-height: 1.6;
  text-align: right;
}

/* ================================================================ More (shared view-more link) */
.more {
  display: inline-flex;
  align-items: center;
  gap: 1.6rem;
  font-family: var(--font-serif);
  font-size: 1.7rem;
  letter-spacing: 0.12em;
  line-height: 1;
}

.more--paper {
  color: var(--c-paper-ink);
}

/* Hand-drawn arrow as a mask; follows the text color. */
.more__arrow {
  display: block;
  width: 5.5rem;
  aspect-ratio: 28.21 / 6.29;
  background: currentColor;
  -webkit-mask: url("../images/common/icon-arw.svg") center / contain no-repeat;
  mask: url("../images/common/icon-arw.svg") center / contain no-repeat;
  transition: transform 0.55s var(--ease-out);
}

.more:hover .more__arrow {
  transform: translateX(0.8rem);
}

.more__label {
  position: relative;
}

.more__label::after {
  content: "";
  position: absolute;
  right: 0;
  bottom: -0.35em;
  left: 0;
  height: 1px;
  background: currentColor;
  transform: scaleX(0);
  transform-origin: right center;
  transition: transform 0.5s var(--ease-out);
}

.more:hover .more__label::after,
.more:focus-visible .more__label::after {
  transform: scaleX(1);
  transform-origin: left center;
}

/* ================================================================ Scribble (blacked-out unannounced info) */
.scribble {
  display: inline-block;
  height: auto;
  vertical-align: -0.3em;
}

/* The SVG is inlined into the span by JS (so the boil filter animates on
   iOS); size the root like the <img> it replaces. */
.scribble svg {
  display: block;
  width: 100%;
  height: auto;
}

.scribble--live  { width: 55.5rem; max-width: 100%; }
.scribble--album { width: 14.5rem; vertical-align: -0.25em; }

/* ================================================================ Side labels
 * Vertical text on the right edge: "Aimer / 15th Anniversary Project /
 * "Noraneko"" as one unit, spaced with flex gap.
 * In vertical-rl the line axis runs top-down, so flex-direction stays row.
 * ================================================================ */
.side-labels {
  position: absolute;
  display: flex;
  flex-wrap: nowrap;
  flex-direction: row;
  gap: 14rem;
  writing-mode: vertical-rl;
  /* All-Latin labels: rotate every glyph together. Without this the curly
     quotes around “NORANEKO” take their upright vertical forms and look
     mismatched with the rotated letters. */
  -webkit-text-orientation: sideways;
  text-orientation: sideways;
  font-family: var(--font-serif);
  font-size: 1.6rem;
  letter-spacing: 0.08em;
  line-height: 1;
  white-space: nowrap;
  pointer-events: none;
  z-index: 9;
}

.side-labels__item {
  display: block;
}

/* Items fade in one by one, top to bottom (not the container). */
.side-labels[data-reveal] {
  opacity: 1;
  transform: none;
}

.side-labels[data-reveal] .side-labels__item {
  opacity: 0;
  transform: translate3d(0, 1.6rem, 0);
  transition: opacity 1.1s var(--ease-out), transform 1.1s var(--ease-out);
}

.side-labels[data-reveal].is-shown .side-labels__item {
  opacity: 1;
  transform: none;
}

.side-labels[data-reveal].is-shown .side-labels__item:nth-child(2) { transition-delay: 0.18s; }
.side-labels[data-reveal].is-shown .side-labels__item:nth-child(3) { transition-delay: 0.36s; }

/* Costume cut: in the whitespace right of the photo, hanging outside it
   (comp: 62% from the photo top, 25% outside on the right, 14rem gaps). */
.side-labels--costume {
  bottom: -25rem;
  right: -83%;
}

/* LIVE: beside the sky cuts, scattered top to bottom. */
.side-labels--live {
  top: -5rem;
  right: 12%;
  gap: 15rem;
}

/* RELEASE: outside the panel's right edge. */
.side-labels--release {
  bottom: 0;
  right: -3rem;
  gap: 22rem;
  z-index: 1;
}

/* ================================================================ Live page (/live/)
 * Comp: PC_2_LIVE (1280 base) / SP_2_LIVE (393 base).
 * The whole page - hero, body and footer - sits on one sky gradient, so the
 * sub-hero's own sky is turned off and there is no seam under it.
 * ================================================================ */
.sky {
  /* Own stacking context so the fixed sky below can sit behind the content
     (z-index -1) without dropping under the body. */
  position: relative;
  z-index: 0;
  background: #1e6ea8;
  color: #fff;
}

/* The sky stays put while the page scrolls over it. A fixed pseudo-element
   rather than background-attachment: fixed, which iOS ignores (and sizes
   the image to the whole page instead of the viewport). Overhangs the
   viewport like the loader does, so the iOS toolbar geometry never leaves
   a band of body colour at the top or bottom. */
.sky::before {
  content: "";
  position: fixed;
  inset: -12vh 0;
  z-index: -1;
  background: #1e6ea8 url("../images/live/singe-bg-pc.webp?v=20260902") center / cover no-repeat;
  pointer-events: none;
}

/* The KV canvas as the sky: fixed like the CSS sky and painted over it
   (same z-index, later in the tree). Hidden when WebGL is out (.is-nogl,
   main.js), which leaves the CSS sky showing. */
.sky__canvas {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100vh;
  height: 100lvh;
  z-index: -1;
  pointer-events: none;
}

.sky.is-nogl .sky__canvas {
  display: none;
}

/* The page's content shows through the sky's clearing: main is masked by
   a cloud-shaped hole (haze-blob.png, a soft disc torn up by noise) that
   grows from the KV entrance's own centre (46% up from the bottom) on its
   timing - the shader's front is at radius (1.55u - 0.48)/0.92 of the
   viewport width for uReveal u, which is nothing until u = 0.31 (0.85s of
   the 2.1s power2.inOut run) and then sweeps out; the hole follows a beat
   behind, so words and pictures surface inside the cleared sky. Once the
   sweep is past the viewport the mask is dropped (body.is-settled, main.js)
   so scrolling is not masked. */
@property --haze-s {
  syntax: "<length>";
  inherits: false;
  initial-value: 0px;
}

/* Second mask layer: a plain rectangle over the site logo in the top-left
   corner, so the logo is outside the sweep and writes itself early, as the
   KV catch does. Sized to clear the logo and stop above the LIVE rule. */
body[data-page] .main {
  --haze-s: 0px;
  -webkit-mask-image: url("../images/common/haze-blob.png?v=20260902"), linear-gradient(#000, #000);
  mask-image: url("../images/common/haze-blob.png?v=20260902"), linear-gradient(#000, #000);
  -webkit-mask-repeat: no-repeat, no-repeat;
  mask-repeat: no-repeat, no-repeat;
  -webkit-mask-size: var(--haze-s) var(--haze-s), 36rem 11rem;
  mask-size: var(--haze-s) var(--haze-s), 36rem 11rem;
  -webkit-mask-position: 50% calc(54vh - var(--haze-s) / 2), 0 0;
  mask-position: 50% calc(54vh - var(--haze-s) / 2), 0 0;
  transition: --haze-s 1.3s cubic-bezier(0.25, 0.1, 0.25, 1) 0.9s;
}

body[data-page]:not(.is-loading) .main {
  --haze-s: 330vw;
}

body[data-page].is-settled .main {
  -webkit-mask-image: none;
  mask-image: none;
}

/* ---------------------------------------------------------- No loader
   The LIVE page opens with no cover (body[data-loader="off"], see main.js).
   The cloud sweep is the loader's own opening carried on into the page, so
   with nothing to carry on from it is dropped: the content is simply there,
   with a short fade so it does not snap in, and the page scrolls at once.
   main.js sets .is-settled up front, which already takes the mask off - this
   also keeps it off for the frames before the module has run. */
body[data-loader="off"] .main {
  -webkit-mask-image: none;
  mask-image: none;
  transition: none;
  animation: page-in 0.4s var(--ease-out) both;
}

body[data-loader="off"] .footer {
  opacity: 1;
  transition: none;
}

@keyframes page-in {
  from { opacity: 0; }
  to   { opacity: 1; }
}

/* The KV canvas is opaque (alpha:false), so it is black until its first draw
   and its first drawn frame is the entrance's ground colour. With no loader
   in front of it, hold it clear and let .sky::before - the same photo - stand
   in until main.js has the finished frame on the canvas. */
body[data-loader="off"] .sky__canvas {
  opacity: 0;
}

body[data-loader="off"].is-kv-ready .sky__canvas {
  opacity: 1;
  transition: opacity 0.6s var(--ease-out);
}

@media (prefers-reduced-motion: reduce) {
  body[data-loader="off"] .main {
    animation: none;
  }
}

/* The footer is below the fold: a plain fade once the sky has cleared. */
body[data-page] .footer {
  opacity: 0;
  transition: opacity 1.4s var(--ease-out) 1.9s;
}

body[data-page]:not(.is-loading) .footer {
  opacity: 1;
}

@media (prefers-reduced-motion: reduce) {
  body[data-page] .main {
    -webkit-mask-image: none;
    mask-image: none;
    transition: none;
  }

  body[data-page] .footer {
    opacity: 1;
    transition: none;
  }
}

.sky .sub-hero {
  background: none;
  /* The block below sets its own distance from the rule (comp: 107px),
     so the hero's generic bottom padding would only double it. */
  padding-bottom: 0;
}

/* Everything sits inside the title rule's own inset (10.9%), like the rows. */
.concert {
  margin-inline: 10.9%;
}

/* Leaf lockup left (comp: 540 of the 1001px content width), info lockup
   flush right (430px - the SVG's own size), tops level, 107px below the rule. */
.concert__head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 3%;
  margin-top: 11.6rem; /* comp: leaf top 116px under the rule */
}

.concert__logo {
  flex: 0 0 54%;
  max-width: 54%;
}

.concert__logo-image {
  width: 100%;
  height: auto;
}

/* Date / venue / times / ticket lockup (buntai-tite.svg, 435x338). */
.concert__info {
  flex: 0 0 43%;
  max-width: 43%;
}

.concert__info-image {
  width: 100%;
  height: auto;
}

/* ---------------------------------------------------------------- Presale table
 * Header strip (rule above and below, dividers between) and the boxed row
 * are one table; the gap between them is an empty spacer row. */
.ticket-table {
  width: 100%;
  margin-top: 7rem; /* comp: header strip 73px under the leaf */
  border-collapse: collapse;
  table-layout: fixed;
  /* 平成角ゴシック StdN (Adobe Fonts: heisei-kaku-gothic-stdn). The family
     ships as W5 only, and the kit carries exactly that one face at 500 -
     asking for 700 would only get the browser's smeared faux bold, so the
     real weight is used. Noto Sans JP stands in until the kit lands. */
  font-family: "heisei-kaku-gothic-stdn", "Noto Sans JP", sans-serif;
  font-weight: 500;
  font-synthesis: none;
  line-height: 1.5;
  text-align: center;
}

/* Comp: 320 / 504 / 173 of the 1001px content width. */
.ticket-table__col--name   { width: 32%; }
.ticket-table__col--period { width: 50%; }
.ticket-table__col--url    { width: 18%; }

/* Header strip (comp: 23px tall): open at the top, ruled below, with
   uprights the strip's own height rising from the rule at both ends and
   between the columns. 13px text centred in the strip, 8px in from the
   upright. The uprights are the cells' own borders: collapsed borders share
   the grid lines with the boxed row below, so both sets of lines sit on the
   same pixels (a pseudo-element landed half a pixel off). */
.ticket-table th {
  height: 2.3rem;
  padding: 0 0 0.5rem 1rem;
  border: 1px solid currentColor;
  border-top: 0;
  vertical-align: middle;
  font-size: 1.3rem;
  letter-spacing: 0.06em;
  line-height: 1;
  text-align: left;
}

/* The spacer between the header strip and the boxed row (comp: 19px). */
.ticket-table tbody::before {
  content: "";
  display: table-row;
  height: 1.8rem;
}

/* The boxed row: 75px tall with 22px text, 25px in from the uprights,
   everything (the URL too) set left. */
.ticket-table td {
  padding: 2.1rem 2.5rem;
  border: 1px solid currentColor;
  font-size: 2.0rem;
  letter-spacing: 0.06em; /* tracking 60, as the top page's LIVE copy */
  text-align: left;
}

/* 平成角ゴシック StdN only ships W5; the comp is set in W7. A thin stroke
   in the text colour thickens every glyph evenly - unlike the browser's
   faux bold, which smears - and reads close to the heavier cut. */
.ticket-table th,
.ticket-table td {
  -webkit-text-stroke: 0.035em currentColor;
  paint-order: stroke fill;
}

/* The day in brackets is set smaller than the date it follows
   (comp: 16px against the cell's 22px), and never breaks across a line -
   （水・祝） was splitting after the 「・」 in the SP cell.
   The negative margin is the comp's 括弧の詰め: a full-width bracket carries
   half an em of white on its outer side, which at this size leaves a hole
   next to the date.
   Sharing a baseline with type this much larger leaves the small run sitting
   low, so it is lifted onto the date's optical centre: its own ink centres
   0.38em above the baseline against the date's 0.36em, which at 16px in a
   22px line is 0.11em of its own size. Same trick as the colon below -
   inline-block, because a transform does nothing to an inline box. */
.ticket-table__dow {
  display: inline-block;
  font-size: 1.5rem;
  margin-inline: -0.2em;
  white-space: nowrap;
}

/* Between two figures this colon reads as sitting low: its ink centres about
   0.34 of the digits' height above the baseline, where the digits centre at
   0.49 - so lift it by the difference and it sits on their optical centre,
   as the comp sets it. inline-block because a transform does nothing to an
   inline box. */
.ticket-table__colon {
  display: inline-block;
  transform: translateY(-0.1em);
}

.ticket-table__link {
  text-decoration: underline;
  text-underline-offset: 0.3em;
  transition: opacity 0.4s var(--ease-out);
}

.ticket-table__link:hover {
  opacity: 0.75;
}

/* Note under the boxed rows (added 2026-09-16): set in the strip's 13px,
   left like the cells, one leading's worth below the last rule. */
.ticket-table__note {
  margin-top: 1.4rem;
  font-family: "heisei-kaku-gothic-stdn", "Noto Sans JP", sans-serif;
  font-weight: 500;
  font-synthesis: none;
  font-size: 1.3rem;
  letter-spacing: 0.06em;
  line-height: 1.8;
  text-align: left;
}

.ticket-table__small {
  font-size: 1.5rem;
  line-height: 1.6;
  display: inline-block;
}

/* ---------------------------------------------------------------- Attention */
.attention {
  margin-top: 5.5rem;
  font-family: var(--font-mincho);
}

.attention__title {
  font-family: var(--font-serif);
  font-size: 2.4rem;
  letter-spacing: 0.06em;
  line-height: 1;
}

/* Comp: 注意事項 sits 45px (baseline to baseline) under -ATTENTION-,
   the items 34px under their heading at 29px leading, groups 74px apart. */
.attention__group {
  margin-top: 2rem;
}

.attention__group + .attention__group {
  margin-top: 4.8rem;
}

.attention__head {
  font-size: 1.6rem;
  letter-spacing: 0.06em;
  line-height: 1.6;
}

.attention__list {
  margin-top: 0.7rem;
  font-size: 1.3rem;
  letter-spacing: 0.06em;
  line-height: 2.15; /* comp: 28px leading */
}

/* Hanging bullets. The dot is drawn, not typed: a typed 「・」 sits in the
   middle of its box, so its ink lands a few px in from the heading's face.
   A drawn dot starts exactly on the face, and a wrapped line starts under
   the text (comp: 8px in from the dot). */
.attention__list li {
  position: relative;
  padding-left: 0.6em;
  text-indent: 0;
}

.attention__list li::before {
  content: "";
  position: absolute;
  top: 0.98em;
  left: 0;
  width: 0.17em;
  height: 0.17em;
  border-radius: 50%;
  background: currentColor;
}

/* A note on the item above it rather than an item of its own: it types its
   own 「※」, so the drawn dot would double up. With the dot gone there is
   nothing left to hang from either, so the indent goes too and the 「※」
   takes the dot's place on the left edge. (SP sets no indent to begin with
   and the dot is a typed 「・」 there - killing the pseudo-element covers
   both.) */
.attention__list li.attention__note {
  padding-left: 0;
}

.attention__list li.attention__note::before {
  content: none;
}

/* ---------------------------------------------------------------- Credits
 * One rule, the three items spread across it. */
.credit {
  display: flex;
  justify-content: space-between;
  gap: 2rem;
  margin-top: 6.3rem; /* comp: rule 64px under the last line */
  padding-top: 1.4rem; /* comp: text 20px under the rule */
  border-top: 1px solid currentColor;
  font-family: var(--font-serif);
  font-size: 1.6rem;
  letter-spacing: 0.06em;
  line-height: 1.6;
}

.credit__item {
  display: flex;
}

/* The three items are set text at a fixed size, so their width does not
   follow the viewport: spread across the rule they run out of room at about
   890px and the lines start breaking inside each item. Well before that the
   rule reads as cramped rather than spread, so from here they are centred
   instead, wrapping as whole items if it ever comes to that.
   The copyright follows the same switch: right-aligned under a centred rule
   reads as a mistake. Only on this page - the top page's footer sits under a
   left-aligned block and stays right. */
@media (max-width: 1024px) {
  .credit {
    flex-wrap: wrap;
    justify-content: center;
    gap: 0.6rem 3rem;
  }

  .sky .footer {
    text-align: center;
  }
}

/* ================================================================ SP */
@media (max-width: 768px) {

  /* -------------------------------------------------- header / menu */
  /* Comp: cat ~34px, button ~32px, 10px right margin (much smaller than PC). */
  .header {
    top: 1.8rem;
    right: 1rem;
    gap: 0rem;
  }

  .header__mark { width: 3.4rem; }

  .header__toggle-icon { width: 3.2rem; }

  .menu__item--top      { top: 13.5%;  left: 36.3%; width: 15.6%; }
  .menu__item--manifest { 
    top: 26.1%;
    left: 44.5%;
    width: 41.1%;
  }
  .menu__item--funclub  { top: 42.4%;  left: 12.5%; width: 38.2%; }
  .menu__item--live     { top: 56.3%;  left: 46.8%; width: 34.6%; }
  .menu__item--release  { top: 78.3%;  left: 13.5%; width: 44%; }

  /* SP comp tilts RELEASE more than PC (comp -16.7deg / asset -6.1deg). */
  .menu__item--release .menu__link {
    transform: rotate(-10.6deg);
    transform-origin: left center;
  }

  /* NEW badge: different values on SP (comp: upper-right of the word's
     end, never covering the letters). Reference size is RELEASE's 31% of
     44% = 13.6% of the menu; MANIFEST and LIVE end within ~12% of the
     right edge, so their badge is pulled back over the word's last letter
     instead of hanging past it, which would run off screen. */
  .menu__badge {
    top: -75%;
    left: 100%;
    width: 31%;
  }

  .menu__item--manifest .menu__badge {
    top: -53%;
    left: 100%;
    width: 25.2%;
  }

  .menu__item--live .menu__badge {
    top: -11%;
    left: 103%;
    width: 39.4%;
  }

  /* -------------------------------------------------- kv */
  .kv {
    height: 100svh;
  }

  .kv.is-nogl {
    background-image: url("../images/kv/kv-01-sp.webp");
  }

  .kv__catch {
    top: 9%;
    left: 6.5%;
    width: 80%;
  }

  .kv__catch-image--pc { display: none; }
  .kv__catch-image--sp { display: block; }

  .kv__scroll {
    right: 2.6rem;
    gap: 1.2rem;
  }

  .kv__scroll-arrow { height: 9.6rem; }

  /* -------------------------------------------------- message */
  /* Layout (flow, no stacking) is shared with PC in the base styles. */
  .kv {
    min-height: 64rem;
  }

  .message{
    padding:9rem 0 7rem;
  }

  .message__inner {
    width: 88%;
    margin-left: 6%;
  }

  .message__sign {
    width: 12.5rem;
    margin: 1.2rem 0 0 auto;
  }

  /* -------------------------------------------------- figure */
  /* Comp: x0-265 (67.4% wide, bleeding off the left edge). */
  .figure--costume { width: 100%; }
  .figure--costume img { width: 67%; }

  .figure--cliff {
    /* Comp: x100-393 (74.6% wide, right bleed), 57px below the item above. */
    width: 76%;
    margin: 7.2rem 0 0 auto;
  }

  .figure--light {
    /* SP comp: small, left-aligned. */
    width: 42%;
    margin: 8rem 0 0 6%;
  }

  .figure--sky {
    width: 63%;
    margin-top: 9rem;
    margin-left: 32%;
  }

  /* SP comp band. Taller than the PC one, so the photo is cropped ~12% at each
     side to fill it - the figure sits well inside that. The vertical crop is
     unchanged (it comes from the img's own 110%). */
  .figure--band {
    aspect-ratio: 786 / 360;
  }

  /* -------------------------------------------------- sub page hero
     No SP comp yet: the logo takes the width the KV catch does on SP, and
     the row lines up with the 5% the title rows use down here. */
  .sub-hero {
    padding: 2.4rem 0 8rem;
  }

  .sub-hero__logo {
    width: 58%;
    max-width: none;
    margin-left: 5%;
  }

  .sub-hero__title {
    margin-top: 6.4rem;
  }

  /* -------------------------------------------------- title rows */
  .title-row {
    margin-inline: 5%;
  }

  .title-row__label {
    padding-left: 1.3rem;
    font-size: 1rem;
    letter-spacing: 1.05em;
  }

  /* Centered; widths equalize ink height (see the PC block). */
  .title-row__art--manifest { width: 72%; margin-inline: auto; margin-bottom: 0;}
  .title-row__art--funclub  { width: 59%; margin-inline: auto; margin-bottom: -0.5rem;}
  .title-row__art--live     { width: 45%; margin-inline: auto; margin-bottom: -0.7rem;}
  .title-row__art--release  { width: 58%; margin-inline: auto; margin-bottom: -0.6rem;}

  /* -------------------------------------------------- manifest */
  .manifest {
    /* Comp: the rule sits ~199px below the costume photo; subtract the
       handwritten title height (~57px) for the padding. */
    padding: 10rem 0 0;
  }

  .manifest__list {
    margin-top: 3.4rem;
    margin-inline: 5%;
  }

  .manifest__item + .manifest__item { margin-top: 2.8rem; }

  .manifest__head {
    padding: 0 0 0.6rem 5.4rem;
  }

  .manifest__head::before { height: 1.4rem; }

  .manifest__num {
    left: 1.2rem;
    font-size: 1.5rem;
  }

  .manifest__head::after {
    bottom: -1.7rem;
    width: 2.9rem;
    height: 3.1rem;
  }

  .manifest__name {
    font-size: 1.6rem;
    letter-spacing: 0.95em;
  }

  .manifest__lead {
    margin: 1rem 0 0 5.4rem;
    font-size: 1.5rem;
    white-space: normal;
  }

  .manifest__masked { margin-left: 5.4rem; }

  /* -------------------------------------------------- funclub */
  .funclub { padding-top: 10rem; margin-bottom: 8rem;}

  .funclub__title { margin-bottom: 4.4rem; }

  .funclub__paper {
    padding: 5rem 0 7rem;
  }

  .funclub__newopen {
    top: 2rem;
    left: 0;
    width: 38%;
  }

  .funclub__inner {
    width: 92%;
  }

  .funclub__logo { width: 14.4rem; }

  .funclub__divider { width: 16rem; max-width: 90%; margin-top: 2.2rem; }

  .funclub__heading {
    margin-top: 3.4rem;
    font-size: 1.55rem;
    letter-spacing: 0.06em;
  }

  /* Undo the PC anti-wrap widening. */
  .funclub__body {
    margin-top: 2rem;
    margin-inline: 0;
  }

  .funclub__text {
    font-size: 1.2rem;
    letter-spacing: 0.06em;
    line-height: 2;
  }

  .funclub__text + .funclub__text { margin-top: 1.8em; }

  /* Single column on SP. */
  .funclub__benefits { margin-top: 4rem; }

  /* The line that overflows its column on PC wraps normally on SP. */
  .funclub__benefit--wide .funclub__benefit-text { white-space: normal; }

  .funclub__benefits-title { width: 25rem; }

  .funclub__benefit-list { margin-top: 1.8rem; }

  /* Kept from the fixed frame: a tag still only ever runs to one line here,
     but a longer one in future should push the frame rather than spill out. */
  .funclub__benefit-label {
    height: auto;
    min-height: 2.2rem;
  }

  .funclub__benefit-label-text {
    line-height: 1.4;
  }

  .funclub__benefit-note {
    font-size: 0.8em;
  }

  .funclub__benefit-text {
    margin-top: 0.rem;
    font-size: 1.5rem;
    letter-spacing: 0em;
  }

  /* 「会報誌」と誌名の間だけ、SP でもう四分アキ足す。ここは letter-spacing を
     0 にしてあるぶん、半角スペース + 『 自身の左アキ（合わせて 0.86em）だけ
     では詰まって見える。PC は現状のまま、SP だけ 1.11em 相当になる。 */
  .funclub__mag {
    margin-left: 0.25em;
  }

  .funclub__benefit-more {
    font-size: 1.5rem;
  }

  .funclub__action { margin-top: 6rem; }

  /* The SP images bake the arrow in (the overlay arrow is PC-only).
     Comp: 348px wide — wider than the 84% inner, so bleed evenly to both
     sides (never past the viewport on narrow phones). */
  /* Cap at the comp width; on narrow screens fall back to the same 90vw
     the section titles use (title-row: 5% margin each side). */
  .funclub__btn {
    width: min(34.8rem, 90vw);
    margin-inline: calc((100% - min(34.8rem, 90vw)) / 2);
  }

  /* Comp: 40px between the two pills. */
  .funclub__btn + .funclub__btn { margin-top: 2rem; }

  /* Text pills, SP: left-aligned label with the arrow on the right
     (per the SP comp); the long detail label wraps to two lines. */
  .funclub__btn-face {
    width: 100%;
    height: auto;
    min-height: 7rem;
    justify-content: flex-start;
    padding: 1.2rem 6.4rem 1.2rem 3.4rem;
    font-size: 1.4rem;
    line-height: 1.55;
    white-space: normal;
    text-align: left;
  }

  .funclub__btn-arrow {
    right: 3rem;
    width: 3.5rem;
  }

  /* Tops in rem from the paper top, not %: everything above the props is
     fixed-height on SP, while the buttons at the bottom get taller on
     narrow screens — % tops drifted the props onto the text at some
     widths. Values retaken from the SP comp (with small shifts where the
     web line widths would otherwise collide). Retune if the copy above
     changes. */
  .funclub__deco--glasses {
    top: 35rem; /* comp: beside the 「意味は…」 line */
    left: 3.8%;
    width: 6.2rem;
  }

  .funclub__deco--lantern {
    top: 77rem; /* comp: beside 「入会特典」〜ボイスメッセージ */
    left: 2.4rem;
    width: 5.3rem;
  }

  .funclub__deco--key {
    /* Comp puts it fully inside; kept slightly off-edge because the web
       lines run wider than the comp's and would graze it on ~375px. */
    top: 47rem; /* beside 「不定期ラジオなど。〜スタッフやAimerによる」 */
    right: 1.2rem;
    width: 6.8rem;
  }

  .funclub__deco--paw {
    top: 105rem; /* beside 「入会1年後に…」, above the button */
    right: 7.6%;
    bottom: auto;
    width: 3.7rem;
  }

  /* -------------------------------------------------- light */
  .light { margin-top: 12rem; }

  /* -------------------------------------------------- live */
  .live__title { margin-top: 7rem; }

  .live__info { 
    margin-top: 4rem; 
    padding: 6rem 8% 6rem; 
    margin-bottom: 7rem;
  }

  .live__name-mark { width: 86%; }

  .live__desc {
    margin-top: 3.4rem;
    font-size: 1.25rem;
    line-height: 2.5;
  }

  .live__desc--fc {
    margin-top: 1.8rem;
  }

  /* SP .title-row margin is 5%, narrower than .live__info's own 8%
     padding, so the gap here is negative: (5 - 8) / (100 - 2*8) * 100
     = -3.57% (pulls right, past .live__info's padding). */
  .live__action {
    margin-top: 3.2rem;
    margin-right: -3.57%;
  }

  /* -------------------------------------------------- release */
  .release { padding-top: 8rem; }

  .release__title { margin-bottom: 3.5rem; }

  .release__panel {
    width: 80%;
    margin-left: 9%;
  }

  .release__body { top: 20%; }

  .release__album { font-size: 1.3rem; }

  .release__soon {
    margin-top: 1.8rem;
    font-size: 1rem;
  }

  .release__credit {
    margin: 4rem 5% 0;
  }
  .release__credit-collapse {
    margin-top: 1.8rem;
  }

  .release__credit-item + .release__credit-item{
    margin-top: 1.8rem;
  }

  .release__credit-title { font-size: 1.2rem; }

  .release__credit-item dt { font-size: 0.8rem; }
  .release__credit-item dd { font-size: 1.2rem; }

  /* SP comp: the LIVE bar runs ~289x37 — the artwork squashed much
     thicker than its natural 550:27 ratio (preserveAspectRatio="none"
     in scribble01.svg allows the stretch). ALBUM keeps its natural
     ratio, just larger than before (comp: ~157px wide). */
  .scribble--live  { width: 100%; max-width: 29rem; height: 3.7rem; }
  .scribble--live svg { height: 100%; }
  .scribble--album { width: 15.5rem; }

  /* -------------------------------------------------- side labels / footer */
  .side-labels {
    gap: 8rem;
    font-size: 0.8rem;
  }

  .side-labels--costume {
    bottom: -10%;
    right: 8%;
    gap: 6.5rem;
  }

  .side-labels--live {
    top: 4%;
    right: 6%;
    gap: 6.5rem;
  }

  .side-labels--release {
    bottom: -2rem;
    right: -2rem;
    gap: 6.5rem;
  }

  .footer {
    padding: 6rem 5.7% 4rem;
    font-size: 1rem;
  }

  .more { font-size: 1.3rem; gap: 1.2rem; }


  /* -------------------------------------------------- live page (/live/) */
  .sky::before {
    background-image: url("../images/live/singe-bg-sp.webp?v=20260902");
    /* Cover crops the sides on tall phones; keep the right edge (the
       contrail) rather than the centre. */
    background-position: right center;
  }

  .concert {
    margin-inline: 5%;
  }

  /* Stacked and centred. */
  .concert__head {
    flex-direction: column;
    align-items: center;
    gap: 0;
    margin-top: 6rem; /* comp: leaf 60px under the rule; the SVG has no top inset */
  }

  /* live-head-sp.svg runs the width of the title rule (the block's own
     5% inset), not the viewport. */
  .concert__logo {
    flex: none;
    width: 100%;
    max-width: none;
  }

  /* ticket-sp.svg: 指定席 ¥9,500（税込） runs 169px wide at 393px, i.e. 48%
     of the block; 42px under the times line. */
  .concert__info {
    flex: none;
    width: 51%; /* comp: 指定席 ¥9,500（税込） runs 180px at 393px */
    max-width: none;
    margin-top: 3.6rem; /* comp: -TICKET- 39px under the times line */
  }

  /* Equal thirds, text left in the cells (comp: 47px under the notes,
     ~7px of which ticket-sp.svg carries itself). */
  .ticket-table {
    margin-top: 4.3rem; /* comp: 51px under the notes */
    text-align: left;
  }

  /* The comp sets equal thirds, but only because its 括弧 are tucked tighter
     than web text can be: at 33.3% the period runs to four lines and breaks
     inside （水・祝）. The URL column holds one short word, so the width comes
     from there and the comp's three lines fit as drawn. */
  .ticket-table__col--name   { width: 38%; }
  .ticket-table__col--period { width: 37%; }
  .ticket-table__col--url    { width: 25%; }

  /* Comp: 15px strip, 14px gap, 73px row with 18.5px leading. */
  .ticket-table th {
    height: 1.6rem;
    padding: 0 0 0.5rem 1rem;
    font-size: 1rem;
  }

  .ticket-table tbody::before {
    height: 1.4rem;
  }

  .ticket-table td {
    padding: 1rem;
    font-size: 1.2rem;
    line-height: 1.55;
    vertical-align: top;
  }

  .ticket-table__tilde {
    margin-inline: 0;
  }

  /* The same proportion against the smaller cell text (comp: ~9px of 12px). */
  .ticket-table__dow {
    font-size: 0.9rem;
  }

  .ticket-table__note {
    margin-top: 1rem;
    font-size: 1rem;
    line-height: 1.7;
  }

  .ticket-table__small {
    font-size: 1.0rem;
    line-height: 1.6;
  }

  .attention {
    margin-top: 6rem;
    text-align: center;
  }

  /* The <br class="u-sp"> in the markup place the breaks that matter; this
     keeps any line that still has to wrap on its own from ending mid-word
     (Chromium only - elsewhere it falls back to breaking anywhere, as now). */
  .attention__list li {
    word-break: auto-phrase;
  }

  .attention__title {
    font-size: 1.6rem;
  }

  .attention__group {
    margin-top: 0.8rem;
  }

  .attention__group + .attention__group {
    margin-top: 3rem;
  }

  .attention__head {
    font-size: 1.2rem;
  }

  .attention__list {
    margin-top: 0.6rem;
    font-size: 1rem;
    line-height: 2; /* comp: 20px leading */
  }

  /* Centred lines: no hanging indent here, and the dot goes back to a
     typed 「・」 in the run of text. */
  .attention__list li {
    position: static;
    padding-left: 0;
    text-indent: 0;
  }

  .attention__list li::before {
    content: "・";
    position: static;
    width: auto;
    height: auto;
    border-radius: 0;
    background: none;
  }

  /* Stacked and centred, no rule (comp). */
  .credit {
    flex-direction: column;
    align-items: center;
    gap: 0.5rem; /* comp: 26px line pitch */
    margin-top: 4rem;
    padding-top: 0;
    border-top: 0;
    font-size: 1.3rem;
    text-align: center;
  }

  .sky .footer {
    padding: 5.3rem 5.7% 5.8rem;
  }

  /* The logo window: smaller here, and it must stop above the LIVE rule
     (102px down on SP). */
  body[data-page] .main {
    -webkit-mask-size: var(--haze-s) var(--haze-s), 30rem 9rem;
    mask-size: var(--haze-s) var(--haze-s), 30rem 9rem;
  }

}

/* ================================================================ Reduced motion */
@media (prefers-reduced-motion: reduce) {
  .kv__scroll-arrow::after { animation: none; }

  /* Child-based reveals (live info lines, side labels) sit in place too;
     !important outweighs their per-block selectors, only under reduce. */
  [data-reveal] > *,
  .side-labels[data-reveal] .side-labels__item {
    opacity: 1 !important;
    transform: none !important;
    transition: none !important;
  }
}
