/* ATALT — ATA — 001 · design system + motion */

/* ============================================================
   ATALT · all things altered · web identity
   tokens from atalt_design_system.docx v1.0 — do not alter
   ============================================================ */
:root{
  --ink:#0A0A0A; --off:#F5F3ED; --cream:#EBE7DA;
  --g1:#8B8775; --g2:#5C5848; --hair:#3D3A32; --reg:#4A4640;
  --sans:"Inter","Helvetica Neue",Helvetica,Arial,sans-serif;
  --mono:"IBM Plex Mono","JetBrains Mono",Menlo,Consolas,monospace;
  --display:"Doto","IBM Plex Mono",Menlo,monospace;   /* dot-matrix LED: headings, names, statements, the countdown */
  --pad:clamp(20px,5vw,72px);
  /* the type scale, site-wide. Display (--fs): every heading, artist name, statement and the countdown, one
     size, set by FIT in atalt.js to what the most crowded screen allows (this clamp is the fallback).
     Lineup (--fs-l): the artist names, at the largest size the lineup screen allows and never above
     display (FIT sets it too). Sub-display: calc(var(--fs) * .4), for the hero facts.
     Body (--t-body): all running copy. Labels: .mono. */
  --fs:clamp(30px,5vw,72px);
  --t-body:clamp(15px,1.15vw,18px);
  --line-y:38vh;--line-y:38svh;  /* where the altering line sits on screen; svh matches the engine's innerHeight on iOS */
  /* rhythm: two section gaps, and the bottom inset every screen keeps */
  --gap-s:clamp(72px,12vh,140px);
  --gap-l:clamp(96px,16vh,180px);
  --nav-h:20px;                  /* top inset of every screen (there is no fixed nav) */
  --chrome-b:calc(84px + max(20px, env(safe-area-inset-bottom, 0px)));   /* every screen keeps the standing button clear */
  /* hero sigil: sized so its bar can sit on the 38% line (the webp's bar is at 50% of its height) */
  --sigil-w:min(100vw, 52svh);
  --hero-top-b:88px;             /* bottom edge of the hero's top row: 52px + two mono lines */
  --cut:cubic-bezier(.9,0,.1,1);
  /* sprung mechanism, not bouncy UI: stiff springs, small overshoot, fast settle.
     generated from a damped harmonic oscillator, baked to linear() curves. */
  --sp-snap:linear(0.0000 0.0%,0.0442 1.6%,0.0831 3.1%,0.1835 4.7%,0.2410 6.2%,0.3630 7.8%,0.4249 9.4%,0.4859 10.9%,0.6025 12.5%,0.6568 14.1%,0.7554 15.6%,0.7992 17.2%,0.8754 18.8%,0.9078 20.3%,0.9366 21.9%,0.9835 23.4%,1.0021 25.0%,1.0306 26.6%,1.0409 28.1%,1.0550 29.7%,1.0592 31.2%,1.0619 32.8%,1.0632 34.4%,1.0622 35.9%,1.0580 37.5%,1.0551 39.1%,1.0517 40.6%,1.0443 42.2%,1.0404 43.8%,1.0327 45.3%,1.0289 46.9%,1.0218 48.4%,1.0186 50.0%,1.0156 51.6%,1.0103 53.1%,1.0080 54.7%,1.0041 56.2%,1.0025 57.8%,0.9999 59.4%,0.9989 60.9%,0.9981 62.5%,0.9969 64.1%,0.9965 65.6%,0.9961 67.2%,0.9960 68.8%,0.9960 70.3%,0.9962 71.9%,0.9963 73.4%,0.9967 75.0%,0.9969 76.6%,0.9974 78.1%,0.9977 79.7%,0.9979 81.2%,0.9984 82.8%,0.9986 84.4%,0.9990 85.9%,0.9992 87.5%,0.9995 89.1%,0.9996 90.6%,0.9997 92.2%,0.9999 93.8%,1.0000 95.3%,1.0001 96.9%,1.0002 98.4%,1.0000 100.0%);   --t-snap:379ms;
  --sp-throw:linear(0.0000 0.0%,0.0500 1.6%,0.1149 3.1%,0.1967 4.7%,0.2891 6.2%,0.3867 7.8%,0.5338 9.4%,0.6273 10.9%,0.7143 12.5%,0.7933 14.1%,0.8631 15.6%,0.9497 17.2%,0.9953 18.8%,1.0318 20.3%,1.0597 21.9%,1.0799 23.4%,1.0932 25.0%,1.1024 26.6%,1.1027 28.1%,1.0995 29.7%,1.0935 31.2%,1.0856 32.8%,1.0715 34.4%,1.0614 35.9%,1.0513 37.5%,1.0415 39.1%,1.0323 40.6%,1.0200 42.2%,1.0130 43.8%,1.0069 45.3%,1.0019 46.9%,0.9979 48.4%,0.9947 50.0%,0.9915 51.6%,0.9902 53.1%,0.9896 54.7%,0.9894 56.2%,0.9896 57.8%,0.9905 59.4%,0.9913 60.9%,0.9923 62.5%,0.9933 64.1%,0.9944 65.6%,0.9959 67.2%,0.9968 68.8%,0.9977 70.3%,0.9984 71.9%,0.9991 73.4%,0.9996 75.0%,1.0003 76.6%,1.0006 78.1%,1.0008 79.7%,1.0010 81.2%,1.0011 82.8%,1.0011 84.4%,1.0011 85.9%,1.0010 87.5%,1.0009 89.1%,1.0008 90.6%,1.0007 92.2%,1.0006 93.8%,1.0005 95.3%,1.0004 96.9%,1.0003 98.4%,1.0000 100.0%); --t-throw:583ms;
  --sp-open:linear(0.0000 0.0%,0.0328 1.6%,0.0757 3.1%,0.1304 4.7%,0.1933 6.2%,0.2613 7.8%,0.3319 9.4%,0.4028 10.9%,0.5066 12.5%,0.5721 14.1%,0.6338 15.6%,0.6910 17.2%,0.7434 18.8%,0.7907 20.3%,0.8330 21.9%,0.8873 23.4%,0.9176 25.0%,0.9435 26.6%,0.9654 28.1%,0.9836 29.7%,0.9984 31.2%,1.0102 32.8%,1.0230 34.4%,1.0289 35.9%,1.0329 37.5%,1.0353 39.1%,1.0364 40.6%,1.0365 42.2%,1.0358 43.8%,1.0335 45.3%,1.0315 46.9%,1.0291 48.4%,1.0266 50.0%,1.0241 51.6%,1.0215 53.1%,1.0189 54.7%,1.0153 56.2%,1.0131 57.8%,1.0110 59.4%,1.0091 60.9%,1.0074 62.5%,1.0059 64.1%,1.0046 65.6%,1.0029 67.2%,1.0019 68.8%,1.0012 70.3%,1.0005 71.9%,1.0000 73.4%,0.9996 75.0%,0.9993 76.6%,0.9989 78.1%,0.9988 79.7%,0.9987 81.2%,0.9987 82.8%,0.9987 84.4%,0.9987 85.9%,0.9988 87.5%,0.9989 89.1%,0.9989 90.6%,0.9990 92.2%,0.9991 93.8%,0.9992 95.3%,0.9993 96.9%,0.9994 98.4%,1.0000 100.0%);  --t-open:571ms;
}
*{box-sizing:border-box;margin:0;padding:0}
html{scroll-behavior:smooth;-webkit-text-size-adjust:100%}
/* the page moves a screen at a time: native snapping on touch; on a mouse or trackpad atalt.js pages
   between screens with Lenis instead (html.paged). Short windows (landscape phones) scroll freely. */
html{scroll-snap-type:y mandatory}
html.paged{scroll-snap-type:none}
@media (max-height:600px){html{scroll-snap-type:none}}
/* Lenis (fine pointers only) owns smooth scrolling when it runs: no CSS smoothing on top, and embeds
   stop swallowing the wheel while a Lenis scroll is in flight */
html.lenis{scroll-behavior:auto}
html.lenis,html.lenis body{height:auto}
.lenis.lenis-smooth iframe{pointer-events:none}
body{
  background:var(--ink);color:var(--off);font-family:var(--sans);font-weight:400;
  font-size:var(--t-body);line-height:1.6;letter-spacing:.005em;
  overflow-x:hidden;overflow-x:clip;-webkit-font-smoothing:antialiased;
}
/* clip, not hidden: thrown and sheared halves must never widen the page (mobile browsers zoom out to fit) */
html{overflow-x:hidden;overflow-x:clip}
/* html's overflow-x stops body's overflow from reaching the viewport, so a script that locks the page
   with body{overflow:hidden} (an artist sheet, the admin wall, the Quicket modal) has to lock html as well */
html:has(body[style*="overflow: hidden"]),html:has(body > [data-quicket-modal]){overflow:hidden}
::selection{background:var(--off);color:var(--ink)}
a{color:inherit;text-decoration:none}
img{display:block;max-width:100%}
button{font:inherit;color:inherit;background:none;border:0;cursor:pointer}
:focus-visible{outline:1px solid var(--off);outline-offset:4px}

.mono{font-family:var(--mono);font-weight:400;letter-spacing:.18em;text-transform:uppercase;font-size:.68rem;line-height:1.4}
.mono.lg{font-size:.82rem;letter-spacing:.22em}
.muted{color:var(--g1)}
.dim{color:var(--g2)}
.hr{height:0;border-top:.5px solid var(--hair);width:100%}

/* the signal behind the page: a WebGL canvas under the content, drawn at a fraction of the screen's
   resolution and scaled up without smoothing, so it reads as digital cells (BACKGROUND SIGNAL in atalt.js).
   Content sits above it in main. */
.bg-gl{position:fixed;inset:0;width:100%;height:100%;display:block;pointer-events:none;z-index:0;image-rendering:pixelated}
main{position:relative;z-index:1}
/* grain: the fallback when the signal is not running (reduced motion, no WebGL, a lost context) */
html.bg .grain{display:none}
.grain{position:fixed;inset:0;pointer-events:none;z-index:60;opacity:.14;mix-blend-mode:screen;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='220' height='220'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.72' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 .96 0 0 0 0 .95 0 0 0 0 .93 0 0 0 1.35 -.12'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
  background-size:220px 220px}
@media print{.grain{display:none}}

/* cursor (desktop, fine pointer only) */
.cur{position:fixed;left:0;top:0;width:22px;height:1px;background:var(--off);pointer-events:none;z-index:70;
  transform:translate(-50%,-50%);display:none}
@media (hover:hover) and (pointer:fine){body.has-cur{cursor:none}body.has-cur a,body.has-cur button{cursor:none}.cur{display:block}}


/* sections */
/* screens: every section is one viewport tall, its content centred between the nav and the Request access bar */
section{position:relative;min-height:100svh;padding:calc(var(--nav-h) + 8px) var(--pad) calc(var(--chrome-b) + 12px);
  display:flex;flex-direction:column;justify-content:center;scroll-snap-align:start;scroll-snap-stop:always}
.wrap{max-width:1180px;margin:0 auto;width:100%}
/* poster screens (html.fit, from FIT in atalt.js): each screen below the hero is exactly one viewport and
   its content column fills it. FIT sizes the type (--fs) so the column is full; the layouts below spread
   whatever is left. html.fitting is the measuring pass: natural heights, no spreading, no motion offsets. */
html.fit main>section:not(.hero){height:100vh;height:100svh}
html.fit [data-fit]{flex:1 1 auto;min-height:0;display:flex;flex-direction:column;gap:clamp(12px,2.4vh,28px)}
html.fit [data-fit]>*{margin-top:0;margin-bottom:0}
html.fitting [data-fit]{justify-content:flex-start!important}
html.fitting [data-fit]>*{flex:none!important;margin-top:0!important;margin-bottom:0!important}
html.fitting .split .b,html.fitting .split .wd,html.fitting .name .n,html.fitting .name .ch .b{transform:none!important;transition:none!important}
html.fit .count .line{flex-wrap:nowrap}
/* sound: label on top, the heading and its copy together in the middle */
html.fit .sound .split{margin-top:auto}
html.fit .sound p.body{margin-top:clamp(12px,3vh,40px);margin-bottom:auto}
/* access: the heading and its intro stay together, centred between the label and the steps at the foot */
html.fit .access .split{margin-top:auto}
html.fit .access .steps{margin-top:clamp(16px,4vh,48px);margin-bottom:auto}
/* lineup: the rows share the whole screen, name and genre centred in each */
html.fit .acc{flex:1 1 auto;align-content:stretch}
html.fit .item{display:flex}
html.fit .name{align-content:center}
/* rules: three bands filling the plate; on a wide screen the rule on the left, the reason on the right */
html.fit .rule-grid{flex:1 1 auto;grid-template-columns:minmax(0,1fr);align-content:stretch;gap:0}
html.fit .rule{display:flex;flex-direction:column;justify-content:center;gap:clamp(6px,1.4vh,14px);padding:clamp(10px,2vh,24px) 0}
html.fit .rules .why{margin-top:0}
/* phones: four bands and their reasons share a small screen, so the bands' air goes to the type */
@media (max-width:760px){
  html.fit .rules [data-fit]{gap:clamp(8px,1.6vh,20px)}
  html.fit .rule{padding:clamp(6px,1.1vh,12px) 0;gap:clamp(3px,.6vh,8px)}
  html.fit .rules .why{line-height:1.4}
}
@media (min-width:761px){html.fit .rule{display:grid;grid-template-columns:minmax(0,1.2fr) minmax(0,1fr);column-gap:clamp(24px,4vw,64px);align-items:end;align-content:center}}
/* the gate: the countdown on top, the partners' marks filling the rest */
html.fit .outro .partners{flex:1 1 auto;min-height:0;display:flex;flex-direction:column;justify-content:center}
html.fit .outro .partners .row{flex:1 1 auto;min-height:0;padding-top:0}
html.fit .outro .partners img{max-height:min(100%,18vh)}
html.fitting .outro .partners img{max-height:80px}

/* headings — Doto at full weight: dot-matrix LED signage. Still two halves so the line can alter them;
   the reveal (MOTION in atalt.js) stamps them in word by word, the bottom half of each word thrown
   further than its top. */
h1,h2,h3{font-weight:400;letter-spacing:-.01em}
.split{position:relative;display:block;font-family:var(--display);font-weight:900;font-size:var(--fs);
  line-height:.95;letter-spacing:0;text-transform:uppercase;text-wrap:balance}
.split .t,.split .b{display:block}
.split .t{clip-path:inset(0 0 50% 0)}
.split .b{position:absolute;inset:0;clip-path:inset(50% 0 0 0);user-select:none;pointer-events:none;will-change:transform}
.split .wd{display:inline-block}
.sr{position:absolute;width:1px;height:1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap}
/* section label: the mono caption, then a hairline running out to the edge of the column */
.eyebrow{margin-bottom:clamp(14px,2.4vh,28px);display:flex;gap:18px;align-items:center}
.eyebrow::after{content:"";flex:1;border-top:.5px solid var(--hair)}
p.body{max-width:60ch;color:var(--off)}
p.body+p.body{margin-top:1.25em}
.lead{font-size:var(--t-body);line-height:1.5;max-width:48ch;text-wrap:pretty}

/* hero */
@media (min-width:761px){:root{--sigil-w:min(100vw, 48vh);--hero-top-b:100px;--nav-h:32px}}
.hero{min-height:100svh;display:flex;flex-direction:column;padding-top:52px;padding-bottom:calc(var(--chrome-b) + 40px)}
.hero .wrap{max-width:none;width:100%;display:flex;flex-direction:column;justify-content:flex-start;flex:1}
.hero-top{display:flex;justify-content:space-between;align-items:flex-start;gap:16px}
.hero-top>.muted{display:flex;flex-direction:column;gap:6px}
.hero-top .date{font-size:clamp(17px,2.6vw,34px);letter-spacing:.12em;white-space:nowrap}
.hero-top>.muted span{white-space:nowrap}
/* the sigil's bar lands on the 38% line when there is room: 38svh minus the top row minus half the sigil's height */
.hero-marks{position:relative;display:flex;flex-direction:column;align-items:center;gap:clamp(24px,5vh,72px);width:100vw;margin-left:calc(50% - 50vw);
  overflow-x:hidden;overflow-x:clip;            /* the thrown halves leave at the viewport edge */
  margin-top:max(16px, calc(38svh - var(--hero-top-b) - 0.382 * var(--sigil-w)))}
.sigil-stack{position:relative;display:block;width:var(--sigil-w)}
.sigil-stack .sg{display:block;width:100%;height:auto}
/* the mark is two registered halves: the top image shows only its top, the clone only its bottom,
   so when the scroll shear moves the bottom half it leaves ink behind (like the wordmark's low group) */
.hero .sg:not(.sg-lo){clip-path:inset(0 0 50% 0)}
.sg-lo-w{position:absolute;inset:0;will-change:transform}
.sigil-stack .sg-lo{position:absolute;inset:0;clip-path:inset(50% 0 0 0);will-change:transform}
.hero .sigil-big{width:var(--sigil-w);max-width:none;height:auto;display:block}

.hero .wm-big{width:min(62vw,340px);height:auto;color:var(--off);display:block;overflow:visible}  /* thrown rows may leave the viewBox */
.hero .wm-big .low{will-change:transform}
.hero .wm-big line{stroke-dasharray:260;stroke-dashoffset:0}

/* ---- the hero's one orchestrated moment: a GSAP timeline (MOTION in atalt.js) ----
   These are its first frames, applied only when a script will run it and motion is welcome.
   html.noanim (no GSAP, or the 4 s failsafe in <head>) drops them, so the hero is simply there. */
.hero-line{position:absolute;left:0;right:0;height:1px;background:var(--off);pointer-events:none;z-index:1;
  top:max(38svh, calc(var(--hero-top-b) + 16px + 0.382 * var(--sigil-w)));transform:scaleX(0);transform-origin:0 50%}
@media (prefers-reduced-motion:no-preference){
  html.js:not(.noanim) .hero .sg:not(.sg-lo){clip-path:inset(0 100% 50% 0)}
  html.js:not(.noanim) .hero .sg-lo{clip-path:inset(50% 100% 0 0)}
  /* 110%, not 100%: Chrome sizes an SVG group's inset from its bbox but places it from the SVG origin */
  html.js:not(.noanim) .hero .wm-big .hi,html.js:not(.noanim) .hero .wm-big .low{clip-path:inset(0 110% 0 0)}
  html.js:not(.noanim) .hero .wm-big line{stroke-dashoffset:260}
  html.js:not(.noanim) .hero-top .muted span,html.js:not(.noanim) .hero-top .date,
  html.js:not(.noanim) .hero-foot .f,html.js:not(.noanim) .hero-foot .muted{clip-path:inset(-30% 100% -30% 0)}
}
/* the WebGL hero draws the marks; the DOM marks stay underneath for assistive tech and as the fallback */
.hero-gl{position:absolute;inset:0;width:100%;height:100%;pointer-events:none;display:block}
html.gl .hero-marks .sigil-stack,html.gl .hero-marks .wm-big{opacity:0}
html.noanim .hero-gl{display:none}
html.noanim.gl .hero-marks .sigil-stack,html.noanim.gl .hero-marks .wm-big{opacity:1}

/* the facts as signage: condensed caps, one line on desktop */
.hero-foot{margin-top:auto;text-align:center;font-family:var(--display);font-weight:700;font-size:max(16px,calc(var(--fs) * .4));letter-spacing:0;line-height:1.15}
.hero-foot .f{white-space:nowrap}
.hero-foot .f,.hero-foot .muted{display:inline-block}
@media (max-width:760px){
  .hero-foot{letter-spacing:0}
  .hero-foot .muted{display:none}            /* one fact per line, so no bullet hangs at a line end */
  .hero-foot .f{display:block}
}


/* rules: the same ink, type and rules as every other screen */
@media print{.split .t,.split .b{clip-path:none!important}.split .b{display:none}}   /* paper gets the whole heading */
.rules .why{margin-top:clamp(8px,1.6vh,16px);max-width:44ch;color:var(--off);font-size:var(--t-body);line-height:1.5}
/* three rules side by side on a wide screen, stacked on a phone */
.rule-grid{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:clamp(20px,3vh,36px) clamp(24px,4vw,56px)}
.rule{border-top:.5px solid var(--hair);padding-top:clamp(12px,2.2vh,24px)}
.rule.rule-end{border-top:1px solid var(--off)}   /* the rules close on the refusal */
@media (max-width:760px){.rule-grid{grid-template-columns:1fr;gap:clamp(12px,2.2vh,20px)}}

/* lineup: one screen of names and genres, two columns on a wide screen. A name opens its artist sheet. */
.acc{display:grid;grid-template-columns:minmax(0,1fr);border-top:.5px solid var(--hair)}
@media (min-width:761px){.acc{grid-template-columns:1fr 1fr;column-gap:clamp(32px,5vw,72px)}}
.item{border-bottom:.5px solid var(--hair)}
.name{width:100%;display:grid;grid-template-columns:minmax(0,1fr) 40px;grid-template-areas:"n s" "m m";align-items:center;gap:0 20px;padding:clamp(8px,1.7vh,22px) 0;text-align:left;min-height:44px}
.name .n{grid-area:n;font-family:var(--display);font-size:var(--fs-l,var(--fs));line-height:1;letter-spacing:0;font-weight:900;transition:transform var(--t-throw) var(--sp-throw)}
.name .m{grid-area:m;display:block;margin-top:6px;max-width:64ch;font-size:.68rem;letter-spacing:.18em;color:var(--g1);line-height:1.4}
.name .sign{grid-area:s;width:40px;height:1px;background:var(--off);transform:scaleX(.5);transform-origin:right center;transition:transform var(--t-throw) var(--sp-throw)}
.name[aria-expanded="true"] .sign{transform:scaleX(1)}

/* artist sheet: a full screen the line cuts open over the lineup (left to right), with the portrait, bio,
   links and set. It scrolls inside itself; the page underneath is locked while it is open. */
.sheet{position:fixed;inset:0;z-index:65;background:var(--ink);overflow-y:auto;overscroll-behavior:contain;
  padding:clamp(12px,2.4vh,28px) var(--pad) clamp(28px,5vh,56px);
  clip-path:inset(0 100% 0 0);visibility:hidden;transition:clip-path var(--t-open) var(--sp-open),visibility 0s linear var(--t-open)}
.sheet.open{clip-path:inset(0 0 0 0);visibility:visible;transition-delay:0s}
.sheet-bar,.sheet-head,.sheet-bodies{max-width:1180px;margin-left:auto;margin-right:auto}
.sheet-bar{display:flex;align-items:center;justify-content:space-between;gap:24px;min-height:52px;border-bottom:.5px solid var(--hair)}
.sheet-nav{display:flex;align-items:center;gap:20px}
.sheet-bar button{min-height:44px;min-width:44px;letter-spacing:.18em;text-transform:uppercase}
.sheet-head{margin-top:clamp(16px,3.5vh,40px);margin-bottom:clamp(16px,3vh,32px)}
.sheet-name{font-family:var(--display);font-weight:900;font-size:var(--fs-l,var(--fs));line-height:.95;letter-spacing:0;margin:0}
.sheet-genre{margin-top:12px}
.sheet .body{display:none}
.sheet .body.on{display:block}
.links a{transition:border-color .2s var(--cut),transform var(--t-snap) var(--sp-snap)}
/* the open row: portrait beside the words, sized by them.
   Desktop: the portrait spans the bio, links and embed and stretches to exactly their height, so the
   photo is never taller than what it sits next to (cropped toward the face, which is high in every shot).
   Phone: portrait and links side by side, then the bio and the embed full width.
   The text column's div is display:contents so its three parts can be placed in the row's own grid. */
.inner{display:grid;grid-template-columns:minmax(0,.62fr) minmax(0,1.4fr);grid-template-areas:"fig bio" "fig links" "fig embed";
  grid-template-rows:auto auto 1fr;column-gap:clamp(24px,5vw,72px);align-items:start}
.inner>div{display:contents}
.inner figure{grid-area:fig;align-self:stretch;position:relative;min-height:clamp(320px,28vw,420px)}
.inner:not(:has(.bio p)) figure{min-height:clamp(240px,21vw,300px)}   /* no bio: a shorter plate, not a tall one beside nothing */
.inner:not(:has(.bio p)) .links{grid-row:1/-1;align-self:end}          /* and its links sit on the plate's baseline, like a caption */
.inner .cut{position:absolute;inset:0}
.inner .genre{display:none}                                           /* the row header already carries the genre */
.bio{grid-area:bio}
.links{grid-area:links}
.embed{grid-area:embed}
@media (max-width:760px){
  .inner{grid-template-columns:minmax(0,1fr) minmax(0,1fr);grid-template-areas:"fig links" "bio bio" "embed embed";grid-template-rows:auto;column-gap:20px}
  .inner figure,.inner:not(:has(.bio p)) figure{min-height:0}
  .inner .cut{position:relative;inset:auto;aspect-ratio:3/4}
  .inner .links{align-self:end;flex-direction:column;flex-wrap:nowrap;gap:0;margin-top:0}
  .inner .bio{margin-top:24px}
}
.inner figure{margin:0}
.genre{transform:translateX(-8px);opacity:0;transition:transform var(--t-throw) var(--sp-throw),opacity 200ms linear;margin-top:18px;text-align:center;font-size:1.02rem;letter-spacing:.16em;color:var(--off);line-height:1.5}
/* the portrait fills its box; the box decides the size. (A height attribute on the img must never size it.) */
.inner img{object-fit:cover;object-position:50% 22%}
.bio{max-width:62ch}
.bio p+p{margin-top:1em}
.links{display:flex;gap:24px;margin-top:16px;flex-wrap:wrap}
.links a{border-bottom:.5px solid var(--hair);padding:10px 0;min-height:44px;display:inline-flex;align-items:center}
.embed{margin-top:28px}
.embed iframe{width:100%;border:0;display:block;filter:grayscale(1) contrast(1.05)}
.embed .ratio{position:relative;aspect-ratio:16/9;background:#111}
.embed .ratio iframe{position:absolute;inset:0;height:100%}

/* structural distortion: images and names carry the altering line */
.cut{position:relative;overflow:hidden}
.cut img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;object-position:50% 22%;display:block}
.cut .lo{position:absolute;inset:0;clip-path:inset(52% 0 0 0);will-change:transform}
.cut .hi{clip-path:inset(0 0 48% 0)}
.cut::after{content:"";position:absolute;left:-4%;right:-8%;top:52%;height:1px;background:var(--off);opacity:.9}
.name .n{position:relative}
.name .n .w{display:inline-block;white-space:nowrap}
.name .n .ch{position:relative;display:inline-block}
.name .n .ch .t{display:block;clip-path:inset(0 0 50% 0)}
.name .n .ch .b{position:absolute;inset:0;clip-path:inset(50% 0 0 0);will-change:transform;user-select:none;pointer-events:none}

/* access / tickets — the countdown is the section's object: the one live thing on the page, sized like it */
.count{margin-top:clamp(14px,3vh,40px);padding:clamp(10px,2vh,24px) 0;border-top:.5px solid var(--hair);border-bottom:.5px solid var(--hair);text-align:center}
.count .line{margin-top:clamp(8px,1.6vh,18px);display:flex;flex-wrap:wrap;justify-content:center;align-items:baseline;gap:.35em 1.2em}
.count .seg{display:inline-flex;align-items:baseline;gap:.3em;white-space:nowrap}
.count .num{display:inline-block;transition:transform var(--t-snap) var(--sp-snap);font-family:var(--display);font-weight:900;font-size:var(--fs);line-height:1;letter-spacing:0;font-variant-numeric:tabular-nums}
.count .unit{font-family:var(--mono);font-size:.68rem;letter-spacing:.18em;text-transform:uppercase;color:var(--g1)}
.count.done .num{color:var(--g1)}
.count .num.kick{transform:translateY(-.05em);transition:none}
@media (max-width:760px){.count .line{display:grid;grid-template-columns:repeat(4,auto);justify-content:center;gap:0 clamp(14px,5vw,28px)}.count .seg{flex-direction:column;align-items:center;gap:4px}}
.steps{display:grid;gap:0 clamp(24px,4vw,56px);margin-top:clamp(10px,2.2vh,32px)}
@media (min-width:761px){.steps{grid-template-columns:1fr 1fr}}
.steps div{padding:clamp(7px,1.3vh,16px) 0;border-bottom:.5px solid var(--hair);display:grid;grid-template-columns:3ch 1fr;gap:16px;font-size:var(--t-body);line-height:1.5}
.steps .mono{color:var(--g1)}
.access .lead{margin-top:clamp(10px,2vh,24px)}
/* Filled, not outlined. A .5px hairline is the weight every rule on this page
   uses, so an outlined box reads as a frame rather than as something to press.
   With no accent colour available, the off-white filled against the ink is the
   strongest thing the palette can say, and it is still only the two brand
   colours. Hover warms to cream rather than inverting, because inverting from
   filled would make pressing it look like turning it off. */
.btn{will-change:transform;display:inline-flex;align-items:center;justify-content:space-between;gap:32px;min-height:56px;padding:0 22px;
  background:var(--off);color:var(--ink);
  border:.5px solid var(--off);font-family:var(--mono);letter-spacing:.2em;text-transform:uppercase;font-size:.74rem;
  transition:background .2s var(--cut),color .2s var(--cut);width:100%;max-width:420px}
.btn{transition:background .18s var(--cut),color .18s var(--cut),transform var(--t-snap) var(--sp-snap)}
/* Hover turns the box inside out: the fill becomes the ink of the page and the
   text becomes the fill. The border stays off-white so the shape does not
   dissolve into the background it has just matched — without it the button
   would appear to vanish rather than invert. */
.btn:hover{background:var(--ink);border-color:var(--off);color:var(--off);transform:translateX(6px)}
.btn:active{background:var(--ink);color:var(--off)}
.btn:active{transform:translateX(2px) scale(.985);transition-duration:90ms}

/* partners */
.partners{margin-top:clamp(24px,5vh,64px)}
.partners .row{display:flex;align-items:center;justify-content:space-between;gap:clamp(16px,5vw,64px);padding-top:clamp(20px,3.5vh,48px)}
.partners img{height:auto;width:auto;flex:0 1 auto;transition:transform var(--t-throw) var(--sp-throw)}
.partners .p-ltm{max-width:min(24%,210px)}
.partners .p-sigil{max-width:min(16%,150px)}
.partners .p-f1{max-width:min(24%,200px)}
/* phone: the three marks stack, in the same order */
@media (max-width:760px){
  .partners .row{flex-direction:column;justify-content:center;gap:clamp(12px,2.6vh,28px)}
  .partners .p-ltm{max-width:46%}
  .partners .p-sigil{max-width:26%}
  .partners .p-f1{max-width:42%}
  html.fit .outro .partners img{max-height:min(100%,11vh)}
  html.fitting .outro .partners img{max-height:52px}
}

/* Request access — the one thing you can press. It sits on the hero, under the time and place, and again
   at the foot of the tickets screen; there is no bar. Off-white on ink so it reads as pressable on the
   page's own ground; hovering turns it inside out, the same gesture the rest of the site's buttons use. */
/* The standing button: the same place on every screen, centred at the foot. Screens keep it clear through
   --chrome-b, so it never covers content. It steps aside under the loading screen, a sheet and the modal. */
.fab{position:fixed;left:50%;transform:translateX(-50%);bottom:max(20px, env(safe-area-inset-bottom, 0px));z-index:48}
/* It arrives last on the first screen, after the marks and the facts, and it arrives torn (MOTION sets .in).
   Without a script, without GSAP or under reduced motion it is simply there from the first frame. */
@media (prefers-reduced-motion:no-preference){
  html.js:not(.noanim) .fab{opacity:0;pointer-events:none}
  html.js:not(.noanim) .fab.in{opacity:1;pointer-events:auto;animation:fab-in .56s steps(1,end) 1}
}
@keyframes fab-in{
  0%{opacity:0;clip-path:inset(0 100% 0 0);transform:translateX(-50%)}
  10%{opacity:1;clip-path:inset(0 52% 0 0);transform:translateX(calc(-50% + 12px))}
  20%{clip-path:inset(0 0 0 0);transform:translateX(calc(-50% - 7px))}
  30%{opacity:.2;clip-path:inset(40% 0 24% 0);transform:translateX(calc(-50% + 16px))}
  40%{opacity:1;clip-path:inset(0 0 0 0);transform:translateX(-50%)}
  54%{clip-path:inset(0 0 48% 0);transform:translateX(calc(-50% + 6px))}
  62%{clip-path:inset(0 0 0 0);transform:translateX(-50%)}
  74%{opacity:.45}
  100%{opacity:1;clip-path:inset(0 0 0 0);transform:translateX(-50%)}
}
html.loading .fab,html:has(.sheet.open) .fab,html:has(body > [data-quicket-modal]) .fab{opacity:0;visibility:hidden;pointer-events:none}
/* ---- the screen index ----
   Six ticks on the trailing edge: how many screens there are, which one you are on, and a way to jump.
   Hairlines, like the registration marks: it reads as part of the page's own furniture, not as a widget. */
.rail{position:fixed;right:max(12px, env(safe-area-inset-right, 0px));top:50%;transform:translateY(-50%);z-index:47;
  display:flex;flex-direction:column;align-items:flex-end;gap:clamp(10px,1.6vh,16px);padding:8px 4px}
.rail button{display:flex;align-items:center;justify-content:flex-end;gap:10px;padding:4px 2px;min-height:22px;cursor:pointer}
/* the numbers are the page's own mono labels, muted like every other label until you are on that screen */
.rail .rail-n{font-size:.58rem;letter-spacing:.16em;color:var(--g1);transition:color .2s var(--cut)}
.rail .tick{display:block;width:12px;border-top:.5px solid var(--hair);
  transition:width var(--t-snap) var(--sp-snap),border-color .2s var(--cut)}
.rail button[aria-current="true"] .rail-n{color:var(--off)}
.rail button[aria-current="true"] .tick{width:28px;border-top-color:var(--off)}
/* the name is there when you go looking for it, the way the row genres are */
.rail .rail-l{font-size:.58rem;letter-spacing:.16em;color:var(--g1);max-width:0;overflow:hidden;opacity:0;white-space:nowrap;
  transition:max-width var(--t-snap) var(--sp-snap),opacity .2s var(--cut)}
@media (hover:hover) and (pointer:fine){
  .rail button:hover .rail-l,.rail button:focus-visible .rail-l{max-width:14ch;opacity:1}
  .rail button:hover .rail-n,.rail button:focus-visible .rail-n{color:var(--off)}
  .rail button:hover .tick{border-top-color:var(--off)}
}
/* phones: the column runs to the edge, so the index keeps to the margin as ticks alone, and the screens
   give it that margin rather than running underneath it */
@media (max-width:760px){
  main > section{padding-inline:calc(var(--pad) + 8px)}    /* symmetric, so the column stays on the button's axis */
  .rail{right:5px;gap:10px;padding:6px 0}
  .rail .rail-l,.rail .rail-n{display:none}
  .rail button{padding:4px 0;min-width:18px}
  .rail .tick{width:8px}
  .rail button[aria-current="true"] .tick{width:16px}
}
@media (max-height:520px){.rail{display:none}}
html.loading .rail,html:has(.sheet.open) .rail,html:has(body > [data-quicket-modal]) .rail{opacity:0;visibility:hidden;pointer-events:none}

/* ---- the first screen's cue ----
   It says there is more below, and it is gone as soon as you move. */
.cue{position:fixed;left:max(20px, env(safe-area-inset-left, 0px));bottom:max(22px, env(safe-area-inset-bottom, 0px));z-index:47;
  display:flex;align-items:center;gap:10px;opacity:0;pointer-events:none;transition:opacity .4s var(--cut)}
body.on-hero .cue{opacity:1}
html.loading .cue{opacity:0}
.cue-l{font-size:.58rem;letter-spacing:.18em;color:var(--g1)}
.cue-line{display:block;width:0;height:26px;border-left:.5px solid var(--hair);transform-origin:50% 0}
@media (prefers-reduced-motion:no-preference){.cue-line{animation:cue-fall 1.9s steps(1,end) infinite}}
@keyframes cue-fall{0%{transform:scaleY(.25);opacity:.5}20%{transform:scaleY(.6);opacity:.9}40%{transform:scaleY(1);opacity:1}60%{transform:scaleY(1);opacity:.35}80%{transform:scaleY(.25);opacity:.5}100%{transform:scaleY(.25);opacity:.5}}
@media (max-width:760px){.cue{bottom:max(18px, env(safe-area-inset-bottom, 0px))}.cue-line{height:20px}}

/* Contact: the second action, so it is an outline of the same shape rather than another plate */
.cta-ghost{display:inline-flex;align-items:center;justify-content:center;min-height:48px;padding:0 26px;
  background:none;color:var(--off);border:1px solid var(--hair);
  font-family:var(--mono);font-weight:500;letter-spacing:.2em;text-transform:uppercase;font-size:.72rem;
  transition:background .18s var(--cut),color .18s var(--cut),border-color .18s var(--cut),transform var(--t-snap) var(--sp-snap)}
.cta-ghost:active{transform:translateX(1px) scale(.99);transition-duration:90ms}
.cta-ghost:focus-visible{outline:none;box-shadow:0 0 0 2px var(--ink),0 0 0 4px var(--off)}
.outro-contact{display:flex;justify-content:center;margin-top:clamp(18px,3.5vh,44px)}
.cta-go{display:inline-flex;align-items:center;justify-content:center;min-height:52px;padding:0 30px;
  background:var(--off);color:var(--ink);border:1px solid var(--off);
  font-family:var(--mono);font-weight:500;letter-spacing:.2em;text-transform:uppercase;font-size:.76rem;
  transition:background .18s var(--cut),color .18s var(--cut),transform var(--t-snap) var(--sp-snap)}
.cta-go:active{transform:translateX(1px) scale(.99);transition-duration:90ms}
.cta-go:focus-visible{outline:none;box-shadow:0 0 0 2px var(--ink),0 0 0 4px var(--off)}
/* Quicket's chat has no floating icon: the Contact us button on the closing screen opens it. */
[data-quiket-chat-launcher]{display:none!important}
@media (max-width:760px){.cta-go{min-height:50px;padding:0 22px;font-size:.72rem}.cta-ghost{min-height:46px;padding:0 20px;font-size:.68rem}}
/* shorter phone screens (in-app browsers, small phones): tighten so each screen still fits */
@media (max-width:760px) and (max-height:780px){
  :root{--nav-h:16px}
  :root{--fs:30px}
  .name{padding:7px 0}
  .rules .why{line-height:1.45}
}

/* hover is a pointer thing: on touch these would fire on tap and stay. :active stays ungated as the tap feedback */
@media (hover:hover){
  .name:hover .n{transform:translateX(.04em)}
  .links a:hover{transform:translateX(5px);border-bottom-color:var(--off)}
  .partners img:hover{transform:translateX(8px)}
  .cta-go:hover{background:var(--ink);color:var(--off);transform:translateX(4px)}
  .cta-ghost:hover{background:var(--off);color:var(--ink);border-color:var(--off)}
}

/* ---- loading screen (LOADER in atalt.js) ----
   One line at the display size, torn at its seam, with a highlight that inverts it left to right, line by
   line, as the page loads, and the count at the foot. It cuts away left to right into the hero.
   Not shown without JS or under reduced motion; the <head> failsafe (html.noanim) removes it too. */
.loader{position:fixed;inset:0;z-index:90;background:var(--ink);color:var(--off);
  padding:calc(var(--nav-h) + 8px) var(--pad) max(28px,env(safe-area-inset-bottom,0px));
  clip-path:inset(0 0 0 0);transition:clip-path var(--t-open) var(--cut)}
html:not(.js) .loader,html.noanim .loader{display:none}
html.loading:not(.noanim){overflow:hidden}
html.loading [data-quiket-chat-launcher]{visibility:hidden!important}
.loader.out{clip-path:inset(0 0 0 100%)}
.ld-wrap{position:relative;max-width:1180px;height:100%;margin:0 auto;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:clamp(24px,6vh,64px)}
.ld-text{position:relative;margin:0;max-width:14ch;font-family:var(--display);font-weight:900;font-size:var(--fs);line-height:.95;
  text-transform:uppercase;text-wrap:balance;text-align:center;opacity:0}
.ld-text .t,.ld-text .b{display:block}
.ld-text .t{clip-path:inset(0 0 50% 0)}
.ld-text .b{position:absolute;inset:0;clip-path:inset(50% 0 0 0);animation:ld-tear 2.4s steps(1,end) infinite}
.ld-text::after{content:"";position:absolute;left:-8vw;right:-8vw;top:50%;height:1px;background:var(--off);animation:ld-seam 2.4s steps(1,end) infinite}
/* the highlight: a copy of the line whose per-line background grows with --p, inverting what it covers */
.ld-text .h{position:absolute;inset:0;color:transparent;mix-blend-mode:difference;pointer-events:none;animation:ld-flick 1.7s steps(1,end) infinite}
.ld-text .h span{background:linear-gradient(var(--off),var(--off)) 0 0/var(--p,0%) 100% no-repeat;-webkit-box-decoration-break:clone;box-decoration-break:clone}
.ld-pct{font-family:var(--display);font-weight:900;font-size:var(--fs);line-height:1;font-variant-numeric:tabular-nums;opacity:0}
.loader.on .ld-text,.loader.on .ld-pct{opacity:1}
@keyframes ld-tear{0%,100%{transform:none}6%{transform:translateX(.22em)}8%{transform:translateX(-.06em)}10%{transform:none}41%{transform:translateX(-.14em)}43%{transform:translateX(.34em)}45%{transform:none}72%{transform:translateX(.1em)}73%{transform:none}}
@keyframes ld-seam{0%,100%{opacity:1}6%{opacity:0}10%{opacity:1}43%{opacity:.3}45%{opacity:1}}
@keyframes ld-flick{0%,100%{transform:none;opacity:1}23%{transform:translateX(.08em);opacity:.85}25%{transform:none;opacity:1}61%{transform:translateX(-.05em)}62%{transform:none}}

@media (prefers-reduced-motion:reduce){
  *,*::before,*::after{transition:none!important;animation:none!important}
  html{scroll-behavior:auto}                                          /* anchor jumps are instant too */
  .bio p,.genre{transform:none!important;opacity:1!important}
  .cur{display:none!important}body.has-cur,body.has-cur a,body.has-cur button{cursor:auto}
  /* every new moment shows its end state from the first frame */
  .hero .sg:not(.sg-lo){clip-path:inset(0 0 50% 0)!important}
  .hero .sg-lo{clip-path:inset(50% 0 0 0)!important}
  .hero .wm-big .hi,.hero .wm-big .low{clip-path:inset(0 -2% 0 0)!important}
  .hero .wm-big line{stroke-dashoffset:0!important}
  .hero-top,.hero-foot{clip-path:none!important}
  .hero-line{display:none}
  .loader{display:none}
  .split .t{clip-path:inset(0 0 50% 0)!important}
  .split .b{clip-path:inset(50% 0 0 0)!important}
}

/* ============ administration ============ */
.admin{position:fixed;inset:0;z-index:80;background:var(--ink);display:flex;align-items:center;justify-content:center;
  padding:var(--pad);clip-path:inset(0 0 100% 0);transition:clip-path var(--t-open) var(--sp-open)}
.admin.open{clip-path:inset(0 0 0 0)}
.admin-inner{width:100%;max-width:760px;position:relative}
.admin-close{position:absolute;top:-56px;right:0;min-height:44px;min-width:44px;color:var(--g1)}
.admin-close:hover{color:var(--off)}
.adm-h{font-weight:400;font-size:clamp(30px,6vw,64px);line-height:1;letter-spacing:-.01em;text-transform:uppercase;margin:18px 0 0}
.adm-sub{color:var(--g1);max-width:44ch;margin-top:20px}
.adm-field{display:flex;gap:14px;margin-top:40px;flex-wrap:wrap}
.adm-field input{flex:1 1 220px;min-height:56px;padding:0 18px;background:transparent;color:var(--off);
  border:.5px solid var(--hair);letter-spacing:.22em;text-transform:uppercase;font-size:.8rem}
.adm-field input:focus{outline:none;border-color:var(--off)}
.adm-go{width:auto;max-width:none;flex:0 0 auto;justify-content:center;gap:0}
.adm-msg{margin-top:22px;min-height:1.2em;color:var(--g1)}
.adm-msg.bad{color:var(--off)}
.adm-docs{margin-top:44px;border-top:.5px solid var(--hair)}
.adm-doc{display:flex;flex-direction:column;align-items:flex-start;gap:8px;width:100%;text-align:left;
  padding:26px 0;border-bottom:.5px solid var(--hair);transition:transform var(--t-snap) var(--sp-snap)}
.adm-doc:hover{transform:translateX(8px)}
.adm-doc-n{font-size:clamp(22px,3.4vw,34px);line-height:1}

/* crumb trail -- with a document open the wall is three levels deep, so every
   page states where it is and keeps the way back one tap away */
.adm-crumb ol{display:flex;align-items:center;flex-wrap:wrap;gap:10px;list-style:none;margin:0;padding:0}
.adm-crumb li{display:flex;align-items:center;gap:10px;color:var(--g2)}
.adm-crumb li+li::before{content:"/";color:var(--hair)}
.adm-crumb li[aria-current]{color:var(--g1)}
.adm-crumb-l{display:inline-flex;align-items:center;min-height:44px;color:var(--off);
  transition:opacity var(--t-snap) var(--sp-snap)}
.adm-crumb-l:hover{opacity:.55}

/* document viewer -- the guideline and the brief render in the wall instead of
   a new browser tab; the iframe keeps their stylesheets off the site's */
.admin.viewing .admin-inner{max-width:1180px}
.adm-view{display:flex;flex-direction:column;height:min(84vh,940px)}
.adm-view[hidden]{display:none}   /* author display: would otherwise beat the UA's [hidden] */
.adm-frame{flex:1 1 auto;width:100%;margin-top:16px;border:.5px solid var(--hair);background:var(--cream)}
