/* ---- header ---- */
.header {
  position: fixed; inset: 0 0 auto 0; z-index: 40;
  display: flex; align-items: center; justify-content: space-between;
  padding: 16px 28px; color: var(--ivory);
  transition: color .4s ease;
}
.header.on-light { color: #14101d; }
.brand { display: flex; align-items: center; gap: 12px; text-decoration: none; }
.header .brand { opacity: var(--brand, 1); }
.header.brand-hidden .brand, .is-playing .header .brand { visibility: hidden; pointer-events: none; }
.is-playing .header .brand { opacity: 0; }
.brand-seat { display: grid; place-items: center; width: 48px; height: 48px; border-radius: 50%; background: rgba(9, 11, 18, .55); }
.brand-mark { width: 40px; height: auto; }
.brand-word { font-size: 1rem; }
.header-left { display: flex; align-items: center; gap: .9rem; }
.is-playing .header .header-left { opacity: 0; pointer-events: none; }
.header-right { display: flex; align-items: center; gap: .8rem; transition: opacity .3s; }
.is-playing .header-right { opacity: 0; pointer-events: none; }


/* ---- sound toggle: top left, a ring with three bars that breathe while sound is on ---- */
/* The ring and its bars are drawn in currentColor, so .header.on-light carries them onto a lit frame
 * with everything else: literal colours here meant the adaptive header never reached them and both
 * washed out over the canopy. The mixes are also the resting contrast - 62% of ivory on the dark header
 * clears WCAG 1.4.11's 3:1 for a control boundary, where the old .45 of silver measured 2.92. */
.sound { position: relative; width: 40px; height: 40px; border-radius: 50%; border: 1px solid color-mix(in srgb, currentColor 62%, transparent); background: transparent; cursor: pointer; display: grid; place-items: center; transition: border-color .2s, box-shadow .2s; }
.sound:hover, .sound:focus-visible { border-color: currentColor; box-shadow: 0 0 0 4px rgba(143, 163, 255, .12); outline: none; }
.sound[aria-pressed="true"] { border-color: currentColor; }
.sound-bars { display: flex; gap: 3px; align-items: center; height: 14px; }
.sound-bars i { display: block; width: 2px; height: 14px; background: currentColor; transform: scaleY(.15); transform-origin: center; transition: transform .3s; }
.sound[aria-pressed="true"] .sound-bars i { animation: sound-breathe 2.4s ease-in-out infinite; }
.sound[aria-pressed="true"] .sound-bars i:nth-child(2) { animation-delay: .4s; }
.sound[aria-pressed="true"] .sound-bars i:nth-child(3) { animation-delay: .8s; }
@keyframes sound-breathe { 0%, 100% { transform: scaleY(.35); } 50% { transform: scaleY(1); } }
.sound-word { position: absolute; top: calc(100% + 6px); left: 50%; transform: translateX(-50%); font: 500 .58rem/1 var(--font-mono); letter-spacing: .16em; text-transform: uppercase; color: var(--mist); opacity: 0; transition: opacity .2s; pointer-events: none; }
.sound:hover .sound-word, .sound:focus-visible .sound-word { opacity: 1; }
.reduced .sound[aria-pressed="true"] .sound-bars i { animation: none; transform: scaleY(.7); }

/* ---- the ghost rail (spec section 6) ----
   A column of tick marks down the left edge: where you are in the film, and how to get anywhere else in it.
   Low-contrast on purpose - it should read as furniture until you look at it, and the name only appears
   beside the tick you are pointing at. It is `hidden` until the first scroll rather than transparent, so
   nobody can tab into a rail that is not on the screen. */
.ghost-nav {
  position: fixed; left: 0; top: 50%; transform: translateY(-50%); z-index: 30;
  display: flex; flex-direction: column; gap: 10px; padding: 14px 10px 14px 14px;
  animation: ghost-in .8s ease both;
}
/* The constellation (Plan 18 round two, his pick T1): the marks are dim points on one hairline, and the
 * one you are at is a star. The hairline is the rail's own ::before, running the column of points and
 * fading out at both ends so it reads as a line drawn between stars rather than a border. */
.ghost-nav::before {
  content: ''; position: absolute; left: 25px; top: 18px; bottom: 18px; width: 1px;
  background: linear-gradient(to bottom, transparent, rgba(200, 184, 219, .32) 14%, rgba(200, 184, 219, .32) 86%, transparent);
  pointer-events: none;
}
.ghost-nav[hidden] { display: none; }
@keyframes ghost-in { from { opacity: 0; transform: translate(-8px, -50%); } to { opacity: 1; transform: translate(0, -50%); } }
.reduced .ghost-nav { animation: none; }
@media (prefers-reduced-motion: reduce) { .ghost-nav { animation: none; } }

/* The mark itself is the button's ::before: a dim point on the hairline that brightens and grows a little
   when it is the one you are pointing at. The button is far bigger than the point so it is comfortable to hit. */
.ghost-mark {
  position: relative; display: block; width: 46px; height: 14px; padding: 0;
  background: none; border: 0; cursor: pointer; -webkit-appearance: none; appearance: none;
}
/* Plan 22, his note: "the nav bar on the side shows a square where the current mark is". The marks were
 * two PNGs, and the lit one carried a faint blue wash over its whole 64x64 square that showed against the
 * ink. Both are drawn here now - a point of light, and a star of four thin spikes in a halo - as
 * gradients, which have no square to show. */
.ghost-mark::before {
  content: ''; position: absolute; left: 11px; top: 50%; width: 12px; height: 12px; margin: -6px 0 0 -6px;
  border-radius: 50%; opacity: .55;
  background: radial-gradient(circle, rgba(255, 255, 255, .95) 0, rgba(200, 184, 219, .7) 22%, rgba(200, 184, 219, .18) 48%, transparent 70%);
  transition: transform .28s cubic-bezier(.22, 1, .36, 1), opacity .28s ease;
}
.ghost-mark:hover::before, .ghost-mark:focus-visible::before { opacity: 1; transform: scale(1.5); }
/* The point you are at is under its star, so it steps aside rather than doubling it. */
.ghost-mark[aria-current]::before { opacity: 0; transform: scale(0); }
.ghost-mark:focus-visible { outline: 1px solid rgba(143, 163, 255, .7); outline-offset: 3px; border-radius: 8px; }
/* The star: the constellation's lit point, four thin spikes and a halo, on the mark you are at. Only the
   current mark wears one, so the eye has one thing to find rather than twelve. It sits on the same column
   as the points, so the line runs through it. */
.ghost-mark::after {
  content: ''; position: absolute; left: 11px; top: 50%; width: 28px; height: 28px;
  margin: -14px 0 0 -14px; transform: scale(0); border-radius: 50%;
  background:
    linear-gradient(to bottom, transparent 4%, rgba(232, 236, 255, .95) 50%, transparent 96%) 50% 0 / 1px 100% no-repeat,
    linear-gradient(to right, transparent 4%, rgba(232, 236, 255, .95) 50%, transparent 96%) 0 50% / 100% 1px no-repeat,
    radial-gradient(circle, rgba(255, 255, 255, 1) 0, rgba(190, 200, 255, .85) 9%, rgba(143, 163, 255, .35) 24%, rgba(143, 163, 255, .08) 44%, transparent 62%);
  transition: transform .28s cubic-bezier(.22, 1, .36, 1);
}
.ghost-mark[aria-current]::after { transform: scale(1); }
.reduced .ghost-mark::before, .reduced .ghost-mark::after, .reduced .ghost-name { transition: none; }

/* The name rides just past the end of the longest tick, and only for the mark under the pointer. */
.ghost-name {
  position: absolute; left: 36px; top: 50%; transform: translateY(-50%);
  white-space: nowrap; opacity: 0; pointer-events: none;
  font: 500 .62rem/1 var(--font-mono); letter-spacing: .16em; text-transform: uppercase;
  color: rgba(232, 226, 240, .85); text-shadow: 0 1px 6px rgba(5, 5, 7, .9);
  transition: opacity .2s ease;
}
.ghost-mark:hover .ghost-name, .ghost-mark:focus-visible .ghost-name { opacity: 1; }

/* No rail on a phone: it would sit in the thumb's path down the left edge of the screen, and the film is
   scrubbed by scrolling there rather than jumped around. */
.phone .ghost-nav { display: none; }
@media (max-width: 760px) { .ghost-nav { display: none; } }

/* ---- the ground the film fades into ---- */
:root { --ground: #0a0a1a; }

/* ---- the finale's two actions (the beat itself is film.css) ---- */
.finale-actions { display: flex; flex-wrap: wrap; align-items: center; gap: 1rem 1.6rem; }

/* The closing band: the dark the fade lands on, one line set like the hero's inscription, one exit. */
.closing { position: relative; background: #0a0a1a; padding: 18vh 6vw 14vh; text-align: center; }
.closing-line { margin: 0 0 2rem; font: 400 clamp(.72rem, .9vw, .84rem)/1.6 var(--font-caps); letter-spacing: .34em; text-indent: .34em; text-transform: uppercase; color: rgba(200, 184, 219, .62); }

/* ---- footer: the same ground, the tree's ember as a faint gold radial at the very bottom edge ---- */
.footer {
  position: relative; isolation: isolate; padding: 3rem 7vw 4rem; color: var(--mist);
  background: radial-gradient(52vw 16vh at 50% 100%, rgba(211, 165, 74, .11), transparent 70%) var(--ground);
  border-top: 1px solid rgba(249, 244, 245, .06);
}
.footer::after {
  content: ''; position: absolute; inset: 0; z-index: 2; pointer-events: none; opacity: .04;
  background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='280' height='280'%3E%3Cfilter id='g'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23g)'/%3E%3C/svg%3E") 0 0 / 280px 280px repeat;
}
.footer-inner { position: relative; z-index: 1; display: flex; flex-wrap: wrap; align-items: center; gap: 1.5rem 3rem; }
.footer .brand-mark { width: 28px; }
.footer .brand-word { font-size: .9rem; }
.footer-links { display: flex; flex-wrap: wrap; gap: 1rem 2rem; }
.footer-links a { font: 500 .72rem/1 var(--font-mono); letter-spacing: .16em; text-transform: uppercase; color: var(--mist); text-decoration: none; padding-bottom: .3rem; border-bottom: 1px solid rgba(211, 165, 74, .45); transition: color .2s, border-color .2s; }
.footer-links a:hover, .footer-links a:focus-visible { color: var(--ivory); border-bottom-color: var(--gold); outline: none; }
.footer-copy { margin: 0; margin-left: auto; font-size: .85rem; }

.phone .header { padding: 12px 16px; }
.phone .brand-seat { width: 40px; height: 40px; }
.phone .brand-mark { width: 32px; }
.phone .brand-word { display: none; }
.phone .footer { padding-left: 6vw; padding-right: 6vw; }
.phone .footer-copy { margin-left: 0; }

/* ---- boot veil ---- */
.veil { position: fixed; inset: 0; z-index: 60; background: var(--ink); display: grid; place-content: center; justify-items: center; transition: opacity .6s ease; }
.veil.is-gone { opacity: 0; pointer-events: none; }
.veil[hidden] { display: none; }
.veil-word { font-size: 1.6rem; }
.veil-bar { display: block; width: 160px; height: 1px; margin-top: 14px; background: rgba(249, 244, 245, .15); }
.veil-bar i { display: block; height: 100%; width: 0; background: var(--gold); transition: width .2s linear; }

/* ---- plain view toggle (Plan 11, spec section 4.1) ----
 * The way out of the film, for anyone who just wants the information. It has to be findable without
 * being loud: dim until hovered, and it never takes the eye off the wordmark. The switch is drawn
 * rather than an <input> because it navigates to another page instead of flipping a state here.
 * Like the sound ring, all three pieces are drawn out of the header's own colour, so they follow it onto
 * a lit frame instead of staying a fixed lilac that vanishes there. PLAIN VIEW is text, so 1.4.3's 4.5:1
 * is its floor - 60% of ivory on the dark header clears it where the old .46 of lilac measured 3.00. */
.plain-toggle {
  display: flex; align-items: center; gap: .5rem; padding: .4rem .5rem;
  text-decoration: none; color: color-mix(in srgb, currentColor 60%, transparent);
  font: 500 .58rem/1 var(--font-mono); letter-spacing: .16em; text-transform: uppercase;
  transition: color .3s ease;
}
.plain-toggle-track {
  position: relative; width: 26px; height: 14px; border-radius: 7px;
  border: 1px solid color-mix(in srgb, currentColor 42%, transparent); transition: border-color .3s ease;
}
.plain-toggle-knob {
  position: absolute; left: 2px; top: 50%; width: 8px; height: 8px; border-radius: 50%;
  transform: translateY(-50%); background: color-mix(in srgb, currentColor 62%, transparent);
  transition: transform .3s cubic-bezier(.16, .6, .2, 1), background-color .3s ease;
}
.plain-toggle:hover, .plain-toggle:focus-visible {
  color: var(--ivory); outline: none;
}
.plain-toggle:hover .plain-toggle-track, .plain-toggle:focus-visible .plain-toggle-track { border-color: rgba(140, 220, 222, .55); }
.plain-toggle:hover .plain-toggle-knob, .plain-toggle:focus-visible .plain-toggle-knob { transform: translateY(-50%) translateX(12px); background: rgba(140, 220, 222, .9); }
.reduced .plain-toggle-knob { transition: background-color .3s ease; }
.reduced .plain-toggle:hover .plain-toggle-knob { transform: translateY(-50%) translateX(12px); }
/* Someone whose system asks for less motion is offered plain view rather than sent there: the control
 * simply stops being quiet, so the choice is visible and still theirs. Spec section 4.1. */
@media (prefers-reduced-motion: reduce) { .plain-toggle { color: var(--mist); } .plain-toggle-track { border-color: rgba(140, 220, 222, .45); } }
/* On a phone the label goes and the switch stands alone. */
.phone .plain-toggle-label { display: none; }
