@import url('./tokens.css?v=20260831d');

/* ============================================================
   GREYMTTR - greymttr.com
   Hand-written static styles.

   Every color, size, spacing step and rule weight lives in
   tokens.css, imported above. Add new values there, not here.
   ============================================================ */

*{box-sizing:border-box}
html,body{margin:0}
html{scroll-behavior:smooth}
body{background:var(--bg); color:var(--body); font-family:var(--sans); overflow-x:hidden; -webkit-font-smoothing:antialiased;}
::selection{background:var(--flare); color:var(--bg);}
a{color:inherit;}
img{max-width:100%; display:block;}

@keyframes flicker{0%,100%{opacity:1}92%{opacity:1}93%{opacity:.6}94%{opacity:1}}
@keyframes scanbeam{0%{top:-18%;opacity:0}10%{opacity:1}90%{opacity:1}100%{top:100%;opacity:0}}
@keyframes crtflicker{0%,100%{opacity:1}50%{opacity:.985}53%{opacity:.96}56%{opacity:.99}}

/* ---- shared bits ---- */
.wrap{max-width:1100px; margin:0 auto; padding:0 var(--sp-6);}
.tag{font-family:var(--mono); font-size:var(--fs-sm); letter-spacing:var(--tr-3); color:var(--orange2); text-transform:uppercase;}
.h{font-family:var(--stencil); font-weight:var(--fw-bold); color:var(--bright); line-height:var(--lh-tight); letter-spacing:var(--tr-1);}
.panel{position:relative; border:var(--rule-hair) solid var(--edge); background:var(--panel-t); padding:var(--sp-10);}
.tick{position:absolute; width:18px; height:18px; z-index:2;}
.tick.tl{top:-1px;left:-1px;border-top:var(--rule-hair) solid var(--orange);border-left:var(--rule-hair) solid var(--orange);}
.tick.tr{top:-1px;right:-1px;border-top:var(--rule-hair) solid var(--orange);border-right:var(--rule-hair) solid var(--orange);}
.tick.bl{bottom:-1px;left:-1px;border-bottom:var(--rule-hair) solid var(--orange);border-left:var(--rule-hair) solid var(--orange);}
.tick.br{bottom:-1px;right:-1px;border-bottom:var(--rule-hair) solid var(--orange);border-right:var(--rule-hair) solid var(--orange);}
section{padding:var(--sp-24) 0;}
.skip{position:absolute; left:-9999px;}
.skip:focus{left:12px; top:12px; z-index:200; background:var(--orange); color:var(--bg); padding:12px 18px; font-family:var(--mono); font-size:var(--fs-sm);}

/* ---- status bar ---- */
.statusbar{position:relative; z-index:5; display:flex; align-items:center; justify-content:center; gap:var(--sp-3); padding:var(--sp-2) var(--sp-5); background:var(--orange); color:var(--bg); font-family:var(--mono); font-size:var(--fs-xs); letter-spacing:var(--tr-2); text-transform:uppercase; text-align:center;}
.statusbar span{animation:flicker 5s infinite;}

/* ---- nav ---- */
/* The bar is sticky and always on. It sits in the flow under the status bar
   and sticks to the top from the first pixel of scroll, so it is never absent
   and never covers anything: a fixed bar that never hides would sit on top of
   the orange status bar and the top of the hero permanently, and pushing the
   page down by the bar's height means hard-coding that height at every
   breakpoint. Sticky costs neither.

   OPAQUE, ABOVE THE TEXTURE, AND MATCHING theme-color EXACTLY. Those three
   together are the whole fix, and it was found by looking at a site whose bar
   does not have this problem. Safari tints its own chrome with theme-color,
   so the strip above the bar is already painted #0a0403. A bar that is also
   flat #0a0403 meets that strip with no boundary at all. The seam was never a
   position to find; it was a colour match to make.

   z-index is var(--z-nav), above the two body texture overlays rather than
   under them. That is the part that actually moved the needle: the overlays
   are fixed, so they stop at the layout viewport, and while they painted over
   the bar it rendered #080202 against a strip of #0a0403 they could not
   reach. Measured, not guessed - sampling the bar's own empty middle returned
   8,2,2 for a bar set to 10,4,3. See the LAYERING block in tokens.css.

   That is why the translucent fill had to go. rgba(--bg,.88) over a blur lets
   page content through, so the bar rendered as bg-plus-whatever-was-behind-it
   while the strip above rendered as flat bg. Two nearly-but-not-quite-equal
   dark surfaces meeting is exactly what reads as a faint band across the top,
   and no amount of repositioning the bar could fix a difference in what the
   bar was made of. Keep background:var(--bg) and the theme-color meta in
   index.html in step; if either changes, the seam comes back.

   Trying to make the bar itself reach higher is a dead end and is measured as
   one: documentElement.clientHeight holds at 721 while innerHeight grows to
   829, so the layout viewport that position:fixed resolves against never
   covers the full screen. Do not re-add, all measured, none of them reached
   it: an overhanging fill on the bar in any form (::before at 7f3ae22, the
   box itself at cfb9257); a sticky strip pinned to the viewport origin
   (PR #39 - a stuck sticky is positioned against the scrollport, so "above
   its top" lands in the same clipped region as fixed); a JS-tracked
   document-layer fill (PR #43 - it did cover the band, but a translucent slab
   over scrolling content looked worse than the content did);
   viewport-fit=cover (honoured, but env() reports 0 here, 57bfccf). None of
   them were needed. The bar does not have to reach the top if the top is
   already the same colour as the bar. */
.nav{position:sticky; top:0; z-index:var(--z-nav); display:flex; align-items:center; justify-content:space-between; gap:var(--sp-5); padding:var(--sp-4) var(--sp-8); background:var(--bg); border-bottom:var(--rule-hair) solid var(--edge-soft);}
.nav-logo{height:56px; width:auto; object-fit:contain;}

.nav-home{display:flex; align-items:center; opacity:.35; transition:opacity .2s;}
.nav-home:hover{opacity:.65;}
.nav-links{display:flex; align-items:center; gap:var(--sp-7); flex-wrap:wrap;}
.nav-links a{font-family:var(--mono); font-size:var(--fs-sm); letter-spacing:var(--tr-2); text-transform:uppercase; color:var(--body); text-decoration:none; transition:color .2s;}
.nav-links a:hover{color:var(--orange);}

/* STORE. The one item in the bar that leaves the site, so it is boxed rather
   than bare: the border is what tells a destination apart from the in-page
   jumps sitting next to it. Square corners, like every other control here -
   the one radius token on the page belongs to the CRT frame. It inherits the
   mono, size and tracking of .nav-links a above, so the box is sized by the
   type rather than set independently of it, and only the border, colour and
   padding are stated. */
.nav-links a.nav-store{border:var(--rule-hair) solid var(--orange); color:var(--orange); padding:var(--sp-2) var(--sp-4); line-height:var(--lh-tight); transition:background .2s,color .2s;}
.nav-links a.nav-store:hover{background:var(--orange); color:var(--bg);}

/* ---- hero ---- */
.hero{position:relative; text-align:center; padding:80px 24px 70px; overflow:hidden;}
.hero .glow{position:absolute; inset:0; background:radial-gradient(ellipse 70% 55% at 50% 42%, rgba(var(--orange-rgb),.14), transparent 70%); z-index:0;}
.hero-inner{position:relative; z-index:3; display:flex; flex-direction:column; align-items:center; gap:22px;}
.emblem{width:clamp(190px,44vw,320px); height:auto; aspect-ratio:1; object-fit:contain; filter:drop-shadow(0 0 34px rgba(var(--orange-rgb),.5));}
.hero .tagline{font-family:var(--mono); font-size:var(--fs-lg); letter-spacing:var(--tr-5); color:#c99; text-transform:uppercase;}
.hero .loc{font-family:var(--mono); font-size:var(--fs-xs); letter-spacing:var(--tr-3); color:var(--mut); text-transform:uppercase;}

/* ---- bio ---- */
.bio-head{display:flex; justify-content:space-between; align-items:flex-end; gap:16px; flex-wrap:wrap; padding-bottom:18px; margin-bottom:26px; border-bottom:var(--rule-hair) dashed var(--edge2);}
.bio h2{font-size:var(--fs-bio);}
.bio-meta{font-family:var(--mono); font-size:var(--fs-2xs); letter-spacing:var(--tr-2); color:var(--mut); text-align:right;}
.bio p{font-size:var(--fs-2xl); line-height:var(--lh-loose); color:var(--body); max-width:820px; margin:0 0 18px;}
.bio p:last-child{margin-bottom:0;}

/* ---- members ---- */
.members-head{text-align:center; margin-bottom:var(--sp-12);}
.members-head h2{font-size:var(--fs-section); margin-top:var(--sp-3);}
.grid3{display:grid; grid-template-columns:repeat(3,1fr); gap:var(--sp-7);}
.mcard{position:relative; border:var(--rule-hair) solid var(--edge); background:var(--panel2); overflow:hidden; display:flex; flex-direction:column;}
.mcard .ph{position:relative; aspect-ratio:1/1; overflow:hidden;}
.mcard .ph img{width:100%; height:100%; object-fit:cover;}
.mcard .ph::after{content:''; position:absolute; inset:0; background:linear-gradient(180deg, transparent 55%, rgba(var(--panel2-rgb),.92));}
.mcard .body{padding:18px 20px 22px; flex:1; display:flex; flex-direction:column; justify-content:flex-end;}
.mcard .role{font-family:var(--mono); font-size:var(--fs-xs); letter-spacing:var(--tr-2); color:var(--orange2); text-transform:uppercase; margin-bottom:var(--sp-2); line-height:var(--lh-snug);}
.mcard .name{font-family:var(--stencil); font-weight:var(--fw-mid); font-size:var(--fs-3xl); color:var(--bright); letter-spacing:var(--tr-1);}
.mcard .origin{font-family:var(--mono); font-size:var(--fs-xs); letter-spacing:var(--tr-2); color:var(--mut); text-transform:uppercase; margin-top:var(--sp-2);}

/* ---- album ---- */
.music-grid{display:grid; grid-template-columns:minmax(220px,360px) 1fr; gap:var(--sp-11); align-items:start;}
.album{position:relative;}
.album .frameline{position:absolute; inset:-14px; border:var(--rule-hair) dashed var(--edge2); z-index:0;}
.album img{position:relative; z-index:1; width:100%; height:auto; box-shadow:0 24px 60px rgba(0,0,0,.6);}
.music h2{font-family:var(--stencil); font-weight:var(--fw-black); font-size:var(--fs-display); color:var(--bright); line-height:var(--lh-display); margin:6px 0 14px;}
.music .rec{font-family:var(--mono); font-size:var(--fs-sm); letter-spacing:var(--tr-2); color:var(--orange); border:var(--rule-hair) solid var(--orange); padding:10px 18px; display:inline-block; text-transform:uppercase; margin-bottom:20px;}
.music p{font-size:var(--fs-xl); line-height:var(--lh-body); color:var(--body); max-width:520px;}

/* ---- archive gateway (CRT frame, ported from the EPK player chrome) ---- */
.crt{position:relative; margin:0 auto; max-width:820px; border:var(--rule-hair) solid var(--edge); border-radius:var(--radius-crt); overflow:hidden; background:var(--panel-crt); box-shadow:0 0 0 1px rgba(var(--orange-rgb),.1),0 24px 70px rgba(0,0,0,.55); animation:crtflicker 6s infinite;}
.crt-head,.crt-foot{position:relative; z-index:6; display:flex; align-items:center; justify-content:space-between; gap:12px; font-family:var(--mono); text-transform:uppercase;}
.crt-head{padding:11px 18px; background:var(--orange); color:var(--bg); font-size:var(--fs-xs); letter-spacing:var(--tr-2); font-weight:var(--fw-mid);}
.crt-foot{padding:9px 18px; border-top:var(--rule-hair) solid var(--edge3); background:var(--bg); font-size:var(--fs-2xs); letter-spacing:var(--tr-2); color:var(--mut);}
.crt-rec{animation:flicker 5s infinite;}
.crt-stage{position:relative; padding:var(--sp-12) var(--sp-8); text-align:center;}
.crt-stage > *{position:relative; z-index:5;}
.crt-scan{position:absolute; inset:0; z-index:3; pointer-events:none; background:repeating-linear-gradient(to bottom, rgba(0,0,0,.28) 0, rgba(0,0,0,.28) 1px, transparent 1px, transparent 3px); mix-blend-mode:multiply; opacity:.5;}
.crt-vig{position:absolute; inset:0; z-index:3; pointer-events:none; background:radial-gradient(ellipse 94% 86% at 50% 48%, transparent 55%, rgba(var(--shade-rgb),.85) 100%);}
.crt-beam{position:absolute; left:0; right:0; height:80px; top:-18%; z-index:4; pointer-events:none; background:linear-gradient(180deg, transparent, rgba(var(--orange2-rgb),.12) 50%, transparent); animation:scanbeam 7s linear infinite;}
.gate-kicker{font-family:var(--mono); font-size:var(--fs-xs); letter-spacing:var(--tr-3); color:var(--orange2); text-transform:uppercase; margin-bottom:var(--sp-4);}
.gate-title{font-family:var(--stencil); font-weight:var(--fw-black); font-size:var(--fs-title); color:var(--bright); line-height:var(--lh-tight); margin:0 0 18px;}
.gate-copy{font-size:var(--fs-xl); line-height:var(--lh-body); color:var(--body); max-width:520px; margin:0 auto var(--sp-8);}
.gate-btn{display:inline-block; font-family:var(--mono); font-size:var(--fs-md); letter-spacing:var(--tr-3); text-transform:uppercase; font-weight:var(--fw-mid); color:var(--bg); background:var(--orange); border:var(--rule-hair) solid var(--orange); padding:17px 34px; text-decoration:none; transition:background .2s,color .2s;}
.gate-btn:hover{background:transparent; color:var(--orange);}

/* ---- signal / mailing list ---- */
.signal{text-align:center; position:relative; overflow:hidden;}
.signal .glow{position:absolute; inset:0; background:radial-gradient(ellipse 60% 60% at 50% 50%, rgba(var(--orange-rgb),.1), transparent 70%);}
/* One bracketed block: heading, the link bars, then the signup. The brackets sit
   in the frame's own padding rather than on negative offsets, so they stay inside
   the viewport at narrow widths instead of forcing horizontal overflow. */
.signal-frame{position:relative; max-width:764px; margin:0 auto; padding:40px 22px;}
.signal-frame .hud{position:absolute; width:52px; height:52px; opacity:.6; pointer-events:none;}
.signal-frame .hud.tl{top:0;left:0;border-top:var(--rule) solid var(--orange);border-left:var(--rule) solid var(--orange);}
.signal-frame .hud.tr{top:0;right:0;border-top:var(--rule) solid var(--orange);border-right:var(--rule) solid var(--orange);}
.signal-frame .hud.bl{bottom:0;left:0;border-bottom:var(--rule) solid var(--orange);border-left:var(--rule) solid var(--orange);}
.signal-frame .hud.br{bottom:0;right:0;border-bottom:var(--rule) solid var(--orange);border-right:var(--rule) solid var(--orange);}
.signal h2{font-size:var(--fs-section-sm); margin:0 0 30px;}
.subrow{display:flex; border:var(--rule-hair) solid var(--orange);}
.subrow input{flex:1; min-width:0; background:transparent; border:none; outline:none; padding:var(--sp-4) var(--sp-5); color:var(--bright); font-family:var(--mono); font-size:var(--fs-md); letter-spacing:var(--tr-1);}
.subrow button{background:var(--orange); color:var(--bg); border:none; padding:var(--sp-4) var(--sp-7); font-family:var(--mono); font-size:var(--fs-sm); letter-spacing:var(--tr-2); text-transform:uppercase; cursor:pointer; transition:background .2s;}
.subrow button:hover{background:var(--orange2);}
.subform{max-width:460px; margin:34px auto 0;}
.subdone{border:var(--rule-hair) solid var(--orange); background:rgba(var(--orange-rgb),.08); padding:18px 20px; font-family:var(--mono); font-size:var(--fs-md); letter-spacing:var(--tr-2); color:var(--orange2); text-transform:uppercase;}
/* ---- channels ----
   One stacked block, not five cards: the rows carry no gap and no box of
   their own, only a hairline between neighbours, and the whole stack is
   framed by the .brackets primitive rather than by a border.

   One inset governs the block: it is the padding that holds the rows clear
   of the bracket arms, and the margin that lines the status line and the
   album panel up with those rows. .signal-frame's content box is already
   the 720px the link bars this replaces used, so nothing here sets a width. */
.signal-frame{--ch-inset:var(--sp-3);}
.ch-status{display:flex; align-items:baseline; justify-content:space-between; gap:var(--sp-4); margin:0 var(--ch-inset) var(--sp-3);}
.channels{list-style:none; margin:0; padding:var(--ch-inset);}
.ch-row + .ch-row{border-top:var(--rule-hair) solid var(--edge2);}

.ch{position:relative; overflow:hidden; display:flex; align-items:center; gap:var(--sp-4); width:100%; padding:var(--sp-4) var(--sp-5); background:transparent; border:0; font-family:var(--mono); font-size:var(--fs-sm); letter-spacing:var(--tr-2); text-transform:uppercase; color:var(--orange2); text-decoration:none; text-align:left; cursor:pointer; transition:color .3s ease;}
/* The sweep. A scaled pseudo-element rather than an animated background
   position, so it is one composited transform. The global
   prefers-reduced-motion block at the foot of this file drops the
   transition, which leaves the same inversion applied instantly. */
.ch::before{content:''; position:absolute; inset:0; z-index:0; background:var(--orange); transform:scaleX(0); transform-origin:left center; transition:transform .3s ease;}
.ch > *{position:relative; z-index:1;}
.ch:hover::before,
.ch:focus-visible::before{transform:scaleX(1);}
.ch:focus-visible{outline:var(--rule) solid var(--bg); outline-offset:calc(var(--sp-1) * -1);}

/* Hierarchy across the row: the index recedes, the name leads, the handle
   answers it. Everything inverts to the page ground once the sweep lands. */
/* The text has to cross-fade over the same .3s the sweep takes. Snapping it
   would put the inverted (near-black) text on the not-yet-swept row for the
   length of the sweep, which reads as the label vanishing. */
.ch-idx{flex:0 0 auto; color:var(--mut); transition:color .3s ease;}
.ch-mark{flex:0 0 auto; width:var(--sp-6); height:var(--sp-6); display:flex; align-items:center; justify-content:center;}
.ch-mark svg{width:100%; height:100%; fill:currentColor;}
.ch-name{flex:0 0 auto; color:var(--bright); transition:color .3s ease;}
/* The leader. currentColor, so it inverts with the rest of the row. */
.ch-fill{flex:1 1 auto; min-width:var(--sp-6); border-bottom:var(--rule-hair) dotted currentColor; opacity:.4;}
.ch-handle{flex:0 1 auto; text-align:right; overflow-wrap:anywhere;}

.ch:hover,
.ch:focus-visible{color:var(--bg);}
.ch:hover .ch-idx, .ch:focus-visible .ch-idx,
.ch:hover .ch-name, .ch:focus-visible .ch-name{color:var(--bg);}

/* The conversion row: filled rather than outlined, taller, and lifted off
   the stack so it reads as the destination rather than a fifth channel. */
.ch-row.is-primary{margin-top:var(--sp-3); border-top:none;}
.is-primary .ch{background:var(--orange); color:var(--bg); padding-top:var(--sp-6); padding-bottom:var(--sp-6);}
.is-primary .ch-idx,
.is-primary .ch-name{color:var(--bg);}
/* A second conversion row joins the first as one block rather than floating
   below it. The margin on .is-primary is the lift that sets the pair apart
   from the platform rows above, and it belongs to the first of them only; a
   hairline in the page ground then keeps the two readable as separate
   targets without reintroducing the gap. */
.ch-row.is-primary + .ch-row.is-primary{margin-top:0; border-top:var(--rule-hair) solid var(--bg);}

/* This row starts filled, so its sweep intensifies rather than inverts:
   sweeping it to the page ground would make the conversion row recede on
   hover, reading as less prominent than the four above it. --flare is the
   token that sits between --orange and --red-hot. Its text is already
   inverted at rest and stays that way. */
.is-primary .ch::before{background:var(--flare);}
.is-primary .ch:hover, .is-primary .ch:focus-visible,
.is-primary .ch:hover .ch-idx, .is-primary .ch:focus-visible .ch-idx,
.is-primary .ch:hover .ch-name, .is-primary .ch:focus-visible .ch-name{color:var(--bg);}

/* The album panel hangs off the primary row and drops the shared edge. It is a
   row of the list now rather than a sibling after it, so the list's own
   --ch-inset padding already lines it up with the rows and it carries no
   margin of its own. */
.ch-panel{margin:0; border:var(--rule-hair) solid var(--edge2); border-top:none; padding:var(--sp-8) var(--sp-5);}

/* The reveal. The panel sits inside .channels, so the .brackets frame - a
   ::before at inset:0 on the list - encloses the expanded content as well as
   the rows. Animating grid-template-rows 0fr -> 1fr grows the list's own
   height over the same .3s the rows use, which is what walks the bracket arms
   down with the panel instead of snapping them to the opened height; it also
   needs no measured height, so the panel can grow with its content.
   .ch-clip is the grid item and carries nothing of its own: min-height:0 lets
   it shrink below its content and overflow:hidden clips that content on the
   way. It has to be a separate element from .ch-panel, because min-height only
   collapses a box's content - the panel's own padding and border would survive
   it and leave the closed frame ~57px taller than the rows. visibility does
   the rest: hidden takes the panel out of the picture and out of the tab order
   at rest, and because it is transitioned it holds the panel visible for the
   whole length of the close rather than cutting it at frame one. */
.ch-reveal{display:grid; grid-template-rows:0fr; transition:grid-template-rows .3s ease;}
.ch-reveal > .ch-clip{min-height:0; overflow:hidden; visibility:hidden; transition:visibility .3s;}
.ch-reveal.is-open{grid-template-rows:1fr;}
.ch-reveal.is-open > .ch-clip{visibility:visible;}

.socials{display:flex; flex-wrap:wrap; gap:var(--sp-3); justify-content:center;}
.socials a{font-family:var(--mono); font-size:var(--fs-sm); letter-spacing:var(--tr-2); text-transform:uppercase; color:var(--orange2); padding:12px 22px; border:var(--rule-hair) solid var(--edge2); text-decoration:none; transition:border-color .2s,color .2s;}
.socials a:hover{border-color:var(--orange); color:var(--orange);}

/* ---- contact ---- */
.contact{text-align:center;}
.contact h2{font-size:var(--fs-section-sm); margin:12px 0 10px;}
.contact .email{display:inline-block; font-family:var(--stencil); font-weight:var(--fw-bold); font-size:var(--fs-email); color:var(--orange); text-decoration:none; letter-spacing:var(--tr-1); margin:8px 0 6px; word-break:break-word;}
.contact .email:hover{color:var(--orange2);}
.contact .based{font-family:var(--mono); font-size:var(--fs-sm); letter-spacing:var(--tr-2); color:var(--mut); text-transform:uppercase; margin-bottom:30px;}


/* ---- prophets: the single promo page ----
   greymttr.com/prophets. A release hero over a link tree, built out of rules
   this stylesheet already carries: .album frames the art, .channels/.ch are
   the same rows as the homepage's, and .gate-btn is the same button as the
   archive gate. Only what the release itself needs is stated below. */
.hero.release{padding:var(--sp-16) var(--sp-6) var(--sp-12);}
.hero.release .hero-inner{gap:var(--sp-5);}

/* The art. .album supplies the dashed frameline and the drop shadow; the
   width has to be set here because the hero centres its children rather than
   stretching them, so the image has no column to size against. */
.single-art{width:min(400px,78vw);}
/* Child combinator, not a descendant selector: the placeholder below has an
   <img> of its own, and a bare `.single-art img` hid that too, leaving the
   pending state as a bare line of text in an empty box. */
.single-art > img{display:none;}
.single-art.has-art > img{display:block;}
/* Shown until the art file is in the repo and has decoded. aspect-ratio holds
   the square the cover will occupy, so nothing below it moves when the image
   lands. assets/prophets.js owns the .has-art flip. */
.art-pending{position:relative; z-index:1; aspect-ratio:1; display:flex; flex-direction:column; align-items:center; justify-content:center; gap:var(--sp-4); background:var(--panel2); border:var(--rule-hair) solid var(--edge);}
.single-art.has-art .art-pending{display:none;}
/* Two class names, not one: .single-art also carries .album, whose
   `.album img{width:100%}` outranks a bare `.art-emblem` and blew the mark up
   to the full width of the frame. Matching that specificity and landing later
   in the file is what wins it back. */
.art-pending .art-emblem{width:44%; height:auto; opacity:.45;}
.art-pending .readout{font-size:var(--fs-xs); letter-spacing:var(--tr-2); color:var(--mut);}

.release-meta{font-size:var(--fs-sm); letter-spacing:var(--tr-2);}
/* Off-screen but still in the accessible tree and still indexed - the single
   art already carries the title visually, so the h1 is not painted, but a page
   built to be shared should not ship without one. Clip rather than
   display:none or visibility:hidden, either of which would take it out of the
   accessible tree along with the layout. */
.vis-hidden{position:absolute; width:1px; height:1px; margin:-1px; padding:0; overflow:hidden; clip-path:inset(50%); white-space:nowrap; border:0;}

/* Countdown. Authored with the `hidden` attribute and revealed by
   assets/prophets.js, so a page with no JS shows nothing rather than four
   zeroes that will never tick. Nothing here sets display on .countdown
   itself, which is what leaves the UA's [hidden] rule able to do that. */
.cd-grid{display:flex; justify-content:center; flex-wrap:wrap; gap:var(--sp-3);}
.cd-unit{display:flex; flex-direction:column; align-items:center; gap:var(--sp-1); min-width:68px; padding:var(--sp-3) var(--sp-4); border:var(--rule-hair) solid var(--edge2); background:var(--panel-t);}
/* tabular-nums is load-bearing: without it the seconds column changes width
   as the digits change and the whole row jitters once a second. */
.cd-num{font-family:var(--mono); font-weight:var(--fw-mid); font-size:var(--fs-3xl); line-height:var(--lh-tight); color:var(--orange); font-variant-numeric:tabular-nums;}
.cd-lab{font-family:var(--mono); font-size:var(--fs-2xs); letter-spacing:var(--tr-2); text-transform:uppercase; color:var(--mut);}
.cd-out{display:none; font-size:var(--fs-lg); letter-spacing:var(--tr-3); color:var(--orange); border:var(--rule-hair) solid var(--orange); padding:var(--sp-3) var(--sp-6);}
.countdown.is-out .cd-grid{display:none;}
.countdown.is-out .cd-out{display:inline-block;}


/* The link tree. One frame, two lists: where to get the single, then where to
   follow the band, with the mailing list closing it out. The notes and the
   second status line align to the rows rather than to the frame, which is
   what --ch-inset is for. */
.linktree h2{margin-bottom:var(--sp-6);}
.lt-note{font-size:var(--fs-2xs); letter-spacing:var(--tr-2); color:var(--mut); text-align:left; margin:var(--sp-3) var(--ch-inset) 0;}
.lt-head{margin-top:var(--sp-10);}
.lt-notify{margin-top:var(--sp-10); padding-top:var(--sp-8); border-top:var(--rule-hair) dashed var(--edge2);}
.lt-notify .subform{margin-top:var(--sp-4);}

/* A row with nowhere to go: a platform listed before its link exists. It is a
   <span> rather than a link or a disabled button, so it is already out of the
   tab order; this drops the hover sweep and the pointer that would promise it
   does something. */
.ch.is-off{color:var(--mut); cursor:default;}
.ch.is-off::before{display:none;}
.ch.is-off .ch-name{color:var(--body);}
.ch.is-off .ch-mark{opacity:.55;}

/* ---- footer ---- */
footer{border-top:var(--rule-hair) solid var(--edge-soft); padding:34px var(--sp-6); display:flex; align-items:center; justify-content:space-between; gap:18px; flex-wrap:wrap; background:var(--bg);}
footer .fl{display:flex; align-items:center; gap:var(--sp-3);}
footer .femblem{width:54px; height:54px; object-fit:contain; flex:0 0 auto;}
.fmono{font-family:var(--mono); font-size:var(--fs-xs); letter-spacing:var(--tr-2); color:var(--mut); text-transform:uppercase;}
footer a.fmono{text-decoration:none; padding:12px 22px; border:var(--rule-hair) solid var(--edge2); color:var(--orange2); transition:border-color .2s,color .2s;}
footer a.fmono:hover{border-color:var(--orange); color:var(--orange);}
.fr{display:flex; align-items:center; gap:var(--sp-5); flex-wrap:wrap;}

/* ---- responsive ---- */
@media (max-width:820px){
  section{padding:var(--sp-16) 0;}
  .panel{padding:26px;}
  .nav{padding:12px 14px; gap:10px;}
  .nav-logo{height:46px;}
  .nav-links{gap:13px;}
  .nav-links a{font-size:var(--fs-2xs); letter-spacing:var(--tr-1); white-space:nowrap;}
  .nav-links a.nav-store{padding:var(--sp-2) var(--sp-3);}
  .grid3{grid-template-columns:1fr; gap:var(--sp-5); max-width:420px; margin:0 auto;}
  .music-grid{grid-template-columns:1fr; gap:var(--sp-7);}
  .album{max-width:360px;}
  .crt-beam{display:none;}
  .crt-head{font-size:var(--fs-3xs); letter-spacing:var(--tr-1); padding:9px 12px;}
  .crt-foot{font-size:var(--fs-3xs); letter-spacing:var(--tr-1); padding:8px 12px;}
  .crt-rec{display:none;}
  .crt-stage{padding:34px 20px;}
  .signal-frame{--ch-inset:var(--sp-2);}
  .ch-status{flex-direction:column; gap:var(--sp-1); align-items:flex-start; font-size:var(--fs-xs); letter-spacing:var(--tr-2);}
  .ch{padding:var(--sp-3) var(--sp-3); gap:var(--sp-3); font-size:var(--fs-xs); letter-spacing:var(--tr-1);}
  .is-primary .ch{padding-top:var(--sp-5); padding-bottom:var(--sp-5);}
  .ch-mark{width:var(--sp-5); height:var(--sp-5);}
  .ch-fill{min-width:var(--sp-4);}
  .ch-panel{padding:var(--sp-7) var(--sp-4);}
  .signal-frame{padding:30px 14px;}
  .signal-frame .hud{width:38px; height:38px;}
  .subrow{flex-direction:column;}
  .subrow button{padding:15px 20px;}

  /* prophets */
  .hero.release{padding:var(--sp-10) var(--sp-5) var(--sp-12);}
  .single-art{width:min(300px,74vw);}
  .cd-grid{gap:var(--sp-2);}
  .cd-unit{min-width:60px; padding:var(--sp-2) var(--sp-3);}
  .cd-num{font-size:var(--fs-xl);}
  .lt-head{margin-top:var(--sp-8);}
  .lt-notify{margin-top:var(--sp-8); padding-top:var(--sp-6);}
}

@media (prefers-reduced-motion:reduce){
  html{scroll-behavior:auto;}
  *,*::before,*::after{animation:none !important; transition:none !important;}
}
