/*
 * LeaveSafe — the page people read.
 *
 * One typeface for the whole site. Martian Mono is a monospace with real
 * personality rather than a code face, which is what lets it carry a headline,
 * a price and a paragraph of KVKK text without any of them looking borrowed
 * from somewhere else.
 *
 * The palette is the product's own, lifted from the application's tokens. The
 * brand blue is held constant because it means "LeaveSafe" rather than "what
 * LeaveSafe is doing"; red means the alarm and appears nowhere else.
 *
 * Nothing on this site is rounded. That is a decision rather than an oversight:
 * every box here is a reading, a file, a plan or a record, and none of those
 * has soft corners.
 */

/* ── type ───────────────────────────────────────────────────────────────── */
/*
 * The variable cut, so one file covers weight 200 through 700 and the page
 * needs two requests rather than six. Served from beside the page for the same
 * reason everything else is: a font fetched from Google's host is a third
 * party on a site whose whole argument is that it talks to nobody.
 */
@font-face {
    font-family: 'Martian Mono';
    font-style: normal;
    font-weight: 200 700;
    font-display: swap;
    src: url('fonts/martian-mono-latin-var.woff2') format('woff2');
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
        U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191,
        U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

/* Turkish needs this one: ğ, ş and İ all live above U+00FF. */
@font-face {
    font-family: 'Martian Mono';
    font-style: normal;
    font-weight: 200 700;
    font-display: swap;
    src: url('fonts/martian-mono-latin-ext-var.woff2') format('woff2');
    unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7,
        U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F,
        U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F,
        U+A720-A7FF;
}

/* ── tokens ─────────────────────────────────────────────────────────────── */
:root {
    --void: #050609;
    --panel: #0a0c11;
    --raised: #0f1218;
    --edge: #1b2029;
    --edge2: #28303c;

    --text: #c8ced8;
    --quiet: #76808e;
    --faint: #606a77;

    /* Held constant across the whole site: this is "LeaveSafe", not a state. */
    --brand: #3d8fc4;
    /* The same blue with the lights on. Used only where something is asking to
       be looked at, which on this page is two things and no more. */
    --brand-lit: #79b4dd;
    /* The alarm, and nothing but the alarm. */
    --trip: #f04438;
    --ok: #4a9d6f;
    --ink: #040508;

    --mono: 'Martian Mono', ui-monospace, 'SF Mono', SFMono-Regular, Menlo, Consolas, monospace;

    --swift: 160ms cubic-bezier(0.32, 0.72, 0, 1);
    --settle: 280ms cubic-bezier(0.32, 0.72, 0, 1);
    --sweep: 620ms cubic-bezier(0.32, 0.72, 0, 1);
}

/* ── base ───────────────────────────────────────────────────────────────── */
/* Border-box everywhere. Without it a control asked to be the width of its
   column is that width plus its own padding, which is how a button ends up
   hanging over the edge of the card it was put in. */
*, *::before, *::after { box-sizing: border-box; }

html { scroll-behavior: smooth; }

body {
    margin: 0;
    background: var(--void);
    color: var(--text);
    font-family: var(--mono);
    font-weight: 300;
    font-size: 13px;
    line-height: 1.85;
    /* Martian Mono sets wide by default; pulling it in is what lets it work as
       running text rather than as a terminal. */
    letter-spacing: -0.04em;
    -webkit-font-smoothing: antialiased;
}

a { color: inherit; text-decoration: none; }
button { font: inherit; }
[hidden] { display: none !important; }

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

.wrap { max-width: 1060px; margin: 0 auto; padding: 0 28px; }
.sec { padding: 76px 0; border-bottom: 1px solid var(--edge); }

h1, h2, h3 { margin: 0; font-weight: 600; letter-spacing: -0.07em; }
h1 { font-size: clamp(24px, 4.2vw, 46px); line-height: 1.14; }
h2 { font-size: clamp(28px, 4.6vw, 42px); line-height: 1.06; margin-bottom: 18px; }
h3 { font-size: 14px; letter-spacing: -0.05em; }
p { margin: 0 0 18px; }
.dim { color: var(--quiet); }
.b { font-weight: 500; color: var(--text); }
.tiny { font-size: 11px; color: var(--faint); }

/*
 * Not an eyebrow.
 *
 * The ten-pixel uppercase label with a fifth of an em of tracking, in the
 * accent colour, sits above the headline of half the internet. This says the
 * same thing at reading size, in the body colour, with a rule doing the work
 * the tracking used to.
 */
.k {
    display: flex;
    align-items: center;
    gap: 12px;
    margin: 0 0 20px;
    font-size: 12.5px;
    font-weight: 300;
    letter-spacing: -0.03em;
    color: var(--quiet);
}

.k::after { content: ''; flex: 1; max-width: 90px; height: 1px; background: var(--edge2); }
.k b { font-weight: 500; color: var(--text); }

/* ── nav ────────────────────────────────────────────────────────────────── */
.nav {
    position: sticky;
    top: 0;
    z-index: 50;
    display: flex;
    align-items: center;
    gap: 22px;
    padding: 13px 28px;
    background: rgba(5, 6, 9, 0.94);
    backdrop-filter: blur(10px);
    border-bottom: 1px solid var(--edge);
}

.foot-brand, .logo { font-weight: 700; letter-spacing: 0.06em; font-size: 13px; }
.logo i, .foot-brand span { font-style: normal; color: var(--brand); }
.nav a.l { font-size: 12px; color: var(--quiet); transition: color var(--settle); }
.nav a.l:hover { color: var(--text); }
.nav .sp { margin-left: auto; }
.lang-switch { margin-left: 0; }

@media (max-width: 720px) {
    .nav { gap: 14px; padding: 11px 18px; flex-wrap: wrap; }
    .nav a.l { font-size: 11.5px; }
}

/* ── buttons ────────────────────────────────────────────────────────────── */
/*
 * A square block wipes in from the left and the label inverts with it. The
 * common version of this is a dot that swells into a pill; a pill would be the
 * only rounded thing on the site, so the idea is rebuilt with a hard edge.
 *
 * The mark says where the action takes you, and that is the only reason it is
 * there — down to a file, right to another section, out to somebody else's
 * host. A chevron drawn from two borders stays sharp at any size and takes the
 * button's colour with it.
 */
.btn {
    position: relative;
    display: inline-flex;
    align-items: center;
    gap: 14px;
    padding: 14px 22px;
    border: 1px solid var(--brand);
    background: transparent;
    color: var(--brand);
    font-weight: 500;
    font-size: 13px;
    letter-spacing: -0.04em;
    line-height: 1.2;
    cursor: pointer;
    overflow: hidden;
    transition: color var(--settle), border-color var(--settle);
}

.btn .mk {
    position: relative;
    z-index: 1;
    flex: none;
    width: 8px;
    height: 8px;
    border-right: 1.5px solid currentColor;
    border-bottom: 1.5px solid currentColor;
    transition: transform var(--settle);
}

.btn .mk[data-d='down'] { transform: rotate(45deg) translate(-1px, -1px); }
.btn .mk[data-d='right'] { transform: rotate(-45deg); }
.btn .mk[data-d='out'] { transform: rotate(-135deg); }
.btn:hover .mk[data-d='down'] { transform: rotate(45deg) translate(1px, 1px); }
.btn:hover .mk[data-d='right'] { transform: rotate(-45deg) translate(1px, -1px); }
.btn:hover .mk[data-d='out'] { transform: rotate(-135deg) translate(1px, 1px); }

/* The waiting card borrows this too: the two ends of the plan grid are one
   shape, and a label with a second line on one side needs the same on the
   other or the pair sits crooked. */
.btn .lb, .soon .lb { position: relative; z-index: 1; display: grid; gap: 2px; text-align: left; }
.btn .lb b, .soon .lb b { font-weight: 500; line-height: 1.2; }
.btn .lb em, .soon .lb em {
    font-style: normal;
    font-size: 10.5px;
    font-weight: 300;
    letter-spacing: -0.03em;
    color: currentColor;
    opacity: 0.62;
}

.btn::before {
    content: '';
    position: absolute;
    inset: 0;
    background: var(--brand);
    transform: scaleX(0);
    transform-origin: left;
    transition: transform 240ms cubic-bezier(0.32, 0.72, 0, 1);
}

.btn:hover::before, .btn:focus-visible::before { transform: scaleX(1); }
.btn:hover, .btn:focus-visible { color: var(--ink); }
.btn:active { transform: translateY(1px); }

/* The secondary reads as a way onward rather than as a second offer. */
.btn-gh { border-color: var(--edge2); color: var(--text); }
.btn-gh::before { background: var(--text); }
.btn-gh:hover, .btn-gh:focus-visible { color: var(--void); border-color: var(--text); }

.btn-lg { padding: 16px 26px; font-size: 13.5px; }
.nav .btn { padding: 10px 16px; font-size: 12px; gap: 10px; }

.row { display: flex; flex-wrap: wrap; gap: 10px; }

/* ── hero ───────────────────────────────────────────────────────────────── */
.hero { padding: 78px 0 84px; }
.hero h1 { max-width: 22ch; }
.hero .sub { margin: 22px 0 28px; max-width: 52ch; color: var(--quiet); }

/*
 * The line under the buttons used to be a spec dump — licence, platforms,
 * "no account". This is the argument those specs were standing in for, and it
 * is a link rather than a label, because the claim being checkable is the
 * whole point of making it.
 */
.src { margin: 20px 0 0; max-width: 52ch; font-size: 12.5px; color: var(--quiet); }
.src b { font-weight: 500; color: var(--text); }
.src a {
    color: var(--brand);
    border-bottom: 1px solid color-mix(in srgb, var(--brand) 40%, transparent);
    padding-bottom: 1px;
    transition: border-color var(--settle);
}
.src a:hover { border-color: var(--brand); }

/* ── what it does ───────────────────────────────────────────────────────── */
.grid { display: grid; grid-template-columns: repeat(3, 1fr); border: 1px solid var(--edge); border-bottom: 0; }
.cell { padding: 22px 20px; border-bottom: 1px solid var(--edge); border-right: 1px solid var(--edge); }
.cell:nth-child(3n) { border-right: 0; }
.cell dt {
    margin-bottom: 9px;
    font-size: 10px;
    letter-spacing: 0.18em;
    text-transform: uppercase;
    color: var(--faint);
}
.cell dd { margin: 0; font-size: 12.5px; color: var(--quiet); }
.cell dd b { color: var(--text); font-weight: 500; }

/* The six sensors, as a row that arms and then takes a hit. */
.six { display: grid; grid-template-columns: repeat(6, 1fr); border: 1px solid var(--edge); margin-top: 22px; }
.six div { padding: 16px 12px; border-right: 1px solid var(--edge); text-align: center; }
.six div:last-child { border-right: 0; }
.six i { display: block; height: 3px; margin-bottom: 11px; background: var(--edge2); transition: background var(--settle); }
.six[data-armed] i { background: var(--brand); }
.six[data-hit] div:last-child i { background: var(--trip); }
.six span { font-size: 10px; letter-spacing: 0.1em; text-transform: uppercase; color: var(--faint); }
.six[data-hit] div:last-child span { color: var(--trip); }

/* ── the open-source band ───────────────────────────────────────────────── */
.os { display: grid; grid-template-columns: 1.15fr 1fr; gap: 36px; align-items: start; }
.badge {
    display: inline-block;
    margin-bottom: 16px;
    padding: 6px 12px;
    border: 1px solid var(--brand);
    color: var(--brand);
    font-size: 10px;
    letter-spacing: 0.18em;
    text-transform: uppercase;
}
.term {
    padding: 18px 20px;
    border: 1px solid var(--edge);
    background: var(--panel);
    font-size: 11.5px;
    line-height: 2.1;
    color: var(--quiet);
    overflow-x: auto;
}
.term b { color: var(--brand); font-weight: 400; }
.term u { text-decoration: none; color: var(--trip); }

/* ── subscription ───────────────────────────────────────────────────────── */
/*
 * The difference between the two plans is a network, not a number of
 * kilometres. So the readout leads with which Wi-Fi each end is on, and the
 * distance is kept because it makes the consequence concrete — not because it
 * is the argument.
 */
/* the sentence under a section heading, kept to a reading measure */
.sub-note { margin: 0; max-width: 52ch; }
.qa-list { margin-top: 20px; }

.subhead { display: flex; flex-wrap: wrap; justify-content: space-between; align-items: end; gap: 18px; margin-bottom: 26px; }
.tabs { display: inline-flex; border: 1px solid var(--edge); }
.tabs button {
    border: 0;
    background: transparent;
    color: var(--quiet);
    font-size: 12px;
    letter-spacing: -0.04em;
    padding: 11px 20px;
    cursor: pointer;
    transition: background var(--settle), color var(--settle);
}
.tabs button + button { border-left: 1px solid var(--edge); }
.tabs button[aria-pressed="true"] { background: var(--raised); color: var(--text); }

/*
 * The pro tab breathes until it is pressed.
 *
 * This whole section exists to be compared, and a visitor who never presses
 * the second tab never sees the comparison — the readout, the plan cards and
 * the paragraph underneath all sit there arguing the free case to somebody who
 * does not know there is another one. The pulse says "this is a control", and
 * it stops the moment it has been believed: an indicator still asking for
 * attention after it has been given some is just noise.
 */
.tabs button[data-plan="pro"][aria-pressed="false"] {
    animation: tab-breathe 2600ms ease-in-out infinite;
}

@keyframes tab-breathe {
    0%, 100% { color: var(--quiet); background: transparent; }
    50% { color: var(--brand-lit); background: rgba(61, 143, 196, 0.14); }
}

.net { position: relative; height: 190px; border: 1px solid var(--edge); background: var(--panel); overflow: hidden; }

/* The two networks, drawn as territory rather than as distance. */
.zone {
    position: absolute;
    top: 20px;
    bottom: 20px;
    border: 1px dashed var(--edge2);
    transition: border-color var(--sweep), opacity var(--sweep);
}
.zone::after {
    content: attr(data-n);
    position: absolute;
    left: 11px;
    top: -8px;
    padding: 0 7px;
    background: var(--panel);
    font-size: 9px;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    color: var(--faint);
}
.zone[data-z="home"] { left: 16px; width: 42%; border-color: color-mix(in srgb, var(--brand) 50%, transparent); }
.zone[data-z="home"]::after { color: var(--brand); }
.zone[data-z="away"] { right: 16px; width: 34%; }
[data-plan="pro"] .zone[data-z="away"] { border-color: color-mix(in srgb, var(--brand) 50%, transparent); }
[data-plan="pro"] .zone[data-z="away"]::after { color: var(--brand); }

.node {
    position: absolute;
    top: 50%;
    transform: translateY(-50%);
    display: grid;
    justify-items: center;
    gap: 9px;
    text-align: center;
    font-size: 9.5px;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--faint);
    transition: color var(--sweep);
}
.node i { width: 13px; height: 13px; border: 1px solid var(--quiet); background: var(--void); }
.node[data-r="mac"] { left: 48px; }
.node[data-r="near"] { left: 31%; }
.node[data-r="far"] { right: 60px; }
.node[data-r="near"] i, .node[data-r="far"] i { border-radius: 50%; }
[data-plan="pro"] .node[data-r="far"] { color: var(--brand); }
[data-plan="pro"] .node[data-r="far"] i { border-color: var(--brand); }

.sig {
    position: absolute;
    top: 50%;
    left: 60px;
    width: 7px;
    height: 7px;
    margin-top: -3.5px;
    background: var(--brand);
    opacity: 0;
}
/* A tail, so the signal reads as travelling rather than as a dot teleporting. */
.sig::after {
    content: '';
    position: absolute;
    right: 6px;
    top: 3px;
    width: 44px;
    height: 1px;
    background: linear-gradient(to left, var(--brand), transparent);
}

[data-plan="free"] .sig { animation: reach-near 3.6s cubic-bezier(0.35, 0, 0.25, 1) infinite; }
[data-plan="pro"] .sig { animation: reach-far 3.6s cubic-bezier(0.35, 0, 0.25, 1) infinite; }

@keyframes reach-near {
    0% { opacity: 0; transform: translateX(0); }
    7% { opacity: 1; }
    40%, 60% { opacity: 1; transform: translateX(var(--near, 240px)); }
    72%, 100% { opacity: 0; transform: translateX(var(--near, 240px)); }
}

@keyframes reach-far {
    0% { opacity: 0; transform: translateX(0); }
    7% { opacity: 1; }
    70%, 88% { opacity: 1; transform: translateX(var(--far, 700px)); }
    100% { opacity: 0; transform: translateX(var(--far, 700px)); }
}

/* On free, the signal stops at the edge of the network — drawn, not implied. */
.wall {
    position: absolute;
    top: 24px;
    bottom: 24px;
    left: calc(16px + 42%);
    width: 1px;
    background: var(--trip);
    opacity: 0;
    transition: opacity var(--sweep);
}
[data-plan="free"] .wall { opacity: 0.55; }
.wall::after {
    content: attr(data-stop);
    position: absolute;
    left: 8px;
    top: 50%;
    transform: translateY(-50%);
    font-size: 9px;
    letter-spacing: 0.13em;
    color: var(--trip);
    white-space: nowrap;
}
[data-plan="pro"] .wall::after { content: ''; }

.read { display: grid; grid-template-columns: repeat(4, 1fr); border: 1px solid var(--edge); border-top: 0; }
.read div { padding: 16px 18px; border-right: 1px solid var(--edge); }
.read div:last-child { border-right: 0; }
.read dt { margin-bottom: 7px; font-size: 9.5px; letter-spacing: 0.16em; text-transform: uppercase; color: var(--faint); }
.read dd { margin: 0; font-size: 13px; font-weight: 500; color: var(--text); }
.read dd.on { color: var(--ok); }
.read dd small { display: block; font-size: 10.5px; font-weight: 300; color: var(--faint); letter-spacing: 0.02em; }

/*
 * No limit, drawn.
 *
 * It arrives the way it means: one continuous stroke laid down from nothing,
 * with no join anywhere on it to say where it started. The dash properties are
 * set on the svg rather than the path because both of them inherit, which
 * leaves the script one element to restart instead of two.
 */
.forever {
    display: block;
    width: 38px;
    height: 19px;
    margin: 1px 0 2px;
    fill: none;
    stroke: var(--brand-lit);
    stroke-width: 2.4;
    stroke-dasharray: 100;
    stroke-dashoffset: 100;
    animation: forever-draw 1100ms cubic-bezier(0.32, 0.72, 0, 1) forwards;
}

@keyframes forever-draw {
    from { stroke-dashoffset: 100; opacity: 0.35; }
    to { stroke-dashoffset: 0; opacity: 1; }
}

.say { margin: 20px 0 0; max-width: 66ch; font-size: 12.5px; color: var(--quiet); }
.say b { color: var(--text); font-weight: 500; }
[data-plan="free"] .say-pro, [data-plan="pro"] .say-free { display: none; }

/* ── the two plans ──────────────────────────────────────────────────────── */
.plans { display: grid; grid-template-columns: 1fr 1fr; border: 1px solid var(--edge); margin-top: 30px; }
/* A column, so the action can be pushed to the floor of the card and the two
   plans finish on one line however unevenly their lists run. */
.plan { display: flex; flex-direction: column; padding: 24px 22px; }
.plan + .plan { border-left: 1px solid var(--edge); background: var(--panel); }
.plan .n { font-size: 10px; letter-spacing: 0.18em; text-transform: uppercase; color: var(--faint); }
.plan .pr { margin: 8px 0 4px; font-size: 30px; font-weight: 600; letter-spacing: -0.07em; }
.plan .pr em { font-style: normal; font-size: 11px; font-weight: 300; color: var(--faint); letter-spacing: 0.04em; }
.plan ul { flex: 1; list-style: none; margin: 14px 0 18px; padding: 0; }
.plan li { position: relative; padding: 8px 0 8px 18px; border-top: 1px solid var(--edge); font-size: 12px; color: var(--quiet); }
.plan li::before { content: '+'; position: absolute; left: 0; top: 8px; color: var(--brand); }
/*
 * The invite, in the card that charges for it.
 *
 * It was a panel of its own above the two plans, which is the wrong place for
 * the strongest thing pro does: the decision is made in the column with the
 * price on it. Three steps down one rail, with a light descending the rail —
 * the same gesture the network diagram uses, turned on its side to fit a card
 * rather than a row.
 *
 * The three steps are a café rather than a diagram. Described as a shape —
 * one device watching another — the feature reads as though the machine were
 * on show; described as an afternoon, it reads as one code handed to one
 * person, which is what it is.
 *
 * The lifetime is written rather than counted down. A clock running on a
 * marketing page is a clock measuring nothing.
 */
.invite {
    margin: 0 0 18px;
    padding: 16px 0 0;
    border-top: 1px solid var(--edge);
}

.invite-k {
    margin: 0 0 6px;
    font-size: 10px;
    letter-spacing: 0.18em;
    text-transform: uppercase;
    color: var(--brand-lit);
}

.invite-lead { margin: 0 0 14px; font-size: 11.5px; color: var(--quiet); line-height: 1.5; }

.invite-flow {
    position: relative;
    overflow: hidden;
    list-style: none;
    margin: 0;
    padding: 0 0 0 22px;
}

/* The rail the three steps hang off. */
.invite-flow::before {
    content: '';
    position: absolute;
    left: 5px;
    top: 6px;
    bottom: 6px;
    width: 1px;
    background: var(--edge2);
}

/*
 * The handover: a full-height rule with one bright stretch in it, travelling
 * from one end to the other. Nothing has to know how tall the list is, and
 * asked not to animate it stays at the zero opacity it starts on — a rail with
 * a frozen highlight halfway down would look like a state rather than a
 * movement that stopped.
 */
.invite-flow::after {
    content: '';
    position: absolute;
    left: 5px;
    top: 0;
    width: 1px;
    height: 100%;
    opacity: 0;
    background: linear-gradient(to bottom, transparent 42%, var(--brand-lit) 48%, var(--brand-lit) 52%, transparent 58%);
    animation: pass-down 4200ms cubic-bezier(0.45, 0, 0.55, 1) infinite;
}

@keyframes pass-down {
    0% { transform: translateY(-100%); opacity: 0; }
    18%, 82% { opacity: 1; }
    100% { transform: translateY(100%); opacity: 0; }
}

/* These are list items inside .plan, so `.plan li` reaches them: it would
   hand each one a rule across the top, eighteen pixels of indent and a plus
   sign, which is the styling for a feature in the column above. Reset rather
   than out-specified, so the two stay readable side by side. */
.invite-flow li {
    position: relative;
    padding: 0 0 14px;
    border-top: 0;
    font-size: 12px;
    color: var(--quiet);
}

.invite-flow li:last-child { padding-bottom: 0; }

/* A square, not a numeral: these are three parts of one handover, not three
   things to do in order. It carries the card's own background so the rail
   passes behind it rather than through it. */
.invite-flow li::before {
    content: '';
    position: absolute;
    left: -22px;
    top: 4px;
    width: 8px;
    height: 8px;
    border: 1.5px solid var(--brand);
    background: var(--panel);
}

.invite-flow li:last-child::before { border-color: var(--brand-lit); }

.invite-flow b { display: block; font-size: 12px; font-weight: 500; color: var(--text); }
.invite-flow em {
    display: block;
    margin-top: 2px;
    font-style: normal;
    font-size: 10.5px;
    color: var(--faint);
    line-height: 1.5;
}

.invite-end { margin: 14px 0 0; font-size: 10.5px; color: var(--faint); line-height: 1.5; }
.invite-end b { font-weight: 500; color: var(--quiet); }

.plan li[data-no] { color: var(--faint); }
.plan li[data-no]::before { content: '-'; color: var(--faint); }
.plan li b { color: var(--text); font-weight: 500; }

/*
 * The two plans end in the same shape.
 *
 * One column ended in a button and the other in a smaller box with different
 * padding, so the cards finished at different heights and the pair read as
 * misaligned. This is the button's box exactly — same padding, same border,
 * same marker slot, same line box — with the marker drawn as a flat bar rather
 * than an arrow, because it does not take you anywhere yet.
 */
.plan-act, .soon {
    display: flex;
    align-items: center;
    gap: 14px;
    width: 100%;
    margin-top: auto;
    padding: 14px 22px;
    border: 1px solid var(--edge2);
    font-size: 13px;
    font-weight: 500;
    letter-spacing: -0.04em;
    line-height: 1.2;
}
.soon { color: var(--faint); border-style: dashed; cursor: default; }
.soon::before { content: ''; flex: none; width: 8px; height: 0; border-bottom: 1.5px solid currentColor; }

/* ── questions ──────────────────────────────────────────────────────────── */
.qa { padding: 18px 0; border-top: 1px solid var(--edge); }
.qa b { display: block; margin-bottom: 4px; font-weight: 500; font-size: 13px; color: var(--text); }
.qa span { font-size: 12.5px; color: var(--quiet); }

/* ── footer ─────────────────────────────────────────────────────────────── */
/*
 * The footer carries its own measure rather than needing a wrapper, because
 * eleven of the twelve pages reach it through a different layout and a shared
 * chrome that only lines up inside one of them is not shared.
 */
.foot {
    display: flex;
    flex-wrap: wrap;
    gap: 24px;
    justify-content: space-between;
    max-width: 1060px;
    margin: 0 auto;
    padding: 44px 28px 54px;
}
.foot-by { margin: 0; font-size: 11px; color: var(--faint); }

/* The prose pages carry their links in a list rather than beside a spacer. */
.nav-links { display: flex; flex-wrap: wrap; align-items: center; gap: 20px; margin-left: auto; }
.nav-links a { font-size: 12px; color: var(--quiet); transition: color var(--settle); }
.nav-links a:hover { color: var(--text); }
.foot-links { display: flex; flex-wrap: wrap; gap: 16px; }
.foot-links a { font-size: 11.5px; color: var(--faint); transition: color var(--settle); }
.foot-links a:hover { color: var(--text); }
.foot-who p { margin: 0; }

/* ── the pages that are mostly words ────────────────────────────────────── */
/*
 * Privacy, terms, support and account deletion. These are read rather than
 * looked at, so the only thing they need from the design is a measure that
 * does not run the width of a monitor, and headings findable while skimming
 * for the one paragraph somebody came for.
 */
.prose { max-width: 74ch; margin: 0 auto; padding: 70px 28px 90px; }
.prose h1 { margin: 0 0 8px; font-size: clamp(26px, 4vw, 38px); }
.prose .updated { margin: 0 0 44px; font-size: 11.5px; color: var(--faint); }
.prose h2 { margin: 48px 0 14px; font-size: clamp(19px, 2.4vw, 24px); }
.prose h3 { margin: 28px 0 10px; font-size: 13.5px; }
.prose p, .prose li { color: var(--quiet); }
.prose ul, .prose ol { margin: 0 0 18px; padding-left: 20px; }
.prose li { margin-bottom: 7px; }
.prose b { color: var(--text); font-weight: 500; }
.prose a { color: var(--brand); border-bottom: 1px solid color-mix(in srgb, var(--brand) 40%, transparent); }
.prose a:hover { border-color: var(--brand); }
.prose code { padding: 1px 5px; border: 1px solid var(--edge); background: var(--raised); color: var(--text); font-size: 0.92em; }

.prose-table { margin: 0 0 22px; overflow-x: auto; }
.prose-table table { width: 100%; min-width: 480px; border-collapse: collapse; font-size: 12px; }
.prose-table th, .prose-table td { padding: 11px 14px; border-bottom: 1px solid var(--edge); text-align: left; vertical-align: top; }
.prose-table th { color: var(--text); font-weight: 500; font-size: 10px; letter-spacing: 0.16em; text-transform: uppercase; }
.prose-table td { color: var(--quiet); }

/* Said once, in the place somebody is looking for the opposite of it. */
.prose-note {
    margin: 0 0 22px;
    padding: 16px 18px;
    border: 1px solid var(--edge);
    border-left: 2px solid var(--brand);
    background: var(--panel);
    color: var(--text);
}

/* ── the download page ──────────────────────────────────────────────────── */
.dl { max-width: 760px; margin: 0 auto; padding: 70px 28px 50px; }
.dl h1 { margin: 0 0 10px; }
.dl-lede { margin: 0 0 34px; max-width: 54ch; color: var(--quiet); }

.dl-panel { display: grid; gap: 16px; justify-items: start; }
/*
 * Until a version has arrived there is nothing honest to offer, so there is no
 * button to press. The file name contains the version, which makes a guess a
 * broken link handed to somebody who believes they are installing an alarm.
 */
.dl-panel #dl-primary,
.dl-panel #dl-version,
.dl-panel .dl-verify-block,
.dl-panel #dl-others { display: none; }
.dl-panel[data-ready] #dl-version,
.dl-panel[data-ready] .dl-verify-block { display: revert; }
.dl-panel[data-ready] #dl-primary { display: inline-flex; }
.dl-panel[data-ready] #dl-others { display: flex; }

#dl-failed { display: none; }
.dl-panel[data-failed] #dl-failed { display: block; max-width: 48ch; color: var(--trip); }

#dl-version { margin: 0; font-size: 11.5px; color: var(--faint); }
#dl-others { list-style: none; margin: 0; padding: 0; flex-wrap: wrap; gap: 8px 18px; }
#dl-others a { font-size: 12px; color: var(--quiet); border-bottom: 1px solid var(--edge2); }
#dl-others a:hover { color: var(--brand); border-color: var(--brand); }

.dl-verify-block { width: 100%; margin-top: 20px; }
.dl-verify-block summary {
    padding: 10px 0;
    cursor: pointer;
    font-size: 11px;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    color: var(--faint);
    transition: color var(--settle);
}
.dl-verify-block summary:hover { color: var(--brand); }
.dl-verify-block[open] summary { color: var(--text); }
.dl-verify-body { padding: 16px 18px; border: 1px solid var(--edge); background: var(--panel); }
.dl-verify-body p { margin: 0 0 12px; font-size: 12px; color: var(--quiet); }
.dl-line { display: flex; align-items: center; gap: 10px; margin-bottom: 10px; }
.dl-line code {
    flex: 1;
    min-width: 0;
    padding: 9px 11px;
    border: 1px solid var(--edge);
    background: var(--raised);
    color: var(--text);
    font-size: 11px;
    white-space: nowrap;
    overflow-x: auto;
}
.copy {
    padding: 9px 14px;
    border: 1px solid var(--edge2);
    background: transparent;
    color: var(--quiet);
    font-size: 11px;
    cursor: pointer;
    transition: color var(--settle), border-color var(--settle);
}
.copy:hover, .copy.is-done { color: var(--brand); border-color: var(--brand); }

.dl-warn { margin: 26px 0 0; max-width: 62ch; font-size: 12px; color: var(--faint); }
.dl-warn b { color: var(--text); font-weight: 500; }

.dl-stores { display: flex; flex-wrap: wrap; gap: 12px; margin-top: 42px; }
.dl-store {
    display: grid;
    gap: 3px;
    padding: 12px 20px;
    border: 1px dashed var(--edge2);
    color: var(--faint);
    font-size: 12px;
}
.dl-store b { color: var(--quiet); font-weight: 500; }
.dl-store span { font-size: 10px; letter-spacing: 0.14em; text-transform: uppercase; }

/* ── arrivals ───────────────────────────────────────────────────────────── */
/*
 * Sections travel in once, as they come into view. The stylesheet is only
 * allowed to hide any of it after intro.js has said so: with no script the
 * page must not be a column of invisible sections.
 */
:root[data-reveals='on'] [data-reveal='out'] { opacity: 0; transform: translateY(10px); }
[data-reveal] { transition: opacity var(--sweep), transform var(--sweep); }

@media (prefers-reduced-motion: reduce) {
    html { scroll-behavior: auto; }
    *, *::before, *::after { animation-duration: 1ms !important; animation-iteration-count: 1 !important; transition-duration: 1ms !important; }
    /* Stopping the draw would leave the mark as a gap, since an undrawn stroke
       is an invisible one. It is simply there instead. */
    .forever { stroke-dashoffset: 0; }
}

@media (max-width: 860px) {
    .grid, .read { grid-template-columns: 1fr; }
    .cell { border-right: 0; }
    .six { grid-template-columns: repeat(3, 1fr); }
    .os, .plans { grid-template-columns: 1fr; }
    .plan + .plan { border-left: 0; border-top: 1px solid var(--edge); }
    .read div { border-right: 0; border-bottom: 1px solid var(--edge); }
}

/* ── gate ───────────────────────────────────────────────────────────────── */
/*
 * The opening screen. Absent until intro.js has confirmed a canvas: with no
 * script the page opens on the hero, the way it did before this existed. A
 * first screen that can fail to appear must not be able to take the page with
 * it.
 */
.gate { display: none; }

:root[data-intro] .gate {
    display: block;
    position: relative;
    /* One screen for the mark, and the rest as runway. The stage is stuck to
       the top across it, so the mark comes apart where it stands instead of
       sliding off. */
    height: 175vh;
    height: 175svh;
}

/*
 * The hero is pulled up into the back half of the runway on purpose. Left where
 * it falls, a sticky stage one screen tall hands over at exactly the moment it
 * ends: the mark finishes leaving, then a screen of nothing, then the page.
 * Overlapped, the page rises through the last of the cells, which is the only
 * version of this that reads as one movement rather than two.
 */
:root[data-intro] .hero {
    /* Far enough that the headline is on screen while the last cells are still
       in the air. Pulled less than this and the mark finishes leaving before
       the hero is anywhere near the middle, which puts a screen of black
       between them — the thing the overlap exists to remove. It can be this far
       because what makes the hero visible is the opacity below, not the scroll:
       it is up there long before anyone can see it. */
    margin-top: -68vh;
    margin-top: -68svh;
    position: relative;
}

/*
 * With the gate in front of it the bar has nothing to sit on top of, and
 * `sticky` would still hold its own height at the top of the document — half a
 * bar of empty space above a screen that is meant to hold one thing. Fixed for
 * as long as the gate exists; identical everywhere else, since a bar pinned at
 * the top is a bar pinned at the top.
 */
:root[data-intro] .nav {
    position: fixed;
    left: 0;
    right: 0;
}

.gate-stage {
    position: sticky;
    top: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    height: 100vh;
    height: 100svh;
    padding: 0 12px;
}

/* Present to assistive technology and absent from layout: the canvas stays the
   flex item it was. */
.mark-holder { display: contents; }

/* The canvas is larger than the mark inside it — the cells need somewhere to go
   when they leave — so the gap under it is measured from the mark's edge, not
   the canvas's. `--mark-pad` is the difference, and the script knows it. */
#gate-mark {
    display: block;
    max-width: 100%;
}

.gate-text {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 12px;
    margin-top: calc(clamp(8px, 2vh, 22px) - var(--mark-pad, 0px));
    opacity: var(--gate-text, 1);
    transform: translateY(var(--gate-lift, 0px));
    will-change: opacity, transform;
}

.gate-word {
    margin: 0;
    font-family: var(--mono);
    font-size: clamp(14px, 2.1vw, 20px);
    font-weight: 700;
    letter-spacing: 0.42em;
    /* Letter-spacing pads the last glyph as well; the indent pulls the line
       back onto the centre it is supposed to share with the mark. */
    text-indent: 0.42em;
    color: var(--text);
}

.gate-word span { color: var(--brand); }

.gate-line {
    margin: 0;
    font-size: 12.5px;
    letter-spacing: -0.03em;
    color: var(--quiet);
    text-align: center;
}

/*
 * The invitation to scroll.
 *
 * One chevron, turned a quarter clockwise so it points the way the page goes,
 * moving down and back. Nothing else: an arrow drawing a line behind it read
 * as a diagram of something, and this is not a diagram — it is the single
 * instruction the first screen has to give.
 *
 * It is brightest at the bottom of the travel rather than the top, so the
 * movement has a direction to it instead of hovering in place.
 */
.gate-cue {
    position: relative;
    width: 18px;
    height: 24px;
    margin-top: 6px;
}

/* Two borders rather than a glyph: it stays sharp at any size and takes the
   brand colour without a font having to load first. */
.gate-cue i {
    position: absolute;
    top: 3px;
    left: 50%;
    width: 11px;
    height: 11px;
    margin-left: -5.5px;
    border-right: 1.5px solid var(--brand);
    border-bottom: 1.5px solid var(--brand);
    transform: rotate(45deg);
    animation: cue-bob 1900ms cubic-bezier(0.45, 0, 0.55, 1) infinite;
}

@keyframes cue-bob {
    0%, 100% { transform: translateY(0) rotate(45deg); opacity: 0.5; }
    50% { transform: translateY(7px) rotate(45deg); opacity: 1; }
}

/* The name, the line under it and the invitation all wait for the mark. It
   takes about two seconds to surface, and a caption that arrives first
   captions nothing. */
:root[data-intro='on'] .gate-word,
:root[data-intro='on'] .gate-line,
:root[data-intro='on'] .gate-cue {
    opacity: 0;
    animation: gate-in 900ms cubic-bezier(0.22, 0.61, 0.36, 1) forwards;
}

:root[data-intro='on'] .gate-word { animation-delay: 1550ms; }
:root[data-intro='on'] .gate-line { animation-delay: 1750ms; }
:root[data-intro='on'] .gate-cue { animation-delay: 2000ms; }

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

/* While the mark holds the screen there is nothing to navigate. */
:root[data-intro='on'] .nav {
    opacity: 0;
    transform: translateY(-101%);
    pointer-events: none;
    transition: opacity var(--state-shift), transform var(--state-shift);
}

:root[data-intro='on'][data-gate-passed='yes'] .nav {
    opacity: 1;
    transform: none;
    pointer-events: auto;
}

