/* CINAMATE — the sign-in page: the dark Slate gate.
   Field #0b0d10, stripe bands top and bottom, the Sticks lockup open above a
   hairline form. Nothing moves on its own except the title rising once on
   arrival and the one clap when the seat is confirmed (js/login-motion.js
   mirrors the form's data-state onto html[data-gate]). */
/* League Gothic is the one display face on this page (the lockup word). The
   file is the wdth 75 static instance, so there is no variation axis to set. */
@font-face{font-family:"League Gothic";src:url('/assets/fonts/LeagueGothic.woff2') format('woff2');font-weight:400;font-style:normal;font-display:swap}
/* Arimo for the Latin range comes from the subsets the rooms load (24 KB a weight), not the full 180 KB files: every glyph this page sets is Latin, so that is all it downloads. The landing package's full files stay the source for anything beyond Latin, behind the Latin Extended range, and are never fetched unless such a character is on the page. scripts/test_login_weight.mjs holds it. */
@font-face{font-family:Arimo;src:url('/assets/fonts/Arimo-Regular-latin.woff2') format('woff2');font-weight:400;font-style:normal;font-display:swap;unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+2080-2089,U+20AC,U+20B9,U+2116,U+2122,U+2153-215E,U+2190-2195,U+2212,U+2215,U+221A,U+221E,U+2248,U+2260,U+2264-2265,U+25A0,U+25B2,U+25BC,U+25CB-25CC,U+25CF,U+263C,U+266A-266B,U+FEFF,U+FFFD}
@font-face{font-family:Arimo;src:url('/assets/fonts/Arimo-Bold-latin.woff2') format('woff2');font-weight:700;font-style:normal;font-display:swap;unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+2080-2089,U+20AC,U+20B9,U+2116,U+2122,U+2153-215E,U+2190-2195,U+2212,U+2215,U+221A,U+221E,U+2248,U+2260,U+2264-2265,U+25A0,U+25B2,U+25BC,U+25CB-25CC,U+25CF,U+263C,U+266A-266B,U+FEFF,U+FFFD}
@font-face{font-family:Arimo;src:url('/assets/cinamate/fonts/Arimo-Regular.woff2') format('woff2');font-weight:400;font-style:normal;font-display:swap;unicode-range:U+0100-0130,U+0132-0151,U+0154-024F,U+02B0-02BA,U+02BD-02C5,U+02C7-02D9,U+02DB,U+02DD-02FF,U+0300-0303,U+0305-0307,U+0309-0328,U+032A-036F,U+1E00-1EFF,U+20A0-20AB,U+20AD-20B8,U+20BA-20CF}
@font-face{font-family:Arimo;src:url('/assets/cinamate/fonts/Arimo-Bold.woff2') format('woff2');font-weight:700;font-style:normal;font-display:swap;unicode-range:U+0100-0130,U+0132-0151,U+0154-024F,U+02B0-02BA,U+02BD-02C5,U+02C7-02D9,U+02DB,U+02DD-02FF,U+0300-0303,U+0305-0307,U+0309-0328,U+032A-036F,U+1E00-1EFF,U+20A0-20AB,U+20AD-20B8,U+20BA-20CF}
:root{color-scheme:dark;--field:#0b0d10;--panel:#13161b;--line:#272b32;--ink:#f2f0ea;--muted:#8a8d93;--cyan:#01eaf8;--blue:#018fed;--violet:#9a1fce;--magenta:#b836c7;--pink:#e05cf5;--grad:linear-gradient(90deg,#01eaf8 0%,#018fed 38%,#9a1fce 72%,#b836c7 100%);--land:cubic-bezier(.16,1,.3,1);--clap:cubic-bezier(.65,0,.35,1);--w:min(300px,80vw);--gap:28px;--pad:clamp(12px,3svh,48px);--band:40px;--stripe:19.8px;--period:50.9px;--leak-blue:radial-gradient(60vw 50svh at 100% 0,rgba(1,143,237,.14),transparent 70%);--leak-magenta:radial-gradient(55vw 45svh at 0 100%,rgba(184,54,199,.12),transparent 70%)}
*{box-sizing:border-box}html{min-width:320px;background:var(--field)}
/* The two light leaks live on the field, never on a panel: blue top-right, magenta bottom-left, faint enough that the hairlines still read. They are sized to the viewport (vw, svh) so each band can paint the same leak behind its own stripes and meet the field without a seam. */
body{margin:0;min-height:100svh;display:grid;grid-template-rows:auto 1fr auto;color:var(--ink);background:var(--leak-blue),var(--leak-magenta),var(--field);font:16px/1.5 Arimo,Arial,sans-serif;-webkit-font-smoothing:antialiased}
button,input{font:inherit}button,a,input{-webkit-tap-highlight-color:transparent}a{color:inherit}button{cursor:pointer}[hidden]{display:none!important}
::selection{background:rgba(1,234,248,.28);color:var(--ink)}
a:focus-visible,button:focus-visible,input:focus-visible{outline:2px solid var(--cyan);outline-offset:3px}
.skip-link{position:fixed;z-index:9;left:16px;top:16px;padding:12px;background:var(--panel);transform:translateY(-180%)}.skip-link:focus{transform:none}
/* ── the bands ────────────────────────────────────────────────────────────
   Drawn here rather than as a stretched SVG, so a stripe is measured in screen pixels and stays at 45°, parallel to the sticks, at every width: the reference band's 28px stripe on a 72px run, across the 45° line (28·sin 45° and 72·sin 45°). The stripes are a mask over the gradient; between them each band paints the field and the one leak that reaches it, so the leak runs through the gaps and the band stays opaque over anything scrolled beneath it. Sticky, so the frame holds wherever the column has to scroll. */
.band{position:sticky;z-index:2;display:block;height:var(--band)}
.band--top{top:0;background:var(--leak-blue),var(--field)}
.band--bottom{bottom:0;background:var(--leak-magenta),var(--field)}
.band::before{content:"";position:absolute;inset:0;background:var(--grad);-webkit-mask:repeating-linear-gradient(-45deg,transparent 0,#000 .6px,#000 var(--stripe),transparent calc(var(--stripe) + .6px),transparent var(--period));mask:repeating-linear-gradient(-45deg,transparent 0,#000 .6px,#000 var(--stripe),transparent calc(var(--stripe) + .6px),transparent var(--period))}
.flash{position:fixed;inset:0;background:var(--ink);opacity:0;pointer-events:none;z-index:50}
/* Centred between the bands. Nothing in the column changes height from state to state (the status line keeps its room, below), so centring never moves the lockup or the button. */
.gate{display:grid;justify-items:center;align-content:center;padding:var(--pad) max(16px,env(safe-area-inset-right,0px)) var(--pad) max(16px,env(safe-area-inset-left,0px))}
.col{width:min(440px,100%);display:grid;gap:var(--gap);justify-items:center}
/* ── the lockup ───────────────────────────────────────────────────────── */
/* The open upper stick rises sin(16°) of its length above the SVG's box (overflow visible); the margin is that rise, so it never crosses the band. The one column is the lockup's own width, never the word's: the sticks are exactly --w wide, and a fallback face (the woff2 missing, or slow) is clipped inside the lockup instead of widening the page. */
.lockup{width:var(--w);margin-top:calc(var(--w) * .28);display:grid;grid-template-columns:minmax(0,1fr);justify-items:start}
.lockup .sticks{width:100%;height:auto;display:block;overflow:visible}
.lockup .upper{transform-box:view-box;transform-origin:0px 18px;transform:rotate(-16deg);will-change:transform}
.lockup .word{max-width:calc(100% + .05em);overflow:hidden;font:400 calc(var(--w) * .5333)/1 "League Gothic",Impact,"Arial Narrow",sans-serif;letter-spacing:.0125em;text-transform:uppercase;margin:calc(var(--w) * .06 - .13em) 0 -.13em -.0125em;white-space:nowrap;color:var(--ink)}
/* ── the door ─────────────────────────────────────────────────────────── */
.door{width:100%;border-top:1px solid var(--line);transition:opacity .24s var(--clap)}
/* The shell's section title: a 28×3 gradient dash, the label muted and the value in ink. */
.dh{display:flex;align-items:center;height:40px;border-bottom:1px solid var(--line);font:700 10px/1 Arimo,Arial,sans-serif;letter-spacing:.2em;text-transform:uppercase;color:var(--muted)}
.dh::before{content:"";flex:none;width:28px;height:3px;margin-right:14px;background:var(--grad)}
.dh h1{flex:1;margin:0;font:inherit;color:inherit}.dh em{font-style:normal;color:var(--ink);transition:color .24s}
.access{margin:0;padding:0;border:0}
.field{display:grid;grid-template-columns:120px 1fr;align-items:center;margin:0;border-bottom:1px solid var(--line)}
/* Focus is the whole row's hairline turning cyan, two pixels and the full width of the form, on every row alike; the reveal button inside the password row keeps a ring of its own. */
.field:focus-within{border-bottom-color:var(--cyan);box-shadow:inset 0 -1px 0 var(--cyan)}
.field__label{display:flex;align-items:center;height:52px;margin:0;padding:0 14px;border-right:1px solid var(--line);font:700 10px/1 Arimo,Arial,sans-serif;letter-spacing:.18em;text-transform:uppercase;color:var(--muted)}
.field input{appearance:none;display:block;width:100%;min-width:0;height:52px;padding:0 14px;border:0;border-radius:0;background:transparent;color:var(--ink);caret-color:var(--cyan);font-size:15px}
.field input:focus-visible{outline:none}
/* A browser's autofill paints its own pale yellow over the field; the inset shadow keeps the row on the panel colour. */
.field input:-webkit-autofill{-webkit-box-shadow:0 0 0 1000px var(--panel) inset;-webkit-text-fill-color:var(--ink);caret-color:var(--ink)}
.field__control{display:flex;align-items:center;min-width:0}
.reveal{flex:none;min-width:60px;height:52px;padding:0 14px;border:0;background:none;color:var(--muted);font:700 10px/1 Arimo,Arial,sans-serif;letter-spacing:.18em;text-transform:uppercase}.reveal:hover{color:var(--ink)}.reveal:focus-visible{outline-offset:-4px}
/* The box is a hairline like every other edge on the page; ticked, it turns ink and carries an ink tick. */
.check{position:relative;display:flex;gap:12px;align-items:center;min-height:52px;margin:0;padding:0 14px;border-bottom:1px solid var(--line);font-size:14px;color:var(--ink);cursor:pointer}
.check input{-webkit-appearance:none;appearance:none;flex:none;width:16px;height:16px;margin:0;border:1px solid var(--muted);border-radius:0;background:transparent;cursor:pointer}
.check input:checked{border-color:var(--ink)}
.check input:checked+span::before{content:"";position:absolute;left:20px;top:50%;width:4px;height:9px;margin-top:-6px;border:solid var(--ink);border-width:0 2px 2px 0;transform:rotate(45deg);pointer-events:none}
.access__submit{display:flex;justify-content:center;align-items:center;width:100%;min-height:52px;margin:20px 0 0;padding:0 20px;border:0;border-radius:999px;background:var(--ink);color:var(--field);font:700 11px/1 Arimo,Arial,sans-serif;letter-spacing:.2em;text-transform:uppercase;transition:opacity .2s,background-color .2s}
.access__submit:hover:not(:disabled){background:var(--cyan)}.access__submit:disabled{opacity:.6;cursor:wait}
/* ── the status line ──────────────────────────────────────────────────────
   Under the button, in a room it always keeps: two lines of text, which is what every sentence the page itself writes takes at any width from 320px up, so a sentence arriving moves nothing — not the button, not the lockup, not the row below. It is painted only on refusal, as a pink rule and one plain sentence. js/login.js also writes a sentence while checking and when confirmed; those stay in the live region for a screen reader and are clipped from view, since the header word and the button already say them. An empty line stays rendered, so the region is in the accessibility tree before its first message. */
/* pretty, not balance: balance halved a two-line refusal and left half the column empty; pretty fills it and keeps the last word company. */
.err{min-height:calc(14px + 3em);margin:16px 0 0;padding:14px 14px 0;border:0;font-size:14px;line-height:1.5;text-wrap:pretty;color:var(--ink)}
/* The rule takes two of the fourteen pixels above the sentence rather than adding two, so it costs no height; and it is not a transparent border the rest of the time, which forced colours would paint. */
[data-gate="refused"] .err:not(:empty){padding-top:12px;border-top:2px solid var(--pink)}
[data-gate="checking"] .err,[data-gate="confirmed"] .err{clip-path:inset(50%)}
/* ── the second step ──────────────────────────────────────────────────── */
h2{margin:0;padding:14px 14px 4px;font:700 11px/1.3 Arimo,Arial,sans-serif;letter-spacing:.2em;text-transform:uppercase;color:var(--ink)}
.access__intro{margin:0;padding:0 14px 14px;border-bottom:1px solid var(--line);font-size:14px;line-height:1.5;color:var(--muted)}.access__intro:empty{padding:0;border:0}
.linkish{display:block;min-height:44px;margin:4px auto 0;padding:0;border:0;background:none;color:var(--muted);font:700 10px/1 Arimo,Arial,sans-serif;letter-spacing:.16em;text-transform:uppercase;text-decoration:underline;text-underline-offset:5px}.linkish:hover{color:var(--ink)}
/* ── legal ─────────────────────────────────────────────────────────────
   One row on the page's axis: the legal links (their own nav) and early access beside them, the same gap between all three. */
.foot{display:flex;flex-wrap:wrap;justify-content:center;gap:0 32px;width:100%;font:700 10px/1 Arimo,Arial,sans-serif;letter-spacing:.16em;text-transform:uppercase;color:var(--muted)}
.legal{display:flex;gap:0 32px}.signup{margin:0}
.foot a{display:inline-flex;align-items:center;min-height:44px;padding:0 6px;margin:0 -6px;text-decoration:none;border-bottom:2px solid transparent}.foot a:hover{color:var(--ink);border-bottom-color:currentColor}
/* ── the states ────────────────────────────────────────────────────────
   idle · checking · confirmed · refused, on html[data-gate]. Under reduced
   motion each state is its end frame: the sticks are shut when confirmed and
   open otherwise, and the flash never paints. The checking dim stops at .86,
   where the muted labels still hold 4.5:1 on the field. */
[data-gate="checking"] .door{opacity:.86}
[data-gate="checking"] .lockup .upper{transition:transform 240ms var(--clap);transform:rotate(-16deg)}
[data-gate="confirmed"] .dh em{color:var(--cyan)}
[data-gate="refused"] .dh em{color:var(--pink)}
/* Confirmed is not disabled-looking: the pill stays at full strength while the page leaves. */
[data-gate="confirmed"] .access__submit:disabled{opacity:1;cursor:default}
/* The clap: the sticks meet at 32% of 820ms (262ms) and the paper flashes for two 60Hz frames as they do; js/login.js leaves at 380ms, after both. */
[data-gate="confirmed"] .lockup .upper{animation:lk-close 820ms var(--clap) both}
[data-gate="confirmed"] .flash{animation:lk-flash 820ms steps(1,end) both}
@keyframes lk-close{0%,22%{transform:rotate(-16deg)}32%,100%{transform:rotate(0)}}
@keyframes lk-flash{0%,31.6%{opacity:0}31.7%,35.7%{opacity:.7}35.8%,100%{opacity:0}}
/* Arrival: the title rises once, then the door. Set by the script after the first frame, so a page with no script is simply there. Filled backwards only: once it has played, the state rules above (the checking dim) apply exactly as they do under reduced motion. */
[data-arrive] .lockup .word{animation:lk-land 420ms var(--land) 80ms backwards}
[data-arrive] .door,[data-arrive] .foot{animation:lk-land 420ms var(--land) 220ms backwards}
@keyframes lk-land{0%{opacity:0;transform:translateY(.04em)}29%{opacity:1}100%{opacity:1;transform:translateY(0)}}
@media(max-width:800px){.field{grid-template-columns:108px 1fr}.field__label{padding:0 10px;white-space:nowrap}}
@media(max-width:700px){:root{--band:28px;--stripe:13.86px;--period:35.63px;--gap:24px;--pad:clamp(12px,3svh,28px)}.foot,.legal{gap:4px 20px}}
/* Short screens (a 768px or 720px laptop, a 667px or 640px phone): the lockup, the air around the column and the gaps in it take their size from the height as well, so both bands stay on screen with nothing to scroll. Below 660px the lockup holds at 150px rather than shrinking to a stamp; the bands are sticky for whatever is left to scroll. */
@media(max-height:820px){:root{--w:min(300px,80vw,30svh);--pad:clamp(10px,2svh,48px)}}
@media(max-height:740px){:root{--w:min(300px,80vw,26svh);--gap:clamp(16px,3svh,28px)}}
@media(max-height:660px){:root{--w:min(150px,80vw)}}
@media(prefers-reduced-motion:reduce){*,*::before,*::after{transition:none!important;animation:none!important}[data-gate="confirmed"] .lockup .upper{transform:rotate(0)}}
@media(forced-colors:active){.access__submit,.reveal,.linkish{border:1px solid ButtonText}.flash{display:none}.field:focus-within{outline:2px solid Highlight;outline-offset:-2px}.check input{border-color:ButtonText}}
