/*
 * PUBLIC ROOM — Night Shift
 *
 * Ported from public/nightshift/FPMB_NightShift_Full.html onto the brand.css tokens.
 * §2.1 calls the hero carousel and the night timeline core brand assets and says to
 * port the patterns rather than substitute a static image or a stock slider, so the
 * structures below follow the reference closely on purpose.
 *
 * Two departures from the reference, both operator rules that outrank it:
 *   no eyebrows  — the reference opens every section with a tracked-caps kicker. None
 *                  of them are here. The headline carries the section.
 *   no em dashes — in any copy a member reads.
 */

/* ------------------------------------------------------------------ skip link */

.skip { position: absolute; left: -9999px; background: var(--lime); color: var(--ink); padding: var(--sp-3) var(--sp-4); border-radius: var(--r-pill); font-weight: var(--w-bold); }
.skip:focus { left: var(--sp-4); top: var(--sp-4); z-index: 60; }

/* -------------------------------------------------------------------- starfield
   Seventy 2px dots, drifting in opacity. Fixed, so the page scrolls past the sky
   rather than dragging it along. */

/*
 * Clipped, because a star can land at left: 100%.
 *
 * They are placed at a random percentage and are two pixels wide, so the ones near the
 * right edge hang over it and widen the document. On a phone that is a page which
 * scrolls sideways for decoration nobody can even see.
 */
.stars { position: fixed; inset: 0; pointer-events: none; z-index: 0; overflow: hidden; }
.stars i { position: absolute; width: 2px; height: 2px; border-radius: 50%; background: #fff; opacity: .25; animation: twinkle 3.4s ease-in-out infinite; }
@keyframes twinkle { 50% { opacity: .75; } }

/* The lime bloom behind a headline. Not a gradient wash; a light source. */
.glow {
    position: absolute; left: 50%; top: 30%; transform: translate(-50%, -50%);
    width: 560px; height: 560px; border-radius: 50%;
    background: radial-gradient(circle, rgba(214, 255, 75, .13), transparent 62%);
    filter: blur(6px); animation: pulse 4.5s ease-in-out infinite; pointer-events: none;
}
@keyframes pulse { 50% { transform: translate(-50%, -50%) scale(1.12); opacity: .8; } }

/* --------------------------------------------------------------------- the nav
   A floating pill, not a bar. It sits over the sky rather than cutting it off. */

.nav {
    position: fixed; top: 14px; left: 50%; transform: translateX(-50%); z-index: 40;
    display: flex; align-items: center; gap: var(--sp-5);
    background: rgba(18, 20, 26, .72); backdrop-filter: blur(14px);
    border: 1px solid var(--hairline); border-radius: var(--r-pill);
    padding: 10px 12px 10px 20px; max-width: calc(100vw - 24px);
}

.nav__mark { font-family: var(--disp); font-weight: var(--w-bold); font-size: var(--t-xs); text-transform: uppercase; letter-spacing: -.01em; white-space: nowrap; }
.nav__mark b { color: var(--lime); font-weight: var(--w-bold); }
.nav__links { display: flex; gap: var(--sp-5); }
.nav__links a { font-size: var(--t-sm); font-weight: var(--w-semi); color: var(--tx); opacity: .7; white-space: nowrap; }
.nav__links a:hover { opacity: 1; color: var(--tx); }

.nav__signin { font-size: var(--t-sm); font-weight: var(--w-semi); color: var(--tx); opacity: .7; white-space: nowrap; }
.nav__signin:hover { opacity: 1; color: var(--tx); }

/*
 * One control, not three links, so the switcher costs the nav bar a single slot at
 * every width instead of three. <details> gives the open/close and the
 * click-outside dismissal for free; this only styles the two states.
 */
.locale-switch { position: relative; font-size: var(--t-sm); }
.locale-switch summary {
    cursor: pointer; list-style: none; color: var(--tx); opacity: .7;
    font-weight: var(--w-semi); white-space: nowrap; padding: 4px 2px;
}
.locale-switch summary:hover, .locale-switch[open] summary { opacity: 1; }
.locale-switch summary::-webkit-details-marker { display: none; }
.locale-switch__menu {
    position: absolute; top: calc(100% + 8px); right: 0; z-index: 50;
    background: var(--ink-2); border: 1px solid var(--hairline); border-radius: var(--r-card);
    padding: 6px; display: flex; flex-direction: column; gap: 2px; min-width: 9em;
}
.locale-switch__menu a {
    display: block; padding: 7px 10px; border-radius: var(--r-pill);
    font-size: var(--t-sm); color: var(--tx-2); white-space: nowrap;
}
.locale-switch__menu a:hover { background: rgba(255, 255, 255, .06); color: var(--tx); }
.locale-switch__menu a[aria-current] { color: var(--lime); }

/*
 * The price never breaks across two lines.
 *
 * The bar is capped at the viewport width, so on a narrow phone the button was the
 * thing that gave, and "Start for $25" came apart mid phrase inside a pill built for
 * one line. A call to action that wraps reads as a mistake wherever it happens.
 */
.nav .btn { white-space: nowrap; flex: 0 0 auto; }

/*
 * What a narrow screen drops, in order.
 *
 * The section links go first: they are places to browse and every one of them is
 * reachable from the page underneath. Then the wordmark, because the shield says the
 * same thing in a fifth of the room. Sign in and the price stay at every width, since
 * one is how a member gets back in and the other is why anybody is here.
 */
@media (max-width: 720px) {
    .nav__links { display: none; }
    .nav { gap: var(--sp-4); padding-left: 14px; }

    /*
     * The wordmark goes at the same width as the links, not at 420.
     *
     * 420 was picked for the narrowest phones, which is the wrong reading: an ordinary
     * iPhone is about 430 CSS pixels, so the name stayed on exactly the devices that
     * needed the room, and adding sign in back made the bar tighter than before.
     *
     * The shield says the same thing in a fifth of the space and is still a link home.
     * What is left is the shield, sign in and the price, which is around 220 pixels and
     * fits the narrowest phone made.
     */
    .nav .nav__word { display: none; }

    /*
     * And the shield grows into the space the name left.
     *
     * 1.6em is right for a mark sitting against a wordmark, where the text carries the
     * brand and the shield is punctuation. Alone in a bar this tall it came out
     * seventeen pixels wide and read as nothing at all: the first report of this was
     * simply "no shield", from a phone where it was rendering perfectly and was just
     * too small to see.
     *
     * Fixed pixels rather than em, because it is no longer being sized off anything.
     */
    .nav .mark__shield { height: 28px; }
}

/* ------------------------------------------------------------------- the hero */

.hero { position: relative; z-index: 1; padding: 120px 0 26px; text-align: center; }
.hero h1 { margin: 0 auto 14px; max-width: 900px; padding: 0 var(--sp-5); }
.hero__sub { font-size: clamp(15px, 1.5vw, 18px); max-width: 520px; margin: 0 auto; padding: 0 var(--sp-5); color: var(--tx-2); }
.hero__ctas { display: flex; gap: var(--sp-3); justify-content: center; margin-top: 26px; flex-wrap: wrap; padding: 0 var(--sp-5); }

/* The three facts under the CTA. Divided, never ticked. */
.herofacts { display: flex; gap: 0 var(--sp-4); list-style: none; margin: var(--sp-5) 0 0; padding: 0 var(--sp-5); justify-content: center; flex-wrap: wrap; font-size: var(--t-xs); color: var(--tx-3); }
.herofacts li + li { border-left: 1px solid var(--hairline-2); padding-left: var(--sp-4); }
@media (max-width: 560px) { .herofacts { flex-direction: column; align-items: center; gap: 6px; } .herofacts li + li { border-left: 0; padding-left: 0; } }

/* ====================================================================== SLIDER
   Four beats, each a live UI vignette rather than a screenshot. The active card is
   full opacity and full scale; its neighbours sit back. Animations are keyed off a
   .is-playing class the script stamps on activation, so a card restarts every time
   it comes round rather than playing once on load. */

/*
 * The rail is clipped to the screen.
 *
 * The track is four slides in a flex row, translated sideways to bring each one to the
 * middle, and nothing was cutting it off. So the document was always about four slides
 * wide however narrow the screen: the layout looked correct because the extra width was
 * off to the right where nobody scrolls, and the moment somebody zoomed out it appeared
 * as a page sitting in a column with half the width empty beside it.
 *
 * clip rather than hidden, because hidden on one axis makes the element a scroll
 * container on the other, and this one contains a sticky nothing but sits inside a page
 * whose anchors need to keep working.
 */
.slider { position: relative; margin-top: 48px; padding-bottom: 24px; z-index: 2; overflow-x: clip; }
.track { display: flex; gap: 26px; will-change: transform; transition: transform var(--dur-slow) var(--ease-travel); }

.slide {
    flex: 0 0 var(--slide-w, 720px);
    height: min(56vh, 470px);
    border-radius: var(--r-slide);
    position: relative; overflow: hidden; text-align: left;
    background: var(--grad-slide);
    border: 1px solid rgba(255, 255, 255, .08);
    opacity: .32; transform: scale(.94);
    transition: opacity .6s ease, transform var(--dur-slow) var(--ease-travel);
}
.slide.is-active { opacity: 1; transform: scale(1); box-shadow: var(--lift-dark); }

/* Slide titles are the body voice, per the type system. Display would shout here. */
.slide__t {
    position: absolute; top: 24px; left: 0; right: 0; text-align: center; z-index: 5;
    font-family: var(--body); font-weight: var(--w-semi);
    font-size: clamp(16px, 1.9vw, 22px); color: #EDEBF5; padding: 0 var(--sp-5);
}

/* An app window inside a vignette. 16px, because that is what an app window is. */
.win { position: absolute; border-radius: var(--r-window); box-shadow: 0 24px 60px rgba(0, 0, 0, .5); overflow: hidden; }
.win__tb { height: 26px; display: flex; align-items: center; gap: 5px; padding: 0 11px; }
.win__tb i { width: 8px; height: 8px; border-radius: 50%; }
.win__tb i:nth-child(1) { background: #FF5F57; }
.win__tb i:nth-child(2) { background: #FEBC2E; }
.win__tb i:nth-child(3) { background: #28C840; }
.win--light { background: #F4F3F7; color: #444444; }
.win--light .win__tb { background: #E7E5EE; }

/* Labelled cursors. Lime is the AI, amber is you. That is the whole story of the
   product told in two colours, so the labels are never dropped. */
.cur { position: absolute; z-index: 8; pointer-events: none; filter: drop-shadow(0 4px 10px rgba(0, 0, 0, .4)); }
.cur__tag {
    position: absolute; left: 16px; top: 14px; background: var(--ink); color: var(--lime);
    font-weight: var(--w-bold); font-size: var(--t-xs); border-radius: 9px; padding: 5px 10px; white-space: nowrap;
}
.cur__tag--you { color: var(--hot); }

.ripple { position: absolute; width: 34px; height: 34px; border: 2px solid var(--lime); border-radius: 50%; opacity: 0; z-index: 7; }

/*
 * Vignette parts hide themselves ONLY once the slider has declared it is going to
 * animate them. Default is visible.
 *
 * The earlier version hid them unconditionally and let the keyframes bring them back,
 * which meant anyone with reduced motion turned on, or anyone whose JS failed to run,
 * got four empty cards. A decoration that hides content when it cannot play is not a
 * decoration, it is a broken page.
 */
.slider.is-live .anim { opacity: 0; }
@keyframes enter { from { opacity: 0; transform: translateY(12px); } to { opacity: 1; transform: none; } }
@keyframes rip { 0% { opacity: .9; transform: scale(.4); } 100% { opacity: 0; transform: scale(1.6); } }
@keyframes flip { from { opacity: 0; transform: scale(.7); } to { opacity: 1; transform: none; } }

/* --- beat 1: it answers ------------------------------------------------- */
.s1 .phone { width: 225px; left: 7%; top: 82px; background: #1D1D1D; }
.s1 .phone .win__tb { background: rgba(255, 255, 255, .06); }
.s1 .pbody { padding: 15px; text-align: center; }
.s1 .ring { font-family: var(--mono); font-size: 11px; letter-spacing: var(--track-data); color: var(--hot); }
.s1 .caller { font-family: var(--disp); font-weight: var(--w-bold); font-size: 14px; margin: 8px 0 2px; color: #fff; text-transform: uppercase; }
.s1 .num { font-size: var(--t-xs); color: var(--tx-3); }
.s1 .pulse { width: 52px; height: 52px; border-radius: 50%; background: radial-gradient(circle, var(--hot), #B26A00); margin: 12px auto 8px; position: relative; }
.s1 .pulse::after { content: ""; position: absolute; inset: -8px; border-radius: 50%; border: 2px solid var(--hot); animation: ringp 1.1s ease-out infinite; }
@keyframes ringp { from { transform: scale(.7); opacity: .9; } to { transform: scale(1.5); opacity: 0; } }
.s1 .ans { display: inline-block; background: #2ECC71; color: #06230F; font-weight: var(--w-bold); font-size: 12.5px; border-radius: var(--r-pill); padding: 8px 18px; margin-top: 4px; }
.s1 .answered { position: absolute; inset: 26px 0 0 0; background: #1D1D1D; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 6px; padding: 0 12px; text-align: center; }
.s1 .answered b { font-family: var(--mono); font-size: 11px; letter-spacing: var(--track-data); color: var(--lime); }
.s1 .answered span { font-size: 11.5px; color: var(--tx-2); }
.s1 .wave { display: flex; align-items: flex-end; gap: 3px; height: 32px; }
.s1 .wave i { width: 5px; background: linear-gradient(180deg, var(--lime), #7FA326); border-radius: 3px; animation: wv .9s ease-in-out infinite; }
.s1 .wave i:nth-child(2n) { animation-delay: .12s; }
.s1 .wave i:nth-child(3n) { animation-delay: .24s; }
@keyframes wv { 0%, 100% { height: 22%; } 50% { height: 100%; } }
.s1 .chat { width: 245px; right: 6%; top: 66px; }
.s1 .cbody { padding: 12px; display: flex; flex-direction: column; gap: 7px; }
.s1 .bub { border-radius: 11px; padding: 7px 10px; font-size: 12.5px; max-width: 88%; background: #E4E1EC; }
.s1 .bub--me { background: var(--ink); color: var(--tx); margin-left: auto; }

.is-playing.s1 .phone { animation: enter .5s .2s both; }
.is-playing.s1 .chat { animation: enter .5s .45s both; }
.is-playing.s1 .b1 { animation: enter .4s .7s both; }
.is-playing.s1 .b2 { animation: enter .4s 1.5s both; }
.is-playing.s1 .b3 { animation: enter .4s 2.6s both; }
.is-playing.s1 .cur1 { animation: cur1move 1.6s 2.2s cubic-bezier(.3, .7, .3, 1) both; }
@keyframes cur1move { 0% { opacity: 0; left: 70%; top: 78%; } 25% { opacity: 1; } 100% { opacity: 1; left: 20%; top: 64%; } }
.is-playing.s1 .rip1 { animation: rip .5s 3.8s both; }
.is-playing.s1 .answered { animation: enter .3s 4.1s both; }

/* --- beat 2: it books --------------------------------------------------- */
.s2 .cal { width: 300px; left: 50%; top: 80px; transform: translateX(-58%); }
.s2 .calb { padding: 14px; }
.s2 .h { font-weight: var(--w-bold); font-size: var(--t-sm); margin-bottom: 9px; color: #444444; }
.s2 .grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 6px; }
.s2 .cell { height: 34px; border-radius: 8px; background: #E7E5EE; font-family: var(--mono); font-size: 9.5px; display: flex; align-items: center; justify-content: center; color: #939393; }
.is-playing.s2 .cell--target { animation: fillcell .01s 2.7s both; }
@keyframes fillcell { to { background: var(--lime); color: var(--lime-ink); font-weight: var(--w-bold); } }
.s2 .toast { width: 238px; right: 6%; bottom: 40px; background: #fff; color: #2A2735; border-radius: 14px; padding: 12px 14px; font-size: 12.5px; }
.s2 .toast b { display: flex; align-items: center; gap: 7px; font-size: var(--t-sm); }
.s2 .toast span { color: #939393; font-size: 11.5px; }
.s2 .ck { width: 18px; height: 18px; border-radius: 50%; background: var(--lime); color: var(--lime-ink); display: inline-flex; align-items: center; justify-content: center; font-size: 11px; font-weight: var(--w-black); }
.is-playing.s2 .cal { animation: enter .5s .2s both; }
.is-playing.s2 .cur2 { animation: cur2move 1.8s .9s cubic-bezier(.3, .7, .3, 1) both; }
@keyframes cur2move { 0% { opacity: 0; left: 12%; top: 22%; } 25% { opacity: 1; } 100% { opacity: 1; left: 45%; top: 50%; } }
.is-playing.s2 .rip2 { animation: rip .5s 2.6s both; }
.is-playing.s2 .toast { animation: toastin .55s 3s var(--ease-arrive) both; }
@keyframes toastin { from { opacity: 0; transform: translateY(24px) scale(.9); } to { opacity: 1; transform: none; } }

/* --- beat 3: it follows up ---------------------------------------------- */
.s3 .crm { width: 308px; left: 50%; top: 76px; transform: translateX(-50%); }
.s3 .crmb { padding: 12px; display: flex; flex-direction: column; gap: 8px; }
.s3 .row { display: flex; justify-content: space-between; align-items: center; background: #fff; border: 1px solid #E7E5EE; border-radius: 11px; padding: 9px 11px; font-size: 12.5px; }
.s3 .who { font-weight: var(--w-semi); color: #444444; }
.s3 .who span { display: block; font-family: var(--mono); font-size: 9.5px; color: #939393; font-weight: var(--w-med); }
.s3 .st { font-family: var(--mono); font-weight: var(--w-semi); font-size: 9.5px; letter-spacing: .06em; border-radius: var(--r-pill); padding: 4px 9px; background: #ECEAF2; color: #939393; position: relative; }
.s3 .st b { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; border-radius: var(--r-pill); background: var(--lime); color: var(--lime-ink); opacity: 0; }
.is-playing.s3 .r1 .st b { animation: flip .3s 1.4s both; }
.is-playing.s3 .r2 .st b { animation: flip .3s 2.2s both; }
.is-playing.s3 .r3 .st b { animation: flip .3s 3s both; }
.s3 .fly { position: absolute; background: var(--ink); color: var(--tx); border: 1px solid rgba(255, 255, 255, .14); border-radius: 11px; padding: 8px 11px; font-size: 11.5px; max-width: 190px; }
.is-playing.s3 .fly1 { animation: flyout 1.2s 1.2s ease both; }
.is-playing.s3 .fly2 { animation: flyout 1.2s 2s ease both; }
@keyframes flyout { 0% { opacity: 0; transform: translate(0, 0); } 20% { opacity: 1; } 100% { opacity: 0; transform: translate(120px, -46px); } }
.s3 .cash { position: absolute; right: 9%; bottom: 44px; font-family: var(--disp); font-weight: var(--w-black); font-size: 25px; color: var(--lime); text-shadow: 0 0 26px rgba(214, 255, 75, .5); }
.is-playing.s3 .crm { animation: enter .5s .2s both; }
.is-playing.s3 .cash { animation: cashin .6s 3.4s var(--ease-arrive) both; }
@keyframes cashin { from { opacity: 0; transform: translateY(18px) scale(.8); } to { opacity: 1; transform: none; } }

/* --- beat 4: we build it with you --------------------------------------- */
.s4 .bld { width: 312px; left: 50%; top: 74px; transform: translateX(-50%); }
.s4 .bb { padding: 13px; }
.s4 .fh { font-weight: var(--w-bold); font-size: var(--t-sm); color: #444444; margin-bottom: 9px; display: flex; justify-content: space-between; align-items: center; }
.s4 .live { font-family: var(--mono); font-size: 9.5px; letter-spacing: .1em; border-radius: var(--r-pill); padding: 4px 10px; background: #ECEAF2; color: #939393; position: relative; }
.s4 .live b { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; gap: 5px; border-radius: var(--r-pill); background: var(--lime); color: var(--lime-ink); opacity: 0; }
.s4 .live b::before { content: "●"; font-size: 8px; }
.s4 .fld { display: flex; gap: 8px; align-items: center; background: #fff; border: 1px solid #E7E5EE; border-radius: 10px; padding: 8px 10px; font-size: var(--t-xs); margin-bottom: 7px; color: #444444; }
.s4 .fld u { text-decoration: none; font-family: var(--mono); font-size: 9px; letter-spacing: .08em; color: #939393; min-width: 56px; }
.s4 .chips { display: flex; flex-wrap: wrap; gap: 6px; margin: 9px 0 11px; }
.s4 .schip { font-family: var(--mono); font-size: 9.5px; background: #EDF6D2; color: #4E6212; border-radius: var(--r-pill); padding: 4px 9px; }
.s4 .appr { display: inline-block; background: var(--ink); color: var(--tx); font-weight: var(--w-bold); font-size: var(--t-xs); border-radius: var(--r-pill); padding: 9px 16px; }
.s4 .evnote { position: absolute; right: 7%; bottom: 46px; background: var(--ink); border: 1px solid rgba(255, 255, 255, .14); color: var(--tx); border-radius: var(--r-chip); padding: 9px 12px; font-size: 11.5px; max-width: 180px; }
.is-playing.s4 .bld { animation: enter .5s .2s both; }
.is-playing.s4 .f1 { animation: enter .35s .6s both; }
.is-playing.s4 .f2 { animation: enter .35s 1s both; }
.is-playing.s4 .f3 { animation: enter .35s 1.4s both; }
.is-playing.s4 .c1 { animation: flip .3s 1.9s both; }
.is-playing.s4 .c2 { animation: flip .3s 2.1s both; }
.is-playing.s4 .c3 { animation: flip .3s 2.3s both; }
.is-playing.s4 .c4 { animation: flip .3s 2.5s both; }
.is-playing.s4 .cur4 { animation: cur4move 1.5s 2.6s cubic-bezier(.3, .7, .3, 1) both; }
@keyframes cur4move { 0% { opacity: 0; left: 76%; top: 24%; } 25% { opacity: 1; } 100% { opacity: 1; left: 44%; top: 72%; } }
.is-playing.s4 .rip4 { animation: rip .5s 4s both; }
.is-playing.s4 .live b { animation: flip .35s 4.3s both; }
.is-playing.s4 .evnote { animation: enter .4s 4.6s both; }

/* --- carousel controls -------------------------------------------------- */
.ctrls { display: flex; align-items: center; justify-content: center; gap: 18px; margin-top: 24px; }
.arrow { width: 44px; height: 44px; border-radius: 50%; border: 1.5px solid var(--hairline-2); background: transparent; color: var(--tx); font-size: 17px; cursor: pointer; transition: border-color var(--dur-fast), color var(--dur-fast); }
.arrow:hover { border-color: var(--lime); color: var(--lime); }
.dots { display: flex; gap: 8px; }
.dot { width: 34px; height: 5px; border-radius: var(--r-pill); background: rgba(255, 255, 255, .14); cursor: pointer; overflow: hidden; position: relative; border: 0; padding: 0; }
.dot i { position: absolute; inset: 0; width: 0; background: var(--lime); border-radius: var(--r-pill); }
.dot.is-on i { animation: prog var(--dur-slide) linear forwards; }
@keyframes prog { to { width: 100%; } }

/* ------------------------------------------------------------------ marquee */

.marq { background: var(--lime); color: var(--ink); overflow: hidden; padding: 13px 0; white-space: nowrap; position: relative; z-index: 2; margin-top: 46px; }
.marq__track { display: inline-block; animation: marq 26s linear infinite; font-family: var(--disp); font-weight: var(--w-bold); font-size: var(--t-sm); letter-spacing: .04em; text-transform: uppercase; }
.marq__track span { margin: 0 22px; }
@keyframes marq { to { transform: translateX(-50%); } }

/* ============================================================ NIGHT TIMELINE
   The clock sticks while the events scroll past it, and it reads whatever event is
   currently in view. The rail fills behind them. */

.night { position: relative; z-index: 1; padding: 120px 20px; }
.night__wrap { max-width: 1040px; margin: 0 auto; display: grid; grid-template-columns: 300px 1fr; gap: 60px; }
@media (max-width: 820px) { .night__wrap { grid-template-columns: 1fr; gap: 20px; } }

.clockbox { position: sticky; top: 22vh; height: max-content; }
@media (max-width: 820px) { .clockbox { position: static; } }
.clock { font-family: var(--disp); font-weight: var(--w-black); font-size: clamp(44px, 5vw, 64px); color: var(--lime); text-shadow: 0 0 40px rgba(214, 255, 75, .35); font-variant-numeric: tabular-nums; }
.clock small { display: block; font-family: var(--mono); font-weight: var(--w-semi); font-size: var(--t-xs); letter-spacing: .24em; color: var(--tx-3); text-shadow: none; margin-top: 6px; }
.youare { margin-top: 18px; font-size: 14px; color: var(--tx-2); max-width: 240px; }
.youare b { color: var(--tx); }

.events { position: relative; padding-left: 34px; }
.nightrail { position: absolute; left: 8px; top: 0; bottom: 0; width: 2px; background: rgba(255, 255, 255, .1); }
.nightrail i { position: absolute; left: 0; top: 0; width: 2px; height: 0; background: var(--lime); box-shadow: 0 0 12px rgba(214, 255, 75, .6); }

.ev { position: relative; margin-bottom: 16vh; opacity: .22; transform: translateY(20px); transition: opacity .5s ease, transform .5s ease; }
.ev.is-on { opacity: 1; transform: none; }
.ev::before { content: ""; position: absolute; left: -32px; top: 8px; width: 12px; height: 12px; border-radius: 50%; background: var(--ink); border: 2px solid var(--hairline-2); transition: background .3s, border-color .3s, box-shadow .3s; }
.ev.is-on::before { background: var(--lime); border-color: var(--lime); box-shadow: 0 0 16px rgba(214, 255, 75, .7); }
.ev__t { font-family: var(--mono); font-weight: var(--w-semi); font-size: var(--t-xs); letter-spacing: .14em; color: var(--lime); }
.ev h3 { margin: 8px 0; }
.ev p { color: #A9ADB5; font-size: var(--t-base); max-width: 440px; }

.evnote { display: inline-block; margin-top: 12px; background: var(--ink-2); border: 1px solid var(--hairline); border-radius: var(--r-chip); padding: 10px 14px; font-size: var(--t-sm); }
.evnote b { color: var(--lime); }
.evnote--hot b { color: var(--hot); }
.sms { background: var(--ink-2); border: 1px solid var(--hairline); border-radius: 14px; padding: 12px 14px; margin-top: 12px; max-width: 380px; font-size: 13.5px; }
.sms__from { font-family: var(--mono); font-size: 10px; letter-spacing: .1em; color: var(--tx-3); margin-bottom: 4px; }

/* ================================================================= LIGHT ROOM
   The morning. A rounded slab of paper dropped into the night. */

.day { background: var(--paper); color: var(--ptx); border-radius: var(--r-light); margin: 0 12px; position: relative; z-index: 2; padding: 120px 22px; }
.day__wrap { max-width: 1040px; margin: 0 auto; }
.day h2 { color: var(--ptx); margin: 0 0 14px; }
.day h2 .hl { background: linear-gradient(120deg, var(--lime), #B6E82E); color: var(--ptx); padding: 0 10px; border-radius: 10px; text-shadow: none; }
.day .lead { color: var(--ptx-2); font-size: var(--t-md); max-width: 560px; }

.grid3 { display: grid; grid-template-columns: repeat(3, 1fr); gap: 16px; margin-top: 44px; }
@media (max-width: 820px) { .grid3 { grid-template-columns: 1fr; } }
.fc { background: var(--paper-card); border: 1.5px solid var(--paper-line); border-radius: var(--r-card); padding: 24px; transition: transform .2s ease, box-shadow .2s ease; }
.fc:hover { transform: translateY(-6px); box-shadow: var(--lift); }
.fc h3 { font-size: var(--t-base); color: var(--ptx); margin-bottom: 6px; }
.fc p { font-size: 14px; color: #6B6E62; }

.counts { display: grid; grid-template-columns: repeat(3, 1fr); gap: 14px; margin-top: 44px; }
@media (max-width: 720px) { .counts { grid-template-columns: 1fr; } }
.count { background: var(--ink); color: var(--tx); border-radius: var(--r-card); padding: 26px; text-align: center; }
.count b { font-family: var(--disp); font-weight: var(--w-black); font-size: clamp(30px, 4vw, 44px); color: var(--lime); display: block; font-variant-numeric: tabular-nums; }
.count span { font-size: var(--t-sm); color: var(--tx-3); }

/* ------------------------------------------------------------------- plans */

.plans { display: grid; grid-template-columns: repeat(4, 1fr); gap: 14px; margin-top: 44px; }
@media (max-width: 920px) { .plans { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 560px) { .plans { grid-template-columns: 1fr; } }
.plan { background: var(--paper-card); border: 1.5px solid var(--paper-line); border-radius: var(--r-card); padding: 22px; display: flex; flex-direction: column; transition: transform .2s ease; }
.plan:hover { transform: translateY(-6px); }
.plan--pop { background: var(--ink); color: var(--tx); border-color: var(--ink); }
.plan h4:not(.plan__name) { font-size: 14px; color: var(--ptx); }
.plan--pop h4:not(.plan__name) { color: var(--tx); }
.plan__pr { font-family: var(--disp); font-weight: var(--w-black); font-size: 32px; margin: 8px 0 2px; color: var(--ptx); }
.plan--pop .plan__pr { color: var(--lime); }
.plan__pr small { font-size: var(--t-xs); font-weight: var(--w-med); font-family: var(--body); opacity: .6; }

/* The monthly, tucked under the one-time figure it belongs to. Quiet, because it is
   the smaller number, but on the card because it is part of the price. */
.plan__sub { font-size: var(--t-xs); color: var(--ptx-3); margin: 0 0 4px; }
.plan--pop .plan__sub { color: var(--tx-3); }

/* What this level has not opened yet, same wording as the ladder on /packages, in the
   quiet caption voice the card already uses for its recurring line. */
.plan__rooms {
    margin: 0 0 14px; padding-top: 12px; border-top: 1px solid var(--paper-line);
    font-size: var(--t-xs); color: var(--ptx-3);
}
.plan--pop .plan__rooms { color: var(--tx-3); border-top-color: var(--ink-3); }
.plan ul { list-style: none; padding: 0; margin: 14px 0 18px; font-size: 13.5px; flex: 1 1 auto; min-height: 0; }
.plan__rooms, .plan .go { flex: 0 0 auto; }
.plan li { padding: 5px 0 5px 18px; position: relative; opacity: .85; }
.plan li::before { content: "\25B8"; position: absolute; left: 0; color: var(--lime-dim); }
.plan--pop li::before { color: var(--lime); }
.plan .go { text-align: center; border-radius: var(--r-pill); padding: 11px; font-weight: var(--w-bold); font-size: 14px; background: #EFEDE2; color: var(--ptx); }
.plan--pop .go { background: var(--lime); color: var(--ink); }
.fine { font-size: 12.5px; color: var(--ptx-3); margin-top: 14px; max-width: var(--measure); }

/* -------------------------------------------------------------- the closer */

.final { position: relative; z-index: 1; text-align: center; padding: 150px 22px 160px; overflow: hidden; }
.final .glow { top: 64%; }
.final h2 { max-width: 800px; margin: 0 auto 18px; }
.final__inner { position: relative; z-index: 2; }

/* ------------------------------------------------------------------ footer */

.foot { position: relative; z-index: 2; border-top: 1px solid var(--hairline); padding: 44px 22px 30px; }
.foot__grid { max-width: 1040px; margin: 0 auto; display: grid; grid-template-columns: 2fr repeat(3, 1fr); gap: 30px; }
@media (max-width: 780px) { .foot__grid { grid-template-columns: 1fr 1fr; } }
.foot__h { font-size: var(--t-xs); color: var(--tx); margin-bottom: 12px; }
.foot ul { list-style: none; margin: 0; padding: 0; display: grid; gap: 8px; }
.foot a { color: var(--tx-3); font-size: var(--t-sm); }
.foot a:hover { color: var(--lime); }
.foot__line { color: var(--tx-3); font-size: var(--t-sm); margin-top: 14px; max-width: 34ch; }
.foot__base { max-width: 1040px; margin: 30px auto 0; padding-top: 18px; border-top: 1px solid var(--hairline); color: var(--tx-3); font-size: var(--t-xs); }

/* ----------------------------------------------------------------- reveals */

.rv { opacity: 0; transform: translateY(30px); transition: opacity .7s ease, transform .7s cubic-bezier(.2, .7, .2, 1); }
.rv.is-in { opacity: 1; transform: none; }
.d1 { transition-delay: .08s; } .d2 { transition-delay: .16s; } .d3 { transition-delay: .24s; }

/* ================================================== forms, auth and checkout
   Same tokens, quieter. These pages are a person typing, not a person deciding. */

/*
 * Interior pages, the doorway and checkout. Display type comes down from its landing
 * page scale: a person on these screens has already decided, and a 68px headline over
 * a payment form reads as a page still trying to sell them something.
 */
.pagehead { position: relative; z-index: 1; padding: 140px 0 0; }
.pagehead h1 { max-width: 18ch; font-size: clamp(26px, 4vw, 44px); }
.pagehead + .section h2,
.section h2 { font-size: clamp(19px, 2.4vw, 28px); }
.pagehead .lead { margin-top: 18px; }

/*
 * The one page whose headline is allowed to be the loudest thing on it.
 *
 * Every other page head is set small and ranged left, because it is a signpost above the
 * content. This one is the content: it is the whole pricing argument in two lines, and a
 * visitor who reads nothing else should still leave knowing there is one product and that
 * how deep you go is up to you. So it gets the full display size, set across the measure
 * rather than boxed to 18 characters, with the half of the sentence that is the actual
 * news carrying the lime.
 */
.pagehead--display h1 {
    max-width: none;
    /*
     * Sized off the column, not the window.
     *
     * Both lines are deliberately the same length, so one size fills them both. Measuring
     * it against the viewport gets that wrong the moment the column stops growing with
     * the window: past that point the type keeps getting bigger against a measure that
     * does not, and the second line falls in half. Against the column itself the ratio
     * holds at every width, and the break stays where the copy puts it.
     */
    font-size: clamp(22px, 4.55cqi, 68px);
    text-transform: uppercase;
    line-height: 1.02;
    letter-spacing: -.025em;
}
.pagehead--display .wrap { container-type: inline-size; }
.pagehead--display h1 span { color: var(--lime); }
/*
 * The standard lead is capped at a comfortable reading measure, which is right for a
 * paragraph and wrong for this one: it is a single sentence sitting directly under a
 * two-line headline, and breaking it in half gives the eye a third line to read where
 * there should be one. The column is the cap here.
 */
.pagehead--centred .section__lead { margin-left: auto; margin-right: auto; }
.pagehead--display .section__lead { max-width: none; }
.section { position: relative; z-index: 1; padding: var(--sp-8) 0; }
.section__lead { color: var(--tx-2); font-size: var(--t-md); max-width: 50ch; margin-top: 14px; }
/* The mark sits with the wordmark, sized off it rather than in pixels, so the two stay
   in proportion at every breakpoint. Height drives it and width follows, because the
   shield is taller than it is wide and a square box would letterbox it. */
.nav__mark { display: inline-flex; align-items: center; gap: .5em; }
.mark__shield { height: 1.6em; width: auto; flex: none; }

.pageaction { margin-top: var(--sp-7); }
.pageaction--minor { margin-top: var(--sp-4); color: var(--tx-2); font-size: var(--t-sm); }

.form { max-width: 460px; margin-top: var(--sp-6); }
.form--inline { display: flex; gap: var(--sp-3); align-items: flex-end; max-width: 640px; }
.form--inline .field { flex: 1; margin-bottom: 0; }
.field { margin-bottom: var(--sp-5); }

/* Same shape as admin.css's .tick, kept in its own stylesheet because public pages
   and the member backoffice never load each other's CSS. Used where a person must
   read something before what happens next depends on it, rather than a preference
   toggle -- the guidelines acknowledgment at checkout, not a settings switch. */
.tick { display: flex; align-items: flex-start; gap: var(--sp-3); padding: var(--sp-3) 0; cursor: pointer; font-size: var(--t-sm); color: var(--tx-2); line-height: 1.45; margin-bottom: var(--sp-4); }
.tick input { flex: none; margin-top: 3px; width: 16px; height: 16px; accent-color: var(--lime); }
.tick:hover { color: var(--tx); }
.tick input:checked + span { color: var(--tx); }
.field--split { display: grid; grid-template-columns: 1fr 1fr; gap: var(--sp-4); }
@media (max-width: 520px) { .field--split { grid-template-columns: 1fr; } }
.field label { display: block; font-size: var(--t-sm); font-weight: var(--w-semi); margin-bottom: 6px; }
.field input, .field select, .field textarea {
    width: 100%; padding: 13px 16px; background: var(--ink-3); border: 1px solid var(--hairline-2);
    border-radius: var(--r-chip); color: var(--tx); font: inherit; font-size: var(--t-base);
}
.field input:focus, .field select:focus, .field textarea:focus { border-color: var(--lime); outline: none; }
.field input::placeholder { color: var(--tx-3); }
.fieldlabel { font-size: var(--t-xs); color: var(--tx-3); margin-bottom: 4px; }
.field__optional { color: var(--tx-3); font-weight: var(--w-med); }
.blockhead { font-size: var(--t-md); margin-bottom: var(--sp-4); }

.line { display: flex; justify-content: space-between; gap: var(--sp-5); padding: var(--sp-3) 0; border-bottom: 1px solid var(--hairline); font-size: var(--t-base); }
.line--total { border-bottom: 0; font-weight: var(--w-bold); }
.line--total .money { font-size: var(--t-lg); color: var(--lime); }

.notice { border: 1px solid var(--hairline); border-left: 3px solid var(--lime); background: var(--ink-2); border-radius: 0 var(--r-chip) var(--r-chip) 0; padding: var(--sp-4); margin-bottom: var(--sp-5); font-size: var(--t-sm); color: var(--tx-2); }
.alarm { border: 1px solid var(--danger); border-left-width: 3px; background: rgba(255, 107, 90, .09); border-radius: 0 var(--r-chip) var(--r-chip) 0; padding: var(--sp-4); margin-bottom: var(--sp-5); }
.draft-note { border: 1px solid var(--hairline); border-left: 3px solid var(--hot); background: var(--ink-2); border-radius: 0 var(--r-chip) var(--r-chip) 0; padding: var(--sp-4); margin-bottom: var(--sp-6); }
.draft-note p { font-size: var(--t-sm); color: var(--tx-2); }

.wrap--narrow h2 { margin-top: var(--sp-7); font-size: var(--t-xl); }
.wrap--narrow p { margin-bottom: var(--sp-4); color: var(--tx-2); }

/* ===================================================== the packages page
   Four tiers as product plans. The plan cards on the home page are a summary;
   these carry the full cumulative feature list, so they sit on ink rather than
   in the light room and get room to breathe. */

/* Four cards that are genuinely one table.
   align-items: start was stopping them stretching, so each box ended wherever its
   own copy ran out and the row read as four unrelated things. */
.tiers { display: grid; grid-template-columns: repeat(4, 1fr); grid-auto-rows: auto; gap: 14px; margin-top: 44px; }
@media (max-width: 1040px) { .tiers { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 560px) { .tiers { grid-template-columns: 1fr; } }

/*
 * Four cards that read as one table.
 *
 * Equal height is the easy half and not the half that shows. What an eye comparing four
 * prices notices is one card's price sitting a line lower than its neighbour's, and that
 * comes from a band above it wrapping to two lines instead of one.
 *
 * So the bands are made to match and the list absorbs the difference. The list is the one
 * band that can afford to: it is a list, and a gap under the last item reads as nothing at
 * all, whereas a gap under a price reads as a mistake.
 *
 * Tried subgrid first, which is the right tool and would align every band without any of
 * the below. It reported as supported and then sized each card's rows from its own content
 * anyway, so this is the version that demonstrably works.
 */
.tier {
    background: var(--ink-2);
    border: 1px solid var(--hairline);
    border-radius: var(--r-card);
    padding: var(--sp-6) var(--sp-5);
    display: flex; flex-direction: column; gap: var(--sp-4);
}

/*
 * Room for two lines, in em so it tracks the type rather than a pixel guess.
 *
 * The first card has no "already set up X?" sentence, because there is nothing below it
 * to have set up, so its breakdown is one line while the other three are two. Left alone
 * that pushes everything under it up by a line on one card out of four.
 */
/*
 * The names are deliberately different sizes, so their band has to be one height.
 *
 * Each step name is sized to fill its own card, which is what makes the row look
 * designed rather than defaulted. The cost is that "MY SELF" at its fill size has a
 * taller line box than "MY WORDS" at its, and everything underneath inherits the
 * difference: four prices that should be a column end up on four different lines.
 *
 * So the band is fixed at the tallest name's line box and the names sit on its floor.
 * Measured in cqi like the names themselves, and the cards are all the same width, so
 * one value is the same number of pixels in each of them. The tallest is MY SELF at
 * 17.18cqi against a .95 line height.
 */
.tier__name {
    min-height: 16.4cqi;
    display: flex;
    align-items: flex-end;
}

/*
 * Measured at four across, which is the tightest the cards ever get before the grid
 * drops to two. That is the worst case for wrapping, so a band sized for it is a band
 * that holds at every wider layout too: the copy needs fewer lines as the cards grow
 * and the minimum takes over.
 *
 * The alternative is a pixel guess that happens to look right on the screen it was
 * written on, which is how a pricing table ends up misaligned on somebody else's.
 */
.tier__summary   { min-height: 7.8em; }
.tier__breakdown { min-height: 7.6em; }

/* The slack goes here, which pins the rooms line and the button to the bottom of every
   card in the row no matter how many things a level opens. */
/*
 * Grows into the slack, but starts from its own content.
 *
 * With a zero basis the card's natural height is worked out as though the list were not
 * there, so the grid row can end up shorter than the longest list needs; that list then
 * refuses to shrink and shoves the rooms line and the button down in that one card. From
 * content, the row is sized honestly by the tallest card and every list absorbs whatever
 * is left over, which is what puts the buttons on one line.
 */
.tier__list { flex: 1 1 auto; min-height: 0; }

/*
 * Everything below the list keeps its natural height.
 *
 * The card's height is set by the grid row, and the row comes out a few pixels short of
 * what the longest card wants: the name band is measured in container-query units, which
 * cannot be resolved while the browser is still working out how wide the card is, so the
 * intrinsic pass undercounts it. Those few pixels have to come off something. Left to
 * itself the browser took them off the button, which is the one band where three pixels
 * are visible as a button that does not match the three beside it. Pinned here, the list
 * gives them up instead, inside a gap where nothing can be seen to move.
 */
.tier__rooms,
.tier__go { flex: 0 0 auto; }
}

/* The one people start with. One lime edge on the page, not four. */
.tier--first { border-color: var(--lime); background: linear-gradient(180deg, rgba(214,255,75,.06), transparent 55%); }

/*
 * Already theirs. Quieter than "first", not louder: a card with nothing left to do on
 * it should recede next to the one still asking for a decision, not compete with it.
 */
.tier--owned { opacity: .74; }
.tier__total--owned { color: var(--lime-dim); }
.tier__go--owned { min-height: 0; }

.tier__head { display: flex; flex-direction: column; gap: var(--sp-2); }
.tier__summary { color: var(--tx-2); font-size: var(--t-sm); }

/*
 * The caption sits under the number, not beside it.
 *
 * Beside it, the caption gets whatever width the number leaves over, so "$25" and
 * "$1,625" hand it two different amounts of room and it wraps to a different number of
 * lines in each card. That alone threw the four cards out of step by up to two lines,
 * and no amount of minimum height below it could put them back.
 */
.tier__price { display: flex; flex-direction: column; gap: 4px; margin-top: var(--sp-3); }
.tier__total {
    font-family: var(--disp); font-weight: var(--w-black);
    font-size: clamp(26px, 3vw, 34px); letter-spacing: -.04em; line-height: 1;
    font-variant-numeric: tabular-nums;
}
.tier--first .tier__total { color: var(--lime); }
.tier__unit { font-size: var(--t-xs); color: var(--tx-3); }
.tier__monthly { font-size: var(--t-sm); color: var(--tx-2); }

/* The number actually charged on day one, said out loud rather than in a footnote. */
.tier__breakdown { font-size: var(--t-xs); color: var(--tx-3); line-height: 1.5; }

.tier__carries { font-size: var(--t-xs); color: var(--tx-3); padding-top: var(--sp-3); border-top: 1px solid var(--hairline); }

.tier__list { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--sp-3); font-size: var(--t-sm); color: var(--tx-2); }
.tier__list li { padding-left: 18px; position: relative; }
.tier__list li::before { content: "\25B8"; position: absolute; left: 0; color: var(--lime-dim); }

/* --------------------------------------------------------------- the catch
   Naming the hard part is a brand pillar, so it gets a rule of its own rather
   than being buried in a paragraph. */

.catch { border-left: 2px solid var(--hot); padding-left: var(--sp-5); margin-top: var(--sp-8); max-width: 60ch; }
.catch p { font-size: var(--t-md); line-height: 1.5; color: var(--tx); }

.field__hint { font-size: var(--t-xs); color: var(--tx-3); margin-top: 6px; }

/* ================================================== CHECKOUT AND THE DOORWAY
 *
 * The quietest surfaces on the platform, deliberately. A person here has already
 * decided; the job is to take their money without making them wonder what they just
 * agreed to. So: one lime action per screen, the real number stated with its cents,
 * and no motion at all.
 */

/* ------------------------------------------------------------- radio cards
   A whole card is the hit target, not a 14px circle beside a label. The native
   input stays in the DOM for keyboard and screen readers and is drawn as a ring
   on the card itself. */

.choice {
    display: flex; align-items: center; gap: var(--sp-4);
    background: var(--ink-2);
    border: 1.5px solid var(--hairline);
    border-radius: var(--r-card);
    padding: var(--sp-5);
    margin-bottom: var(--sp-3);
    cursor: pointer;
    transition: border-color var(--dur-fast), background var(--dur-fast);
}

.choice:hover { border-color: var(--hairline-2); }

.choice input {
    appearance: none; -webkit-appearance: none;
    width: 20px; height: 20px; flex: 0 0 auto; margin: 0;
    border: 2px solid var(--hairline-2); border-radius: 50%;
    background: transparent; cursor: pointer;
    transition: border-color var(--dur-fast), box-shadow var(--dur-fast);
}

.choice input:checked { border-color: var(--lime); box-shadow: inset 0 0 0 4px var(--lime); }

/* :has lets the card react to its own input. Where it is unsupported the card simply
   does not light up, which is a missing flourish rather than a broken form. */
.choice:has(input:checked) { border-color: var(--lime); background: rgba(214, 255, 75, .05); }
.choice:has(input:focus-visible) { outline: 2px solid var(--lime); outline-offset: 3px; }

.choice--tight { padding: var(--sp-4) var(--sp-5); }

.choice__body { flex: 1; display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.choice__title { font-weight: var(--w-bold); font-size: var(--t-md); }
.choice__desc { color: var(--tx-2); font-size: var(--t-sm); }

.choice__price { text-align: right; flex: 0 0 auto; display: flex; flex-direction: column; gap: 2px; }
.choice__amount {
    font-family: var(--disp); font-weight: var(--w-black);
    font-size: var(--t-xl); letter-spacing: -.03em; line-height: 1;
    font-variant-numeric: tabular-nums;
}
.choice:has(input:checked) .choice__amount { color: var(--lime); }
.choice__unit { font-family: var(--mono); font-size: var(--t-xs); color: var(--tx-3); }

@media (max-width: 560px) {
    .choice { flex-wrap: wrap; }
    .choice__price { text-align: left; width: 100%; flex-direction: row; align-items: baseline; gap: var(--sp-2); }
}

.form--wide { max-width: 720px; }
.subline { color: var(--tx-2); font-size: var(--t-sm); margin-top: var(--sp-4); max-width: 60ch; }

/* --------------------------------------------------------------- receipts
   Cents always. This is the one place on the platform where a rounded price
   would be a lie about what is being charged. */

.receipt {
    background: var(--ink-2);
    border: 1px solid var(--hairline);
    border-radius: var(--r-card);
    padding: var(--sp-6);
    margin-top: var(--sp-5);
    max-width: 480px;
}

.receipt--light { background: var(--ink-3); }
.receipt__after { color: var(--tx-3); font-size: var(--t-sm); margin-top: var(--sp-4); }

/* ------------------------------------------------- the earning opt-in step
   §2.3 step 6, and the legal disclosure point the public site deliberately
   omits. It is a wall of plain text on purpose, and neither answer is
   pre-selected or styled to look like the expected one. */

.planbox {
    background: var(--ink-2);
    border: 1px solid var(--hairline);
    border-radius: var(--r-card);
    padding: var(--sp-3) var(--sp-5);
    margin: var(--sp-4) 0 var(--sp-6);
    max-width: 560px;
}

.planrow {
    display: flex; justify-content: space-between; align-items: baseline; gap: var(--sp-4);
    padding: var(--sp-3) 0;
    border-bottom: 1px solid var(--hairline);
    font-size: var(--t-sm);
}
.planrow:last-child { border-bottom: 0; }

/* Two buttons of equal weight. Declining is a real choice (C5), so it is not
   dressed as the smaller one. */
.decision { display: flex; gap: var(--sp-3); flex-wrap: wrap; margin-top: var(--sp-6); }

/* --------------------------------------------------------- the doorway */

/*
 * Scoped through .wrap on purpose, and not with !important.
 *
 * `.wrap--narrow p` sets body copy to the muted colour and scores 0,1,1. A bare
 * `.field__error` scores 0,1,0 and loses, so every validation message on every narrow
 * page rendered in exactly the same grey as the hint text underneath it. The error was
 * always there and never looked like one.
 *
 * That is what made a failed signup read as "the form did nothing": the message was
 * below the fold AND the same colour as the help text when you got to it.
 */
.wrap .form__error,
.wrap .field__error {
    color: var(--danger);
    font-size: var(--t-sm);
    margin-top: 6px;
}

.form__error {
    border: 1px solid var(--danger);
    border-left-width: 3px;
    background: rgba(255, 107, 90, .07);
    border-radius: 0 var(--r-chip) var(--r-chip) 0;
    padding: var(--sp-3) var(--sp-4);
    margin: 0 0 var(--sp-5);
    color: var(--tx);
}

/* Six digits, spaced out, in the data voice. Nobody mistypes their code twice. */
.input--code {
    font-family: var(--mono);
    font-size: 28px;
    font-weight: var(--w-semi);
    letter-spacing: .32em;
    text-align: center;
    padding: var(--sp-4);
}

.sponsor-lock {
    background: var(--ink-3);
    border: 1px solid var(--hairline);
    border-radius: var(--r-chip);
    padding: var(--sp-3) var(--sp-4);
    margin-bottom: var(--sp-5);
    font-size: var(--t-sm);
}
.sponsor-lock b { color: var(--lime); }

.linkbutton {
    background: none; border: 0; padding: 0;
    color: var(--lime); font: inherit; font-size: var(--t-sm);
    cursor: pointer; text-decoration: underline; text-underline-offset: 3px;
}

/* Only ever rendered when CI_ENVIRONMENT is development. Amber so nobody ships
   a build with it showing and mistakes it for a real message. */
.dev-banner {
    border: 1px dashed var(--hot);
    border-radius: var(--r-chip);
    background: rgba(255, 180, 67, .07);
    color: var(--hot);
    padding: var(--sp-3) var(--sp-4);
    margin-bottom: var(--sp-5);
    font-family: var(--mono);
    font-size: var(--t-sm);
}

/* The summary above a form that came back with problems. Links jump to the field. */
.wrap .form__error p { margin: 0; color: var(--danger); }
.form__error ul { margin: var(--sp-2) 0 0; padding-left: 1.1em; }
.form__error li + li { margin-top: 3px; }
.form__error a { color: var(--danger); text-decoration: underline; text-underline-offset: 2px; }
.form__error a:hover { color: var(--tx); }

/* A field jumped to from that summary should be obvious once you land on it. */
.field :target { outline: 2px solid var(--danger); outline-offset: 3px; border-radius: var(--r-chip); }

/* One button per pricing card. The subgrid above is what lines them up now; this
   rule set the card to flex a second time, 230 lines after it was already set to
   grid, and the later one silently won. */
.tier__go { display: block; text-align: center; margin-top: var(--sp-2); }

/* ------------------------------------------------- the four steps, named
   "Future Proof" above in small bold grey, then the step: MY in white, the noun
   in lime. The noun is what the eye should land on, so it is the only lime.

   Each title fills its line exactly, at every width, and that is arithmetic
   rather than a guess. A string set in a given face has a fixed width in ems:
   "MY WORDS" in Unbounded 900 is 7.406em, "MY SELF" only 5.645em. Divide the
   container width by that number and you get the font size at which the string
   is precisely as wide as its box. So the rule is one calc and the only thing
   that changes per step is how wide its own name happens to be.

   cqi and not vw, because a card is a column of a grid that reflows from four
   across to two to one. Its width and the window's width are different stories,
   and only the card's own width can promise the line will not break.

   The 97 is three percent of headroom for a fallback face or subpixel rounding.
   nowrap is the backstop, not the mechanism: if a name ever grows a third word
   the answer is a new measurement here, and the overflow will say so loudly.

   To re-measure after a font change: render the name at font-size 100px in the
   real face and divide the resulting pixel width by 100. */

.tier, .plan { container-type: inline-size; }

.tier__brand, .plan__brand {
    font-family: var(--mono);
    font-weight: var(--w-bold);
    font-size: var(--t-xs);
    letter-spacing: .2em;
    text-transform: uppercase;
    margin-bottom: 4px;
}

.tier__brand { color: var(--tx-3); }
.plan__brand { color: var(--ptx-3); }
.plan--pop .plan__brand { color: var(--tx-3); }

.tier__name, .plan__name {
    font-family: var(--disp);
    font-weight: var(--w-black);
    text-transform: uppercase;
    line-height: .95;
    letter-spacing: -.02em;
    white-space: nowrap;
    font-size: var(--name-fit, 13.1cqi);
}

/*
 * MY stays quiet, the noun carries the colour. Which colour depends on the ground
 * it is standing on.
 *
 * The packages cards are ink, so it is white and lime as the operator specified.
 * Three of the four home cards are paper, where white is very nearly invisible and
 * lime on near-white is barely a colour at all. The brand already answers this: --ptx
 * is the ink used for text on paper, and --lime-ptx exists precisely because lime does
 * not survive there. Same idea, same hierarchy, legible on both grounds.
 */
.tier__name        { color: var(--tx); }
.tier__name span   { color: var(--lime); }

.plan__name        { color: var(--ptx); }
.plan__name span   { color: var(--lime-ptx); }

/* The one dark card in that row goes back to the dark treatment. */
.plan--pop .plan__name      { color: var(--tx); }
.plan--pop .plan__name span { color: var(--lime); }

/* One number per step, not a division done at render time.
   97 divided by the name's width in ems, which is the font size, expressed as a
   percentage of the card, at which the string is exactly as wide as its box.
   Worked out here rather than in a calc() because a stylesheet that computes the
   answer is one more thing that can be dropped as invalid and fall silently back
   to whatever came before it, which is precisely what happened. */
.tier--t1, .plan--t1 { --name-fit: 13.10cqi; }   /* MY WORDS, 7.406em */
.tier--t2, .plan--t2 { --name-fit: 15.19cqi; }   /* MY VOICE, 6.384em */
.tier--t3, .plan--t3 { --name-fit: 14.02cqi; }   /* MY REACH, 6.919em */
.tier--t4, .plan--t4 { --name-fit: 17.18cqi; }   /* MY SELF,  5.645em */

/* ------------------------------------------------- paying in bitcoin
   Three facts in the order somebody with a wallet open needs them: how much,
   where to, how long. Everything else on the page is subordinate. */

.paystate { margin-bottom: var(--sp-6); }

/* One block visible at a time, chosen by the server's answer. Hidden by default so
   a page that never gets its state, because script is off or a poll failed, still
   shows the state it was rendered with rather than all four at once. */
.paystate__banner { display: none; padding: var(--sp-5); border-radius: var(--r-card); border: 1px solid var(--hairline); border-left-width: 3px; background: var(--ink-2); font-size: var(--t-sm); }
.paystate[data-state="waiting"] [data-when="waiting"],
.paystate[data-state="seen"]    [data-when="seen"],
.paystate[data-state="paid"]    [data-when="paid"],
.paystate[data-state="expired"] [data-when="expired"] { display: block; }

.paystate__banner { border-left-color: var(--hot); }
.paystate__banner--seen { border-left-color: var(--lime); }
.paystate__banner--paid { border-left-color: var(--lime); background: rgba(214, 255, 75, .07); }
.paystate__banner--expired { border-left-color: var(--danger); background: rgba(255, 107, 90, .06); }

.paystate__clock { display: block; margin-top: var(--sp-2); font-family: var(--mono); color: var(--tx-3); font-size: var(--t-xs); }
.paystate__banner form { margin-top: var(--sp-4); }

/* One centred column. The order down the page is the order somebody does it in:
   scan or copy, check the amount, check the address. */
.pay { display: flex; flex-direction: column; align-items: center; text-align: center; gap: var(--sp-5); }

.pay__qr { display: block; width: 260px; height: 260px; border-radius: var(--r-chip); background: #fff; padding: 10px; }
.pay__hint { margin: 0; font-size: var(--t-xs); color: var(--tx-3); }

.pay__amount, .pay__address { width: 100%; }

/* Prose stays narrow even when it is centred. Centred text that runs the full width
   of a card is the hardest kind to read, because the eye loses where the next line
   starts on every single line rather than once. */
.pay__note { font-size: var(--t-xs); color: var(--tx-3); max-width: 48ch; margin: var(--sp-3) auto 0; }

.pay .fieldlabel { margin-bottom: 4px; }
.pay .btn { margin-top: var(--sp-4); }

.pagehead--centred { text-align: center; }
.pagehead--centred .lead { margin-left: auto; margin-right: auto; }

/* An address is one long word. It wraps anywhere rather than pushing the page
   sideways, and it is never truncated: this is the screen where the whole string
   matters more than the layout. */
.keyline { font-family: var(--mono); font-size: var(--t-sm); color: var(--tx); overflow-wrap: anywhere; letter-spacing: .02em; }
.keyline--big { font-size: var(--t-md); font-weight: var(--w-semi); }

/* What is on the order, itemised and centred with the rest of the payment column.
   Each item is a name, its price, and one line saying what kind of charge it is,
/* What is on the order: name, what kind of charge it is, price.
   A receipt line, which is a shape people already know how to read. The block is
   centred on the page and its rows are not, because a price column only works if
   the figures line up under each other. */
.bought { list-style: none; margin: var(--sp-6) auto 0; padding: 0; max-width: 34rem; text-align: left; }

.bought__item {
    display: grid;
    grid-template-columns: minmax(0, auto) minmax(0, 1fr) auto;
    align-items: baseline;
    gap: var(--sp-3) var(--sp-4);
    padding: var(--sp-4) 0;
    border-bottom: 1px solid var(--hairline);
}
.bought__item:first-child { border-top: 1px solid var(--hairline); }

/* Placed explicitly rather than left to source order.
   The two layouts want different orders from the same markup: wide reads name,
   description, price across; narrow wants the name and its price together on one
   line with the description underneath. Auto placement can only give one of those,
   and it silently gave a third thing: the price on a row of its own. */
.bought__what  { grid-column: 1; font-size: var(--t-base); color: var(--tx-2); }
.bought__what strong { color: var(--tx); font-weight: var(--w-bold); }
.bought__note  { grid-column: 2; font-size: var(--t-xs); color: var(--tx-3); }

/* Tabular figures, or the decimal points wander between rows and the column stops
   reading as a column. */
.bought__price { grid-column: 3; font-weight: var(--w-bold); color: var(--tx); text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }

/* Narrow: the name and the price keep each other company on one line and the
   description drops underneath, rather than three things fighting over 320px. */
@media (max-width: 560px) {
    .bought__item { grid-template-columns: minmax(0, 1fr) auto; }
    .bought__what  { grid-column: 1; grid-row: 1; }
    .bought__price { grid-column: 2; grid-row: 1; }
    .bought__note  { grid-column: 1 / -1; grid-row: 2; }
}

.bought__total {
    display: flex; justify-content: space-between; align-items: baseline;
    gap: var(--sp-4);
    max-width: 34rem; margin: var(--sp-5) auto 0;
    text-align: left;
    font-size: var(--t-md); color: var(--tx-2);
}
.bought__total .money { font-family: var(--disp); font-weight: var(--w-black); font-size: var(--t-xl); color: var(--lime); font-variant-numeric: tabular-nums; }

/* ------------------------------------------------- the workspace, then the setups
   The product first, at the size of a product, then the four depths of setup under
   it. One lime edge on the page belongs to the workspace, because that is the thing
   somebody is actually subscribing to. */

.workspace-card {
    display: grid;
    grid-template-columns: 1.3fr 1fr;
    gap: var(--sp-7);
    align-items: start;
    background: linear-gradient(160deg, var(--ink-2), var(--ink));
    border: 1px solid rgba(214, 255, 75, .34);
    border-radius: var(--r-card);
    padding: var(--sp-6) var(--sp-7);
    container-type: inline-size;
}
@media (max-width: 820px) { .workspace-card { grid-template-columns: 1fr; gap: var(--sp-5); padding: var(--sp-5); } }

/* Sized off the card like the step names, so the product reads as the biggest thing
   on the page at any width without a media query per breakpoint. */
/* Set exactly like the step names: brand above in grey, first word white, second
   lime, and sized to fill its own column on one line.

   "AI WORKSPACE" is 9.947em wide in Unbounded 900, so 97cqi divided by that is the
   size at which it is as wide as the box. Measured the same way as the four step
   names, and worth keeping in step with them: this card and those four are one
   family and a different sizing rule would show. */
.workspace-card__name {
    font-family: var(--disp); font-weight: var(--w-black); text-transform: uppercase;
    line-height: .98; letter-spacing: -.02em; color: var(--tx);
    white-space: nowrap;
    font-size: 9.75cqi;
    margin-bottom: var(--sp-4);
}
.workspace-card__name span { color: var(--lime); }

.workspace-card__lead  { color: var(--tx-2); font-size: var(--t-base); max-width: 52ch; }
.workspace-card__pause {
    margin-top: var(--sp-5); padding-top: var(--sp-4);
    border-top: 1px dashed var(--hairline);
    color: var(--tx-3); font-size: var(--t-sm); max-width: 52ch;
}

.workspace-card__figure {
    font-family: var(--disp); font-weight: var(--w-black);
    font-size: clamp(34px, 9cqi, 52px); color: var(--lime); line-height: 1;
}
.workspace-card__figure small { font-family: var(--body); font-weight: var(--w-med); font-size: var(--t-sm); color: var(--tx-3); }

/* The workspace's list is the same list as a setup card's. It used a class that
   only exists in the member stylesheet, which this page does not load, so it fell
   back to browser default bullets. */
.workspace-card .tier__list { margin-top: var(--sp-4); }

/*
 * The setup levels sit right under the workspace box, not a screen below it.
 *
 * Two sections' worth of padding plus this margin put nearly two hundred pixels between
 * the product and the four ways to set it up, which reads as two unrelated pages stacked.
 * They are one argument: here is the thing, here is how deep we build it. Closing the gap
 * is what makes the second half read as the answer to the first.
 */
.setup-head { margin-top: 20px; text-align: center; }

/* Centred under a centred page head, so the whole column reads on one axis. */
.setup-head__lead { margin-left: auto; margin-right: auto; text-align: center; max-width: 66ch; }
.section--flush-bottom { padding-bottom: 0; }
.section--flush-top { padding-top: 0; }
.setup-head__lead { margin-bottom: var(--sp-6); }

/* What this level has not opened yet. Named rather than hidden, so a visitor can see
   the product goes further than the part they are looking at. */
.tier__rooms {
    margin-top: var(--sp-4); padding-top: var(--sp-4);
    border-top: 1px solid var(--hairline);
    font-family: var(--mono); font-size: var(--t-xs); letter-spacing: .06em;
    color: var(--hot);
    /* "Still locked: Voice · Reach · Studio" wraps to two lines and "Every room open"
       does not, which was the last thing knocking the buttons out of line. */
    min-height: 4.6em;
}
