/* the guy - homepage redesign (staging)
   tokens ------------------------------------------------------------------ */
:root {
    --black: #000000;
    --green: #39FF14;
    --green-dim: rgba(57, 255, 20, 0.15);
    --red: #FF6B6B;
    --white: #EDEDED;
    --gray: #8A8A8A;
    --border: rgba(57, 255, 20, 0.2);
    --red-dim: rgba(255, 107, 107, 0.7);
    --mono: 'JetBrains Mono', ui-monospace, 'SF Mono', Menlo, monospace;
    --header-h: 60px;

    /* fluid type scale -----------------------------------------------------
       one family, so the scale does all the work that a second face would.
       roles are separated by size, weight, tracking and color instead.
       every step interpolates 375px -> 1440px, so nothing steps at a
       breakpoint. mono sets wider than a sans at the same px, so the body
       steps sit slightly lower than you would set Inter, with more leading. */
    /* floors raised so the ramp stays monotonic at every width and nothing
       renders under ~10.5px. 3xs used to bottom out at 9.3px, and 2xl used to
       fall below xl below ~836px, which made the price bigger than the section
       headline on every phone. */
    --fs-3xs: clamp(0.66rem, 0.630rem + 0.13vw, 0.72rem);
    --fs-2xs: clamp(0.70rem, 0.672rem + 0.12vw, 0.78rem);
    --fs-xs:  clamp(0.78rem, 0.745rem + 0.15vw, 0.88rem);
    --fs-s:   clamp(0.88rem, 0.845rem + 0.15vw, 0.98rem);
    --fs-m:   clamp(0.98rem, 0.931rem + 0.21vw, 1.12rem);
    --fs-l:   clamp(1.10rem, 0.960rem + 0.60vw, 1.50rem);
    --fs-xl:  clamp(1.70rem, 1.455rem + 1.05vw, 2.40rem);
    --fs-2xl: clamp(1.85rem, 1.525rem + 1.39vw, 2.60rem);
    --fs-3xl: clamp(2.00rem, 1.440rem + 2.39vw, 3.60rem);
    --fs-4xl: clamp(2.40rem, 1.490rem + 3.89vw, 5.00rem);

    /* fluid space ---------------------------------------------------------- */
    --section-y: clamp(56px, 7.5vw, 120px);
    --gutter:    clamp(20px, 2.6vw, 32px);
    /* mono runs wide, so the page column is wider than a sans site would take.
       safe to widen because every prose block is capped in ch below, which
       holds line length no matter how much room the container is given. */
    --measure:   1240px;
    --stack-s:   clamp(10px, 1.2vw, 16px);
    --stack-m:   clamp(20px, 2.6vw, 32px);
    --stack-l:   clamp(32px, 4.2vw, 56px);
}

/* base -------------------------------------------------------------------- */
*, *::before, *::after { margin: 0; padding: 0; box-sizing: border-box; }

html {
    scroll-behavior: smooth;
    scroll-padding-top: calc(var(--header-h) + 16px);
    -webkit-text-size-adjust: 100%;
}

body {
    background: var(--black);
    color: var(--white);
    /* the bible is explicit: JetBrains Mono, no other fonts. */
    font-family: var(--mono);
    font-size: var(--fs-s);
    line-height: 1.75;
    letter-spacing: 0.005em;
    overflow-x: hidden;
    /* light type on pure black gains weight without this */
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    text-rendering: optimizeLegibility;
}

/* headings set tight and balanced; body avoids single-word last lines */
h1, h2, h3, .closer-h, .panel-kicker, .display-line, .legend-foot {
    text-wrap: balance;
}

p, li, blockquote { text-wrap: pretty; }

::selection { background: var(--green); color: var(--black); }

/* horizontal rails must not hand their overscroll to the page: without this,
   swiping a rail to its end bounces the whole document on ios. */
.steps, .tabbar { overscroll-behavior-inline: contain; }

/* prices line up as a column of figures, so they get real tabular figures */
.plan-amt, .pack-qty, .pack-amt, .plan-per { font-variant-numeric: tabular-nums; }

h1, h2, h3 { font-family: var(--mono); font-weight: 700; }

a { color: var(--green); }

:focus-visible {
    outline: 2px solid var(--green);
    outline-offset: 3px;
}

button { -webkit-tap-highlight-color: transparent; }

.sr-only {
    position: absolute;
    width: 1px; height: 1px;
    padding: 0; margin: -1px;
    overflow: hidden;
    clip: rect(0 0 0 0);
    white-space: nowrap;
    border: 0;
}

/* short lead copy balances its lines rather than filling greedily, which is
   what left "The Guy." alone on a third line under the hero. brand name and
   "text box" also carry nbsp in the markup so neither can ever split. */
/* balance is a headline tool: it evens every line to the same length, which on
   a left-aligned paragraph produces a rag that reads as a mistake rather than
   as type. headlines get balance, running copy gets pretty, which only pulls up
   orphans and otherwise lets the lines fill naturally. */
.h2,
.closer-h,
.hero-h1,
.plan-name {
    text-wrap: balance;
}

.hero-sub,
.price-lead,
.section-lead,
.closer-body,
.plan-sub,
.how-desc,
.scene-label,
.share-q {
    text-wrap: pretty;
}

.container {
    max-width: var(--measure);
    margin: 0 auto;
    padding-left: var(--gutter);
    padding-right: var(--gutter);
}

.section { padding: var(--section-y) 0; }

/* type -------------------------------------------------------------------- */
.label {
    font-family: var(--mono);
    font-weight: 500;
    font-size: var(--fs-2xs);
    letter-spacing: 0.08em;
    color: var(--green);
    margin-bottom: 14px;
}

.h2 {
    font-size: var(--fs-2xl);
    line-height: 1.15;
    margin-bottom: var(--stack-m);
}

.prose { max-width: 62ch; }

.prose p { margin-bottom: 1.5em; }

.prose p:last-child { margin-bottom: 0; }

.prose .green {
    font-style: normal;
    color: var(--green);
}

/* buttons ----------------------------------------------------------------- */
.btn {
    position: relative;
    display: inline-block;
    overflow: hidden;
    font-family: var(--mono);
    font-weight: 700;
    font-size: var(--fs-xs);
    letter-spacing: 0.04em;
    text-decoration: none;
    text-align: center;
    padding: 0.95rem 2rem;
    border: 1px solid var(--green);
    cursor: pointer;
    transition: background 150ms ease, color 150ms ease, box-shadow 150ms ease;
}

/* the scan ------------------------------------------------------------------
   a skewed band passes across the button, then the button sits still. the
   reference version sweeps every 2s, which on a page with five buttons reads as
   a page full of things demanding attention. here the pass takes ~1.5s of a 7s
   cycle, so each button is quiet ~80% of the time, and the delays below stagger
   them so they never sweep in unison.

   the band is tinted per variant because the sweep has to contrast with what it
   crosses: green on the outlined buttons, white on the solid green ones, where
   a green band would be invisible.
   -------------------------------------------------------------------------- */
.btn::before {
    content: '';
    position: absolute;
    top: 0;
    left: 0;
    width: 42%;
    height: 100%;
    pointer-events: none;
    transform: skewX(-20deg) translateX(-190%);
    animation: btn-scan 7s ease-in-out infinite;
}

@keyframes btn-scan {
    0%   { transform: skewX(-20deg) translateX(-190%); }
    22%  { transform: skewX(-20deg) translateX(330%); }
    100% { transform: skewX(-20deg) translateX(330%); }
}

/* stagger so no two buttons pass at the same moment. side-by-side pairs get
   their own offsets, otherwise the two hero CTAs and the two pricing CTAs
   sweep in lockstep and read as one wide flash. */
.nav .btn::before                  { animation-delay: 2.6s; }
.hero-ctas .btn:first-child::before { animation-delay: 0s; }
.hero-ctas .btn:last-child::before  { animation-delay: 3.1s; }
.plan .btn::before                 { animation-delay: 1.3s; }
.plan-best .btn::before            { animation-delay: 4.5s; }
.closer .btn::before               { animation-delay: 3.4s; }
.doc-section .btn::before          { animation-delay: 1.9s; }
.footer .btn::before               { animation-delay: 5.2s; }

@media (prefers-reduced-motion: reduce) {
    .btn::before { animation: none; opacity: 0; }
}

.btn-primary {
    background: var(--green);
    color: var(--black);
}

.btn-primary::before {
    background: linear-gradient(
        90deg,
        transparent,
        rgba(255, 255, 255, 0.42),
        transparent
    );
}

.btn-ghost::before {
    background: linear-gradient(
        90deg,
        transparent,
        rgba(57, 255, 20, 0.38),
        transparent
    );
}

.btn-primary::after {
    content: ' _';
    animation: blink 1s step-end infinite;
}

.btn-primary:hover {
    background: var(--black);
    color: var(--green);
    box-shadow: 0 0 24px var(--green-dim);
}

.btn-ghost {
    background: transparent;
    color: var(--green);
}

.btn-ghost:hover {
    background: var(--green-dim);
    box-shadow: 0 0 24px var(--green-dim);
}

.btn-small {
    font-size: var(--fs-2xs);
    padding: 0.55rem 0.9rem;
}

@keyframes blink {
    0%, 50% { opacity: 1; }
    51%, 100% { opacity: 0; }
}

.block-cursor {
    display: inline-block;
    color: var(--green);
    animation: blink 1s step-end infinite;
}

/* header ------------------------------------------------------------------ */
.site-header {
    position: sticky;
    top: 0;
    z-index: 100;
    background: var(--black);
    border-bottom: 1px solid var(--green-dim);
}

.header-inner {
    max-width: var(--measure);
    margin: 0 auto;
    min-height: var(--header-h);
    padding: 8px var(--gutter);
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
}

.logo {
    font-family: var(--mono);
    font-weight: 700;
    font-size: var(--fs-s);
    color: var(--green);
    text-decoration: none;
    white-space: nowrap;
}

.cap {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 2px;
    font-family: var(--mono);
}

.cap-track {
    font-size: var(--fs-3xs);
    letter-spacing: 0;
    color: var(--green);
    white-space: nowrap;
}

.cap-label {
    font-size: var(--fs-3xs);
    letter-spacing: 0.08em;
    color: var(--gray);
    white-space: nowrap;
}

.nav {
    display: flex;
    align-items: center;
    gap: 20px;
}

.nav-link {
    /* the links are the whole mobile nav now, so they carry their own tap
       height rather than relying on the 20px text line box */
    padding: 10px 0;
    font-family: var(--mono);
    font-weight: 500;
    font-size: var(--fs-2xs);
    letter-spacing: 0.08em;
    color: var(--white);
    text-decoration: none;
    transition: color 150ms ease;
}

.nav-link:hover { color: var(--green); }

/* the header ------------------------------------------------------------------
   flush at the top of the page, then it detaches. once you scroll it lifts into
   a bar inset from the edges with its own edge and a faint green ground under
   it, so the page appears to slide beneath the nav rather than behind a lid.

   the reference for this floats a rounded pill. the pill is the part that does
   not transfer: square corners, and the separation comes from a hairline plus a
   low green bloom instead of a blur.
   ---------------------------------------------------------------------------- */
.nav-link { display: inline; }

.site-header {
    transition: padding 460ms cubic-bezier(0.16, 1, 0.3, 1),
                background 300ms linear,
                border-color 300ms linear;
}

.site-header[data-stuck] {
    padding: 12px var(--gutter);
    background: transparent;
    border-bottom-color: transparent;
}

.site-header[data-stuck] .header-inner {
    max-width: calc(var(--measure) - 2 * var(--gutter));
    background: rgba(0, 0, 0, 0.94);
    border: 1px solid rgba(57, 255, 20, 0.4);
    box-shadow:
        0 0 0 1px rgba(57, 255, 20, 0.06),
        0 18px 50px -22px rgba(57, 255, 20, 0.55),
        0 4px 18px -8px rgba(0, 0, 0, 0.9);
    padding-left: clamp(16px, 1.8vw, 24px);
    padding-right: clamp(16px, 1.8vw, 24px);
    transform: translateY(2px);
}

.header-inner {
    border: 1px solid transparent;
    transition: background 300ms linear, border-color 300ms linear,
                box-shadow 420ms linear,
                max-width 460ms cubic-bezier(0.16, 1, 0.3, 1),
                transform 460ms cubic-bezier(0.16, 1, 0.3, 1),
                padding 460ms cubic-bezier(0.16, 1, 0.3, 1);
}

@media (max-width: 699px) {
    .nav-link { display: none; }
}

/* the meter left the header: logo, two links and a CTA is already a full row,
   and a scarcity readout competing with the CTA made the bar read as busy. it
   now lives in the drawer and at the foot of the page, where it has room. */
.cap { flex-direction: row; align-items: center; gap: 10px; }
.cap-track { font-size: var(--fs-2xs); }
.cap-label { font-size: var(--fs-3xs); }

/* the toggle: a 3x3 of squares. a monospace grid is a terminal glyph, which a
   hamburger is not, and unlike a hamburger it does not promise "links" when
   what is behind it is a directory. */
.navtoggle {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 42px;
    height: 42px;
    margin-left: -4px;
    margin-right: -8px;
    appearance: none;
    background: none;
    border: 0;
    padding: 0;
    cursor: pointer;
}

.navtoggle-grid {
    width: 18px;
    height: 18px;
    background-image: radial-gradient(circle, var(--green) 1.7px, transparent 1.8px);
    background-size: 6px 6px;
    background-position: 1px 1px;
    opacity: 0.85;
    transition: transform 320ms cubic-bezier(0.16, 1, 0.3, 1), opacity 200ms linear;
}

.navtoggle:hover .navtoggle-grid { opacity: 1; }

.navtoggle[aria-expanded="true"] .navtoggle-grid {
    transform: rotate(45deg) scale(0.86);
    opacity: 1;
}

.navtoggle:focus-visible { outline: 2px solid var(--green); outline-offset: 2px; }

/* the drawer -------------------------------------------------------------------
   it comes in from the right rather than dropping the full width of the page.
   a full-bleed dropdown covers the thing you were reading and gives four short
   columns a whole screen to rattle around in; a drawer keeps the page visible
   behind it, and a single column is the right shape for a list of destinations.
   ---------------------------------------------------------------------------- */
.nav-scrim {
    position: fixed;
    inset: 0;
    background: rgba(0, 0, 0, 0.62);
    opacity: 0;
    visibility: hidden;
    transition: opacity 300ms linear, visibility 0s linear 300ms;
}

.site-header[data-nav-open] .nav-scrim {
    opacity: 1;
    visibility: visible;
    transition: opacity 300ms linear, visibility 0s;
}

.nav-panel {
    position: fixed;
    top: 0;
    right: 0;
    height: 100dvh;
    width: min(430px, 88vw);
    overflow-y: auto;
    overscroll-behavior: contain;
    background: var(--black);
    border-left: 1px solid rgba(57, 255, 20, 0.3);
    box-shadow: -30px 0 70px -30px rgba(57, 255, 20, 0.32);
    transform: translateX(100%);
    visibility: hidden;
    transition: transform 460ms cubic-bezier(0.16, 1, 0.3, 1),
                visibility 0s linear 460ms;
}

.site-header[data-nav-open] .nav-panel {
    transform: none;
    visibility: visible;
    transition: transform 460ms cubic-bezier(0.16, 1, 0.3, 1), visibility 0s;
}

/* the panel covers the toggle once it slides over, so it carries its own close
   control and starts at the top of the screen rather than below the header.
   the sub-lists pair up: five compare links and four company links stacked in
   one column ran past the bottom of a laptop screen. */
.nav-panel-inner {
    display: flex;
    flex-direction: column;
    gap: clamp(22px, 3.2vh, 34px);
    padding: clamp(20px, 3vh, 30px) clamp(24px, 4.5vw, 34px) clamp(28px, 4vh, 40px);
}

.nav-panel-top {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding-bottom: clamp(4px, 1vh, 10px);
}

.nav-panel-title {
    font-size: var(--fs-2xs);
    letter-spacing: 0.16em;
    color: var(--green);
}

.nav-close {
    appearance: none;
    background: none;
    border: 1px solid rgba(57, 255, 20, 0.3);
    color: var(--green);
    width: 34px;
    height: 34px;
    font-size: var(--fs-m);
    line-height: 1;
    cursor: pointer;
    transition: background 160ms linear, border-color 160ms linear;
}

.nav-close:hover { background: rgba(57, 255, 20, 0.12); border-color: var(--green); }
.nav-close:focus-visible { outline: 2px solid var(--green); outline-offset: 2px; }

.nav-cols-pair {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: clamp(16px, 3vw, 26px);
}

.nav-col-title {
    font-size: var(--fs-3xs);
    letter-spacing: 0.16em;
    color: rgba(57, 255, 20, 0.6);
    margin-bottom: 9px;
}

.nav-col a {
    display: block;
    padding: 6px 0;
    color: var(--white);
    font-family: var(--mono);
    font-size: var(--fs-s);
    letter-spacing: 0.03em;
    text-decoration: none;
    transition: color 150ms linear, padding-left 220ms cubic-bezier(0.16, 1, 0.3, 1);
}

.nav-col a::before {
    content: '> ';
    color: rgba(57, 255, 20, 0.45);
    transition: color 150ms linear;
}

.nav-col a:hover,
.nav-col a:focus-visible {
    color: var(--green);
    padding-left: 6px;
}

.nav-col a:hover::before { color: var(--green); }

.nav-col-main a { font-size: var(--fs-l); padding: 8px 0; }

/* the meter earns its place in the drawer at every width now: the header only
   shows it above 700px, and the drawer is where the rest of the site lives */
.nav-col-cap { display: block; }
.cap-foot { margin-top: 16px; }

@media (min-width: 768px) {
    .foot-share .cap-foot { justify-content: flex-end; }
}

@media (prefers-reduced-motion: reduce) {
    .site-header, .header-inner, .nav-panel, .nav-scrim,
    .navtoggle-grid, .nav-col a { transition: none; }
}
}

/* hero -------------------------------------------------------------------- */
.hero {
    position: relative;
    padding: 72px 0;
}

@media (min-width: 768px) {
    .hero { padding: 120px 0 130px; }
}

/* scanlines: hero only, desktop only, barely there */
@media (min-width: 768px) {
    .hero::after {
        content: '';
        position: absolute;
        inset: 0;
        pointer-events: none;
        background: repeating-linear-gradient(
            0deg,
            rgba(57, 255, 20, 0.03) 0px,
            rgba(57, 255, 20, 0.03) 1px,
            transparent 1px,
            transparent 3px
        );
    }
}

.hero-grid {
    position: relative;
    z-index: 1;
    display: flex;
    flex-direction: column;
    gap: 56px;
}

@media (min-width: 900px) {
    .hero-grid {
        flex-direction: row;
        align-items: center;
        gap: 48px;
    }
    .hero-copy { flex: 0 1 55%; }
    .hero-visual { flex: 1 1 45%; display: flex; justify-content: center; }
}

.hero-h1 {
    font-size: var(--fs-4xl);
    line-height: 1.05;
    margin-bottom: 28px;
    overflow-wrap: break-word;
}

/* in the two-column layout the headline shares the row with the phone, so it
   needs a gentler fluid slope to break as "never fumble / again." instead of
   one word per line */
@media (min-width: 900px) {
}

.hero-h1 .block-cursor { margin-left: 0.08em; }

/* the symptom line. it names what he already knows before the sub tells him
   what to do about it. this was red-dim and unreadable at this size: red-dim
   is 70% of a mid red on black, which is fine on a two word stamp and not on
   a sentence. grey at 500 recedes under the headline without fighting it. */
.hero-hook {
    font-size: var(--fs-s);
    font-weight: 500;
    letter-spacing: 0.02em;
    max-width: 46ch;
    color: var(--gray);
    margin-bottom: 12px;
}

.hero-sub {
    font-size: var(--fs-m);
    max-width: 52ch;
    color: var(--white);
    margin-bottom: 36px;
}

.hero-ctas {
    display: flex;
    flex-wrap: wrap;
    gap: 14px;
    margin-bottom: 20px;
}

.trust {
    font-family: var(--mono);
    font-weight: 500;
    font-size: var(--fs-2xs);
    letter-spacing: 0.08em;
    color: var(--gray);
}

@media (max-width: 480px) {
    .hero-ctas { flex-direction: column; }
    .hero-ctas .btn { width: 100%; }
}

/* hero entrance: sub / ctas / trust / visual hidden until the scramble lands */
html.js .hero-item {
    opacity: 0;
    transform: translateY(14px);
    transition: opacity 0.5s ease-out, transform 0.5s ease-out;
}

html.js .hero-item.in {
    opacity: 1;
    transform: none;
}

/* phone mockup (pure css) -------------------------------------------------- */
.phone {
    width: min(300px, 82vw);
    aspect-ratio: 9 / 17;
    border: 1px solid rgba(57, 255, 20, 0.35);
    background: var(--black);
    display: flex;
    flex-direction: column;
    font-family: var(--mono);
    font-size: var(--fs-xs);
}

/* on phones the mockup takes the whole column. at 82vw it sat in a gutter of
   its own and read as an inset card rather than as the thing being shown.
   this has to come after the base rule: same specificity, so source order is
   what decides it. */
@media (max-width: 699px) {
    .phone { width: 100%; }
}

.phone-screen {
    flex: 1;
    padding: 22px 16px;
    display: flex;
    flex-direction: column;
    gap: 8px;
    justify-content: flex-end;
    overflow: hidden;
}

.pm-label {
    font-size: var(--fs-3xs);
    font-weight: 500;
    letter-spacing: 0.08em;
    color: var(--gray);
    margin-top: 8px;
}

.pm-bubble {
    max-width: 88%;
    padding: 10px 12px;
    border-radius: 4px;
    line-height: 1.5;
}

.pm-her {
    align-self: flex-start;
    background: rgba(138, 138, 138, 0.14);
    color: var(--white);
}

/* The Guy's read. this was grey until 2026-08-26 and was the hardest thing on
   the page to actually read; it is the product speaking, so it gets the green. */
.pm-roast {
    color: var(--green);
    font-size: var(--fs-2xs);
    line-height: 1.5;
}

.pm-reco {
    align-self: flex-end;
    background: rgba(57, 255, 20, 0.12);
    color: var(--green);
}

/* the line he was about to send. same red vocabulary the situations threads use
   for a message that landed badly. */
.pm-draft {
    align-self: flex-end;
    background: rgba(255, 107, 107, 0.08);
    color: var(--red-dim);
}

/* him talking to The Guy, which is not him talking to her: neutral, his side. */
.pm-you {
    align-self: flex-end;
    background: rgba(237, 237, 237, 0.06);
    color: var(--white);
}

/* the context line above her message. not a message, so no bubble. */
.pm-meta {
    font-size: var(--fs-3xs);
    letter-spacing: 0.08em;
    color: var(--gray);
    padding-bottom: 4px;
    border-bottom: 1px solid var(--border);
    margin-bottom: 4px;
}

/* the sting of the bad draft: needs to read, not fade into the gray meta line */
.pm-meta-bad {
    color: var(--red-dim);
    font-weight: 500;
}

/* hero reel ---------------------------------------------------------------
   beats are removed from flow rather than faded, so the thread grows upward
   from the input the way a real one does instead of sitting in a fixed block
   of empty space. it plays once and stops. no js and reduced motion both fall
   through to the finished scene, which is why the hiding is scoped to
   html.js. */
html.js [data-beat] { display: none; }

html.js [data-beat].beat-on {
    display: block;
    animation: beat-in 0.28s ease-out both;
}

@keyframes beat-in {
    from { opacity: 0; transform: translateY(6px); }
    to   { opacity: 1; transform: none; }
}

@media (prefers-reduced-motion: reduce) {
    html.js [data-beat] { display: block; }
    html.js [data-beat].beat-on { animation: none; }
}

.phone-input {
    border-top: 1px solid var(--border);
    padding: 12px 16px;
    font-size: var(--fs-xs);
}

/* scroll reveal ------------------------------------------------------------ */
html.js .rv {
    opacity: 0;
    transform: translateY(14px);
    transition: opacity 0.5s ease-out, transform 0.5s ease-out;
}

html.js .rv.on {
    opacity: 1;
    transform: none;
}

/* situations: tabs + scenes ------------------------------------------------- */
/* the tab bar is a command row, not a chrome tab strip. mobile: one scrolling
   line with snap. the active item carries the block cursor. */
.tabs { border: 1px solid var(--border); }

/* no scroll gradient here on purpose: it painted over the active tab, and a
   half-visible next tab is already the affordance. */
.tabbar-wrap { position: relative; }

/* the rail scrolls, so the edges fade to say so. an earlier pass laid a
   gradient OVER the tabs and it covered the active one; a mask fades the tabs
   themselves instead, and only on the side that still has somewhere to go, so a
   fully-scrolled rail has hard edges and never fakes hidden content. */
.tabbar {
    --fade: 30px;
    display: flex;
    gap: 0;
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    scroll-padding-left: 1px;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
    border-bottom: 1px solid var(--border);
    -webkit-mask-image: linear-gradient(90deg, transparent 0, #000 var(--fade), #000 calc(100% - var(--fade)), transparent 100%);
    mask-image: linear-gradient(90deg, transparent 0, #000 var(--fade), #000 calc(100% - var(--fade)), transparent 100%);
}

.tabbar[data-at-start] {
    -webkit-mask-image: linear-gradient(90deg, #000 0, #000 calc(100% - var(--fade)), transparent 100%);
    mask-image: linear-gradient(90deg, #000 0, #000 calc(100% - var(--fade)), transparent 100%);
}

.tabbar[data-at-end] {
    -webkit-mask-image: linear-gradient(90deg, transparent 0, #000 var(--fade), #000 100%);
    mask-image: linear-gradient(90deg, transparent 0, #000 var(--fade), #000 100%);
}

.tabbar[data-at-start][data-at-end] {
    -webkit-mask-image: none;
    mask-image: none;
}

.tabbar::-webkit-scrollbar { display: none; }

.tab {
    flex: 0 0 auto;
    scroll-snap-align: start;
    appearance: none;
    background: none;
    border: 0;
    border-right: 1px solid var(--border);
    /* the inactive tabs sat at 400 in --gray and went muddy against black.
       500 is the mid weight the family is already loaded at, and the lift in
       colour does as much for legibility as the weight does. */
    color: rgba(237, 237, 237, 0.62);
    font-family: var(--mono);
    font-weight: 500;
    font-size: var(--fs-xs);
    letter-spacing: 0.02em;
    padding: 14px 16px;
    cursor: pointer;
    white-space: nowrap;
    transition: color 220ms cubic-bezier(0.4, 0, 0.2, 1), background 220ms cubic-bezier(0.4, 0, 0.2, 1);
}

.tab:hover { color: var(--white); }

.tab::before {
    content: '> ';
    color: rgba(57, 255, 20, 0.35);
}

/* a tab group marked data-sequence is a timeline, not a menu: these six
   scenarios happen in this order, so the index is real information and it
   replaces the prompt caret rather than sitting next to it. */
.tabs[data-sequence] .tabbar { counter-reset: sit; }

.tabs[data-sequence] .tab::before {
    counter-increment: sit;
    content: counter(sit, decimal-leading-zero) "  ";
    color: rgba(57, 255, 20, 0.4);
}

.tabs[data-sequence] .tab[aria-selected="true"]::before {
    color: rgba(0, 0, 0, 0.55);
}

.tab:hover { color: var(--white); }

.tab[aria-selected="true"] {
    color: var(--black);
    background: var(--green);
}

.tab[aria-selected="true"]::before { color: var(--black); }

.tab:focus-visible {
    outline: 2px solid var(--green);
    outline-offset: -2px;
}

.tabpanel { padding: 28px 22px; }

@media (min-width: 768px) {
    /* once the whole timeline fits, the tabs grow to fill the bar instead of
       leaving dead space at the end. auto basis keeps them proportional to
       their labels rather than forcing six equal cells. */
    .tab { flex: 1 1 auto; font-size: var(--fs-xs); padding: 16px 18px; }
    .tabpanel { padding: clamp(36px, 3.4vw, 52px); }
}

.scene-context { margin-bottom: 28px; }

.scene-label {
    font-family: var(--mono);
    font-weight: 500;
    font-size: var(--fs-xs);
    letter-spacing: 0.08em;
    color: var(--gray);
    margin-bottom: 10px;
}

.scene-context .m-her { max-width: 34ch; }

.scene-grid {
    display: grid;
    grid-template-columns: 1fr;
    gap: 36px;
}

@media (min-width: 768px) {
    .scene-grid { grid-template-columns: 1fr 1fr; gap: 48px; }
}

.thread {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 10px;
    font-family: var(--mono);
    font-size: var(--fs-s);
}

.thread-label {
    font-family: var(--mono);
    font-weight: 500;
    font-size: var(--fs-2xs);
    letter-spacing: 0.08em;
    margin-bottom: 6px;
}

.thread-bad .thread-label { color: var(--red-dim); }
.thread-guy .thread-label { color: var(--green); }

.msg {
    max-width: 92%;
    padding: 10px 14px;
    border-radius: 4px;
    line-height: 1.55;
}

.m-her {
    align-self: flex-start;
    background: rgba(138, 138, 138, 0.14);
    color: var(--white);
}

.m-draft {
    align-self: flex-end;
    background: rgba(255, 107, 107, 0.08);
    color: var(--red-dim);
}

.m-guy {
    align-self: flex-end;
    background: rgba(57, 255, 20, 0.1);
    color: var(--green);
}

.stamp {
    align-self: stretch;
    margin-top: 10px;
    padding-top: 12px;
    font-family: var(--mono);
    font-weight: 500;
    font-size: var(--fs-2xs);
    letter-spacing: 0.08em;
}

.stamp-bad {
    color: var(--red-dim);
    border-top: 1px solid rgba(255, 107, 107, 0.2);
}

.stamp-good {
    color: var(--green);
    border-top: 1px solid var(--border);
}

/* the beat after the ghosting: where she actually went. not a message, so no
   bubble, and deliberately grey rather than red because it is not his failure
   speaking, it is what happened next. */
.aside {
    align-self: stretch;
    margin-top: 8px;
    font-family: var(--mono);
    font-size: var(--fs-2xs);
    line-height: 1.6;
    letter-spacing: 0.02em;
    color: var(--gray);
}

.read {
    align-self: stretch;
    margin-top: 8px;
    font-family: var(--mono);
    font-size: var(--fs-2xs);
    line-height: 1.5;
    letter-spacing: 0.02em;
    opacity: 0.85;
}

.read-bad { color: var(--red-dim); }
.read-good { color: var(--green); }

/* THE SIGNATURE -------------------------------------------------------------
   the read, rendered the way an editor renders a problem in a line you did not
   notice: a wavy underline plus a margin marker. the whole product claim is
   "there is a layer under your message you cannot see", and a compiler warning
   is the one device in this vocabulary that means exactly that. red = what it
   cost you. green = what it bought you. */
.anno {
    align-self: stretch;
    display: flex;
    gap: 10px;
    margin-top: -2px;
    padding-top: 10px;
    font-family: var(--mono);
    font-size: var(--fs-2xs);
    line-height: 1.6;
    letter-spacing: 0.01em;
    background-repeat: repeat-x;
    background-position: top left;
    background-size: 6px 3px;
}

.anno + .stamp {
    border-top: 0;
    margin-top: 2px;
    padding-top: 6px;
}

.anno-mark { flex: 0 0 auto; font-weight: 700; }
.anno-text { display: block; }
.anno-text b { font-weight: 700; letter-spacing: 0.04em; }

.anno-bad {
    color: var(--red-dim);
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 6 3'%3E%3Cpath d='M0 2.2 Q1.5 0.2 3 2.2 T6 2.2' stroke='%23FF6B6B' stroke-opacity='0.75' fill='none' stroke-width='0.9'/%3E%3C/svg%3E");
}

.anno-good {
    color: var(--green);
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 6 3'%3E%3Cpath d='M0 2.2 Q1.5 0.2 3 2.2 T6 2.2' stroke='%2339FF14' stroke-opacity='0.6' fill='none' stroke-width='0.9'/%3E%3C/svg%3E");
}

/* proof / testimonials (empty until real quotes exist) ---------------------- */
.proof-grid {
    display: grid;
    grid-template-columns: 1fr;
    gap: 20px;
}

@media (min-width: 768px) {
    .proof-grid { grid-template-columns: repeat(3, 1fr); }
}

.proof-card { border: 1px solid var(--border); padding: 24px; }
.proof-card blockquote { font-size: var(--fs-s); line-height: 1.65; }

.proof-card figcaption {
    font-family: var(--mono);
    font-size: var(--fs-2xs);
    letter-spacing: 0.08em;
    color: var(--gray);
    margin-top: 16px;
}

/* replay animation: messages hidden until popped in by js */
html.js [data-pop] {
    opacity: 0;
    transform: scale(0.97) translateY(5px);
    transition: opacity 0.25s ease-out, transform 0.25s ease-out;
}

html.js [data-pop].on {
    opacity: 1;
    transform: none;
}

html.js .stamp.on {
    animation: settle 0.3s ease-out;
}

@keyframes settle {
    0% { transform: scale(1.03); }
    100% { transform: scale(1); }
}

.section-cta {
    margin-top: 48px;
    text-align: center;
}

/* terminal (signature) ------------------------------------------------------ */
.terminal {
    border: 1px solid var(--green);
    background: var(--black);
    max-width: 860px;
}

.terminal-bar {
    display: flex;
    align-items: center;
    gap: 14px;
    padding: 12px 16px;
    border-bottom: 1px solid var(--border);
}

.t-dots {
    display: flex;
    gap: 6px;
}

.t-dots i {
    width: 9px;
    height: 9px;
    background: var(--green-dim);
}

.t-title {
    font-family: var(--mono);
    font-weight: 500;
    font-size: var(--fs-2xs);
    letter-spacing: 0.08em;
    color: var(--gray);
}

.terminal-body { padding: 20px 16px 24px; }

@media (min-width: 768px) {
    .terminal-body { padding: 28px 28px 32px; }
}

.chips {
    display: flex;
    flex-wrap: wrap;
    gap: 10px;
    padding-bottom: 20px;
    border-bottom: 1px solid var(--border);
    margin-bottom: 20px;
}

.chip {
    font-family: var(--mono);
    font-size: var(--fs-xs);
    background: transparent;
    color: var(--white);
    border: 1px solid rgba(57, 255, 20, 0.35);
    padding: 9px 14px;
    cursor: pointer;
    transition: background 150ms ease, color 150ms ease, border-color 150ms ease;
}

.chip:hover {
    background: var(--green-dim);
    border-color: var(--green);
}

.chip[aria-pressed="true"] {
    background: var(--green);
    color: var(--black);
    border-color: var(--green);
}

.t-output {
    font-family: var(--mono);
    font-size: var(--fs-s);
    line-height: 1.6;
    min-height: 340px;
}

@media (min-width: 768px) {
    .t-output { min-height: 250px; }
}

.t-line { margin-bottom: 0.7em; }

.t-line:last-child { margin-bottom: 0; }

.t-her { color: var(--white); }

.t-draft { color: var(--red-dim); }

.t-roast { color: var(--gray); }

.t-think { color: var(--gray); }

.t-reco { color: var(--green); }

.t-cta a {
    color: var(--green);
    text-decoration: underline;
    text-underline-offset: 3px;
}

.t-cta a:hover { background: var(--green-dim); }

.t-caret {
    display: inline-block;
    width: 0.55em;
    height: 1em;
    margin-left: 2px;
    vertical-align: text-bottom;
    background: var(--green);
    animation: blink 1s step-end infinite;
}

/* persistent cursor on the finished recommendation line */
.t-reco .reco-cursor {
    display: inline-block;
    color: var(--green);
    margin-left: 0.15em;
    animation: blink 1s step-end infinite;
}

.scope-line {
    font-family: var(--mono);
    font-size: var(--fs-xs);
    line-height: 1.6;
    color: var(--gray);
    margin-top: 48px;
    letter-spacing: 0.02em;
}

/* not for everyone ----------------------------------------------------------- */
.not-list {
    list-style: none;
    max-width: 62ch;
    margin-bottom: 40px;
}

.not-list li {
    font-family: var(--mono);
    font-size: var(--fs-s);
    padding: 10px 0;
}

.not-list .x {
    color: var(--red);
    margin-right: 14px;
}

.display-line {
    font-family: var(--mono);
    font-weight: 700;
    font-size: var(--fs-l);
    line-height: 1.3;
    color: var(--green);
    margin-top: 56px;
    max-width: 26ch;
}

/* how it works --------------------------------------------------------------- */
/* how it works: stepper + stage ----------------------------------------------
   steps left, one stage right. the stage advances on a timer and the active
   step fills a progress line, so the sequence plays itself. it is a real
   sequence, so the numbering is real information.
   ---------------------------------------------------------------------------- */
.how {
    display: grid;
    grid-template-columns: 1fr;
    gap: var(--stack-l);
    align-items: start;
}

@media (min-width: 860px) {
    .how { grid-template-columns: minmax(0, 1fr) minmax(0, 0.9fr); gap: clamp(40px, 5vw, 72px); }
}

/* each step is its own card. they were a single ruled column before, which read
   as one list with a moving marker rather than three things. same surface
   language as the FAQ rows: neutral fill at rest, green fill plus a lit left
   edge when active, so "active" means the same thing everywhere on the page. */
.how-steps { display: flex; flex-direction: column; gap: 8px; }

.how-step {
    position: relative;
    appearance: none;
    background: rgba(237, 237, 237, 0.045);
    border: 0;
    border-left: 2px solid transparent;
    text-align: left;
    display: flex;
    gap: 18px;
    padding: 22px 24px 24px 22px;
    cursor: pointer;
    color: inherit;
    font: inherit;
    transition: background 300ms cubic-bezier(0.4, 0, 0.2, 1);
}

.how-step:hover { background: rgba(237, 237, 237, 0.075); }

/* the active card is lit BY its own edge. rather than a flat green wash, the
   fill is a horizontal falloff that is brightest against the progress bar and
   gone by two thirds across, so the bar reads as the light source and the card
   reads as the surface it falls on. the scanline layer only shows up where that
   light lands, which is what gives the green some structure instead of being a
   tint. both effects are on the bible's own list; the idea underneath them is
   one thing, not three.

   hover previews the same gradient at a fraction of the strength, so the
   interaction hints at what selecting will do. */
/* the lighting lives on its own layer and crossfades. putting it on
   `background` meant switching between two different background definitions,
   and gradients cannot interpolate, so every step change hard-cut. an opacity
   fade on a layer that is always present is the only way this gets smooth. */
.how-step::after {
    content: '';
    position: absolute;
    inset: 0;
    pointer-events: none;
    opacity: 0;
    transition: opacity 420ms cubic-bezier(0.4, 0, 0.2, 1);
    background:
        repeating-linear-gradient(
            to bottom,
            rgba(57, 255, 20, 0.07) 0px,
            rgba(57, 255, 20, 0.07) 1px,
            transparent 1px,
            transparent 3px
        ),
        linear-gradient(
            90deg,
            rgba(57, 255, 20, 0.30) 0%,
            rgba(57, 255, 20, 0.12) 36%,
            rgba(57, 255, 20, 0) 70%
        );
}

.how-step[aria-selected="true"]::after { opacity: 1; }

/* the label sits above its own lighting */
.how-step > * { position: relative; z-index: 1; }

.how-step:not([aria-selected="true"]):hover {
    background:
        linear-gradient(
            90deg,
            rgba(57, 255, 20, 0.06) 0%,
            rgba(57, 255, 20, 0) 52%
        ),
        rgba(237, 237, 237, 0.055);
}

/* the progress line rides the left edge of the active card and doubles as the
   dwell timer, so the card shows how long it has left */
.how-step::before {
    content: '';
    position: absolute;
    left: -2px;
    top: 0;
    width: 2px;
    height: 100%;
    background: var(--green);
    transform: scaleY(0);
    transform-origin: top;
}

.how-step[aria-selected="true"]::before {
    transform: scaleY(1);
    box-shadow: 0 0 10px rgba(57, 255, 20, 0.6), 0 0 24px rgba(57, 255, 20, 0.25);
}

.how[data-running] .how-step[aria-selected="true"]::before {
    animation: how-fill var(--how-dwell, 5200ms) linear forwards;
}

@keyframes how-fill { from { transform: scaleY(0); } to { transform: scaleY(1); } }

.how-num {
    flex: 0 0 auto;
    font-weight: 500;
    font-size: var(--fs-2xs);
    letter-spacing: 0.1em;
    color: rgba(57, 255, 20, 0.4);
    padding-top: 4px;
    transition: color 200ms linear;
}

.how-step[aria-selected="true"] .how-num { color: var(--green); }

.how-body { display: block; }

.how-title {
    display: block;
    font-weight: 700;
    font-size: var(--fs-l);
    line-height: 1.25;
    color: rgba(237, 237, 237, 0.45);
    margin-bottom: 8px;
    transition: color 200ms linear;
}

.how-step[aria-selected="true"] .how-title { color: var(--white); }

.how-desc {
    display: block;
    font-size: var(--fs-s);
    line-height: 1.7;
    color: rgba(237, 237, 237, 0.35);
    max-width: 44ch;
    transition: color 200ms linear;
}

.how-step[aria-selected="true"] .how-desc { color: rgba(237, 237, 237, 0.8); }

.how-step:hover .how-title { color: var(--white); }

.how-step:focus-visible { outline: 2px solid var(--green); outline-offset: 2px; }

.how-stage { display: flex; justify-content: center; }

.how-stage .phone { width: 100%; max-width: 300px; }

.stage-panel { animation: stage-in 260ms ease-out; }

@keyframes stage-in {
    from { opacity: 0; transform: translateY(6px); }
    to { opacity: 1; transform: none; }
}

/* a pasted attachment, step 01 */
.pm-attach {
    align-self: flex-end;
    border: 1px dashed rgba(57, 255, 20, 0.45);
    color: var(--green);
    font-size: var(--fs-3xs);
    letter-spacing: 0.06em;
    padding: 10px 12px;
}

/* .pm-dim retired 2026-08-26: the read is green now, nothing dims it. */

.pm-stamp {
    align-self: stretch;
    margin-top: 10px;
    padding-top: 10px;
    border-top: 1px solid var(--border);
    font-size: var(--fs-3xs);
    letter-spacing: 0.08em;
    color: var(--green);
}

.phone-hint {
    font-size: var(--fs-3xs);
    letter-spacing: 0.08em;
    color: var(--gray);
    margin-right: 6px;
}

@media (prefers-reduced-motion: reduce) {
    .how[data-running] .how-step[aria-selected="true"]::before { animation: none; transform: scaleY(1); }
    .stage-panel { animation: none; }
    .how-num, .how-title, .how-desc { transition: none; }
}

/* pricing -------------------------------------------------------------------
   two cards. the featured one carries depth from the bible's own Effects list
   (scanline overlay, phosphor glow) rather than a SaaS bloom gradient: same
   premium weight, no new hues, no rounded corners.
   -------------------------------------------------------------------------- */
.price-lead,
.section-lead {
    font-size: var(--fs-m);
    line-height: 1.7;
    color: var(--gray);
    max-width: 56ch;
    margin-bottom: var(--stack-l);
}

.plans {
    display: grid;
    grid-template-columns: 1fr;
    gap: 20px;
    align-items: start;
}

/* single column: lead with the $14 subscription so the $5 pack lands as relief
   rather than as the opening price. the two-column layout keeps packs on the
   left, where reading order already puts the cheaper option first. */
@media (max-width: 779px) {
    .plan-best { order: -1; }
}

@media (min-width: 780px) {
    .plans { grid-template-columns: 1fr 1fr; gap: 28px; }
}

.plan {
    position: relative;
    border: 1px solid var(--border);
    padding: clamp(24px, 3vw, 36px);
    display: flex;
    flex-direction: column;
    height: 100%;
}

/* the featured card: phosphor bloom plus scanlines. green only. */
.plan-best {
    border-color: rgba(57, 255, 20, 0.55);
    box-shadow:
        0 0 0 1px rgba(57, 255, 20, 0.10),
        0 0 40px -10px rgba(57, 255, 20, 0.18),
        inset 0 0 70px -34px rgba(57, 255, 20, 0.22);
}

.plan-best::after {
    content: '';
    position: absolute;
    inset: 0;
    pointer-events: none;
    background: repeating-linear-gradient(
        to bottom,
        rgba(57, 255, 20, 0.045) 0px,
        rgba(57, 255, 20, 0.045) 1px,
        transparent 1px,
        transparent 3px
    );
}

.plan > * { position: relative; z-index: 1; }

/* the aura -------------------------------------------------------------------
   a broad green gradient turns clockwise behind the card's content. two soft
   lobes rather than an even sweep, so the light builds and fades instead of
   strobing past at a constant rate.

   the conic's convergence point is parked off the card's top-left corner: a
   conic centred in the box shows its spokes meeting in the middle and reads as
   a pinwheel. pushed off-canvas, the card only ever sees a wide arc of it, so
   it reads as light moving through.

   alphas are deliberately low. an earlier pass ran a bright drifting bloom in
   here and the card went from lit to washed out; the border and the price
   should be the brightest greens on the card, not the background.
   -------------------------------------------------------------------------- */
.plan-best { overflow: hidden; }

.plan .plan-aura {
    position: absolute;
    top: 50%;
    left: 50%;
    width: 260%;
    aspect-ratio: 1;
    translate: -62% -56%;
    z-index: 0;
    pointer-events: none;
    background: conic-gradient(
        from 0deg,
        transparent 0deg,
        rgba(57, 255, 20, 0.10) 62deg,
        transparent 145deg,
        rgba(57, 255, 20, 0.055) 232deg,
        transparent 318deg,
        transparent 360deg
    );
    animation: aura-rotate 24s linear infinite;
}

@keyframes aura-rotate {
    to { rotate: 360deg; }
}

@media (prefers-reduced-motion: reduce) {
    .plan .plan-aura { animation: none; rotate: 40deg; }
}

.plan-tag {
    align-self: flex-start;
    background: var(--green);
    color: var(--black);
    font-weight: 700;
    font-size: var(--fs-3xs);
    letter-spacing: 0.12em;
    padding: 4px 10px;
    margin-bottom: 18px;
}

.plan-name {
    font-weight: 700;
    font-size: var(--fs-l);
    line-height: 1.25;
    color: var(--white);
    margin-bottom: 10px;
}

.plan-best .plan-name { color: var(--green); }

.plan-sub {
    font-size: var(--fs-xs);
    line-height: 1.7;
    color: var(--gray);
    margin-bottom: var(--stack-m);
    max-width: 34ch;
}

.plan-price { margin-bottom: 6px; }

.plan-amt {
    font-weight: 700;
    font-size: var(--fs-xl);
    color: var(--white);
    font-variant-numeric: tabular-nums;
}

.plan-per { font-size: var(--fs-s); color: var(--gray); margin-left: 4px; }

/* credit packs read as a price list, so they align as one */
.packs { list-style: none; margin-bottom: var(--stack-m); }

.packs li {
    display: grid;
    grid-template-columns: 1fr auto;
    grid-template-areas: "name amt" "qty amt";
    gap: 2px 16px;
    align-items: center;
    padding: 14px 0;
    border-bottom: 1px solid var(--border);
}

.packs li:last-child { border-bottom: 0; }

.pack-name { grid-area: name; font-size: var(--fs-xs); color: var(--white); }
.pack-qty { grid-area: qty; font-size: var(--fs-2xs); color: var(--gray); font-variant-numeric: tabular-nums; }

.pack-amt {
    grid-area: amt;
    font-weight: 700;
    font-size: var(--fs-l);
    color: var(--green);
    font-variant-numeric: tabular-nums;
}

.perks { list-style: none; margin-bottom: var(--stack-m); }

.perks li {
    position: relative;
    padding: 9px 0 9px 22px;
    font-size: var(--fs-s);
    line-height: 1.6;
}

.perks li::before {
    content: '>';
    position: absolute;
    left: 0;
    color: rgba(57, 255, 20, 0.5);
}

.plan-cta { margin-top: auto; text-align: center; }


/* dynamic glow ---------------------------------------------------------------
   opt in with data-glow on any element. a soft phosphor bloom tracks the
   pointer across the surface; script.js writes --gx/--gy. this is the bible's
   "glow following mouse" effect, and it is a utility rather than a one-off so
   other key surfaces can take it.
   touch devices have no pointer, so they get a slow breathe instead of nothing.
   reduced motion gets a still bloom, centred.
   ---------------------------------------------------------------------------- */
[data-glow] {
    --gx: 50%;
    --gy: 0%;
    position: relative;
    isolation: isolate;
}

[data-glow]::before {
    content: '';
    position: absolute;
    inset: 0;
    z-index: 0;
    pointer-events: none;
    background: radial-gradient(
        circle 280px at var(--gx) var(--gy),
        rgba(57, 255, 20, 0.20),
        rgba(57, 255, 20, 0.06) 45%,
        transparent 72%
    );
}

@media (hover: none) {
    [data-glow]::before { animation: glow-breathe 6s ease-in-out infinite; }
}

@keyframes glow-breathe {
    0%, 100% { opacity: 0.5; }
    50% { opacity: 1; }
}

@media (prefers-reduced-motion: reduce) {
    [data-glow]::before { animation: none; opacity: 0.8; }
}

/* proof ----------------------------------------------------------------------
   six columns. two measured tiles, a full-width panel for the outlier, then the
   quotes. the composition argues: typical case, best case, what it sounded like.

   the tiles follow the reference that prompted this: hairline border, near-black
   fill, and the CAPTION ABOVE the number rather than under it. the label has to
   land first, because "12" means nothing until you know it is messages, and a
   number you have to re-read is a number you do not trust.

   the panel is the only place in the section with atmosphere. three slow radial
   blobs drift behind it so the light is organic rather than a clean gradient,
   which is what separates the reference from the usual bento tile. everything
   else in the block stays flat so the panel is unmistakably the moment.
   ---------------------------------------------------------------------------- */
.label-flag {
    margin-left: 10px;
    padding: 2px 7px;
    background: rgba(255, 107, 107, 0.14);
    border: 1px solid rgba(255, 107, 107, 0.45);
    color: var(--red);
    font-size: var(--fs-3xs);
    letter-spacing: 0.1em;
}

.proof-grid {
    display: grid;
    grid-template-columns: repeat(6, 1fr);
    gap: 12px;
}

.proof-quote {
    grid-column: span 6;
    border: 1px solid rgba(57, 255, 20, 0.16);
    background: rgba(237, 237, 237, 0.022);
    padding: clamp(22px, 2.4vw, 30px);
    transition: border-color 240ms linear, background 240ms linear;
}

.proof-quote:hover {
    border-color: rgba(57, 255, 20, 0.34);
    background: rgba(237, 237, 237, 0.045);
}

/* three quotes, one row, equal columns. the uneven spans this grid used to
   carry existed to keep a stat tile and the outlier panel from reading as a
   spec sheet. with every number gone there is nothing left to break up, and
   three matched slots say plainly that these are three testimonials. */
@media (min-width: 720px) {
    .proof-grid > .proof-quote { grid-column: span 2; }
}

/* quotes -------------------------------------------------------------------- */
.proof-quote {
    display: flex;
    flex-direction: column;
}

.proof-quote blockquote {
    font-size: var(--fs-s);
    line-height: 1.7;
    color: rgba(237, 237, 237, 0.88);
    margin-bottom: 22px;
    text-wrap: pretty;
}

.proof-quote figcaption {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 10px;
    margin-top: auto;
    font-size: var(--fs-2xs);
    letter-spacing: 0.06em;
}

.proof-quote figcaption::before {
    content: '>';
    color: rgba(57, 255, 20, 0.5);
}

.proof-who { color: var(--white); font-weight: 500; }
.proof-where { color: var(--gray); }

/* real app screenshots -----------------------------------------------------
   the frames are sized 9/16 and capped so the row does not reflow when the
   images land. drop an <img> inside .shot-frame and delete the .shot-note. */
.shots { margin-top: clamp(40px, 6vw, 72px); }

.shots-label {
    font-size: var(--fs-2xs);
    letter-spacing: 0.1em;
    color: var(--green);
    margin-bottom: 20px;
}

.shots-grid {
    display: grid;
    grid-template-columns: 1fr;
    gap: 20px;
}

@media (min-width: 720px) {
    .shots-grid { grid-template-columns: repeat(3, 1fr); }
}

.shot {
    display: flex;
    flex-direction: column;
    gap: 12px;
}

.shot-frame {
    aspect-ratio: 9 / 16;
    width: 100%;
    max-width: 260px;
    border: 1px dashed rgba(57, 255, 20, 0.35);
    background: rgba(237, 237, 237, 0.022);
    display: flex;
    align-items: center;
    justify-content: center;
}

.shot-frame img { width: 100%; height: 100%; object-fit: cover; display: block; }

.shot-note {
    font-size: var(--fs-2xs);
    letter-spacing: 0.08em;
    color: var(--gray);
}

.shot figcaption {
    font-size: var(--fs-2xs);
    letter-spacing: 0.06em;
    color: var(--gray);
}

@media (prefers-reduced-motion: reduce) {
    .proof-quote { transition: none; }
}

/* the alternatives -------------------------------------------------------------
   rows, not a two-column tick grid. a tick grid asserts that the alternatives
   are the same kind of thing with fewer features, and they are not: a group
   chat and a chatbot fail in completely different ways, and the specific way
   each one fails is the whole argument. so every row gets a sentence.

   flush rows on a single hairline apiece, same construction as the FAQ list.
   only the last row is lit, so the resolution reads as one.
   ---------------------------------------------------------------------------- */
.alts {
    border-top: 1px solid var(--border);
}

.alt {
    display: grid;
    grid-template-columns: 26px 1fr;
    grid-template-areas:
        'mark name'
        '.    out';
    gap: 6px 12px;
    align-items: baseline;
    padding: clamp(20px, 2.2vw, 26px) 0;
    border-bottom: 1px solid var(--border);
    border-left: 2px solid transparent;
    transition: background 220ms cubic-bezier(0.16, 1, 0.3, 1);
}

@media (min-width: 780px) {
    .alt {
        grid-template-columns: 26px minmax(0, 0.9fr) minmax(0, 1.5fr);
        grid-template-areas: 'mark name out';
        gap: 0 clamp(20px, 3vw, 44px);
        align-items: start;
    }
}

.alt:hover { background: rgba(237, 237, 237, 0.035); }

.alt-mark {
    grid-area: mark;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 22px;
    height: 22px;
    border: 1px solid currentColor;
    font-weight: 700;
    font-size: var(--fs-3xs);
    line-height: 1;
    color: rgba(57, 255, 20, 0.55);
    transition: color 200ms linear, background 200ms linear;
}

.alt-mark-bad { color: var(--red-dim); }

.alt:hover .alt-mark-bad { color: var(--red); background: rgba(255, 107, 107, 0.1); }

.alt-name {
    grid-area: name;
    font-size: var(--fs-m);
    font-weight: 500;
    line-height: 1.6;
    letter-spacing: 0.01em;
    color: var(--white);
}

.alt-out {
    grid-area: out;
    font-size: var(--fs-s);
    line-height: 1.7;
    color: var(--gray);
    text-wrap: pretty;
}

/* the one that resolves */
.alt-win {
    position: relative;
    overflow: hidden;
    isolation: isolate;
    background: rgba(57, 255, 20, 0.06);
    border-left-color: var(--green);
    padding-left: clamp(16px, 2vw, 22px);
    padding-right: clamp(16px, 2vw, 22px);
}

.alt-aura {
    position: absolute;
    inset: -60%;
    z-index: -1;
    pointer-events: none;
    background:
        radial-gradient(closest-side circle at 18% 50%, rgba(57, 255, 20, 0.22), transparent 70%),
        radial-gradient(closest-side circle at 62% 40%, rgba(57, 255, 20, 0.10), transparent 64%);
    animation: aura-drift 26s ease-in-out infinite alternate;
}

/* lived in the proof section as proof-drift until that section lost its last
   number. this row is the only thing that uses it now, so it lives here. */
@keyframes aura-drift {
    0%   { transform: translate3d(-4%, -3%, 0) scale(1); }
    50%  { transform: translate3d(5%,  4%, 0) scale(1.12); }
    100% { transform: translate3d(-2%, 6%, 0) scale(1.04); }
}

.alt-win .alt-mark { background: rgba(57, 255, 20, 0.12); }

.alt-win:hover { background: rgba(57, 255, 20, 0.075); }
.alt-win .alt-name { color: var(--green); }
.alt-win .alt-out { color: rgba(237, 237, 237, 0.88); }
.alt-win .alt-mark { color: var(--green); }

@media (prefers-reduced-motion: reduce) {
    .alt, .alt-mark { transition: none; }
    .alt-aura { animation: none; }
}

/* faq -------------------------------------------------------------------------
   filled rows, no outlines. each question is its own surface lifted off black
   and separated by a gap, so the stack reads as a list of cards.

   the earlier version outlined every row instead of filling it, which put two
   borders and a gap between neighbours and read as a doubled line. fill plus a
   gap gives the same separation with one edge instead of two.

   closed rows are a neutral lift so they read as surface. the open row switches
   to green: stronger tint, a bright left edge, and a hairline, so state reads as
   energy rather than as size.
   ---------------------------------------------------------------------------- */
.faq-list {
    max-width: none;
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.faq-item {
    position: relative;
    background: rgba(237, 237, 237, 0.045);
    border: 0;
    border-left: 2px solid transparent;
    overflow: hidden;
    transition: background 220ms cubic-bezier(0.16, 1, 0.3, 1), border-color 220ms linear;
}

/* the green edge draws itself down the card once the panel has finished
   opening, rather than being there the moment you click. a border cannot do
   this: it has no direction and nothing to interpolate, so the edge is a bar
   that scales from its top. the delay is what sells it, the panel settles
   first and the edge follows it down.

   closing pulls it back up fast and without delay, because a slow retreat
   reads as the UI being reluctant to let go.

   it sits at left:0 rather than over the border: overflow clips to the padding
   box, so a bar in the border area would be cut away entirely. */
.faq-item::before {
    content: '';
    position: absolute;
    left: 0;
    top: 0;
    bottom: 0;
    width: 2px;
    background: var(--green);
    transform: scaleY(0);
    transform-origin: top;
    transition: transform 240ms cubic-bezier(0.16, 1, 0.3, 1) 0s;
}

.faq-item[open]::before {
    transform: scaleY(1);
    transition: transform 520ms cubic-bezier(0.16, 1, 0.3, 1) 260ms;
}

.faq-item:hover { background: rgba(237, 237, 237, 0.075); }

.faq-item[open] {
    background: rgba(57, 255, 20, 0.06);
    border: 1px solid var(--border);
    border-left: 2px solid transparent;
}

.faq-item[open]:hover { background: rgba(57, 255, 20, 0.075); }

.faq-item > summary {
    list-style: none;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 24px;
    padding: clamp(16px, 2vw, 22px) clamp(16px, 2.2vw, 26px);
    cursor: pointer;
}

.faq-item > summary::-webkit-details-marker { display: none; }

.faq-q {
    font-size: var(--fs-s);
    font-weight: 500;
    line-height: 1.5;
    color: var(--white);
    transition: color 150ms linear;
}

.faq-item > summary:hover .faq-q,
.faq-item[open] .faq-q { color: var(--green); }

.faq-item > summary::after {
    content: '+';
    flex: 0 0 auto;
    font-weight: 700;
    font-size: var(--fs-l);
    line-height: 1;
    color: var(--green);
    transition: transform 420ms cubic-bezier(0.16, 1, 0.3, 1);
}

.faq-item[open] > summary::after { transform: rotate(45deg); }

.faq-item > summary:focus-visible {
    outline: 2px solid var(--green);
    outline-offset: -2px;
}

.faq-a {
    padding: 0 clamp(16px, 2.2vw, 26px) clamp(20px, 2.4vw, 26px);
}

.faq-a > * {
    opacity: 0;
    transform: translateY(8px);
    transition: opacity 240ms linear, transform 320ms cubic-bezier(0.16, 1, 0.3, 1);
}

.faq-item[open] .faq-a > * {
    opacity: 1;
    transform: none;
}

/* the stagger starts after the panel has committed to opening */
.faq-item[open] .faq-a > *:nth-child(1) { transition-delay: 120ms; }
.faq-item[open] .faq-a > *:nth-child(2) { transition-delay: 175ms; }
.faq-item[open] .faq-a > *:nth-child(3) { transition-delay: 225ms; }
.faq-item[open] .faq-a > *:nth-child(n+4) { transition-delay: 265ms; }

.faq-a p {
    font-size: var(--fs-m);
    line-height: 1.8;
    color: rgba(237, 237, 237, 0.82);
    margin-bottom: 1.1em;
}

.faq-a p:last-child { margin-bottom: 0; }
.faq-a a { text-decoration: underline; text-underline-offset: 3px; }

@media (prefers-reduced-motion: reduce) {
    .faq-item, .faq-q, .faq-item > summary::after { transition: none; }
    .faq-a > * { opacity: 1; transform: none; transition: none; }
    .faq-item::before { transition: none; }
}

/* closer ---------------------------------------------------------------------- */
.closer-inner { text-align: center; }

.closer-inner .label { color: var(--green); }

.closer-h {
    font-size: var(--fs-2xl);
    line-height: 1.15;
    letter-spacing: -0.01em;
    max-width: 22ch;
    margin: 0 auto var(--stack-m);
}

.closer-body {
    font-size: var(--fs-m);
    line-height: 1.8;
    color: rgba(237, 237, 237, 0.78);
    max-width: 58ch;
    margin: 0 auto var(--stack-l);
}

/* the closer runs three beats: scope (it is not just the apps), mechanism
   (what it does), value prop (the promise, restated in green). the scope and
   mechanism lines are one thought, so they sit tight together and the value
   prop takes the full gap before the button. */
.closer-body-tight { margin-bottom: var(--stack-m); }

.closer-vp {
    font-size: var(--fs-l);
    font-weight: 500;
    line-height: 1.4;
    color: var(--green);
    max-width: 30ch;
    margin: 0 auto var(--stack-l);
}

.closer .section-cta { display: flex; justify-content: center; }

/* the last button on the page is the biggest one on the page. it runs wider
   than the fine print beneath it so the eye lands on the button first and reads
   the conditions second, rather than the other way round. */
.closer-btn {
    width: 100%;
    max-width: 540px;
    padding: clamp(1.3rem, 2.4vw, 1.75rem) 2rem;
    font-size: var(--fs-l);
    letter-spacing: 0.06em;
}

/* outlined at rest and solid on hover: the page's other CTAs are already solid
   green, so the last one earns attention by changing rather than by shouting
   from the start. the caret comes along because it is the brand's tell and the
   ghost variant does not carry one. */
.closer-btn::after {
    content: ' _';
    animation: blink 1s step-end infinite;
}

.closer-btn:hover,
.closer-btn:focus-visible {
    background: var(--green);
    color: var(--black);
    box-shadow: 0 0 38px rgba(57, 255, 20, 0.28);
}

/* the sweep is green on outlined buttons, which would vanish once the fill
   turns green, so it flips to white for the duration of the hover */
.closer-btn:hover::before {
    background: linear-gradient(
        90deg,
        transparent,
        rgba(255, 255, 255, 0.45),
        transparent
    );
}

@media (prefers-reduced-motion: reduce) {
    .closer-btn::after { animation: none; }
}

.closer .trust { margin-top: 16px; }

.trust-offer {
    margin-top: 6px;
    color: var(--green);
    opacity: 0.85;
}

.closer .trust { margin-top: 18px; }

/* footer ---------------------------------------------------------------------------- */
/* share lives here, not under the closer. it is a secondary action and it was
   competing with the one tap this page is built to get.

   the reveal: the footer is pinned to the bottom of the viewport and main
   scrolls over it on an opaque black ground, so the last scroll uncovers the
   footer rather than pushing it up. main carries a bottom margin equal to the
   footer height, which script.js measures into --foot-h.

   what gets revealed is an idle terminal prompt at full bleed, not an oversized
   wordmark. the caret is already the brand's motif in the nav, the hero and the
   buttons, so the bottom of the page is the cursor sitting there waiting for
   you. the mark is ghosted and the caret is the only lit thing in it.

   gated on .foot-pinned, which script.js only sets when the footer actually
   fits the viewport. a footer taller than the screen cannot be uncovered by
   scrolling to the bottom, so on short screens it stays in normal flow. no JS
   means no class, which lands on the same safe fallback. */
html.foot-pinned main {
    position: relative;
    z-index: 1;
    background: var(--black);
    margin-bottom: var(--foot-h, 0px);
}

html.foot-pinned .footer {
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 0;
}

.footer {
    position: relative;
    border-top: 1px solid var(--border);
    padding: clamp(44px, 5.5vw, 76px) 0 clamp(36px, 4vw, 56px);
    overflow: hidden;
    isolation: isolate;
}

/* the glow the mark sits in. the reveal only lands if what gets uncovered
   looks lit rather than just dark, so the footer reads as a screen that is
   still on in a dark room. */
.footer::before {
    content: '';
    position: absolute;
    left: 50%;
    bottom: -26%;
    width: 150%;
    aspect-ratio: 1.7 / 1;
    transform: translateX(-50%);
    z-index: -2;
    pointer-events: none;
    background: radial-gradient(
        ellipse at 50% 100%,
        rgba(57, 255, 20, 0.28),
        rgba(57, 255, 20, 0.09) 40%,
        transparent 72%
    );
}

/* scanlines across the revealed layer, same treatment as the featured card */
.footer::after {
    content: '';
    position: absolute;
    inset: 0;
    z-index: -1;
    pointer-events: none;
    background: repeating-linear-gradient(
        to bottom,
        rgba(57, 255, 20, 0.05) 0px,
        rgba(57, 255, 20, 0.05) 1px,
        transparent 1px,
        transparent 3px
    );
}

.foot-mark {
    /* sized to run almost edge to edge and still keep the caret on screen.
       23vw looked better until you notice it pushes the cursor past the right
       edge, and the cursor is the whole idea: the page ends on a prompt that is
       still waiting. "The Guy_" is 8 monospace characters, so the string is
       ~4.8em wide and 19.5vw lands it just inside the viewport at every size. */
    font-size: clamp(4rem, 19.5vw, 17rem);
    font-weight: 700;
    /* the full glyph box has to fit: the footer clips, so anything the line box
       cuts off is gone rather than bleeding. 1.02 clears the descender on y. */
    line-height: 1.02;
    letter-spacing: -0.035em;
    white-space: nowrap;
    text-align: center;
    color: rgba(57, 255, 20, 0.19);
    margin-top: clamp(34px, 5vw, 64px);
    user-select: none;
}

.foot-caret {
    color: var(--green);
    opacity: 0.9;
    text-shadow: 0 0 24px rgba(57, 255, 20, 0.75), 0 0 60px rgba(57, 255, 20, 0.35);
    animation: blink 1.1s steps(1, end) infinite;
}

@media (prefers-reduced-motion: reduce) {
    .foot-caret { animation: none; }
}

.foot-grid {
    display: flex;
    flex-direction: column;
    gap: var(--stack-l);
}

@media (min-width: 768px) {
    .foot-grid {
        flex-direction: row;
        align-items: flex-start;
        justify-content: space-between;
        gap: var(--stack-l);
    }
    .foot-share { text-align: right; flex: 0 0 auto; }
}

.share-q {
    font-size: var(--fs-2xs);
    line-height: 2.2;
    color: var(--gray);
    margin-bottom: 12px;
}

.foot-row {
    font-family: var(--mono);
    font-size: var(--fs-2xs);
    line-height: 2.2;
    color: var(--gray);
}

.foot-row a {
    display: inline-block;
    /* the row is a dense line of legal links; padding grows the tap target
       without changing the line box or how the row wraps */
    padding: 7px 1px;
    color: var(--gray);
    text-decoration: underline;
    text-underline-offset: 3px;
    transition: color 150ms ease;
}

.foot-row a:hover { color: var(--green); }

/* reduced motion: everything visible, nothing animated ------------------------------- */
@media (prefers-reduced-motion: reduce) {
    html { scroll-behavior: auto; }

    *, *::before, *::after {
        animation-duration: 0.01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.01ms !important;
    }

    html.js .rv,
    html.js .hero-item,
    html.js [data-pop] {
        opacity: 1;
        transform: none;
    }

    .block-cursor,
    .t-caret,
    .btn-primary::after,
    .t-reco .reco-cursor {
        animation: none !important;
    }
}
