/* Gravity 2026 — landing design.
   Loaded on pages using either 2026 template — Gravity Opera 2026 new, or
   Gravity Techno 2026 new (see gravity26_2026_templates() in
   inc/gravity-2026-data.php). Header, nav, cart and footer come from the
   theme, not from here.

   Both templates render the same body and differ by a variant, which arrives
   in the markup as a class on the page's <main>:

       <main class="gravity-2026 is-opera">      the tangerine page
       <main class="gravity-2026 is-techno">     the green one

   So the Techno skin is written here, as overrides of the tokens below,
   scoped to `.gravity-2026.is-techno`. Nothing else in the theme changes to
   add it. The Look tab's per-page accent colours still win over whatever is
   set here, on both templates. */

/* ============================================================
   GRAVITY — shared mockup foundation
   Tokens derived from gravitycph.dk (tangerine #FF520E, Clash Display + DM Sans) and tightened for conversion work.
   ============================================================ */

:root{
  /* surfaces */
  --ink:        #08080A;
  --ink-2:      #101013;
  --ink-3:      #17171C;
  --bone:       #F2EDE4;
  --line:       rgba(255,255,255,.10);
  --line-2:     rgba(255,255,255,.18);

  /* text */
  --fg:         #FFFFFF;
  --fg-2:       rgba(255,255,255,.66);
  --fg-3:       rgba(255,255,255,.42);
  /* small type on the message cards needs 4.5:1; the shared muted grey gives 4.0 */
  --fg-card:    rgba(255,255,255,.62);

  /* action vs urgency — deliberately separated so the buy button
     never competes with a scarcity badge for the same attention */
  --action:     #FF520E;   /* Gravity tangerine — buy actions only */
  --action-hi:  #FF6B33;
  --urgent:     #FFB020;   /* amber — price rises, low stock */
  --gone:       #FF4438;   /* sold out */
  --ok:         #34D07F;

  --r-sm: 8px;
  --r:    14px;
  --r-lg: 22px;
  --r-pill: 999px;

  --display: 'Clash Display', 'Helvetica Neue', Arial, sans-serif;
  --body: 'DM Sans', -apple-system, 'Segoe UI', Roboto, sans-serif;

  --pad: clamp(20px, 5vw, 72px);
}
/* Scoped on purpose. These rules used to be bare element selectors, which is
   fine in a standalone mockup but here they also reached the theme's own header
   and footer — a white footer inherited white text and vanished. */
.gravity-2026, .gravity-2026 *, .gravity-2026 *::before, .gravity-2026 *::after{ box-sizing: border-box; }
html, body{
  margin: 0;
  padding: 0;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}
body{ background: var(--ink); }
.gravity-2026{
  color: var(--fg);
  font-family: var(--body);
}
.gravity-2026 :is(img, video){ display: block; max-width: 100%; }
.gravity-2026 a{ color: inherit; text-decoration: none; }
/* Two things at once. :where() keeps the reset at element weight so anything
   with a class outranks it, and the exclusion keeps it away from the shop's
   ticket component entirely — including in the armoured copy below, which
   carries !important and would otherwise repaint the plugin's own buttons.
   Both wrappers contribute nothing to specificity, so this still loses to
   every one of our own .btn rules, exactly as before. */
:where(.gravity-2026) button:where(:not([class*="wcvcl"])){ font: inherit; color: inherit; border: 0; background: none; cursor: pointer; }
.wrap{ width: 100%; max-width: 1280px; margin-inline: auto; padding-inline: var(--pad); }
/* ---------- type ---------- */
.display{
  font-family: var(--display);
  font-weight: 600;
  line-height: .86;
  letter-spacing: -.035em;
  text-transform: uppercase;
  margin: 0;
}
.eyebrow{
  font-size: 11px;
  letter-spacing: .22em;
  text-transform: uppercase;
  color: var(--fg-3);
  font-weight: 500;
  margin: 0;
}
.lede{ font-size: clamp(15px, 1.5vw, 18px); line-height: 1.55; color: var(--fg-2); margin: 0; }
/* ---------- buttons ---------- */
/* The theme loads Bootstrap 5 site-wide and these class names collide with it:
   Bootstrap's .btn-primary carries a 1px #0d6efd border and a blue focus
   box-shadow. Every property Bootstrap sets is therefore stated here
   explicitly — omitting one lets the blue leak through. */
.gravity-2026 .btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 10px;
  padding: 16px 28px;
  border: 0;
  border-radius: var(--r-pill);
  font-weight: 700; font-size: 15px; letter-spacing: .01em; line-height: 1.2;
  transition: transform .18s cubic-bezier(.2,.8,.2,1), background-color .18s, box-shadow .18s;
  white-space: nowrap;
}
.gravity-2026 .btn:hover, .gravity-2026 .btn:focus, .gravity-2026 .btn:focus-visible, .gravity-2026 .btn:active, .gravity-2026 .btn:first-child:active, .gravity-2026 .btn.active{
  border: 0; box-shadow: none; outline: 0;
}
.gravity-2026 .btn:active{ transform: scale(.975); }
.gravity-2026 .btn-primary, .gravity-2026 .btn-primary:focus, .gravity-2026 .btn-primary:active {
  background: var(--action); color: #fff; box-shadow: 0 6px 30px -8px rgba(255,82,14,.7); }
.gravity-2026 .btn-primary:hover { background: var(--action-hi); color: #fff; }
.gravity-2026 .btn-ghost, .gravity-2026 .btn-ghost:focus, .gravity-2026 .btn-ghost:active { background: transparent; border: 1px solid var(--line-2); color: var(--fg); }
.gravity-2026 .btn-ghost:hover { background: transparent; border-color: #fff; color: var(--fg); }
.gravity-2026 .btn-lg { padding: 19px 34px; font-size: 16px; }
.gravity-2026 .btn-block { display: flex; width: 100%; }
/* ---------- badges ---------- */
.badge{
  display: inline-flex; align-items: center; gap: 7px;
  font-size: 11px; font-weight: 700; letter-spacing: .12em; text-transform: uppercase;
  padding: 6px 12px; border-radius: var(--r-pill);
  border: 1px solid var(--line-2);
}
.badge-gone{ color: var(--gone);   border-color: rgba(255,68,56,.4);   background: rgba(255,68,56,.08); }
.badge-live{ color: var(--ok);     border-color: rgba(52,208,127,.4);  background: rgba(52,208,127,.08); }
.badge-urgent{ color: var(--urgent); border-color: rgba(255,176,32,.4);  background: rgba(255,176,32,.10); }
.dot{ width: 6px; height: 6px; border-radius: 50%; background: currentColor; }
.dot-pulse{ animation: pulse 1.8s ease-in-out infinite; }
@keyframes pulse { 0%,100% { opacity: 1 } 50% { opacity: .25 } }
/* ---------- payment strip ---------- */
.pay{ display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.pay span{
  font-size: 10px; font-weight: 700; letter-spacing: .06em;
  padding: 5px 9px; border-radius: 5px;
  border: 1px solid var(--line); color: var(--fg-3);
}
.pay .mp{ color: #fff; border-color: rgba(255,255,255,.35); }
/* ---------- annotation pins (mockup-only commentary) ---------- */
.note{
  position: relative;
  outline: 1px dashed rgba(255,176,32,.0);
}
.note-tag{
  position: absolute; z-index: 40;
  background: var(--urgent); color: #12100A;
  font-size: 10px; font-weight: 700; letter-spacing: .06em; text-transform: uppercase;
  padding: 4px 8px; border-radius: 5px;
  pointer-events: none; opacity: 0; transition: opacity .2s;
  white-space: nowrap;
}
body.show-notes .note-tag{ opacity: 1; }
body.show-notes .note{ outline-color: rgba(255,176,32,.45); outline-offset: 4px; }
/* ---------- utility ---------- */
.hairline{ height: 1px; background: var(--line); border: 0; margin: 0; }
.stack > * + *{ margin-top: var(--gap, 16px); }
.muted{ color: var(--fg-2); }
.tnum{ font-variant-numeric: tabular-nums; }
.sr{ position:absolute; width:1px; height:1px; overflow:hidden; clip:rect(0 0 0 0); }
/* sticky mobile buy bar — shared across all three directions */
.buybar{
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 60;
  display: flex; align-items: center; gap: 14px;
  padding: 12px 16px calc(12px + env(safe-area-inset-bottom));
  background: rgba(8,8,10,.86);
  backdrop-filter: blur(20px) saturate(1.4);
  border-top: 1px solid var(--line);
  transform: translateY(110%);
  transition: transform .35s cubic-bezier(.2,.8,.2,1);
}
.buybar.in{ transform: translateY(0); }
.buybar .price{ font-family: var(--display); font-size: 20px; font-weight: 600; line-height: 1; }
.buybar .price small{ display:block; font-family: var(--body); font-size: 10px; letter-spacing:.14em; text-transform: uppercase; color: var(--fg-3); font-weight: 500; margin-bottom: 4px; }
.buybar .btn{ flex: 1; }
/* ===== THE PAGE — built on hero 3 (Shutter) ================================
   Pinned wordmark at the top, sticky buy bar at the bottom, and everything
   between them in the same dark / grid / tangerine language as the hero.
   ========================================================================== */

/* --bar-h is the sticky buy bar; the theme header replaced --brand-h */
:root{ --bar-h: 98px; }
body{ padding-bottom: var(--bar-h); }
/* ---------- hero ---------- */
/* "full height" means up to the buy bar — the last 98/126px of 100svh sit
   behind it, so the CTA and scroll hint were being covered */
/* Full height means "down to where the sticky bar starts". The theme header is
   fixed and transparent, so the video runs behind it and the copy is pushed
   clear of the logo with padding — --hdr-h is measured at runtime. */
.presents{ margin: 0 0 -.1em; font-family: var(--body); font-size: clamp(15px, 1.75vw, 21px);
  font-weight: 500; letter-spacing: .30em; text-transform: uppercase; color: var(--fg-2); }
/* A word the editor wrapped in {braces}. <mark> is the right element for
   "this bit matters", but its yellow-highlighter default has to go. */
.g26-mark{ background: none; color: var(--action); font-weight: 700; }
.hero{ position: relative; height: calc(100vh - var(--bar-h)); height: calc(100svh - var(--bar-h)); width: 100%;
  display: flex; flex-direction: column; overflow: hidden;
  padding-top: var(--hdr-h, 96px);
  padding-bottom: 8px; }
.hero video{ position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; z-index: 0; }
.hero .hero-poster, .hero .hero-poster img{ position: absolute; inset: 0; width: 100%; height: 100%; z-index: 0; }
.hero .hero-poster img{ object-fit: cover; }
/* Two layers: a pool of shade around the copy, and a vertical ramp. Measured, not guessed — over a white video frame the meta row needs 0.71 alpha to
   clear 4.5:1, so the shade is centred on the copy rather than the viewport. */
.hero::before{
  content: ''; position: absolute; inset: 0; z-index: 1; pointer-events: none;
  background:
    radial-gradient(72% 48% at 50% 54%, rgba(8,8,10,.8) 0%, rgba(8,8,10,.64) 52%, rgba(8,8,10,.14) 88%, rgba(8,8,10,0) 100%),
    linear-gradient(180deg, rgba(8,8,10,.72) 0%, rgba(8,8,10,.24) 26%, rgba(8,8,10,.14) 66%, rgba(8,8,10,.24) 100%);
}
.hero .fx{ position: absolute; inset: 0; z-index: 2; pointer-events: none;
  background-image:
    linear-gradient(rgba(255,255,255,.055) 1px, transparent 1px),
    linear-gradient(90deg, rgba(255,255,255,.055) 1px, transparent 1px);
  background-size: 64px 64px; background-position: center;
  -webkit-mask-image: radial-gradient(118% 76% at 50% 44%, #000 18%, rgba(0,0,0,.35) 55%, transparent 82%);
  mask-image: radial-gradient(118% 76% at 50% 44%, #000 18%, rgba(0,0,0,.35) 55%, transparent 82%);
}
.hero .stack{ position: relative; z-index: 3; flex: 1; display: flex; flex-direction: column;
  align-items: center; justify-content: center; text-align: center;
  padding: 0 var(--pad); gap: clamp(13px, 2.1vh, 24px); }
/* ---------- undo the parent theme's element-level shouting ----------
   style-new.css sets alignment, colour, transform and the whole font shorthand
   on bare `p`, `h1` and `h2` with !important — including properties this file
   never mentions, which is how centred headings and 20px kickers got through.
   Restating the browser's own behaviour (inherit from the parent) hands control
   back to the rules below, which stay free to say something else.
   :where() keeps the specificity at element level so every class still wins. */
:where(.gravity-2026) h1, :where(.gravity-2026) h2, :where(.gravity-2026) h3, :where(.gravity-2026) h4{
  text-align: inherit; color: inherit; text-transform: inherit;
}
:where(.gravity-2026) p{
  text-align: inherit; color: inherit; text-transform: inherit;
  font-family: inherit; font-size: inherit; font-weight: inherit;
  line-height: inherit; letter-spacing: inherit;
}
/* the theme aims a second, more specific shot at the footer */
:where(.gravity-2026) footer p{ color: inherit; text-align: inherit; }
/* ---------- shutter type — the motif, reused four times on the page ----------
   Six clipped copies of the same words. Without JS nothing is hidden and
   nothing animates; .go is what starts it, and the sweep in the script makes
   sure a throttled observer can never leave a heading invisible. */
.shut{ position: relative; display: inline-grid; margin: 0;
  font-family: var(--display); font-weight: 500; text-transform: uppercase;
  letter-spacing: -.045em; line-height: .82; }
.shut > span{ grid-area: 1/1; display: block;
  clip-path: inset(calc(var(--i) * 16.667%) 0 calc((5 - var(--i)) * 16.667%) 0); }
/* em, not %. A percentage in translateX resolves against the element's own
   width — the span is the full width of the word, so a 1.6% loop offset was
   8.5px and shredded the letters. */
.shut > span:nth-child(odd){ --d: -.34em; --dl: -.05em; }
.shut > span:nth-child(even){ --d: .34em;  --dl: .05em; }
.anim .shut > span{ opacity: 0 }
.anim .shut.go > span{ animation: shutter .85s cubic-bezier(.19,1,.22,1) calc(var(--i) * 85ms + .1s) both }
/* every instance re-slices on a 3s cycle. --lo offsets each one so they never
   pulse in unison, which is what would make four of them feel busy. */
.anim .shut.loop.go > span{ animation:
  shutter .85s cubic-bezier(.19,1,.22,1) calc(var(--i) * 85ms + .1s) both,
  shutterLoop 3s cubic-bezier(.4,0,.2,1) calc(var(--i) * 60ms + 2s + var(--lo, 0s)) infinite; }
.anim .shut.loop.go::after{
  content: ''; position: absolute; inset: 0; pointer-events: none;
  background: repeating-linear-gradient(180deg, rgba(255,255,255,.5) 0 1px, transparent 1px calc(100% / 6));
  opacity: 0; animation: seams 3s ease-out calc(2s + var(--lo, 0s)) infinite;
}
@keyframes shutter { from { transform: translateX(var(--d)); opacity: 0 } to { transform: none; opacity: 1 } }
@keyframes shutterLoop { 0%,64% { transform: none } 76% { transform: translateX(var(--dl)) } 90%,100% { transform: none } }
@keyframes seams { 0%,62% { opacity: 0 } 76% { opacity: .28 } 92%,100% { opacity: 0 } }
.gravity-2026 .title{ font-size: clamp(44px, 8.6vw, 132px); white-space: nowrap }
.pitch{ font-size: clamp(14px, 1.5vw, 18px); line-height: 1.5; color: rgba(255,255,255,.9); margin: 0; max-width: 46ch; }
.pitch b{ color: #fff; font-weight: 500; }
.metarow{ display: flex; flex-wrap: wrap; gap: 6px 0; margin: 0; padding: 0; list-style: none; justify-content: center; }
.metarow li{ font-size: 13px; letter-spacing: .16em; text-transform: uppercase; color: var(--fg-2);
  padding-right: 15px; margin-right: 15px; border-right: 1px solid var(--line-2); white-space: nowrap; }
.metarow li:last-child{ border-right: 0; margin-right: 0; padding-right: 0; }
.metarow b{ color: #fff; font-weight: 500; }
.scroll-hint{ position: absolute; bottom: 14px; left: 50%; transform: translateX(-50%); z-index: 3;
  font-size: 10px; letter-spacing: .3em; text-transform: uppercase; color: var(--fg-3); }
/* ---------- shimmer ----------
   A highlight sweeps the text once, then rests. The rest is most of the
   cycle on purpose: a continuous shimmer reads as a loading skeleton. */
/* ---------- how headings break ----------
   Three rules, and between them no heading ever ends on a single stranded word.

   1. A measure in ch. Left to itself a heading fills whatever width it is
      given, so on a wide screen it becomes one very long line and on a laptop
      an uneven two. Capping it in ch ties the line length to the type rather
      than to the monitor, so the same heading breaks the same way everywhere.

   2. text-wrap: balance. Once it wraps, the browser evens the lines out
      instead of filling the first and leaving one word on the second. Where it
      is not supported nothing changes — this only ever improves the result.

   3. The editor's own break, honoured only where it fits. A newline typed in
      the admin becomes <br class="brk">; below the width where a heading needs
      two lines of its own, it is ignored, because there the manual break is
      what creates the stray word rather than preventing it.

   All three apply to every heading on the page, so this is settled once. */
.gravity-2026 h1, .gravity-2026 h2, .gravity-2026 h3 { text-wrap: balance }
.gravity-2026 .brk { display: inline }
@media (max-width: 900px) {
  .gravity-2026 .brk { display: none }
}

.shim{ background-image: linear-gradient(100deg,
    var(--shim-base, #fff) 0 40%, var(--action) 47%, var(--shim-peak, #fff) 51%, var(--action) 55%,
    var(--shim-base, #fff) 62% 100%);
  background-size: 250% 100%; background-position: 170% 0;
  -webkit-background-clip: text; background-clip: text;
  color: transparent; -webkit-text-fill-color: transparent;
  animation: shim 6s linear infinite; }
.bone .shim{ --shim-base: #14110E; --shim-peak: #4a2a12 }
/* The concept heading is a sentence — "An Opera is not a rave." — and a
   sentence set in capitals stops being read and starts being scanned. The
   section headings that are labels keep their capitals; this one loses them. */
#opera h2 { text-transform: none; letter-spacing: -.03em }
/* linear, not ease-in-out. Easing accelerates through the middle — which is
   exactly where the highlight crosses the words — so the pass read as fast
   even after the duration went up. 4.6s of travel, then a rest. */
@keyframes shim{
  0%        { background-position: 170% 0 }
  77%, 100% { background-position: -70% 0 }
}
/* ---------- shared section furniture ---------- */
.sec{ padding-block: clamp(64px, 9vw, 120px); }
/* matches the tightened header, not the tall hero-state one */
section[id]{ scroll-margin-top: 80px; }
/* Caps is the default for section headings. Three of them opt out below —
   the emotional beats read better in sentence case, and the contrast between
   the two is the rhythm. Sizes stay identical either way. */
.sec h2{ font-family: var(--display); font-weight: 500; text-transform: uppercase; letter-spacing: -.04em;
  line-height: .94; font-size: clamp(32px, 5.2vw, 64px); margin: 0; }
.sec .lede{ margin-top: 18px; max-width: 54ch; }
.kicker{ font-family: var(--body); font-size: 10.5px; font-weight: 400; letter-spacing: .26em;
  text-transform: uppercase; color: var(--fg-2); margin: 0 0 14px; display: flex; align-items: center; gap: 9px; }
.kicker i{ width: 6px; height: 6px; border-radius: 50%; background: var(--ok); }
.split{ display: grid; grid-template-columns: 1fr 1fr; gap: clamp(26px, 5vw, 80px); align-items: start; }
/* ---------- line-up ----------
   Headliner dominant, support acts a third of the size. A flat list of
   six equal 64px names would be four screens of nothing but names. */
.acts{ margin-top: 34px; border-top: 1px dashed rgba(255,255,255,.22); }
.act{ position: relative; display: flex; align-items: baseline; gap: 16px; padding: 18px 0;
  border-bottom: 1px dashed rgba(255,255,255,.22); }
.act::before, .act::after{ content: ''; position: absolute; bottom: -9px; width: 18px; height: 18px;
  border-radius: 50%; background: var(--ink); }
.act::before{ left: -9px }
.act::after{ right: -9px }
.act .nm{ font-family: var(--display); font-size: clamp(22px, 2.6vw, 34px); font-weight: 600;
  text-transform: uppercase; letter-spacing: -.02em; line-height: .95; }
.act .cc{ font-size: clamp(11px, 1.1vw, 13px); color: var(--fg-3); letter-spacing: .1em; text-transform: uppercase; }
.act .role{ margin-left: auto; font-size: 10.5px; letter-spacing: .2em; text-transform: uppercase;
  color: var(--fg-3); white-space: nowrap; }
.act.head{ padding: 26px 0 }
.act.head .nm{ font-size: clamp(34px, 6vw, 76px); letter-spacing: -.035em }
.act.head .cc{ font-size: clamp(12px, 1.3vw, 16px) }
.act.head .role{ color: var(--action); font-weight: 700 }
.act.tba .nm{ color: var(--fg-3); font-weight: 500 }
/* ---------- artist row extras: watch / follow ----------
   Low-contrast until the row is hovered, so the names stay the loudest thing
   in the section. */
.act .links{ display: inline-flex; gap: 7px; margin-left: 6px; align-items: center; }
.ic{ width: 34px; height: 34px; border-radius: 50%; display: grid; place-items: center; flex: none;
  border: 1px solid var(--line-2); color: var(--fg-2); opacity: .75; cursor: pointer;
  transition: opacity .2s, color .2s, border-color .2s, background-color .2s, transform .2s; }
.ic svg{ width: 14px; height: 14px; display: block; }
.ic svg, .ic svg path{ fill: currentColor !important; }
.act:hover .ic, .act:focus-within .ic{ opacity: .9 }
.ic:hover, .ic:focus-visible{ opacity: 1; color: #fff; border-color: #fff; transform: scale(1.08) }
.ic.play:hover{ background: var(--action); border-color: var(--action) }
.act.tba .links{ display: none }
/* ---------- artist video modal ---------- */
/* ---------- ticket modal — the shop's buying panel in an overlay ---------- */
/* A double tap on a stepper used to zoom the page instead of counting twice:
   the browser waits to see whether a second tap is coming and reads the pair as
   a zoom gesture. manipulation says these are controls, not a document to be
   magnified — pinch to zoom still works everywhere. */
.gravity-2026, .tmodal, .vmodal { touch-action: manipulation }
.gravity-2026 .btn, .wcvcl-circ-btn, .wcvcl-info, .vclose,
.gravity-2026 button, .gravity-2026 a { touch-action: manipulation }

.tmodal{ position: fixed; inset: 0; z-index: 100010; display: grid; place-items: center;
  background: rgba(5,5,7,.82); backdrop-filter: blur(6px); padding: 18px; }
/* The panel is parked, not removed — and its state is a class, not the hidden
   attribute.
   Stripe builds its Apple Pay / Google Pay button into a container that lives
   in here, and Stripe Elements will not mount into a box with no dimensions.
   Parked, the panel keeps a layout box for the button to be built in while
   being invisible, untouchable and out of the accessibility tree.
   The attribute cannot be used for this: Bootstrap loads across the whole site
   and its reset carries `[hidden] { display: none !important }`, which no rule
   written here can outrank. A class is beyond its reach. */
.tmodal{ visibility: hidden; opacity: 0; pointer-events: none;
  backdrop-filter: none; -webkit-backdrop-filter: none; }
.tmodal.open{ visibility: visible; opacity: 1; pointer-events: auto;
  backdrop-filter: blur(6px); -webkit-backdrop-filter: blur(6px); }
.tmbox{ position: relative; width: min(560px, 100%); max-height: calc(100vh - 36px); max-height: calc(100svh - 36px);
  overflow-y: auto; overscroll-behavior: contain; -webkit-overflow-scrolling: touch;
  background: none; border: 0; padding: 0 0 6px;
  /* The panel keeps scrolling, it just stops drawing the bar. A grey track
     down the side of a white card is the browser's furniture, not ours, and
     on a machine set to show scrollbars always it sits there through the
     whole purchase. What tells people there is more below is the chevron
     under the panel, which the script raises exactly when the Add button
     has gone off screen — a cue that says something, where the bar only
     said "this scrolls". */
  scrollbar-width: none; }
.tmbox::-webkit-scrollbar { display: none }
/* The scroll nudge. Sits above the panel, never inside it, so it stays put
   while the rows move. Hidden until the JS decides the Add button is off
   screen — with scripting off it simply never appears, and nothing is lost:
   the list still scrolls. */
/* The colour needs !important because the armour block ends with
   `:where(.gravity-2026) button:where(:not([class*="wcvcl"])) { color: inherit !important }`.
   It caught this button too and painted the arrow white on a white disc —
   a circle with nothing in it. Measured live: color came out rgb(255,255,255). */
/* The wait state over the ticket panel. Sits inside .tmbox, so the page
   behind stays scrollable and reachable — if anything ever went wrong here
   the buyer is not trapped behind it. */
/* Anchored to .tmodal, which is fixed to the viewport — not to .tmbox, which
   scrolls. Inside the scrolling box `inset: 0` resolves against the content,
   so the overlay sat over the top of the ticket list while the pay buttons
   below stayed bright and tappable. Covering them is the point: nothing on
   this panel should be pressable while a payment is going through. */
.tmwait{ position: fixed; inset: 0; z-index: 100014;
  background: rgba(8,8,10,.88); backdrop-filter: blur(3px);
  display: grid; place-items: center; }
.tmwait[hidden]{ display: none }
.tmwait-in{ text-align: center; padding: 24px; max-width: 24ch }
.tmwait-in b{ display: block; font-family: var(--display); font-size: 19px; font-weight: 600;
  text-transform: uppercase; letter-spacing: .02em; color: #fff; margin: 16px 0 6px }
.tmwait-in span{ display: block; font-size: 13px; color: var(--fg-2) }
.tmwait-ring{ display: block; width: 34px; height: 34px; margin: 0 auto; border-radius: 50%;
  border: 3px solid rgba(255,255,255,.20); border-top-color: var(--action);
  animation: tmspin .9s linear infinite; }
@keyframes tmspin{ to{ transform: rotate(360deg) } }
/* Motion off: the ring stops turning but the words still say what is
   happening, which is the part that actually carries the message. */
@media (prefers-reduced-motion: reduce){
  .tmwait-ring{ animation: none; border-top-color: rgba(255,255,255,.55) }
}

.tmnudge{ position: absolute; left: 50%; bottom: 26px; z-index: 100012;
  width: 44px; height: 44px; border-radius: 50%; border: 0; padding: 0;
  background: var(--ink); color: #fff !important; display: grid; place-items: center;
  cursor: pointer; box-shadow: 0 8px 24px rgba(0,0,0,.42);
  opacity: 0; pointer-events: none; transform: translate(-50%, 0);
  transition: opacity .25s ease; }
.tmnudge svg{ width: 17px; height: 17px; display: block }
.tmnudge svg path{ stroke: #fff !important; }
.tmnudge.show{ opacity: 1; pointer-events: auto; animation: tmbob 1.8s ease-in-out infinite }
@keyframes tmbob{ 0%,100%{ transform: translate(-50%, 0) } 50%{ transform: translate(-50%, 4px) } }
@media (prefers-reduced-motion: reduce){ .tmnudge.show{ animation: none } }

/* Above the wait overlay (z-index 100014): whatever happens during a
   payment, the way out stays reachable. */
.tmbox .vclose{ position: sticky; top: 0; float: right; z-index: 100015; margin: 0 0 -12px }

/* The title and the two facts above the card, set the way the product page
   sets them: white on the dark overlay, grey label above a large value. */
.g26-tickethead{ padding: 4px 6px 20px; text-align: left; padding-right: 60px }
.g26-tickethead h3{ margin: 0 0 16px; font-family: var(--display); font-weight: 600;
  text-transform: uppercase; letter-spacing: -.01em; line-height: 1.05;
  font-size: clamp(24px, 5.4vw, 34px); color: #fff }
.g26-tktfacts{ display: flex; gap: 34px }
.g26-tktfacts span{ display: block; font-size: 12px; color: #9D9D9D; margin-bottom: 4px }
.g26-tktfacts b{ display: block; font-family: var(--body); font-weight: 600;
  text-transform: uppercase; font-size: clamp(18px, 4.4vw, 24px); line-height: 1; color: #fff }

/* Two things the shop's card has no concept of, added in its own language:
   how few are left, and what went wrong when the basket refuses. */
/* Same reason as the panel above: the button needs somewhere with real
   dimensions to be built. The slot is therefore always laid out, lifted out of
   the flow and invisible, and only drops back into place once a ticket has
   been chosen and there is something to pay for. */
/* Never seen, never in the way, never reachable by a keyboard — but present,
   with real dimensions, because Stripe reads it rather than being told. */
.g26-shadow{ position: absolute; width: 1px; height: 1px; overflow: hidden;
  clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap;
  pointer-events: none; opacity: 0 }

/* Full width from the very first moment, not only once it is shown.

   Stripe measures this box when it mounts and sizes its buttons to what it
   finds — once. It was finding the 240px floor below, in a parent the shop's
   stylesheet lays out as max-content columns, so it built two 240px buttons
   and left them sitting against the left edge of a much wider panel, with the
   pair spilling past the right. Giving the box its real width before Stripe
   ever looks means the buttons come out the width of the panel on their own,
   and there is nothing left to centre. */
#wcvcl-express{ height: 0; overflow: hidden; visibility: hidden; pointer-events: none;
  width: 100%; max-width: 100% }
/* The inner container is the one Stripe measures and mounts into, so it is the
   one that must have a size — full width of the panel and the height of a
   payment button. Clipping it to nothing above hides it without taking that
   size away: overflow affects what is painted, never what is laid out. */
/* The shop's stylesheet lays this slot out as a row of max-content columns and
   forces `width: auto !important` on whatever is inside it — which for an empty
   container means no width at all, and Stripe will not build a button into a
   box of nothing. min-width is not on that list, so it is what gives the
   container a real size to be born into. */
#wcvcl-express > #wc-stripe-express-checkout-element{
  /* The floor stays as a last resort — if anything ever collapses the slot to
     nothing again, Stripe still has a box to be born into rather than refusing
     to build at all. Above it, the real width now wins. */
  min-width: 240px; min-height: 48px;
  width: 100%; max-width: 100%;
  /* and whatever width Stripe settles on, it sits in the middle */
  display: flex; flex-direction: column; align-items: center; gap: 8px }
#wcvcl-express > #wc-stripe-express-checkout-element > *{
  width: 100%; max-width: 420px; margin-left: auto; margin-right: auto }
#wcvcl-express.ready{ height: auto; overflow: visible; visibility: visible;
  pointer-events: auto; margin-top: 12px }

.g26-left{ display: inline-block; margin-left: 8px; font-size: 11px; font-weight: 700;
  letter-spacing: .12em; text-transform: uppercase; color: #C2410C }
.tmmount .wcvcl-bottombar{ justify-content: space-between; align-items: center; gap: 14px }
/* the amount must not break across two lines — a price split down the middle
   reads as two prices */
.tmmount .wcvcl-bottom-total{ color: #fff; white-space: nowrap; flex: none }
.tmmount .wcvcl-direct-btn{ flex: 1; text-align: center }
.vmodal{ position: fixed; inset: 0; z-index: 100010; display: grid; place-items: center;
  padding: var(--pad); background: rgba(4,4,6,.88); backdrop-filter: blur(10px); }
.vmodal[hidden]{ display: none }
/* The clip decides its own shape, so the box has to be told about both
   directions. Width alone was enough for a landscape clip and wrong for an
   upright one: at 880px across, a 9:16 video is over 1500px tall and the
   bottom half simply falls off the screen.

   width/height auto with a cap on each side lets the video keep its own
   proportions and fit whichever way it is tall — and because the box shrinks
   to the video rather than the video stretching to the box, an upright clip
   gets no black bars beside it. The room left over is for the caption
   underneath and the close button above. */
.vbox{ position: relative; width: auto; max-width: min(880px, 100%);
  display: flex; flex-direction: column; align-items: center; }
.vbox video{ display: block; background: #000; border-radius: var(--r);
  width: auto; height: auto;
  max-width: 100%;
  max-height: calc(100vh - 150px);
  max-height: calc(100svh - 150px); }
.vbox .who{ margin: 14px 0 0; text-align: center; font-size: 12px; letter-spacing: .2em; text-transform: uppercase; color: var(--fg-2) }
.vbox .who b{ color: #fff; font-family: var(--display); font-size: 17px; letter-spacing: -.01em; margin-right: 10px }
/* padding: 0 because the parent theme puts 8px 16px on every button. Inside
   a 36px circle that leaves a 4px content box and shoves the glyph to the
   right of the ring — measured live at 17px from the left edge. */
.vclose{ position: absolute; top: -46px; right: 0; width: 36px; height: 36px; border-radius: 50%;
  border: 1px solid var(--line-2); color: #fff; display: grid; place-items: center;
  padding: 0 !important; line-height: 1 !important; }
.vclose:hover{ border-color: #fff }
/* ---------- dot field ----------
   Two grids of dots: a dim static one, and an orange one revealed by a pool
   of light that drifts across the section. @property is what lets the mask
   position interpolate; where it is unsupported the pool simply sits still. */
@property --gx{ syntax: '<percentage>'; initial-value: 30%; inherits: false }
@property --gy { syntax: '<percentage>'; initial-value: 40%; inherits: false }
.dots{ position: absolute; inset: 0; z-index: 0; pointer-events: none; overflow: hidden;
  -webkit-mask-image: radial-gradient(125% 92% at 50% 50%, #000 28%, transparent 86%);
  mask-image: radial-gradient(125% 92% at 50% 50%, #000 28%, transparent 86%); }
.dots i, .dots b{ position: absolute; inset: -30px; display: block; background-size: 26px 26px;
  animation: dotdrift 26s linear infinite; }
.dots i{ background-image: radial-gradient(circle, rgba(255,255,255,.085) 1px, transparent 1px); }
.dots b{ background-image: radial-gradient(circle, var(--action) 1px, transparent 1px); opacity: .8;
  -webkit-mask-image: radial-gradient(26% 36% at var(--gx) var(--gy), #000 0%, rgba(0,0,0,.4) 46%, transparent 74%);
  mask-image: radial-gradient(26% 36% at var(--gx) var(--gy), #000 0%, rgba(0,0,0,.4) 46%, transparent 74%);
  animation: dotdrift 26s linear infinite, glowmove 15s ease-in-out infinite alternate; }
@keyframes dotdrift { to { background-position: 26px 26px } }
@keyframes glowmove {
  0%   { --gx: 16%; --gy: 28% }
  50%  { --gx: 74%; --gy: 64% }
  100% { --gx: 42%; --gy: 20% }
}
/* ---------- why this one — the proof, rewritten quiet ----------
   Was three full-width strips stacked (marquee, giant number, marquee) plus
   a route. Same facts, one editorial block. */
.why{ position: relative; overflow: hidden; }
/* exclude the dot layer — otherwise it matches this rule too and only stays
   behind the copy by accident of DOM order */
.why > *:not(.dots){ position: relative; z-index: 1; }
.why h2{ text-transform: none; letter-spacing: -.035em; }
.why .lede{ color: var(--fg-2); }
.why .lede em{ font-style: normal; color: #fff; }
/* the facts, back to the quiet hairline list they were */
.facts{ margin: 0; display: grid; }
.facts > div{ display: flex; align-items: baseline; justify-content: space-between; gap: 20px;
  padding: 15px 0; border-bottom: 1px solid var(--line); }
.facts > div:first-child{ border-top: 1px solid var(--line); }
.facts dt{ font-size: 11px; letter-spacing: .18em; text-transform: uppercase; color: var(--fg-3); margin: 0; }
.facts dd{ margin: 0; font-family: var(--display); font-size: clamp(17px, 1.9vw, 24px); font-weight: 600;
  letter-spacing: -.01em; text-align: right; }
/* the road here — four stops, each one a line you can actually read */
/* The road CamelPhat took to this room. Rows with a name floating in the middle
   read as an accident; a four-across strip keeps every name on its own left
   edge and costs a quarter of the height. */
.road{ margin-top: clamp(44px, 6vw, 70px); display: grid; grid-template-columns: repeat(4, minmax(0, 1fr));
  border-top: 1px solid var(--line); border-bottom: 1px solid var(--line); }
.stopr{ position: relative; padding: clamp(18px, 2vw, 26px) clamp(14px, 1.6vw, 22px) clamp(20px, 2.2vw, 28px);
  border-left: 1px solid var(--line); }
.stopr:first-child{ border-left: 0 }
.stopr .no{ display: block; margin-bottom: 12px; font-size: 10px; letter-spacing: .16em; color: var(--fg-3); }
.stopr b{ display: block; font-family: var(--display); font-weight: 600; text-transform: uppercase;
  font-size: clamp(22px, 2.3vw, 36px); letter-spacing: -.03em; line-height: .95; }
.stopr span{ display: block; margin-top: 10px; font-size: 11px; letter-spacing: .16em; text-transform: uppercase;
  color: var(--fg-3); text-align: left; }
.stopr.here{ background: linear-gradient(180deg, rgba(255,82,14,.10), rgba(255,82,14,0) 72%); }
.stopr.here b, .stopr.here span, .stopr.here .no{ color: var(--action) }
.stopr.here::before{ content: ''; position: absolute; left: 0; right: 0; top: -1px;
  height: 2px; background: var(--action); }
/* boxed instead of a footnote under a rule — same restraint, more presence */
.madewith{ margin: clamp(34px, 5vw, 52px) 0 0; padding: 22px 26px 24px;
  border: 1px solid var(--line); border-radius: var(--r); background: rgba(255,255,255,.02);
  font-size: clamp(15px, 1.7vw, 18px); line-height: 1.85; color: var(--fg-3); }
.madewith b{ color: var(--urgent); font-weight: 400; letter-spacing: .22em; text-transform: uppercase;
  font-size: 10.5px; display: block; margin-bottom: 14px; }
.madewith span{ color: rgba(255,255,255,.92); }
.madewith span::after{ content: ' · '; color: var(--fg-3); }
.madewith span:last-child::after{ content: '' }
/* ---------- gallery ----------
   Base state is a plain swipeable row — that is also the no-JS fallback.
   JS adds .hscroll, which turns the section into a tall sticky panel whose
   track is driven horizontally by page scroll. Frames are deliberately all
   different sizes and sit at different heights; the one crossing the centre
   of the screen comes into colour. */
.gal{ position: relative; padding-block: clamp(46px, 7vw, 84px) clamp(56px, 8vw, 100px); }
/* one of the three sentence-case beats */
.gal h2{ font-family: var(--display); font-weight: 500; text-transform: none; letter-spacing: -.04em;
  line-height: .94; font-size: clamp(32px, 5.2vw, 64px); margin: 0; }
.gal-head{ padding-inline: var(--pad); margin-bottom: 30px; position: relative; z-index: 2; }
/* the strip: every panel shares the width until one takes over. Without JS
   they simply stay equal, so all eight photos are always visible. */
.strip{ display: flex; gap: 10px; padding-inline: var(--pad);
  height: min(70vh, 600px); height: min(70svh, 600px); position: relative; z-index: 1; }
.strip figure{ flex: 1 1 0; min-width: 0; margin: 0; position: relative; overflow: hidden;
  border-radius: var(--r); cursor: pointer; background: var(--ink-2);
  transition: flex-grow .75s cubic-bezier(.2,.8,.2,1);
  box-shadow: 0 30px 70px -46px rgba(0,0,0,.95); }
.strip figure.on{ flex-grow: 4.4 }
/* The closed photographs used to be drained to grey and dimmed by half, which
   read as "these ones don't count". They are the same nights as the open one.
   A little desaturation and a light hand on the brightness keeps them quiet
   without denying them their colour, and the open one still clearly wins. */
.strip img{ width: 100%; height: 100%; object-fit: cover;
  filter: saturate(.55) brightness(.76) contrast(1.04); transform: scale(1.04);
  transition: filter .75s ease, transform 1s cubic-bezier(.2,.8,.2,1); }
.strip figure.on img{ filter: saturate(1) brightness(1) contrast(1.02); transform: none }
.strip figure::after{ content: ''; position: absolute; inset: 0; border-radius: inherit; pointer-events: none;
  border: 1px solid rgba(255,255,255,.08); transition: border-color .5s; }
.strip figure.on::after{ border-color: rgba(255,255,255,.22) }
/* the number runs vertically while the panel is a sliver */
.strip .tag{ position: absolute; left: 0; bottom: 0; padding: 16px 0 18px 16px; z-index: 2;
  writing-mode: vertical-rl; transform: rotate(180deg);
  font-size: 10px; letter-spacing: .22em; text-transform: uppercase; color: rgba(255,255,255,.62);
  white-space: nowrap; transition: opacity .35s; }
.strip figure.on .tag{ opacity: 0 }
.strip figcaption{ position: absolute; left: 0; right: 0; bottom: 0; z-index: 2;
  padding: 22px 24px; opacity: 0; transform: translateY(10px);
  transition: opacity .5s .15s, transform .6s .15s cubic-bezier(.2,.8,.2,1);
  background: linear-gradient(transparent, rgba(8,8,10,.9)); }
.strip figure.on figcaption{ opacity: 1; transform: none }
.strip figcaption b{ display: block; font-family: var(--display); font-size: clamp(17px, 1.8vw, 24px);
  font-weight: 600; text-transform: uppercase; letter-spacing: -.01em; margin-bottom: 5px; }
.strip figcaption span{ font-size: 12px; letter-spacing: .16em; text-transform: uppercase; color: var(--fg-2) }
.strip figcaption i{ font-style: normal; color: var(--action); margin-right: 9px; font-weight: 700 }
/* A light travelling around the frame — the edge, never across the picture.
   A conic gradient turns behind the figure and a mask keeps all but the 1px
   ring hidden, so what shows is a bright point running the border.

   Not every photograph gets one, and each has its own delay and speed, so the
   strip never ticks. @property is what lets the angle interpolate; where it
   is unsupported the gradient simply sits still and the border looks normal —
   the same graceful floor the dot field already relies on. */
@property --g26a{ syntax: '<angle>'; initial-value: 0deg; inherits: false }

.strip figure.sheen::before{
  content: ''; position: absolute; inset: 0; z-index: 3; pointer-events: none;
  border-radius: inherit; padding: 1px;
  background: conic-gradient(from var(--g26a),
    transparent 0deg, transparent 288deg,
    rgba(255,255,255,.75) 330deg,
    rgba(255,255,255,.10) 352deg,
    transparent 360deg);
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
          mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
          mask-composite: exclude;
  animation: g26edge var(--sw, 11s) linear var(--sd, 0s) infinite;
}
@keyframes g26edge{ to{ --g26a: 360deg } }

@media (prefers-reduced-motion: reduce){
  .strip figure.sheen::before{ animation: none; display: none }
}

/* The second gallery is the same component with a different subject, so it
   needs no styling of its own — only a little less air above it, because the
   music section directly before it already ends on a wide margin. */
.gal-room{ padding-block: clamp(28px, 4vw, 56px) clamp(56px, 8vw, 100px) }

/* the word sits behind the strip and never moves */
.gal-ghost{ position: absolute; inset: 0; z-index: 0; display: grid; place-items: center; pointer-events: none; }
.gal-ghost .ghostword{ font-weight: 600; font-size: clamp(70px, 17vw, 260px);
  letter-spacing: -.05em; line-height: 1; white-space: nowrap; }
.gal-ghost .ghostword > span{ color: transparent; -webkit-text-stroke: 1px rgba(255,255,255,.07); }
/* ---------- ticket card ---------- */
/* flex, not grid: `width: min(960px, 100%)` needs a definite containing width
   to resolve against. As a centred grid item the area was sized by the card's
   own content, so the card grew past the section instead of fitting it. */
.tkt{ position: relative; overflow: hidden; isolation: isolate;
  display: flex; justify-content: center; align-items: center;
  padding: clamp(64px, 9vw, 120px) var(--pad); }
.tkt > img{ position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover;
  object-position: 50% 32%; z-index: 0; filter: grayscale(1) contrast(1.18) brightness(.4); }
/* same duotone as the production section, so the two photo moments rhyme */
.tkt .tint{ position: absolute; inset: 0; z-index: 1; pointer-events: none;
  background: var(--action); mix-blend-mode: color; opacity: .9; }
.tkt::after{ content: ''; position: absolute; inset: 0; z-index: 2; pointer-events: none;
  background: linear-gradient(180deg, rgba(8,8,10,.66), rgba(8,8,10,.34) 42%, rgba(8,8,10,.82)); }
.tkt .ticket{ z-index: 3 }
.ticket{ position: relative; z-index: 2; display: grid; grid-template-columns: 1fr 300px;
  width: min(960px, 100%); border-radius: 24px; align-items: stretch;
  background: rgba(12,12,14,.58); backdrop-filter: blur(26px) saturate(1.25);
  border: 1px solid rgba(255,255,255,.18); box-shadow: 0 50px 110px -40px rgba(0,0,0,.95); }
.ticket .main, .ticket .stub{ min-width: 0 }
.ticket .main{ padding: 34px clamp(24px, 3vw, 40px) 30px; display: flex; flex-direction: column; gap: 16px; }
.ticket .release{ display: flex; align-items: center; gap: 10px; font-size: 10.5px;
  letter-spacing: .18em; text-transform: uppercase; }
.ticket .release .live{ color: var(--ok); font-weight: 700; display: inline-flex; align-items: center; gap: 7px }
.ticket .release .out{ color: var(--fg-3) }
.ticket .tname{ font-family: var(--display); font-weight: 500; text-transform: uppercase;
  letter-spacing: -.05em; line-height: .82; font-size: clamp(48px, 8vw, 92px); margin: 0 }
.ticket .pitch{ font-size: 16.5px; max-width: 40ch }
.ticket .tfacts{ display: grid; grid-template-columns: repeat(3, auto); gap: 24px; justify-content: start;
  padding-top: 14px; border-top: 1px solid rgba(255,255,255,.16); margin: 0 }
.ticket .tfacts dt{ font-size: 10px; letter-spacing: .16em; text-transform: uppercase; color: var(--fg-3); margin: 0 0 6px }
.ticket .tfacts dd{ font-family: var(--display); font-size: 19px; font-weight: 600; margin: 0 }
.stub{ position: relative; border-radius: 0 23px 23px 0; border-left: 2px dashed rgba(255,255,255,.28);
  background: rgba(255,255,255,.05); padding: 34px 30px 30px;
  display: flex; flex-direction: column; gap: 14px; text-align: center }
.stub::before, .stub::after{ content: ''; position: absolute; left: -11px; width: 22px; height: 22px;
  border-radius: 50%; background: var(--ink) }
.stub::before{ top: -11px }
.stub::after{ bottom: -11px }
.stub .when{ font-size: 10px; letter-spacing: .18em; text-transform: uppercase; color: var(--fg-3); margin-bottom: 8px }
.stub .amount{ font-family: var(--display); font-size: 54px; font-weight: 600; line-height: 1; letter-spacing: -.03em }
.stub .later{ font-size: 12px; color: var(--fg-2); margin-top: 8px }
.stub .rise{ font-size: 11.5px; color: var(--urgent); font-weight: 700; letter-spacing: .06em }
.stub .cta{ margin-top: auto }
.stub .pay{ font-size: 10.5px; letter-spacing: .06em; color: var(--fg-3); margin-top: 10px }
/* ---------- spotify ---------- */
.spot iframe{ width: 100%; height: 352px; border: 0; border-radius: 14px; display: block; }
/* ---------- opera concept (bone) ---------- */
.bone{ background: var(--bone); color: #14110E; }
.bone .kicker{ color: rgba(20,17,14,.5) }
.bone .lede{ color: rgba(20,17,14,.72) }
/* The chapters are the visual proof of the concept: four frames from four
   nights. Past ones sit muted; the current one carries the colour. A card
   without a photo falls back to the flat bone card, so nothing breaks while
   images are still being chosen. */
.chapters{ display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 12px; margin-top: 44px; }
.chap{ position: relative; overflow: hidden; border-radius: var(--r);
  border: 1px solid rgba(20,17,14,.18); padding: 15px 17px;
  display: flex; flex-direction: column; justify-content: flex-end; min-height: 96px; }
.chap .c{ font-size: 10px; letter-spacing: .22em; text-transform: uppercase; color: rgba(20,17,14,.45) }
.chap b{ display: block; font-family: var(--display); font-size: clamp(17px, 1.6vw, 22px); text-transform: uppercase; margin: 7px 0 5px; letter-spacing: -.01em; }
.chap span{ font-size: 12px; color: rgba(20,17,14,.6) }
/* photo cards */
.chap.pic{ aspect-ratio: 3 / 4; padding: 16px; border: 0; }
.chap.pic img{ position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover;
  filter: grayscale(.85) contrast(1.02) brightness(.92);
  transition: filter .45s ease, transform .6s cubic-bezier(.2,.8,.2,1); }
.chap.pic::before{ content: ''; position: absolute; inset: 0; z-index: 1;
  background: linear-gradient(180deg, rgba(8,8,10,0) 38%, rgba(8,8,10,.78) 82%); }
.chap.pic .c, .chap.pic b, .chap.pic span{ position: relative; z-index: 2 }
.chap.pic .c{ color: rgba(255,255,255,.65) }
.chap.pic b{ color: #fff }
.chap.pic span{ color: rgba(255,255,255,.66) }
.chap.pic:hover img{ filter: grayscale(0) brightness(1); transform: scale(1.04) }
/* the current chapter is the only one in colour, ringed in the accent */
.chap.now{ background: #14110E; border-color: #14110E; }
.chap.now .c{ color: var(--action) }
.chap.now b{ color: #fff }
.chap.now span{ color: rgba(255,255,255,.6) }
.chap.pic.now{ box-shadow: 0 0 0 2px var(--action), 0 24px 50px -24px rgba(20,17,14,.55) }
.chap.pic.now img{ filter: none }
.chap.now .live{ display: inline-flex; align-items: center; gap: 6px }
.chap.now .live i{ width: 5px; height: 5px; border-radius: 50%; background: var(--action) }
/* ---------- production accent — the second video moment ----------
   Same footage as the hero, but desaturated and tinted orange so it reads as
   a different room rather than a repeat. isolation keeps the blend modes
   inside this section. */
.prod{ position: relative; min-height: 84vh; min-height: 84svh; display: flex; align-items: center;
  overflow: hidden; isolation: isolate; }
.prod video{ position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; z-index: 0;
  filter: grayscale(1) contrast(1.18) brightness(.4); }
.prod .tint{ position: absolute; inset: 0; z-index: 1; pointer-events: none;
  background: var(--action); mix-blend-mode: color; opacity: .9; }
/* ambient drift — the swirl idea without pulling in WebGL */
.prod .amb{ position: absolute; inset: -25%; z-index: 2; pointer-events: none;
  mix-blend-mode: screen; opacity: .45; filter: blur(44px);
  background:
    radial-gradient(38% 42% at 22% 34%, rgba(255,82,14,.6), transparent 62%),
    radial-gradient(32% 36% at 76% 62%, rgba(255,176,32,.42), transparent 64%),
    radial-gradient(28% 30% at 54% 16%, rgba(255,110,40,.38), transparent 66%);
  animation: drift 30s ease-in-out infinite alternate; }
@keyframes drift {
  0%   { transform: translate3d(-2%, -1%, 0) scale(1) }
  50%  { transform: translate3d(3%, 2%, 0) scale(1.09) }
  100% { transform: translate3d(-1%, 3%, 0) scale(1.03) }
}
.prod::after{ content: ''; position: absolute; inset: 0; z-index: 3; pointer-events: none;
  background: linear-gradient(180deg, rgba(8,8,10,.66), rgba(8,8,10,.3) 42%, rgba(8,8,10,.86)); }
.prod .inner{ position: relative; z-index: 4; padding-block: clamp(56px, 8vw, 96px) }
.prod .shut{ font-size: clamp(46px, 10vw, 150px) }
.prod .lede{ max-width: 40ch; margin-top: 22px; color: rgba(255,255,255,.88) }
.specs{ display: flex; flex-wrap: wrap; gap: 0; margin: 34px 0 0; padding: 0; list-style: none;
  border-top: 1px solid rgba(255,255,255,.18) }
.specs li{ flex: 1 1 200px; padding: 18px 22px 18px 0; border-bottom: 1px solid rgba(255,255,255,.18) }
.specs dt, .specs .k{ font-size: 10px; letter-spacing: .22em; text-transform: uppercase;
  color: var(--urgent); margin-bottom: 8px }
.specs .v{ font-size: clamp(14px, 1.5vw, 17px); line-height: 1.45; color: rgba(255,255,255,.9) }
/* ---------- faq ---------- */
.faq{ border-top: 1px solid var(--line); margin-top: 30px }
.faq details{ border-bottom: 1px solid var(--line) }
.faq summary{ list-style: none; cursor: pointer; padding: 20px 0; display: flex; justify-content: space-between;
  gap: 20px; font-size: 16px; font-weight: 500; }
.faq summary::-webkit-details-marker{ display: none }
.faq summary::after{ content: '+'; color: var(--fg-3); font-size: 20px; line-height: 1 }
.faq details[open] summary::after{ content: '−' }
.faq p{ margin: 0 0 20px; color: var(--fg-2); font-size: 14px; line-height: 1.65; max-width: 70ch }
/* ---------- releases: the same idea as arrival pricing, but about when you
   buy rather than when you turn up ---------- */
.rel-rows{ margin-top: 30px; border-top: 1px solid var(--line); }
.rel-row{ display: flex; align-items: baseline; gap: clamp(12px, 2vw, 26px);
  padding: 20px 0; border-bottom: 1px solid var(--line); position: relative; }
.rel-row .nm{ font-family: var(--display); font-weight: 600; text-transform: uppercase;
  font-size: clamp(20px, 2.4vw, 30px); letter-spacing: -.02em; }
.rel-row .st{ font-size: 10.5px; letter-spacing: .18em; text-transform: uppercase; color: var(--fg-3); }
.rel-row .pr{ margin-left: auto; font-family: var(--display); font-weight: 600;
  font-size: clamp(20px, 2.4vw, 30px); letter-spacing: -.02em; white-space: nowrap; }
.rel-row.gone .nm, .rel-row.gone .pr{ color: var(--fg-3); text-decoration: line-through }
.rel-row.gone .st{ color: var(--gone) }
.rel-row.now{ background: linear-gradient(90deg, rgba(52,208,127,.09), transparent 62%) }
.rel-row.now .st{ color: var(--ok); font-weight: 700 }
.rel-row.now::before{ content: ''; position: absolute; left: calc(var(--pad) * -.5); top: 0; bottom: 0;
  width: 2px; background: var(--ok) }
.rel-row.next .pr, .rel-row.next .st{ color: var(--urgent) }
.rel-row.door .nm, .rel-row.door .pr{ color: var(--gone) }
/* ---------- closing ---------- */
.close{ position: relative; overflow: hidden; text-align: center;
  padding-block: clamp(84px, 13vw, 160px); }
.close .glow{ position: absolute; inset: -35%; z-index: 0; pointer-events: none; filter: blur(60px);
  background: radial-gradient(36% 42% at 50% 50%, rgba(255,82,14,.22), transparent 68%);
  animation: breathe 16s ease-in-out infinite alternate; }
.close .wrap{ position: relative; z-index: 1 }
.close h2{ font-family: var(--display); font-weight: 500; letter-spacing: -.04em; line-height: .95;
  font-size: clamp(38px, 7vw, 92px); margin: 18px 0 34px; text-transform: none; }
@keyframes breathe {
  0%   { transform: translate3d(-7%, -5%, 0) scale(1);    opacity: .5 }
  100% { transform: translate3d(7%, 6%, 0)   scale(1.28); opacity: .95 }
}
/* ---------- sticky buy bar ---------- */
.bbar{ position: fixed; left: 0; right: 0; bottom: 0; z-index: 40;
  display: flex; align-items: center; gap: clamp(16px, 3vw, 44px);
  padding: 13px var(--pad) calc(13px + env(safe-area-inset-bottom));
  background: rgba(6,6,8,.93); backdrop-filter: blur(22px) saturate(1.3); border-top: 1px solid var(--line); }
.bbar .price{ flex: none }
.bbar .price small{ display: block; font-size: 10px; letter-spacing: .22em; text-transform: uppercase;
  color: var(--fg-3); margin-bottom: 5px; }
.bbar .price b{ font-family: var(--display); font-size: clamp(24px, 3vw, 38px); font-weight: 600;
  line-height: 1; letter-spacing: -.02em; }
.bbar .mid{ flex: 1; min-width: 0 }
.bbar .rel{ display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  font-size: 11px; letter-spacing: .1em; text-transform: uppercase; }
.bbar .rel .gone{ color: var(--fg-3); text-decoration: line-through }
.bbar .rel .live{ color: var(--ok); font-weight: 700; display: inline-flex; align-items: center; gap: 6px }
.bbar .rel .up{ color: var(--urgent); font-weight: 700 }
.bbar .rel .sep{ width: 3px; height: 3px; border-radius: 50%; background: var(--line-2) }
.bbar .prog{ height: 5px; border-radius: 99px; background: rgba(255,255,255,.12); margin-top: 10px; overflow: hidden }
.bbar .prog i{ display: block; height: 100%; width: 71%; border-radius: 99px;
  background: linear-gradient(90deg, var(--action), var(--urgent)); }
/* rotating light on the buy button */
/* A light travels around the edge of every button.
   The old version laid a rotating disc behind the button and covered the middle
   with a solid pill, which left the unlit part of the ring showing the page
   behind — that dark gap is the stray border. Masking the gradient down to the
   ring itself means the button keeps its own fill and only the outline lights. */
.gravity-2026 .btn{ position: relative; isolation: isolate; }
.gravity-2026 .btn > span{ position: relative; z-index: 1 }
.gravity-2026 .btn-beam { background: var(--action) }
.gravity-2026 .btn-beam:hover { background: var(--action-hi) }
/* the theme kills outlines globally, which leaves keyboard users with nothing
   and lets the browser's own blue ring show through in places — this is both */
.gravity-2026 .btn:focus-visible { outline: 2px solid #fff !important; outline-offset: 3px; box-shadow: none; }
/* ---------- scroll reveal (gated on .anim so no-JS never hides content) ---------- */
.anim .rv{ opacity: 0; transform: translateY(22px); transition: opacity .75s ease, transform .75s cubic-bezier(.2,.8,.2,1) }
.anim .rv.in{ opacity: 1; transform: none }
.gravity-2026 footer{ padding: 44px 0 60px; border-top: 1px solid var(--line); color: var(--fg-3); font-size: 13px }
/* ==========================================================================
   Mockup sync — social proof sections, hero CTA, progress bar.

   Ported from gravity-landing-mockups/page.html. Only rules that are new or
   that changed are here; everything identical was left alone. Written at the
   end so later declarations win without editing the blocks above.
   ========================================================================== */

:root { --brand-h: 100px; --bar-h: 98px;
}
.hero { position: relative; height: calc(100vh - var(--bar-h)); height: calc(100svh - var(--bar-h)); width: 100%;
  display: flex; flex-direction: column; overflow: hidden;
  padding-top: var(--brand-h); padding-bottom: 8px;
}
.ic { width: 30px; height: 30px; border-radius: 50%; display: grid; place-items: center; flex: none;
  border: 1px solid var(--line-2); color: var(--fg-3); opacity: .5; cursor: pointer;
  transition: opacity .2s, color .2s, border-color .2s, background-color .2s, transform .2s;
}
.ic svg { width: 13px; height: 13px; display: block; fill: currentColor;
}
.chap { flex: none; scroll-snap-align: start; min-width: 172px; padding: 15px 17px;
  border: 1px solid rgba(20,17,14,.18); border-radius: var(--r);
}
.chap b { display: block; font-family: var(--display); font-size: 18px; text-transform: uppercase; margin: 7px 0 5px; letter-spacing: -.01em;
}
.chap.now { background: #14110E; border-color: #14110E; position: relative; overflow: hidden
}
.chap.now::after { content: ''; position: absolute; inset: 0; pointer-events: none;
  background: linear-gradient(115deg, transparent 34%, rgba(255,82,14,.3) 50%, transparent 66%);
  transform: translateX(-130%); animation: chapsheen 4.5s ease-in-out infinite;
}
@keyframes chapsheen { 0% { transform: translateX(-130%) } 38%, 100% { transform: translateX(130%) }
}
.bbar .prog { height: 7px; border-radius: 99px; background: rgba(255,255,255,.12); margin-top: 10px; overflow: hidden
}
/* The earlier take on this effect used to live here: a cone 280% of the
   button's width, spun behind it and meant to be clipped into a ring by the
   button's own edges. Nothing was clipping it, so the wedge swept out across
   the page — and its companion ::after covered the ring that the rule further
   up already draws correctly, masked to the outline and staying inside the
   button. Two descriptions of one effect, and the wrong one was winning.
   The masked ring above is the whole effect now. */
.morning { padding: clamp(76px, 10vw, 140px) 0 clamp(70px, 9vw, 120px); overflow: hidden;
}
.morning .head { text-align: center; margin-bottom: 52px; padding-inline: var(--pad);
}
.morning .head h2, .ledger .head h2 { font-family: var(--display); font-weight: 500;
  letter-spacing: -.035em; line-height: .98; font-size: clamp(32px, 4.8vw, 58px); margin: 0;
  max-width: 22ch; margin-inline: auto;
}
.morning .head .kicker { justify-content: center;
}
.mscroll { overflow: hidden;
}
.mscroll + .mscroll { margin-top: 16px;
}
.mrow { display: flex; gap: 16px; width: max-content; padding-inline: 40px;
}
.mrow.r1 { animation: mdrift1 46s linear infinite;
}
.mrow.r2 { animation: mdrift2 58s linear infinite;
}
@keyframes mdrift1 { from { transform: translateX(0) } to { transform: translateX(-50%) }
}
@keyframes mdrift2 { from { transform: translateX(-50%) } to { transform: translateX(0) }
}
/* The strip is scrollable everywhere, so a finger can always take hold of it.
   The drift itself is driven from JavaScript rather than by the animation
   below — a CSS transform cannot be grabbed mid-flight, and stopping it the
   moment a screen is touched is what made the section feel dead on a phone.
   Scrolling the container instead keeps it moving and lets go when asked.
   Without JavaScript the keyframes still run, so it is never simply static. */
.mscroll { overflow-x: auto; overscroll-behavior-x: contain;
  scrollbar-width: none; -webkit-overflow-scrolling: touch }
.mscroll::-webkit-scrollbar { display: none }
.mscroll.js .mrow { animation: none }
@media (max-width: 640px) {
  .mrow { padding-inline: var(--pad) }
}
.morning:hover .mrow { animation-play-state: paused;
}
.story { flex: none; width: 296px; padding: 16px 18px 14px; border-radius: 18px;
  background: var(--ink-2); border: 1px solid var(--line); transform: rotate(var(--tilt, 0deg));
}
.story .top { display: flex; align-items: center; gap: 9px; margin-bottom: 9px;
}
.story .av { width: 26px; height: 26px; border-radius: 50%; flex: none;
  background: linear-gradient(135deg, var(--action), #7b2ff7);
}
.story .who { font-size: 12px; font-weight: 700;
}
/* read aloud, never drawn — for text the design renders as decoration */
.gravity-2026 .g26-sr { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap; border: 0 }
.story .when { margin-left: auto; font-size: 10.5px; color: var(--fg-card);
}
.story p { margin: 0; font-size: 14px; line-height: 1.5; color: rgba(255,255,255,.88);
}
.story .re { margin-top: 9px; font-size: 9.5px; letter-spacing: .16em; text-transform: uppercase; color: var(--fg-card);
}
.story .re b { color: var(--action);
}
.voices { padding: clamp(84px, 11vw, 150px) 0; text-align: center; border-top: 1px solid var(--line);
  background: radial-gradient(60% 60% at 50% 0%, rgba(255,82,14,.06), transparent 70%);
}
.voices .stage { position: relative; display: grid;
}
.voice-slide { grid-area: 1 / 1; display: flex; flex-direction: column; align-items: center;
  justify-content: center; opacity: 0; transform: translateY(10px); transition: opacity .6s ease, transform .6s ease;
  pointer-events: none;
}
.voice-slide.on { opacity: 1; transform: none; pointer-events: auto;
}
.voice-slide blockquote { margin: 0 auto; max-width: 18ch;
  font-family: var(--display); font-weight: 500; letter-spacing: -.03em; line-height: 1.04;
  font-size: clamp(30px, 5.4vw, 72px);
}
.voice-slide blockquote em { font-style: normal; color: var(--action);
}
.voice-slide .by { margin-top: 26px; display: inline-flex; align-items: center; gap: 9px; font-size: 13px; color: var(--fg-2);
}
.voice-slide .by b { color: #fff
}
.voice-slide .by svg { width: 14px; height: 14px; fill: #4BA3FF; flex: none
}
.vtabs { display: flex; gap: 6px; justify-content: center; flex-wrap: wrap; margin-top: 40px;
}
.vtab { padding: 9px 16px; border-radius: var(--r-pill); border: 1px solid var(--line);
  font-size: 11px; font-weight: 700; letter-spacing: .14em; text-transform: uppercase;
  color: var(--fg-3); transition: color .2s, border-color .2s;
}
.vtab.on { color: #fff; border-color: var(--action);
}
.vtab:hover { color: #fff
}
.ledger { padding: clamp(76px, 10vw, 140px) 0; border-top: 1px solid var(--line);
}
.ledger .head { margin-bottom: 38px;
}
.led { border-top: 1px solid var(--line);
}
.led-row { display: grid; grid-template-columns: 88px 1fr auto auto; gap: clamp(14px, 3vw, 40px);
  align-items: baseline; padding: 21px 0; border-bottom: 1px solid var(--line);
}
.led-row .no { font-size: 11px; letter-spacing: .2em; color: var(--fg-3);
}
.led-row .nm { font-family: var(--display); font-weight: 600; text-transform: uppercase;
  letter-spacing: -.02em; font-size: clamp(22px, 3vw, 38px); line-height: 1;
}
.led-row .ppl { font-size: 13px; color: var(--fg-2); font-variant-numeric: tabular-nums; text-align: right;
}
.led-row .st { justify-self: end; font-size: 10px; font-weight: 700; letter-spacing: .18em; text-transform: uppercase;
  padding: 6px 11px; border-radius: 4px; transform: rotate(-2deg);
  border: 1.5px solid var(--gone); color: var(--gone);
}
.led-row.now .st { border-color: var(--ok); color: var(--ok); transform: none;
}
.led-row.now .nm { color: var(--action);
}
.led-row.now { background: linear-gradient(90deg, rgba(255,82,14,.07), transparent 65%);
}
.iflike { padding: clamp(80px, 10vw, 140px) 0; text-align: center; overflow: hidden;
  border-top: 1px solid var(--line);
}
.iflike .kicker { justify-content: center;
}
.iflike h2 { font-size: clamp(30px, 4vw, 48px);
}
.namesbelt { margin: 38px 0 30px; overflow: hidden;
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 12%, #000 88%, transparent);
          mask-image: linear-gradient(90deg, transparent, #000 12%, #000 88%, transparent);
}
.namesbelt .belt { display: flex; gap: clamp(28px, 4vw, 56px); width: max-content;
  animation: beltdrift 30s linear infinite;
}
.namesbelt .belt span { font-family: var(--display); font-weight: 600; text-transform: uppercase;
  letter-spacing: -.02em; font-size: clamp(34px, 5.6vw, 76px); line-height: 1; white-space: nowrap;
  color: transparent; -webkit-text-stroke: 1px rgba(255,255,255,.34);
}
.namesbelt .belt span.solid { color: #fff; -webkit-text-stroke: 0;
}
@keyframes beltdrift { from { transform: translateX(0) } to { transform: translateX(-50%) }
}
/* The names never stop. Pausing them under a cursor made sense while they were
   the only thing moving; now that the strip below can be taken by hand, a
   second thing that halts on contact just reads as the page freezing. */
.iflike:hover .belt { animation-play-state: running;
}
.iflike .tail { font-size: clamp(17px, 2vw, 22px); color: var(--fg-2); margin: 0 0 30px;
}
.iflike .tail b { color: #fff;
}
.ledger { background: var(--ink-2); border-top: 0;
}
.ledger::before { content: ''; position: absolute; top: 0; left: 0; right: 0; height: 2px;
  background: linear-gradient(90deg, var(--action), rgba(255,82,14,.25) 45%, transparent 75%);
}
.iflike { background: radial-gradient(70% 90% at 50% 10%, rgba(255,82,14,.10), transparent 62%);
}
.morning {
}
.morning .orb { position: absolute; border-radius: 50%; filter: blur(90px); pointer-events: none; z-index: 0;
}
.morning .orb.a { width: 460px; height: 460px; left: 4%; top: 22%;
  background: rgba(255,82,14,.20); animation: orbfloat 14s ease-in-out infinite alternate;
}
.morning .orb.b { width: 400px; height: 400px; right: 2%; bottom: 2%;
  background: rgba(123,47,247,.17); animation: orbfloat 18s ease-in-out infinite alternate-reverse;
}
@keyframes orbfloat { from { transform: translateY(-16px) } to { transform: translateY(20px) }
}
.morning .head, .morning .mrow { position: relative; z-index: 1;
}
.voices { background:
  radial-gradient(60% 60% at 50% 0%, rgba(255,82,14,.07), transparent 70%),
  radial-gradient(46% 52% at 82% 100%, rgba(123,47,247,.07), transparent 70%);
}
.spot { background: radial-gradient(44% 60% at 78% 42%, rgba(30,215,96,.05), transparent 70%);
}
.heroctas { display: flex; gap: 12px; justify-content: center; flex-wrap: wrap;
}
.operalink { display: inline-block; margin-top: 14px; font-size: 11px; font-weight: 600;
  letter-spacing: .2em; text-transform: uppercase; color: var(--fg-3);
  border-bottom: 1px solid var(--line-2); padding-bottom: 3px; transition: color .2s, border-color .2s;
}
.operalink:hover { color: #fff; border-color: #fff;
}
.stopr { position: relative; display: block; padding: clamp(18px, 2vw, 26px) clamp(14px, 1.6vw, 22px) clamp(20px, 2.2vw, 28px);
  border-left: 1px solid var(--line); border-bottom: 0;
}
.stopr .no { display: block; width: auto; margin-bottom: 12px; font-size: 10px; letter-spacing: .16em; color: var(--fg-3);
}
.stopr span { display: block; margin: 10px 0 0; width: auto; font-size: 11px; letter-spacing: .16em;
  text-transform: uppercase; color: var(--fg-3); text-align: left;
}
.stopr.here::before { content: ''; position: absolute; left: 0; right: 0; top: -1px; bottom: auto;
  width: auto; height: 2px; background: var(--action);
}
.chapters { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 12px; margin-top: 44px;
  overflow: visible;
}
.chap { position: relative; overflow: hidden; min-width: 0; border-radius: var(--r);
  border: 1px solid rgba(20,17,14,.18); padding: 15px 17px;
  display: flex; flex-direction: column; justify-content: flex-end; min-height: 96px;
}
.chap b { font-size: clamp(17px, 1.6vw, 22px);
}
.chap.now::after { content: none
}
.gravity-2026 .btn { position: relative; isolation: isolate; overflow: visible;
}
.gravity-2026 .btn::before { content: none
}
/* ---------- the sheen ----------
   The old version of this was a conic gradient spun behind the button and
   clipped into a ring by a mask. It was written three times in three places,
   each redefining the others' keyframes, and what reached the screen was a
   hard white line across the top edge.

   This is the same idea done the way it cannot come apart: a soft diagonal
   band inside the button, travelling left to right, with `overflow: hidden`
   on the button itself doing the clipping. No mask to fail, no keyframes
   anyone else touches, and nothing that can leave the pill even if a later
   rule changes its shape. */
.gravity-2026 .btn-beam { position: relative; background: var(--action); overflow: hidden }
.gravity-2026 .btn-beam > span { position: relative; z-index: 1 }
.gravity-2026 .btn-beam::before {
  content: ''; position: absolute; top: -60%; bottom: -60%; left: -40%; width: 32%;
  z-index: 0; pointer-events: none; transform: rotate(18deg);
  background: linear-gradient(90deg, transparent, rgba(255,255,255,.30) 42%,
    rgba(255,255,255,.46) 52%, transparent);
  animation: sheen 4.6s cubic-bezier(.5,0,.3,1) infinite;
}
@keyframes sheen {
  0%       { left: -40% }
  62%, 100%{ left: 118% }
}
@media (prefers-reduced-motion: reduce) {
  .gravity-2026 .btn-beam::before { animation: none; opacity: 0 }
}
.ic { width: 34px; height: 34px; color: var(--fg-2); opacity: .75;
}
.ic svg { width: 14px; height: 14px;
}
.ic svg, .ic svg path { fill: currentColor;
}
.voices .stage { position: relative; display: grid; margin-top: 8px; text-align: left;
}
.voice-slide { grid-area: 1 / 1; display: grid;
  grid-template-columns: clamp(150px, 17vw, 230px) 1fr; gap: clamp(24px, 3.4vw, 52px);
  align-items: center; text-align: left;
  opacity: 0; transform: translateY(10px); transition: opacity .55s ease, transform .55s ease;
  pointer-events: none;
}
.voice-slide.on { opacity: 1; transform: none; pointer-events: auto;
}
.voice-slide .shot { position: relative; aspect-ratio: 4 / 5; border-radius: var(--r);
  overflow: hidden; background: var(--ink-3);
}
.voice-slide .shot img { width: 100%; height: 100%; object-fit: cover; filter: grayscale(.6) contrast(1.05);
}
.voice-slide .shot::after { content: ''; position: absolute; inset: 0;
  background: linear-gradient(180deg, transparent 55%, rgba(8,8,10,.55));
}
.voice-slide .said { min-width: 0
}
/* The quote is the argument; the name only says who is making it. It used
   to be the other way round — a 86px name over a 30px sentence. */
.voice-slide .nm { display: block; font-family: var(--display); font-weight: 600;
  text-transform: uppercase; letter-spacing: -.03em; line-height: .92;
  font-size: clamp(26px, 3.6vw, 48px);
}
.voice-slide .meta { display: flex; align-items: center; gap: 8px; margin: 10px 0 20px;
  font-size: 11px; letter-spacing: .2em; text-transform: uppercase; color: var(--fg-3);
}
.voice-slide .meta svg { width: 13px; height: 13px; fill: #4BA3FF; flex: none
}
.voice-slide blockquote { margin: 0; max-width: 26ch;
  font-family: var(--body); font-weight: 400; letter-spacing: normal;
  font-size: clamp(23px, 3.1vw, 40px); line-height: 1.26; color: rgba(255,255,255,.94);
}
.voice-slide blockquote em { font-style: normal; color: var(--action);
}
.act { padding: 12px 0
}
.act .nm { font-size: clamp(20px, 2vw, 27px); line-height: 1.05
}
.act.head { padding: 24px 0
}
html { scroll-behavior: smooth;
}
.namesbelt + .namesbelt { margin-top: 10px
}
.b-nights .belt { animation-duration: 38s; animation-direction: reverse;
}
.b-nights .belt span { font-size: clamp(26px, 4vw, 54px);
  -webkit-text-stroke-color: rgba(255,255,255,.24);
}
.b-nights .belt span.solid { color: rgba(255,255,255,.82)
}
.watchroom { cursor: pointer
}
.watchroom span { display: inline-flex; align-items: center; gap: 10px
}
.watchroom .pl { width: 15px; height: 15px; fill: currentColor; flex: none
}
.heroproof { margin: 16px 0 0; font-size: clamp(11px, 1.2vw, 13px); letter-spacing: .04em;
  color: var(--fg-2);
}
.bbar .prog { position: relative
}
.bbar .prog i { position: relative; overflow: hidden; border-radius: 99px
}
@keyframes progfill { from { width: 0 }
}
.bbar .prog i.grow { animation: progfill 1s cubic-bezier(.2,.8,.2,1) both
}
.bbar .prog i::after {
  content: ''; position: absolute; top: 0; bottom: 0; left: 0; width: 55%;
  border-radius: inherit; pointer-events: none;
  background: linear-gradient(90deg,
    rgba(255,255,255,0) 0%, rgba(255,255,255,.55) 46%, rgba(255,255,255,.8) 58%, rgba(255,255,255,0) 100%);
  transform: translateX(-120%);
  animation: progsweep 4.5s cubic-bezier(.36,.66,.3,1) 1s infinite;
}
@keyframes progsweep {
  0%   { transform: translateX(-120%) }
  42%  { transform: translateX(190%) }
  100% { transform: translateX(190%) }
}
.bbar .progrow { display: flex; align-items: center; gap: 12px; margin-top: 10px
}
.bbar .progrow .prog { flex: 1; margin-top: 0
}
.bbar .pctnum { flex: none; font-family: var(--display); font-weight: 600; font-size: 15px;
  line-height: 1; letter-spacing: -.01em; color: #fff; font-variant-numeric: tabular-nums;
  display: inline-flex; align-items: baseline; gap: 5px
}
.bbar .pctnum span { font-family: var(--body); font-weight: 500; font-size: 9.5px;
  letter-spacing: .16em; text-transform: uppercase; color: var(--fg-3)
}
.bbar .prog { overflow: visible
}
.bbar .prog::after {
  content: ''; position: absolute; top: 50%; left: var(--pct, 71%); width: 14px; height: 14px;
  margin: -7px 0 0 -7px; border-radius: 50%; pointer-events: none;
  background: radial-gradient(circle, rgba(255,255,255,.85), rgba(255,176,32,.45) 42%, transparent 70%);
  animation: proghead 2.4s ease-in-out infinite;
}
@keyframes proghead {
  0%, 100% { opacity: .4; transform: scale(.8) }
  50%      { opacity: .95; transform: scale(1.1) }
}


/* ---------- conditional blocks, grouped so position never decides ---------- */

@media (max-width: 900px) {
.split { grid-template-columns: 1fr; gap: 26px }
  .spot iframe { height: 232px }
  .note-tag { white-space: normal; max-width: min(70vw, 300px); line-height: 1.35 }
  /* eight slivers across 375px would be 40px each — stack the accordion
     instead, so flex-grow drives height rather than width */
  /* The accordion is gone on phones. It showed one photograph and five 74px
     slivers, and a sliver sells nothing — these pictures are the strongest
     argument the page has. Two columns, six real photographs, full colour.

     Grid rather than flex, so `flex-grow` from the desktop rules cannot
     resize a cell: tapping still toggles `.on`, but here that only brings up
     the caption instead of expanding the panel. */
  .strip { display: grid; grid-template-columns: 1fr 1fr; gap: 8px;
    flex-direction: unset; height: auto }
  .strip figure { flex: none; height: auto; aspect-ratio: 3 / 4; transition: none }
  .strip figure.on { flex: none; height: auto }
  /* Desaturating them made sense when five were closed and one was open.
     With all six open there is nothing to play down. */
  .strip img { filter: none; transform: none }
  .strip .tag { display: none }
  .strip figcaption { padding: 14px 15px }
  .strip figcaption b { font-size: 15px }
  .ticket { grid-template-columns: 1fr }
  .stub { border-radius: 0 0 23px 23px; border-left: 0; border-top: 2px dashed rgba(255,255,255,.28); text-align: left }
  .stub::before { top: -11px; left: -11px }
  .stub::after { top: -11px; bottom: auto; left: auto; right: -11px }
  .ticket .tfacts { grid-template-columns: 1fr 1fr; gap: 16px 24px }
  .ticket .tname { font-size: clamp(40px, 11vw, 92px) }
}

@media (max-width: 640px) {
.tmodal{ padding: 0; align-items: end; }
  /* Near the top, not floated at the bottom. Seven ticket types plus a header
     do not fit in the lower two thirds of a phone, and what was left over was
     a band of dead page above a panel already scrolled past its own title. */
  .tmodal{ align-items: start; padding-top: 8px }
  .tmbox{ width: 100%; max-height: calc(100vh - 16px); max-height: calc(100svh - 16px);
    padding: 0 0 10px }
  .g26-tickethead{ padding: 4px 60px 14px 16px }
  .g26-tktfacts{ gap: 26px }
  /* the way out stays on screen, whatever the list is doing underneath */
  .tmbox .vclose{ position: fixed; top: 14px; right: 14px; float: none; margin: 0;
    background: rgba(10,10,12,.72); backdrop-filter: blur(8px) }
/* --bar-h must be >= the bar's real height; body padding-bottom is what
     keeps the footer from sliding under it */
  :root{ --bar-h: 126px }

  /* ---- mobile typography ----
     vw-only clamps collapse to their minimum on a 375px screen, which left
     every heading at desktop's smallest step. These raise the floor so the
     phone gets the same weight of type, not a shrunken copy of it. */
  .gravity-2026 .title { font-size: clamp(52px, 14vw, 132px) }
  .presents{ font-size: 12px; letter-spacing: .3em }
  /* .gal is not a .sec — without it the gallery heading kept the desktop
     floor and sat 4px smaller than every other one */
  .sec h2, .gal h2{ font-size: clamp(36px, 9vw, 64px); line-height: .96 }
  .sec .lede, .lede{ font-size: 15.5px; line-height: 1.6 }
  .kicker{ font-size: 11px; letter-spacing: .22em; margin-bottom: 12px }
  .sec{ padding-block: clamp(56px, 14vw, 92px) }
  .metarow li{ font-size: 12px; letter-spacing: .12em; padding-right: 11px; margin-right: 11px }
  .facts dd{ font-size: 19px }
  .facts > div{ padding: 13px 0 }
  /* the specs sit over playing video — they need weight to stay readable */
  .specs li{ padding: 17px 0 }
  .specs .k{ font-size: 11px; letter-spacing: .2em; margin-bottom: 9px }
  .specs .v{ font-size: 17px; line-height: 1.5 }
  /* tighter rows: the role sat a full line away from the name */
  .act{ gap: 3px 10px }
  .act .role{ font-size: 10px; letter-spacing: .16em }
  /* release rows: name on top, status under, price hard right */
  .rel-row{ flex-wrap: wrap; gap: 4px 12px; padding: 16px 0 }
  .rel-row .nm{ font-size: 22px }
  .rel-row .pr{ font-size: 22px }
  .rel-row .st{ width: 100%; order: 3; font-size: 10px }
  .rel-row.now::before{ left: -10px }
  .close h2{ font-size: clamp(50px, 15vw, 92px) }
  .road{ grid-template-columns: repeat(2, minmax(0, 1fr)) }
  .stopr{ padding: 16px 14px 18px }
  .stopr:nth-child(odd){ border-left: 0 }
  .stopr:nth-child(-n+2){ border-bottom: 1px solid var(--line) }
  .stopr b{ font-size: clamp(22px, 6.6vw, 32px) }
  .stopr .no{ margin-bottom: 8px }
  .stopr span{ margin-top: 7px; font-size: 10px }
  .madewith{ font-size: 13px; line-height: 2 }
  .route-line{ font-size: 11.5px; gap: 6px 10px }
  .prod .shut{ font-size: clamp(52px, 15vw, 150px) }
  .prod .inner{ padding-block: clamp(52px, 13vw, 96px) }
  .specs li{ flex-basis: 100% }
  .ticket .tname{ font-size: clamp(46px, 13vw, 92px) }
  /* the address is the least useful line on a phone and it wraps to three */
  .ticket .tfacts > div:nth-child(3){ display: none }
  .ticket .tfacts{ grid-template-columns: 1fr 1fr }
  .stub .amount{ font-size: 48px }
  .faq summary{ font-size: 15px; padding: 17px 0 }
  .chap.pic{ aspect-ratio: 4 / 5 }

  /* ---- artist rows: name on its own line, then country + icons, then role ---- */
  /* auto/1fr so the country sits immediately after the name instead of being
     pushed to the far edge — same reading order as desktop */
  .act{ display: grid; grid-template-columns: auto 1fr; align-items: baseline; gap: 10px 10px; padding: 18px 0 }
  .act .nm{ grid-column: 1; grid-row: 1; min-width: 0 }
  .act .cc{ grid-column: 2; grid-row: 1; justify-self: start }
  .act .role{ grid-column: 1; grid-row: 2; margin-left: 0; width: auto; align-self: center }
  .act .links{ grid-column: 2; grid-row: 2; justify-self: end; margin-left: 0 }
  .act.head .nm{ font-size: clamp(40px, 11vw, 76px) }
  .act .nm{ font-size: clamp(26px, 7vw, 34px) }
  /* over a bright frame on a phone the copy sits lower, so the ramp is heavier */
  .hero::before{
    background:
      radial-gradient(80% 44% at 50% 52%, rgba(8,8,10,.82) 0%, rgba(8,8,10,.66) 54%, rgba(8,8,10,.16) 88%, rgba(8,8,10,0) 100%),
      linear-gradient(180deg, rgba(8,8,10,.76) 0%, rgba(8,8,10,.28) 24%, rgba(8,8,10,.16) 66%, rgba(8,8,10,.3) 100%);
  }
  .hero .stack{ gap: 15px }
  .pitch{ font-size: 14px }
  .chapters{ grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px }
  .river figure{ width: 62vw }
  /* On a phone the buttons were built at desktop weight: 19px of padding above
     and below a 16px label is a lot of ink for a thumb-sized screen, and full
     width already makes them easy to hit. The height comes down, the sides
     stay generous, and the tap target is still well past the 44px minimum. */
  .gravity-2026 .btn { padding: 13px 24px; font-size: 14.5px }
  .gravity-2026 .btn-lg { padding: 15px 26px; font-size: 15.5px }

  /* ---------- the buy bar, rebuilt for a phone ----------
     It was three stacked rows — a wrapping release ladder, then the price and
     the button — and took a fifth of the screen for the whole scroll. Most of
     that was a table: which release ran out, which one is running, which one is
     next, all repeating the price already set in large type beside them.

     A phone gets one row instead. The price and the button are the two things
     a thumb is looking for, so they take the whole width and nothing wraps. The
     line underneath keeps only what the big price cannot say: how much is gone
     and what it costs next. And the progress line moves to the top edge of the
     bar as a hairline — full width, no label, no box — so the urgency is still
     visible while costing no height at all. */
  /* Three columns side by side left the middle one about ninety pixels wide,
     which cut the sentence in half. A two-column grid instead: the price and
     its one supporting line share the left, the button takes the right and
     spans both rows, so the small line has the full width of the price block
     to finish itself in. */
  .bbar{ display: grid; grid-template-columns: minmax(0, 1fr) auto;
    align-items: center; column-gap: 14px; row-gap: 3px;
    padding: 11px 16px calc(11px + env(safe-area-inset-bottom)) }

  .bbar .price{ grid-column: 1; grid-row: 1 }
  .bbar .price small{ font-size: 9px; letter-spacing: .2em; margin-bottom: 1px }
  .bbar .price b{ font-size: 29px; line-height: 1 }

  .bbar .mid{ grid-column: 1; grid-row: 2; min-width: 0 }
  .bbar .buy{ grid-column: 2; grid-row: 1 / span 2; margin-left: 0; align-self: center }

  /* one line, no wrapping, and only the parts the price does not already say */
  /* Sentence case, not capitals. Small uppercase type with tracking is a
     label; this line is a sentence about the night, and at 10px it is far
     easier to take in at a glance set the way it is spoken. */
  .bbar .rel{ font-size: 11px; letter-spacing: 0; text-transform: none; gap: 5px;
    flex-wrap: nowrap; white-space: nowrap; overflow: hidden }
  .bbar .rel .live{ text-transform: none }
  .bbar .rel .up{ text-transform: none }
  .bbar .rel .gone,
  .bbar .rel .sep,
  .bbar .rel .relname,
  .bbar .rel .up .upname{ display: none }
  /* With no percentage to introduce, the live marker is a green dot sitting on
     its own in front of a stray separator. Nothing to announce, nothing shown. */
  .bbar .rel .live:not(:has(.pctv)) { display: none }
  /* The separator introduces the price only when something came before it.
     With no percentage to lead with, the line was opening on a stray dot. */
  .bbar .rel .up::before{ content: 'next '; color: var(--fg-3); font-weight: 500 }
  .bbar .rel .live:has(.pctv) ~ .up::before{ content: '· next ' }

  /* the fill becomes the top edge of the bar itself */
  .bbar .progrow{ position: absolute; left: 0; right: 0; top: 0; margin: 0; gap: 0 }
  .bbar .progrow .prog{ height: 3px; border-radius: 0; margin: 0; overflow: visible }
  /* the glowing head travels on the phone too — it is the part that reads as
     the line being alive rather than printed, and it costs no height */
  .bbar .progrow .prog::after{ display: block; width: 11px; height: 11px; margin: -5.5px 0 0 -5.5px }
  .bbar .pctnum{ display: none }
.morning .orb { display: none
  }
  .heroctas .btn { width: 100%;
  }
  .iflike { padding: 62px 0 58px
  }
  .morning { padding: 62px 0 58px
  }
  .voices { padding: 64px 0
  }
  .ledger { padding: 62px 0
  }
  .namesbelt { margin: 26px 0 22px
  }
  .iflike .tail { margin-bottom: 24px
  }
  .led-row { grid-template-columns: 1fr auto
  }
  .led-row .no, .led-row .ppl { display: none
  }
  .story { width: 260px
  }
  .vtab { padding: 8px 12px; font-size: 10px
  }
  :root { --brand-h: 86px; --bar-h: 126px
  }
  .specs li { padding: 17px 0
  }
  .act { gap: 3px 10px
  }
  .act .role { font-size: 10px; letter-spacing: .16em
  }
  .chap { min-width: 158px
  }
  .act .nm { grid-column: 1; grid-row: 1; min-width: 0
  }
  .chapters { margin-inline: calc(var(--pad) * -1); padding-inline: var(--pad)
  }
.chapters { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; margin-inline: 0; padding-inline: 0
  }
  .chapters .chap:first-of-type { display: flex
  }
  .voice-slide { grid-template-columns: 1fr; gap: 18px; align-content: start; align-items: start
  }
  .voice-slide .shot { width: 132px; aspect-ratio: 1; border-radius: 50%
  }
  .voice-slide .nm { font-size: clamp(22px, 6vw, 32px)
  }
  .voice-slide blockquote { max-width: none; font-size: 21px
  }
  .voice-slide .meta { margin: 8px 0 14px
  }
.gravity-2026 .btn { width: auto
  }
  .heroctas .btn { width: auto
  }
  .heroctas { flex-direction: column; align-items: center
  }
  .act { padding: 11px 0
  }
  .act .nm { font-size: clamp(19px, 5.4vw, 26px)
  }
  .act.head { padding: 20px 0
  }
  .act.head .nm { font-size: clamp(36px, 10vw, 60px)
  }
  .voice-slide { justify-items: center; text-align: center
  }
  .vtabs { flex-wrap: nowrap; overflow-x: auto; scroll-snap-type: x proximity;
    justify-content: flex-start; padding-inline: var(--pad); margin-inline: calc(var(--pad) * -1);
    scrollbar-width: none; -webkit-overflow-scrolling: touch
  }
  .vtabs::-webkit-scrollbar { display: none
  }
  .vtabs button { flex: none; scroll-snap-align: center
  }
  .voice-slide .shot { width: 116px
  }
  .voice-slide .said { text-align: center
  }
  .voice-slide .meta { justify-content: center
  }
  .voice-slide blockquote { margin-inline: auto; max-width: 30ch
  }
.act:not(.head) { display: flex; flex-wrap: nowrap; align-items: center; gap: 8px; padding: 9px 0
  }
  .act:not(.head) .nm { flex: 0 1 auto; min-width: 0; font-size: clamp(17px, 4.8vw, 22px);
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap
  }
  .act:not(.head) .cc { flex: none; font-size: 10px
  }
  .act:not(.head):not(.tba) .role { display: none
  }
  .act.tba .role { flex: none; margin-left: auto; order: 3; font-size: 9px; letter-spacing: .14em
  }
  .act:not(.head) .links { flex: none; order: 4; margin-left: 8px
  }
  .act:not(.head) .ic { width: 28px; height: 28px
  }
  .act:not(.head) .ic svg { width: 12px; height: 12px
  }
.namesbelt + .namesbelt { margin-top: 6px
  }
.heroproof { font-size: 11.5px; max-width: 30ch; margin-inline: auto; line-height: 1.5
  }
.bbar .progrow { gap: 9px
  }
  .bbar .pctnum { font-size: 13px
  }
  .bbar .pctnum span { display: none
  }
}

@media (prefers-reduced-motion: reduce) {
.anim .shut > span, .anim .shut.go > span, .anim .shut.loop.go > span { animation: none; opacity: 1; transform: none }
  .anim .shut.loop.go::after { display: none }
  .prod .amb, .dot-pulse, .close .glow { animation: none }
  .shim { animation: none; background: none; color: inherit; -webkit-text-fill-color: currentColor }
  .dots i, .dots b { animation: none }
  .anim .rv { transition: none; opacity: 1; transform: none }
.mrow, .belt, .morning .orb { animation: none
  }
  .prod .amb, .gravity-2026 .btn-beam::before, .dot-pulse, .close .glow { animation: none
  }
  .dots i, .dots b, .chap.now::after { animation: none
  }
html { scroll-behavior: auto;
  }
.bbar .prog i::after { animation: none; opacity: 0
  }
  .bbar .prog i.grow { animation: none
  }
.bbar .prog::after { animation: none; opacity: .6
  }
}

@media (max-width: 360px) {
  /* a label that cannot fit on one line should use two rather than the gutter */
  .gravity-2026 .btn { white-space: normal; text-align: center; padding: 15px 20px; font-size: 14px }
  .gravity-2026 .btn-lg { padding: 16px 22px; font-size: 15px }
  /* "Audiovisual" is eleven characters of display type — it needs the room */
  .prod .shut { font-size: clamp(38px, 12vw, 150px) }
  .act.head .nm { font-size: clamp(26px, 8vw, 60px) }
  .ticket .tname { font-size: clamp(34px, 10vw, 92px) }
  .voice-slide .nm { font-size: clamp(28px, 9vw, 52px) }
}


/* The outlined word behind the gallery is deliberately larger than its box, and
   the chapter grid must stay inside the container it was given — neither should
   be able to widen the page on a small phone. */
.gal, .gal-ghost { overflow: hidden }
.chapters { margin-inline: 0; padding-inline: 0; max-width: 100% }

/* ---------- a lit line, and what falls off it ----------
   The filament is drawn in CSS — a hairline that brightens to the accent in
   the middle and fades out well before either end, with a soft bloom under it.
   The sparks are a canvas below, masked so they thin out toward the edges and
   never reach a hard boundary. Nothing here carries meaning: it is aria-hidden
   and the section reads the same without it. */
.sparkbar { position: relative; width: min(420px, 84%); height: 128px;
  margin: 54px auto 0; pointer-events: none; }
/* The filament reads as the source the sparks come off, so it has to be
   visible before they are. At 1px and half-opacity white it was neither. */
.sparkbar > i { position: absolute; left: 0; right: 0; top: 0; height: 2px; display: block;
  background: linear-gradient(90deg, transparent, rgba(255,255,255,.72) 18%,
    var(--action) 50%, rgba(255,255,255,.72) 82%, transparent);
  box-shadow: 0 0 12px rgba(255,82,14,.55); }
.sparkbar > i::after { content: ''; position: absolute; inset: -12px 10% auto; height: 34px;
  background: radial-gradient(50% 100% at 50% 0%, rgba(255,82,14,.62), transparent 74%);
  filter: blur(10px); }
.sparkbar canvas { position: absolute; inset: 0; width: 100%; height: 100%; display: block;
  -webkit-mask-image: radial-gradient(66% 96% at 50% 0%, #000 22%, rgba(0,0,0,.55) 66%, transparent 94%);
          mask-image: radial-gradient(66% 96% at 50% 0%, #000 22%, rgba(0,0,0,.55) 66%, transparent 94%); }
@media (max-width: 640px) {
  .sparkbar { width: 86%; height: 104px; margin-top: 40px }
}
@media (prefers-reduced-motion: reduce) {
  .sparkbar > i::after { display: none }
}

/* ---------- closing sparkles ---------- */
.close .sparkles {
  position: absolute; inset: 0; z-index: 0; pointer-events: none;
  width: 100%; height: 100%; display: block;
  /* densest under the line, fading out before the edges */
  -webkit-mask-image: radial-gradient(60% 55% at 50% 62%, #000 25%, rgba(0,0,0,.35) 62%, transparent 88%);
          mask-image: radial-gradient(60% 55% at 50% 62%, #000 25%, rgba(0,0,0,.35) 62%, transparent 88%);
}
/* a thin seam of light the sparkles seem to rise from */
.close .seam {
  position: absolute; left: 50%; translate: -50% 0; bottom: 26%;
  width: min(560px, 74%); height: 1px; z-index: 0; pointer-events: none;
  background: linear-gradient(90deg, transparent, rgba(255,255,255,.5) 22%, var(--action) 50%, rgba(255,255,255,.5) 78%, transparent);
  opacity: .55;
}
.close .seam::after {
  content: ''; position: absolute; inset: -14px 12% auto; height: 30px;
  background: radial-gradient(50% 100% at 50% 0%, rgba(255,82,14,.35), transparent 70%);
  filter: blur(10px);
}
@media (max-width: 640px) {
  .close .seam { bottom: 22%; width: 80% }
}
@media (prefers-reduced-motion: reduce) {
  .close .seam::after { display: none }
}

/* ---------- ticket panel — same design, no iframe ---------- */




/* ---------- what a refused payment looks like ----------
   Stripe hands us the wording — "Your card was declined", whatever the bank
   said — and it arrives as .woocommerce-error inside the wrapper above. All
   this does is make it look like it belongs to the panel rather than to a
   shop template, and put it where the eye already is: under the button that
   was just pressed. Nothing is invented: if Stripe says nothing, nothing shows.
   The green variant is here because the same channel carries successes. */
.g26-notices:empty { display: none }
/* Pinned to the top of the panel's own scroll, so a refusal stays on screen
   wherever the buyer happens to be — including down at the pay buttons, which
   is exactly where they are when a card is declined. The right-hand padding
   keeps the text clear of the close button, which is pinned to the same line.
   Behind it, so the X stays pressable. */
.g26-notices { margin: 0 6px 12px; position: sticky; top: 0; z-index: 2; padding-right: 46px }
.g26-notices .woocommerce-error,
.g26-notices .woocommerce-message,
.g26-notices .woocommerce-info {
  margin: 0 0 8px; padding: 13px 14px 13px 42px; position: relative;
  border-radius: 12px; list-style: none;
  font-family: var(--body); font-size: 14px; line-height: 1.4; font-weight: 700;
  /* A refused payment is the one message on this page that must not be
     mistaken for a hint. Filled rather than tinted, white on red rather than
     red on black: readable at arm's length, on a phone, outdoors, by someone
     who has just been told their card did not work. */
  background: #D42A1E; border: 1px solid #D42A1E; color: #fff;
  box-shadow: 0 6px 20px rgba(212,42,30,.35);
}
.g26-notices .woocommerce-error::before,
.g26-notices .woocommerce-message::before,
.g26-notices .woocommerce-info::before {
  content: '!'; position: absolute; left: 13px; top: 13px;
  width: 19px; height: 19px; border-radius: 50%;
  display: grid; place-items: center;
  font-size: 13px; font-weight: 800; line-height: 1;
  background: #fff; color: #D42A1E;
}
/* A success is good news, not an alarm — it keeps the quieter treatment. */
.g26-notices .woocommerce-message {
  background: rgba(52,208,127,.13); border-color: rgba(52,208,127,.4); color: #9BE8C2;
  font-weight: 500; box-shadow: none;
}
.g26-notices .woocommerce-message::before { content: '\2713'; background: #34D07F; color: #14110E }
.g26-notices a { color: inherit; text-decoration: underline; text-underline-offset: 3px }
@media (max-width: 640px) {
  .g26-notices { margin: 0 16px 12px }
}

.tmmsg { margin: 10px 6px 0; padding: 0; font-size: 12.5px; line-height: 1.5; color: var(--fg-3) }
.tmmsg:empty { display: none }
.tmmsg.is-error { color: #FF6B4A; padding-top: 10px }
.tmmsg a { color: inherit; text-decoration: underline; text-underline-offset: 3px }

@media (max-width: 640px) {
}


/* ==========================================================================
   Parent-theme armour.  GENERATED — do not hand-edit.

   style-new.css and responsive.css set typography on bare `p`, `h1`, `h2` and
   `h2 span` with !important, which no amount of specificity can outrank. Every
   typographic declaration above is therefore restated here with !important, in
   source order and inside its original media query.

   Nothing new is introduced: change a value above and run
   `python3 tools/build-armour.py` to refresh this block.
   ========================================================================== */
  .gravity-2026 { color: var(--fg) !important; font-family: var(--body) !important; }
  .gravity-2026 a { color: inherit !important; }
  :where(.gravity-2026) button:where(:not([class*="wcvcl"])) { font: inherit !important; color: inherit !important; }
  .display { font-family: var(--display) !important; font-weight: 600 !important; line-height: .86 !important; letter-spacing: -.035em !important; text-transform: uppercase !important; }
  .eyebrow { font-size: 11px !important; letter-spacing: .22em !important; text-transform: uppercase !important; color: var(--fg-3) !important; font-weight: 500 !important; }
  .lede { font-size: clamp(15px, 1.5vw, 18px) !important; line-height: 1.55 !important; color: var(--fg-2) !important; }
  .gravity-2026 .btn { font-weight: 700 !important; font-size: 15px !important; letter-spacing: .01em !important; line-height: 1.2 !important; }
  .gravity-2026 .btn-primary, .gravity-2026 .btn-primary:focus, .gravity-2026 .btn-primary:active { color: #fff !important; }
  .gravity-2026 .btn-primary:hover { color: #fff !important; }
  .gravity-2026 .btn-ghost, .gravity-2026 .btn-ghost:focus, .gravity-2026 .btn-ghost:active { color: var(--fg) !important; }
  .gravity-2026 .btn-ghost:hover { color: var(--fg) !important; }
  .gravity-2026 .btn-lg { font-size: 16px !important; }
  .badge { font-size: 11px !important; font-weight: 700 !important; letter-spacing: .12em !important; text-transform: uppercase !important; }
  .badge-gone { color: var(--gone) !important; }
  .badge-live { color: var(--ok) !important; }
  .badge-urgent { color: var(--urgent) !important; }
  .pay span { font-size: 10px !important; font-weight: 700 !important; letter-spacing: .06em !important; color: var(--fg-3) !important; }
  .pay .mp { color: #fff !important; }
  .note-tag { color: #12100A !important; font-size: 10px !important; font-weight: 700 !important; letter-spacing: .06em !important; text-transform: uppercase !important; }
  .muted { color: var(--fg-2) !important; }
  .buybar .price { font-family: var(--display) !important; font-size: 20px !important; font-weight: 600 !important; line-height: 1 !important; }
  .buybar .price small { font-family: var(--body) !important; font-size: 10px !important; letter-spacing: .14em !important; text-transform: uppercase !important; color: var(--fg-3) !important; font-weight: 500 !important; }
  .presents { font-family: var(--body) !important; font-size: clamp(15px, 1.75vw, 21px) !important; font-weight: 500 !important; letter-spacing: .30em !important; text-transform: uppercase !important; color: var(--fg-2) !important; }
  .g26-mark { color: var(--action) !important; font-weight: 700 !important; }
  .hero .stack { text-align: center !important; }
  :where(.gravity-2026) h1, :where(.gravity-2026) h2, :where(.gravity-2026) h3, :where(.gravity-2026) h4 { text-align: inherit !important; color: inherit !important; text-transform: inherit !important; }
  :where(.gravity-2026) p { text-align: inherit !important; color: inherit !important; text-transform: inherit !important; font-family: inherit !important; font-size: inherit !important; font-weight: inherit !important; line-height: inherit !important; letter-spacing: inherit !important; }
  :where(.gravity-2026) footer p { color: inherit !important; text-align: inherit !important; }
  .shut { font-family: var(--display) !important; font-weight: 500 !important; text-transform: uppercase !important; letter-spacing: -.045em !important; line-height: .82 !important; }
  .gravity-2026 .title { font-size: clamp(44px, 8.6vw, 132px) !important; }
  .pitch { font-size: clamp(14px, 1.5vw, 18px) !important; line-height: 1.5 !important; color: rgba(255,255,255,.9) !important; }
  .pitch b { color: #fff !important; font-weight: 500 !important; }
  .metarow li { font-size: 13px !important; letter-spacing: .16em !important; text-transform: uppercase !important; color: var(--fg-2) !important; }
  .metarow b { color: #fff !important; font-weight: 500 !important; }
  .scroll-hint { font-size: 10px !important; letter-spacing: .3em !important; text-transform: uppercase !important; color: var(--fg-3) !important; }
  .shim { color: transparent !important; }
  #opera h2 { text-transform: none !important; letter-spacing: -.03em !important; }
  .sec h2 { font-family: var(--display) !important; font-weight: 500 !important; text-transform: uppercase !important; letter-spacing: -.04em !important; line-height: .94 !important; font-size: clamp(32px, 5.2vw, 64px) !important; }
  .kicker { font-family: var(--body) !important; font-size: 10.5px !important; font-weight: 400 !important; letter-spacing: .26em !important; text-transform: uppercase !important; color: var(--fg-2) !important; }
  .act .nm { font-family: var(--display) !important; font-size: clamp(22px, 2.6vw, 34px) !important; font-weight: 600 !important; text-transform: uppercase !important; letter-spacing: -.02em !important; line-height: .95 !important; }
  .act .cc { font-size: clamp(11px, 1.1vw, 13px) !important; color: var(--fg-3) !important; letter-spacing: .1em !important; text-transform: uppercase !important; }
  .act .role { font-size: 10.5px !important; letter-spacing: .2em !important; text-transform: uppercase !important; color: var(--fg-3) !important; }
  .act.head .nm { font-size: clamp(34px, 6vw, 76px) !important; letter-spacing: -.035em !important; }
  .act.head .cc { font-size: clamp(12px, 1.3vw, 16px) !important; }
  .act.head .role { color: var(--action) !important; font-weight: 700 !important; }
  .act.tba .nm { color: var(--fg-3) !important; font-weight: 500 !important; }
  .ic { color: var(--fg-2) !important; }
  .ic:hover, .ic:focus-visible { color: #fff !important; }
  .tmwait-in { text-align: center !important; }
  .tmwait-in b { font-family: var(--display) !important; font-size: 19px !important; font-weight: 600 !important; text-transform: uppercase !important; letter-spacing: .02em !important; color: #fff !important; }
  .tmwait-in span { font-size: 13px !important; color: var(--fg-2) !important; }
  .g26-tickethead { text-align: left !important; }
  .g26-tickethead h3 { font-family: var(--display) !important; font-weight: 600 !important; text-transform: uppercase !important; letter-spacing: -.01em !important; line-height: 1.05 !important; font-size: clamp(24px, 5.4vw, 34px) !important; color: #fff !important; }
  .g26-tktfacts span { font-size: 12px !important; color: #9D9D9D !important; }
  .g26-tktfacts b { font-family: var(--body) !important; font-weight: 600 !important; text-transform: uppercase !important; font-size: clamp(18px, 4.4vw, 24px) !important; line-height: 1 !important; color: #fff !important; }
  .g26-left { font-size: 11px !important; font-weight: 700 !important; letter-spacing: .12em !important; text-transform: uppercase !important; color: #C2410C !important; }
  .tmmount .wcvcl-bottom-total { color: #fff !important; }
  .tmmount .wcvcl-direct-btn { text-align: center !important; }
  .vbox .who { text-align: center !important; font-size: 12px !important; letter-spacing: .2em !important; text-transform: uppercase !important; color: var(--fg-2) !important; }
  .vbox .who b { color: #fff !important; font-family: var(--display) !important; font-size: 17px !important; letter-spacing: -.01em !important; }
  .vclose { color: #fff !important; }
  .why h2 { text-transform: none !important; letter-spacing: -.035em !important; }
  .why .lede { color: var(--fg-2) !important; }
  .why .lede em { color: #fff !important; }
  .facts dt { font-size: 11px !important; letter-spacing: .18em !important; text-transform: uppercase !important; color: var(--fg-3) !important; }
  .facts dd { font-family: var(--display) !important; font-size: clamp(17px, 1.9vw, 24px) !important; font-weight: 600 !important; letter-spacing: -.01em !important; text-align: right !important; }
  .stopr .no { font-size: 10px !important; letter-spacing: .16em !important; color: var(--fg-3) !important; }
  .stopr b { font-family: var(--display) !important; font-weight: 600 !important; text-transform: uppercase !important; font-size: clamp(22px, 2.3vw, 36px) !important; letter-spacing: -.03em !important; line-height: .95 !important; }
  .stopr span { font-size: 11px !important; letter-spacing: .16em !important; text-transform: uppercase !important; color: var(--fg-3) !important; text-align: left !important; }
  .stopr.here b, .stopr.here span, .stopr.here .no { color: var(--action) !important; }
  .madewith { font-size: clamp(15px, 1.7vw, 18px) !important; line-height: 1.85 !important; color: var(--fg-3) !important; }
  .madewith b { color: var(--urgent) !important; font-weight: 400 !important; letter-spacing: .22em !important; text-transform: uppercase !important; font-size: 10.5px !important; }
  .madewith span { color: rgba(255,255,255,.92) !important; }
  .madewith span::after { color: var(--fg-3) !important; }
  .gal h2 { font-family: var(--display) !important; font-weight: 500 !important; text-transform: none !important; letter-spacing: -.04em !important; line-height: .94 !important; font-size: clamp(32px, 5.2vw, 64px) !important; }
  .strip .tag { font-size: 10px !important; letter-spacing: .22em !important; text-transform: uppercase !important; color: rgba(255,255,255,.62) !important; }
  .strip figcaption b { font-family: var(--display) !important; font-size: clamp(17px, 1.8vw, 24px) !important; font-weight: 600 !important; text-transform: uppercase !important; letter-spacing: -.01em !important; }
  .strip figcaption span { font-size: 12px !important; letter-spacing: .16em !important; text-transform: uppercase !important; color: var(--fg-2) !important; }
  .strip figcaption i { color: var(--action) !important; font-weight: 700 !important; }
  .gal-ghost .ghostword { font-weight: 600 !important; font-size: clamp(70px, 17vw, 260px) !important; letter-spacing: -.05em !important; line-height: 1 !important; }
  .gal-ghost .ghostword > span { color: transparent !important; }
  .ticket .release { font-size: 10.5px !important; letter-spacing: .18em !important; text-transform: uppercase !important; }
  .ticket .release .live { color: var(--ok) !important; font-weight: 700 !important; }
  .ticket .release .out { color: var(--fg-3) !important; }
  .ticket .tname { font-family: var(--display) !important; font-weight: 500 !important; text-transform: uppercase !important; letter-spacing: -.05em !important; line-height: .82 !important; font-size: clamp(48px, 8vw, 92px) !important; }
  .ticket .pitch { font-size: 16.5px !important; }
  .ticket .tfacts dt { font-size: 10px !important; letter-spacing: .16em !important; text-transform: uppercase !important; color: var(--fg-3) !important; }
  .ticket .tfacts dd { font-family: var(--display) !important; font-size: 19px !important; font-weight: 600 !important; }
  .stub { text-align: center !important; }
  .stub .when { font-size: 10px !important; letter-spacing: .18em !important; text-transform: uppercase !important; color: var(--fg-3) !important; }
  .stub .amount { font-family: var(--display) !important; font-size: 54px !important; font-weight: 600 !important; line-height: 1 !important; letter-spacing: -.03em !important; }
  .stub .later { font-size: 12px !important; color: var(--fg-2) !important; }
  .stub .rise { font-size: 11.5px !important; color: var(--urgent) !important; font-weight: 700 !important; letter-spacing: .06em !important; }
  .stub .pay { font-size: 10.5px !important; letter-spacing: .06em !important; color: var(--fg-3) !important; }
  .bone { color: #14110E !important; }
  .bone .kicker { color: rgba(20,17,14,.5) !important; }
  .bone .lede { color: rgba(20,17,14,.72) !important; }
  .chap .c { font-size: 10px !important; letter-spacing: .22em !important; text-transform: uppercase !important; color: rgba(20,17,14,.45) !important; }
  .chap b { font-family: var(--display) !important; font-size: clamp(17px, 1.6vw, 22px) !important; text-transform: uppercase !important; letter-spacing: -.01em !important; }
  .chap span { font-size: 12px !important; color: rgba(20,17,14,.6) !important; }
  .chap.pic .c { color: rgba(255,255,255,.65) !important; }
  .chap.pic b { color: #fff !important; }
  .chap.pic span { color: rgba(255,255,255,.66) !important; }
  .chap.now .c { color: var(--action) !important; }
  .chap.now b { color: #fff !important; }
  .chap.now span { color: rgba(255,255,255,.6) !important; }
  .prod .shut { font-size: clamp(46px, 10vw, 150px) !important; }
  .prod .lede { color: rgba(255,255,255,.88) !important; }
  .specs dt, .specs .k { font-size: 10px !important; letter-spacing: .22em !important; text-transform: uppercase !important; color: var(--urgent) !important; }
  .specs .v { font-size: clamp(14px, 1.5vw, 17px) !important; line-height: 1.45 !important; color: rgba(255,255,255,.9) !important; }
  .faq summary { font-size: 16px !important; font-weight: 500 !important; }
  .faq summary::after { color: var(--fg-3) !important; font-size: 20px !important; line-height: 1 !important; }
  .faq p { color: var(--fg-2) !important; font-size: 14px !important; line-height: 1.65 !important; }
  .rel-row .nm { font-family: var(--display) !important; font-weight: 600 !important; text-transform: uppercase !important; font-size: clamp(20px, 2.4vw, 30px) !important; letter-spacing: -.02em !important; }
  .rel-row .st { font-size: 10.5px !important; letter-spacing: .18em !important; text-transform: uppercase !important; color: var(--fg-3) !important; }
  .rel-row .pr { font-family: var(--display) !important; font-weight: 600 !important; font-size: clamp(20px, 2.4vw, 30px) !important; letter-spacing: -.02em !important; }
  .rel-row.gone .nm, .rel-row.gone .pr { color: var(--fg-3) !important; }
  .rel-row.gone .st { color: var(--gone) !important; }
  .rel-row.now .st { color: var(--ok) !important; font-weight: 700 !important; }
  .rel-row.next .pr, .rel-row.next .st { color: var(--urgent) !important; }
  .rel-row.door .nm, .rel-row.door .pr { color: var(--gone) !important; }
  .close { text-align: center !important; }
  .close h2 { font-family: var(--display) !important; font-weight: 500 !important; letter-spacing: -.04em !important; line-height: .95 !important; font-size: clamp(38px, 7vw, 92px) !important; text-transform: none !important; }
  .bbar .price small { font-size: 10px !important; letter-spacing: .22em !important; text-transform: uppercase !important; color: var(--fg-3) !important; }
  .bbar .price b { font-family: var(--display) !important; font-size: clamp(24px, 3vw, 38px) !important; font-weight: 600 !important; line-height: 1 !important; letter-spacing: -.02em !important; }
  .bbar .rel { font-size: 11px !important; letter-spacing: .1em !important; text-transform: uppercase !important; }
  .bbar .rel .gone { color: var(--fg-3) !important; }
  .bbar .rel .live { color: var(--ok) !important; font-weight: 700 !important; }
  .bbar .rel .up { color: var(--urgent) !important; font-weight: 700 !important; }
  .gravity-2026 footer { color: var(--fg-3) !important; font-size: 13px !important; }
  .ic { color: var(--fg-3) !important; }
  .chap b { font-family: var(--display) !important; font-size: 18px !important; text-transform: uppercase !important; letter-spacing: -.01em !important; }
  .morning .head { text-align: center !important; }
  .morning .head h2, .ledger .head h2 { font-family: var(--display) !important; font-weight: 500 !important; letter-spacing: -.035em !important; line-height: .98 !important; font-size: clamp(32px, 4.8vw, 58px) !important; }
  .story .who { font-size: 12px !important; font-weight: 700 !important; }
  .story .when { font-size: 10.5px !important; color: var(--fg-card) !important; }
  .story p { font-size: 14px !important; line-height: 1.5 !important; color: rgba(255,255,255,.88) !important; }
  .story .re { font-size: 9.5px !important; letter-spacing: .16em !important; text-transform: uppercase !important; color: var(--fg-card) !important; }
  .story .re b { color: var(--action) !important; }
  .voices { text-align: center !important; }
  .voice-slide blockquote { font-family: var(--display) !important; font-weight: 500 !important; letter-spacing: -.03em !important; line-height: 1.04 !important; font-size: clamp(30px, 5.4vw, 72px) !important; }
  .voice-slide blockquote em { color: var(--action) !important; }
  .voice-slide .by { font-size: 13px !important; color: var(--fg-2) !important; }
  .voice-slide .by b { color: #fff !important; }
  .vtab { font-size: 11px !important; font-weight: 700 !important; letter-spacing: .14em !important; text-transform: uppercase !important; color: var(--fg-3) !important; }
  .vtab.on { color: #fff !important; }
  .vtab:hover { color: #fff !important; }
  .led-row .no { font-size: 11px !important; letter-spacing: .2em !important; color: var(--fg-3) !important; }
  .led-row .nm { font-family: var(--display) !important; font-weight: 600 !important; text-transform: uppercase !important; letter-spacing: -.02em !important; font-size: clamp(22px, 3vw, 38px) !important; line-height: 1 !important; }
  .led-row .ppl { font-size: 13px !important; color: var(--fg-2) !important; text-align: right !important; }
  .led-row .st { font-size: 10px !important; font-weight: 700 !important; letter-spacing: .18em !important; text-transform: uppercase !important; color: var(--gone) !important; }
  .led-row.now .st { color: var(--ok) !important; }
  .led-row.now .nm { color: var(--action) !important; }
  .iflike { text-align: center !important; }
  .iflike h2 { font-size: clamp(30px, 4vw, 48px) !important; }
  .namesbelt .belt span { font-family: var(--display) !important; font-weight: 600 !important; text-transform: uppercase !important; letter-spacing: -.02em !important; font-size: clamp(34px, 5.6vw, 76px) !important; line-height: 1 !important; color: transparent !important; }
  .namesbelt .belt span.solid { color: #fff !important; }
  .iflike .tail { font-size: clamp(17px, 2vw, 22px) !important; color: var(--fg-2) !important; }
  .iflike .tail b { color: #fff !important; }
  .operalink { font-size: 11px !important; font-weight: 600 !important; letter-spacing: .2em !important; text-transform: uppercase !important; color: var(--fg-3) !important; }
  .operalink:hover { color: #fff !important; }
  .stopr .no { font-size: 10px !important; letter-spacing: .16em !important; color: var(--fg-3) !important; }
  .stopr span { font-size: 11px !important; letter-spacing: .16em !important; text-transform: uppercase !important; color: var(--fg-3) !important; text-align: left !important; }
  .chap b { font-size: clamp(17px, 1.6vw, 22px) !important; }
  .ic { color: var(--fg-2) !important; }
  .voices .stage { text-align: left !important; }
  .voice-slide { text-align: left !important; }
  .voice-slide .nm { font-family: var(--display) !important; font-weight: 600 !important; text-transform: uppercase !important; letter-spacing: -.03em !important; line-height: .92 !important; font-size: clamp(26px, 3.6vw, 48px) !important; }
  .voice-slide .meta { font-size: 11px !important; letter-spacing: .2em !important; text-transform: uppercase !important; color: var(--fg-3) !important; }
  .voice-slide blockquote { font-family: var(--body) !important; font-weight: 400 !important; letter-spacing: normal !important; font-size: clamp(23px, 3.1vw, 40px) !important; line-height: 1.26 !important; color: rgba(255,255,255,.94) !important; }
  .voice-slide blockquote em { color: var(--action) !important; }
  .act .nm { font-size: clamp(20px, 2vw, 27px) !important; line-height: 1.05 !important; }
  .b-nights .belt span { font-size: clamp(26px, 4vw, 54px) !important; }
  .b-nights .belt span.solid { color: rgba(255,255,255,.82) !important; }
  .heroproof { font-size: clamp(11px, 1.2vw, 13px) !important; letter-spacing: .04em !important; color: var(--fg-2) !important; }
  .bbar .pctnum { font-family: var(--display) !important; font-weight: 600 !important; font-size: 15px !important; line-height: 1 !important; letter-spacing: -.01em !important; color: #fff !important; }
  .bbar .pctnum span { font-family: var(--body) !important; font-weight: 500 !important; font-size: 9.5px !important; letter-spacing: .16em !important; text-transform: uppercase !important; color: var(--fg-3) !important; }
@media (max-width: 900px) {
  .note-tag { line-height: 1.35 !important; }
  .strip figcaption b { font-size: 15px !important; }
  .stub { text-align: left !important; }
  .ticket .tname { font-size: clamp(40px, 11vw, 92px) !important; }
}
@media (max-width: 640px) {
  .gravity-2026 .title { font-size: clamp(52px, 14vw, 132px) !important; }
  .presents { font-size: 12px !important; letter-spacing: .3em !important; }
  .sec h2, .gal h2 { font-size: clamp(36px, 9vw, 64px) !important; line-height: .96 !important; }
  .sec .lede, .lede { font-size: 15.5px !important; line-height: 1.6 !important; }
  .kicker { font-size: 11px !important; letter-spacing: .22em !important; }
  .metarow li { font-size: 12px !important; letter-spacing: .12em !important; }
  .facts dd { font-size: 19px !important; }
  .specs .k { font-size: 11px !important; letter-spacing: .2em !important; }
  .specs .v { font-size: 17px !important; line-height: 1.5 !important; }
  .act .role { font-size: 10px !important; letter-spacing: .16em !important; }
  .rel-row .nm { font-size: 22px !important; }
  .rel-row .pr { font-size: 22px !important; }
  .rel-row .st { font-size: 10px !important; }
  .close h2 { font-size: clamp(50px, 15vw, 92px) !important; }
  .stopr b { font-size: clamp(22px, 6.6vw, 32px) !important; }
  .stopr span { font-size: 10px !important; }
  .madewith { font-size: 13px !important; line-height: 2 !important; }
  .route-line { font-size: 11.5px !important; }
  .prod .shut { font-size: clamp(52px, 15vw, 150px) !important; }
  .ticket .tname { font-size: clamp(46px, 13vw, 92px) !important; }
  .stub .amount { font-size: 48px !important; }
  .faq summary { font-size: 15px !important; }
  .act.head .nm { font-size: clamp(40px, 11vw, 76px) !important; }
  .act .nm { font-size: clamp(26px, 7vw, 34px) !important; }
  .pitch { font-size: 14px !important; }
  .gravity-2026 .btn { font-size: 14.5px !important; }
  .gravity-2026 .btn-lg { font-size: 15.5px !important; }
  .bbar .price small { font-size: 9px !important; letter-spacing: .2em !important; }
  .bbar .price b { font-size: 29px !important; line-height: 1 !important; }
  .bbar .rel { font-size: 11px !important; letter-spacing: 0 !important; text-transform: none !important; }
  .bbar .rel .live { text-transform: none !important; }
  .bbar .rel .up { text-transform: none !important; }
  .bbar .rel .up::before { color: var(--fg-3) !important; font-weight: 500 !important; }
  .vtab { font-size: 10px !important; }
  .act .role { font-size: 10px !important; letter-spacing: .16em !important; }
  .voice-slide .nm { font-size: clamp(22px, 6vw, 32px) !important; }
  .voice-slide blockquote { font-size: 21px !important; }
  .act .nm { font-size: clamp(19px, 5.4vw, 26px) !important; }
  .act.head .nm { font-size: clamp(36px, 10vw, 60px) !important; }
  .voice-slide { text-align: center !important; }
  .voice-slide .said { text-align: center !important; }
  .act:not(.head) .nm { font-size: clamp(17px, 4.8vw, 22px) !important; }
  .act:not(.head) .cc { font-size: 10px !important; }
  .act.tba .role { font-size: 9px !important; letter-spacing: .14em !important; }
  .heroproof { font-size: 11.5px !important; line-height: 1.5 !important; }
  .bbar .pctnum { font-size: 13px !important; }
}
@media (prefers-reduced-motion: reduce) {
  .shim { color: inherit !important; }
}
@media (max-width: 360px) {
  .gravity-2026 .btn { text-align: center !important; font-size: 14px !important; }
  .gravity-2026 .btn-lg { font-size: 15px !important; }
  .prod .shut { font-size: clamp(38px, 12vw, 150px) !important; }
  .act.head .nm { font-size: clamp(26px, 8vw, 60px) !important; }
  .ticket .tname { font-size: clamp(34px, 10vw, 92px) !important; }
  .voice-slide .nm { font-size: clamp(28px, 9vw, 52px) !important; }
}
  .g26-notices .woocommerce-error, .g26-notices .woocommerce-message, .g26-notices .woocommerce-info { font-family: var(--body) !important; font-size: 14px !important; line-height: 1.4 !important; font-weight: 700 !important; color: #fff !important; }
  .g26-notices .woocommerce-error::before, .g26-notices .woocommerce-message::before, .g26-notices .woocommerce-info::before { font-size: 13px !important; font-weight: 800 !important; line-height: 1 !important; color: #D42A1E !important; }
  .g26-notices .woocommerce-message { color: #9BE8C2 !important; font-weight: 500 !important; }
  .g26-notices .woocommerce-message::before { color: #14110E !important; }
  .g26-notices a { color: inherit !important; }
  .tmmsg { font-size: 12.5px !important; line-height: 1.5 !important; color: var(--fg-3) !important; }
  .tmmsg.is-error { color: #FF6B4A !important; }
  .tmmsg a { color: inherit !important; }

/* ============================================================
   TABLES
   An application, not a purchase, and the styling says so: one
   full-colour button inside the section where the decision is
   actually being made, and an outline everywhere else. Orange on
   this page has meant "buy a ticket" since the first release —
   spending it on a form that takes a week would blunt it.
   ============================================================ */
.tbl-grid{ display: grid; grid-template-columns: minmax(0,1fr) minmax(0,.82fr); gap: clamp(28px, 5vw, 64px); align-items: center; }
.tbl-copy{ max-width: 54ch; }
.tbl-copy .lede{ margin-top: 14px; }

.tbl-list{ list-style: none; margin: 26px 0 0; padding: 0; display: grid; gap: 1px; background: var(--line); border-block: 1px solid var(--line); }
.tbl-list li{ background: var(--ink); padding: 13px 0 13px 26px; position: relative; font-size: clamp(14px, 1.4vw, 16px); color: var(--fg-2); }
.tbl-list li::before{
  content: ''; position: absolute; left: 2px; top: 50%; width: 10px; height: 1px;
  background: var(--action); transform: translateY(-50%);
}

.tbl-limit{ margin: 20px 0 0; font-size: 13px; color: var(--fg-3); }
.tbl-cta{ margin-top: 26px; display: flex; flex-wrap: wrap; gap: 12px; }

.tbl-shot{ margin: 0; }
.tbl-shot img{ width: 100%; height: 100%; max-height: 560px; object-fit: cover; border-radius: var(--r); }

/* the third fact in the ticket panel — stated like the date, not sold like a button */
.g26-tktfacts-tbl a{
  display: block; font-family: var(--body); font-weight: 600; text-transform: uppercase;
  font-size: clamp(15px, 3.4vw, 18px); line-height: 1; color: var(--action);
  text-decoration: underline; text-underline-offset: 3px;
  text-decoration-color: rgba(255,82,14,.42);
}
.g26-tktfacts-tbl a:hover, .g26-tktfacts-tbl a:focus-visible{ text-decoration-color: var(--action); }

@media (max-width: 860px){
  .tbl-grid{ grid-template-columns: 1fr; }
  /* the photo leads on a phone, where the copy would otherwise open the
     section with four lines of type and no reason to keep reading */
  .tbl-shot{ order: -1; }
  .tbl-shot img{ max-height: 300px; }
}
@media (max-width: 560px){
  .g26-tktfacts{ flex-wrap: wrap; gap: 18px 26px; }
}

/* ============================================================
   Icon links next to the artists — the tap area, not the circle

   The circle is 34px beside the headliner and 28px beside the
   rest, which looks right and is too small for a thumb. Measured
   on a phone: every one of them under the 44px a finger needs, so
   they were being missed rather than pressed — which reads exactly
   like a link that does not work.

   The circle keeps its size. A pseudo-element carries the tap area
   out to 44px around it, which is invisible, changes no spacing,
   and is what the finger actually lands on.
   ============================================================ */
.act .links .ic{ position: relative; }
.act .links .ic::before{
  content: ''; position: absolute; left: 50%; top: 50%;
  width: 44px; height: 44px; transform: translate(-50%, -50%);
  border-radius: 50%;
}
/* Neighbouring targets must not overlap, or the wrong one answers. */
.act .links{ gap: 12px; }

@media (hover: none){
  /* no hover to reveal them, so they sit a little brighter to begin with */
  .act .ic{ opacity: .9; }
}

/* The Instagram mark is an outline, not a solid.
   It used to be a single filled path whose outer square was drawn as a block
   rather than a frame, so with the nonzero fill rule it rendered as a white
   slab with a hole in it — recognisable as nothing at all. Drawn with a
   stroke instead, and the fill has to be beaten back explicitly because
   .ic svg carries `fill: currentColor !important` for the other icons. */
.ic.ig svg{ fill: none !important; stroke: currentColor; }
.ic.ig svg rect, .ic.ig svg circle{ fill: none !important; }
.ic.ig svg circle.dot{ fill: currentColor !important; stroke: none; }

/* ---------- button icons ----------
   The span inside a .btn already centres the label; the icon joins it there
   rather than being positioned against the button, so it stays put whatever
   the padding does at each size. 1em keeps it tied to the label rather than
   to a number that has to be maintained per button size. */
.gravity-2026 .btn.has-i > span{ display: inline-flex; align-items: center; gap: .6em; }
.gravity-2026 .btn .bi{ width: 1.15em; height: 1.15em; flex: none; }
/* The play triangle is filled and sits in the same slot — it is not one of
   these, and must not inherit the stroke treatment. */
.gravity-2026 .btn .pl{ width: 1em; height: 1em; fill: currentColor; }

/* The Instagram mark was the smallest thing on the row and the one people
   were aiming at. Three pixels is the difference between an icon you notice
   and one you have to look for. */
.ic.ig svg{ width: 17px !important; height: 17px !important; }
