/* WiFi Get Leads — public site.
   Brand: navy #172d50, accent #B7EB35. Same pairing as the product, so the
   site and the app do not read as two companies. No framework, no CDN, no
   build step - consistent with the rest of this repository. */

:root {
    --navy:        #172d50;
    --navy-deep:   #0e1d35;
    --navy-soft:   #22406f;
    --accent:      #B7EB35;
    --accent-dark: #a6d92c;
    --ink:         #172d50;
    --ink-soft:    #5a6a85;
    --line:        #e3e9f1;
    --tint:        #f4f7fb;
    --white:       #ffffff;
    --radius:      16px;
    --radius-sm:   10px;
    --wrap:        1140px;
    --shadow:      0 18px 48px rgba(8, 18, 38, .10);
}

* { box-sizing: border-box; }

html { scroll-behavior: smooth; }
/* Anchored sections must not land under the sticky header. */
:target { scroll-margin-top: 88px; }

body {
    margin: 0;
    background: var(--white);
    color: var(--ink);
    font: 400 17px/1.65 -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
          Helvetica, Arial, sans-serif;
    -webkit-font-smoothing: antialiased;
}

img { max-width: 100%; height: auto; display: block; }
a   { color: inherit; }

.wrap { width: 100%; max-width: var(--wrap); margin: 0 auto; padding: 0 24px; }

.skip {
    position: absolute; left: -9999px;
    background: var(--navy); color: #fff; padding: 10px 16px; border-radius: 0 0 8px 0;
}
.skip:focus { left: 0; top: 0; z-index: 100; }

/* --------------------------------- type -------------------------------- */
h1, h2, h3, h4 { margin: 0; line-height: 1.15; letter-spacing: -.015em; }
h1 { font-size: clamp(2.4rem, 5.2vw, 3.9rem); font-weight: 800; }
h2 { font-size: clamp(1.7rem, 3.2vw, 2.5rem); font-weight: 800; max-width: 22ch; }
.h2-wide { max-width: 34ch; }
h3 { font-size: 1.12rem; font-weight: 700; }
p  { margin: 0; }

.eyebrow, .kicker {
    margin: 0 0 14px;
    font-size: 12px;
    font-weight: 800;
    letter-spacing: .12em;
    text-transform: uppercase;
    color: var(--accent-dark);
}
.kicker { color: #7fa32a; }
.kicker-on-dark { color: var(--accent); }
.lede { font-size: clamp(1.05rem, 1.7vw, 1.22rem); line-height: 1.6; }
.section-lede { margin-top: 14px; max-width: 60ch; color: var(--ink-soft); }

/* -------------------------------- buttons ------------------------------ */
.btn {
    display: inline-flex; align-items: center; justify-content: center;
    gap: 8px;
    padding: 11px 20px;
    border: 1px solid transparent;
    border-radius: 999px;
    font-size: 15px; font-weight: 700;
    text-decoration: none;
    cursor: pointer;
    transition: background-color .15s ease, border-color .15s ease,
                transform .15s ease, color .15s ease;
}
.btn:active { transform: translateY(1px); }
.btn-lg { padding: 14px 26px; font-size: 16px; }
.btn-accent { background: var(--accent); border-color: var(--accent); color: var(--navy); }
.btn-accent:hover { background: var(--accent-dark); border-color: var(--accent-dark); }
.btn-ghost { background: transparent; border-color: rgba(255,255,255,.32); color: #fff; }
.btn-ghost:hover { background: rgba(255,255,255,.12); }

/* -------------------------------- lockup ------------------------------- */
/* The mark we have is the WiFi arc on its own, so the wordmark is type. The
   arc bitmap is square with empty space below the glyph - the negative
   margin-bottom pulls the baseline back up so it sits WITH the word instead
   of floating above it. */
.lockup {
    display: inline-flex;
    align-items: center;
    gap: 9px;
    text-decoration: none;
    white-space: nowrap;
}
/* Height-driven: the logo is a wide lockup (578x239), so fixing the height and
   letting the width follow keeps its proportions. The source is ~6x the nav
   size, so it stays sharp on retina screens. */
.lockup-logo { display: block; height: 40px; width: auto; }
.lockup-lg .lockup-logo { height: 56px; }

/* ---------------------------------- nav -------------------------------- */
.nav {
    position: sticky; top: 0; z-index: 50;
    background: rgba(23, 45, 80, .92);
    -webkit-backdrop-filter: saturate(140%) blur(10px);
    backdrop-filter: saturate(140%) blur(10px);
    border-bottom: 1px solid rgba(255,255,255,.08);
}
.nav-inner { display: flex; align-items: center; gap: 24px; height: 72px; }
.nav-links { display: flex; gap: 18px; margin-left: 8px; }
.nav-links a {
    font-size: 14px; font-weight: 600; text-decoration: none;
    color: rgba(255,255,255,.78);
    /* Portuguese and Spanish labels are longer than the English ones, and a
       wrapped link turns the bar into two rows and squashes the CTA. */
    white-space: nowrap;
}
.nav-links a:hover { color: #fff; }
.nav-right { display: flex; align-items: center; gap: 14px; margin-left: auto; }

.langs {
    display: flex; gap: 2px; padding: 3px;
    border: 1px solid rgba(255,255,255,.18);
    border-radius: 999px;
    background: rgba(255,255,255,.06);
}
.lang {
    /* flex + centring rather than padding alone, so a min-height can make the
       whole pill tappable instead of only the text's line box. */
    display: inline-flex; align-items: center; justify-content: center;
    min-width: 40px; min-height: 30px;
    padding: 5px 11px;
    border-radius: 999px;
    font-size: 12px; font-weight: 800; letter-spacing: .04em;
    text-decoration: none;
    color: rgba(255,255,255,.7);
}
.lang:hover { color: #fff; }
.lang.is-on { background: var(--accent); color: var(--navy); }

/* --------------------------------- hero -------------------------------- */
.hero {
    padding: clamp(56px, 8vw, 104px) 0 0;
    background:
        radial-gradient(120% 130% at 78% 8%, var(--navy-soft) 0%, var(--navy) 46%, var(--navy-deep) 100%);
    color: #fff;
}
.hero-inner {
    display: grid;
    grid-template-columns: minmax(0, 1.15fr) minmax(0, .85fr);
    gap: clamp(24px, 5vw, 64px);
    align-items: center;
}
.hero-copy .lede { margin-top: 20px; max-width: 52ch; color: rgba(255,255,255,.78); }
.hero-actions { display: flex; flex-wrap: wrap; gap: 12px; margin-top: 30px; }
.hero-note { margin-top: 18px; font-size: 13.5px; color: rgba(255,255,255,.55); }

.stats {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 20px;
    margin-top: clamp(40px, 6vw, 72px);
    padding-bottom: clamp(40px, 6vw, 72px);
}
.stat {
    padding: 20px 22px;
    border: 1px solid rgba(255,255,255,.14);
    border-radius: var(--radius);
    background: rgba(255,255,255,.05);
}
.stat b    { display: block; font-size: clamp(1.6rem, 3vw, 2.1rem); font-weight: 800; color: var(--accent); }
.stat span { display: block; margin-top: 4px; font-size: 14px; font-weight: 700; color: #fff; }
.stat i    { display: block; margin-top: 6px; font-size: 12.5px; font-style: normal;
             line-height: 1.5; color: rgba(255,255,255,.55); }

/* ------------------------- hero scene animation ------------------------ */
/* One 9s loop tells the whole story: phones connect, the connection becomes
   a record, the records fill the list, the list sends. Every element is on
   the SAME duration with a different delay, so the beats stay in order no
   matter how long the page has been open - staggering by duration instead
   would let them drift apart. */
.scene { width: 100%; height: auto; overflow: visible; }

/* 1. the access point casting downward */
.wave { transform-origin: 230px 45px; }
.w1 { animation: wgl-wave 2.4s ease-out infinite; }
.w2 { animation: wgl-wave 2.4s ease-out .28s infinite; }
.w3 { animation: wgl-wave 2.4s ease-out .56s infinite; }
@keyframes wgl-wave {
    0%   { opacity: 0;   transform: scale(.82); }
    28%  { opacity: .95; }
    70%  { opacity: 0;   transform: scale(1.06); }
    100% { opacity: 0;   transform: scale(1.06); }
}

/* 2. a phone lights up as it connects */
.phone .screen { opacity: .18; }
.p1 .screen { animation: wgl-screen 9s ease-in-out infinite; }
.p2 .screen { animation: wgl-screen 9s ease-in-out 1.1s infinite; }
.p3 .screen { animation: wgl-screen 9s ease-in-out 2.2s infinite; }
@keyframes wgl-screen {
    0%, 4%   { opacity: .18; }
    8%, 26%  { opacity: .95; }
    34%,100% { opacity: .18; }
}

/* 3. the record travelling from that phone into the list.
      translate() on a circle at the origin, so the keyframes read as the
      actual coordinates on the drawing. */
.packet { opacity: 0; }
.k1 { animation: wgl-k1 9s linear .35s infinite; }
.k2 { animation: wgl-k2 9s linear 1.45s infinite; }
.k3 { animation: wgl-k3 9s linear 2.55s infinite; }
@keyframes wgl-k1 {
    0%       { opacity: 0; transform: translate(89px, 206px); }
    4%       { opacity: 1; }
    22%      { opacity: 1; transform: translate(230px, 268px); }
    26%,100% { opacity: 0; transform: translate(230px, 268px); }
}
@keyframes wgl-k2 {
    0%       { opacity: 0; transform: translate(230px, 206px); }
    4%       { opacity: 1; }
    22%      { opacity: 1; transform: translate(230px, 268px); }
    26%,100% { opacity: 0; transform: translate(230px, 268px); }
}
@keyframes wgl-k3 {
    0%       { opacity: 0; transform: translate(371px, 206px); }
    4%       { opacity: 1; }
    22%      { opacity: 1; transform: translate(230px, 268px); }
    26%,100% { opacity: 0; transform: translate(230px, 268px); }
}

/* 4. the list filling. translateY on a rect clipped to the cylinder, so the
      fill keeps the cylinder's curved bottom. */
.dbfill { animation: wgl-fill 9s ease-in-out infinite; }
@keyframes wgl-fill {
    0%      { transform: translateY(58px); }
    45%     { transform: translateY(14px); }
    72%     { transform: translateY(14px); }
    100%    { transform: translateY(58px); }
}
/* A pulse at the moment the list is full - the cue that something is about
   to leave it. */
.db { animation: wgl-db 9s ease-in-out infinite; transform-origin: 230px 300px; }
@keyframes wgl-db {
    0%, 42%  { transform: scale(1); }
    48%      { transform: scale(1.035); }
    56%,100% { transform: scale(1); }
}

/* 5. and the sends leaving it */
.send { opacity: 0; }
.s1 { animation: wgl-s1 9s ease-out 4.9s infinite; }
.s2 { animation: wgl-s2 9s ease-out 5.25s infinite; }
.s3 { animation: wgl-s3 9s ease-out 5.6s infinite; }
@keyframes wgl-s1 {
    0%       { opacity: 0; transform: translate(230px, 320px) scale(.6); }
    6%       { opacity: 1; transform: translate(230px, 320px) scale(1); }
    26%      { opacity: 1; transform: translate(64px, 378px) scale(1); }
    34%,100% { opacity: 0; transform: translate(64px, 386px) scale(1); }
}
@keyframes wgl-s2 {
    0%       { opacity: 0; transform: translate(230px, 320px) scale(.6); }
    6%       { opacity: 1; transform: translate(230px, 320px) scale(1); }
    26%      { opacity: 1; transform: translate(396px, 378px) scale(1); }
    34%,100% { opacity: 0; transform: translate(396px, 386px) scale(1); }
}
@keyframes wgl-s3 {
    0%       { opacity: 0; transform: translate(230px, 320px) scale(.6); }
    6%       { opacity: 1; transform: translate(230px, 320px) scale(1); }
    26%      { opacity: 1; transform: translate(230px, 392px) scale(1); }
    34%,100% { opacity: 0; transform: translate(230px, 400px) scale(1); }
}

/* -------------------------------- bands -------------------------------- */
.band { padding: clamp(64px, 9vw, 112px) 0; }
.band-tint { background: var(--tint); }
.band-dark {
    background: radial-gradient(110% 120% at 20% 0%, var(--navy-soft) 0%, var(--navy) 55%, var(--navy-deep) 100%);
    color: #fff;
}
.band-dark h2 { max-width: 26ch; }

/* ---------------------------- client logos ----------------------------- */
/* A moving strip. Greyscale at rest, colour on hover - ten logos drawn by ten
   different designers, at ten different weights, are visual noise in full
   colour; flattening them to one grey is what makes the row read as one row. */
.clients {
    padding: 40px 0;
    background: var(--white);
    border-bottom: 1px solid var(--line);
}
.clients-title {
    margin-bottom: 24px;
    text-align: center;
    font-size: 12px; font-weight: 800; letter-spacing: .12em;
    text-transform: uppercase; color: var(--ink-soft);
}

/* No .wrap around this one: the strip runs the full width of the viewport,
   which is what makes it read as continuous rather than as a row in a box. */
.clients-marquee {
    overflow: hidden;
    /* Fades the logos out at both ends instead of slicing them off at the
       viewport edge. Masked rather than covered by a gradient overlay, so it
       works whatever colour the section is. */
    -webkit-mask-image: linear-gradient(90deg, transparent, #000 6%, #000 94%, transparent);
            mask-image: linear-gradient(90deg, transparent, #000 6%, #000 94%, transparent);
}
.clients-track {
    display: flex;
    width: max-content;
    animation: wgl-marquee var(--marquee-dur, 40s) linear infinite;
}
/* Stops so a visitor can actually look at one - which is also where the colour
   comes back. A strip that will not hold still cannot be read. */
.clients-marquee:hover .clients-track { animation-play-state: paused; }

.clients-set {
    display: flex;
    align-items: center;
    /* The gap is on both sides of every logo, so the space between the last of
       one copy and the first of the next matches the rest. Without the padding
       the two copies would butt together and the seam would show. */
    gap: clamp(28px, 4vw, 56px);
    padding: 0 clamp(14px, 2vw, 28px);
}
.clients-set img {
    /* Height, not width: the set arrives in every aspect ratio and matching
       the heights is what makes them look equally sized. flex-shrink off,
       or the track would compress instead of scrolling. */
    flex: 0 0 auto;
    height: 48px;
    width: auto;
    max-width: 150px;
    object-fit: contain;
    filter: grayscale(1);
    /* .55 disappeared against white once the logos were real - most of them
       are mid-tone emblems, not black wordmarks. */
    opacity: .72;
    transition: filter .2s ease, opacity .2s ease;
}
.clients-set img:hover { filter: none; opacity: 1; }
/* A white logo cannot reveal its colour on a white strip, so it stays a dark
   silhouette and only lifts in opacity. brightness(0) flattens every shade to
   black - interior detail is the trade for being visible at all. Send a
   dark-ink version and drop the -light suffix to get the detail back. */
.clients-set img.is-light { filter: brightness(0); }
.clients-set img.is-light:hover { filter: brightness(0); opacity: 1; }

@keyframes wgl-marquee {
    /* One set to the left, so a copy lands exactly where the original started.
       --marquee-shift is measured and published by site.js, because the width
       of one set depends on which logos are in the folder. The -50% fallback
       is what the two sets PHP prints come to when the script has not run. */
    to { transform: translateX(calc(-1 * var(--marquee-shift, 50%))); }
}

@media (max-width: 560px) {
    .clients-set { gap: 26px; }
    .clients-set img { height: 38px; max-width: 116px; }
}

/* Motion that never stops is the clearest case for this preference. Stopped,
   the strip becomes a plain centred row - and the second copy goes, or the
   static row would show the same ten logos twice. */
@media (prefers-reduced-motion: reduce) {
    .clients-marquee {
        -webkit-mask-image: none;
                mask-image: none;
    }
    .clients-track { animation: none; width: 100%; justify-content: center; flex-wrap: wrap; }
    .clients-set[aria-hidden="true"] { display: none; }
    .clients-set { flex-wrap: wrap; justify-content: center; row-gap: 22px; }
}

/* ---------------------------- what we do ------------------------------- */
.cards {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
    gap: 20px;
    margin-top: 44px;
}
.card {
    padding: 26px 24px 28px;
    border: 1px solid var(--line);
    border-radius: var(--radius);
    background: var(--white);
    transition: border-color .15s ease, box-shadow .15s ease, transform .15s ease;
}
.card:hover { border-color: #c9d6e6; box-shadow: var(--shadow); transform: translateY(-2px); }
.card-icon {
    display: inline-flex; align-items: center; justify-content: center;
    width: 44px; height: 44px; margin-bottom: 18px;
    border-radius: 12px;
    background: var(--navy); color: var(--accent);
}
.card-icon svg { width: 22px; height: 22px; }
.card h3 { margin-bottom: 8px; }
.card p  { color: var(--ink-soft); font-size: 15.5px; }

/* --------------------------- what we solve ----------------------------- */
.solves { display: grid; gap: 14px; margin-top: 44px; }
.solve {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1.35fr);
    gap: clamp(16px, 3vw, 40px);
    align-items: start;
    padding: 24px 26px;
    border: 1px solid var(--line);
    border-radius: var(--radius);
    background: var(--white);
}
.solve-problem {
    font-size: 1.06rem; font-weight: 700; line-height: 1.45;
    color: var(--navy);
}
.solve-solution { color: var(--ink-soft); font-size: 15.5px; }
/* The mark that ties the two halves together without a word for it. */
.solve-solution::before {
    content: "";
    display: block; width: 26px; height: 3px; margin-bottom: 12px;
    border-radius: 2px; background: var(--accent);
}

/* ------------------------------- steps --------------------------------- */
.steps {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
    gap: 24px;
    margin: 44px 0 0;
    padding: 0;
    list-style: none;
    counter-reset: step;
}
.steps li { padding-top: 8px; border-top: 3px solid var(--line); }
.step-n {
    display: inline-flex; align-items: center; justify-content: center;
    width: 30px; height: 30px; margin: 12px 0 14px;
    border-radius: 999px;
    background: var(--navy); color: var(--accent);
    font-size: 14px; font-weight: 800;
}
.steps h3 { margin-bottom: 8px; }
.steps p  { color: var(--ink-soft); font-size: 15.5px; }

/* ------------------------- technical diagram --------------------------- */
/* "Point your WiFi at a page" is the sentence a network person distrusts, so
   the path gets drawn. Four nodes in traffic order; on a narrow screen the
   row becomes a column and the arrows rotate rather than being hidden - the
   direction IS the content here. */
.diagram {
    margin-top: clamp(36px, 5vw, 60px);
    padding: clamp(24px, 4vw, 40px);
    border: 1px solid var(--line);
    border-radius: var(--radius);
    background: var(--tint);
}
.diagram-title {
    max-width: 44ch;
    margin-bottom: 26px;
    font-size: 1.05rem;
    font-weight: 700;
    color: var(--navy);
}
.flow { display: flex; align-items: stretch; gap: 10px; }
.node {
    flex: 1 1 0;
    min-width: 0;
    padding: 18px 16px;
    border: 1px solid var(--line);
    border-radius: var(--radius-sm);
    background: var(--white);
    text-align: center;
}
.node-icon {
    display: inline-flex; align-items: center; justify-content: center;
    width: 38px; height: 38px; margin-bottom: 12px;
    border-radius: 10px;
    background: var(--navy); color: var(--accent);
}
.node-icon svg { width: 20px; height: 20px; }
.node b { display: block; font-size: 14px; font-weight: 700; color: var(--navy); line-height: 1.3; }
.node i { display: block; margin-top: 4px; font-size: 12.5px; font-style: normal; color: var(--ink-soft); }

.flow-arrow {
    flex: 0 0 auto;
    display: flex; align-items: center;
    color: #a9bcd4;
}
.flow-arrow svg { width: 30px; height: 16px; }

.diagram-note {
    margin-top: 22px;
    max-width: 74ch;
    font-size: 14px;
    color: var(--ink-soft);
}

/* --------------------------- install paths ----------------------------- */
.installs {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
    gap: 20px;
    margin-top: 44px;
}
.install {
    padding: 28px 26px;
    border: 1px solid var(--line);
    border-radius: var(--radius);
    background: var(--white);
}
/* The self-install path is the cheaper, faster one and the one most venues
   land on, so it is the one that reads first. */
.install.is-primary { border-color: var(--navy); box-shadow: var(--shadow); }
.install-tag {
    display: inline-block;
    margin-bottom: 14px;
    padding: 5px 12px;
    border-radius: 999px;
    background: var(--tint);
    font-size: 11.5px; font-weight: 800; letter-spacing: .08em;
    text-transform: uppercase; color: var(--navy);
}
.install.is-primary .install-tag { background: var(--accent); }
.install h3 { margin-bottom: 10px; font-size: 1.2rem; }
.install p  { color: var(--ink-soft); font-size: 15.5px; }
.install-points { margin: 18px 0 0; padding: 0; list-style: none; }
.install-points li {
    position: relative;
    padding: 7px 0 7px 26px;
    font-size: 14.5px;
    border-top: 1px solid var(--line);
}
.install-points li:first-child { border-top: 0; }
/* A check drawn in CSS: two borders rotated, so there is no icon font and no
   extra request for six ticks. */
.install-points li::before {
    content: "";
    position: absolute; left: 4px; top: 13px;
    width: 10px; height: 5px;
    border-left: 2px solid var(--accent-dark);
    border-bottom: 2px solid var(--accent-dark);
    transform: rotate(-45deg);
}

/* ------------------------------- values -------------------------------- */
.values {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
    gap: 20px;
    margin-top: 44px;
}
.value {
    padding: 24px 22px;
    border: 1px solid rgba(255,255,255,.14);
    border-radius: var(--radius);
    background: rgba(255,255,255,.05);
}
.value h3 { margin-bottom: 8px; color: #fff; }
.value p  { color: rgba(255,255,255,.7); font-size: 15.5px; }

/* -------------------------------- form --------------------------------- */
.book {
    display: grid;
    grid-template-columns: minmax(0, .8fr) minmax(0, 1.2fr);
    gap: clamp(28px, 5vw, 64px);
    align-items: start;
}
.book-intro { position: sticky; top: 100px; }

.form {
    padding: clamp(22px, 3vw, 34px);
    border: 1px solid var(--line);
    border-radius: var(--radius);
    background: var(--white);
    box-shadow: var(--shadow);
}
.grid-2 { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 16px; }

.field { display: block; margin-bottom: 16px; }
.grid-2 .field { margin-bottom: 0; }
/* The grid owns its own gaps, so a field that follows it needs the space the
   grid did not give it - the notes box was landing against the selects. */
.grid-2 + .field { margin-top: 16px; }
.field-label {
    display: block; margin-bottom: 6px;
    font-size: 13px; font-weight: 700; color: var(--navy);
}
.field-label em { color: #d33; font-style: normal; }
.field input, .field select, .field textarea {
    width: 100%;
    padding: 11px 13px;
    border: 1px solid var(--line);
    border-radius: var(--radius-sm);
    background: var(--white);
    color: var(--ink);
    font: inherit; font-size: 15px;
    transition: border-color .15s ease, box-shadow .15s ease;
}
.field textarea { resize: vertical; }
.field input:focus, .field select:focus, .field textarea:focus {
    outline: none;
    border-color: var(--navy);
    box-shadow: 0 0 0 3px rgba(23, 45, 80, .10);
}
.field.has-error input, .field.has-error select, .field.has-error textarea {
    border-color: #d33;
}
.field-error { display: block; margin-top: 5px; font-size: 12.5px; color: #c22; }

.check { display: flex; gap: 10px; align-items: flex-start; margin: 20px 0 0; font-size: 14.5px; }
.check input { margin-top: 3px; width: 17px; height: 17px; accent-color: var(--navy); flex: 0 0 auto; }
.check.has-error span { color: #c22; }

.form-foot { display: flex; flex-wrap: wrap; align-items: center; gap: 16px; margin-top: 22px; }
.form-privacy { font-size: 13px; color: var(--ink-soft); }
.form-privacy a { color: var(--navy); }

.form-msg {
    margin-top: 20px;
    padding: 16px 18px;
    border-radius: var(--radius-sm);
    font-size: 15px;
}
.form-msg b { display: block; margin-bottom: 4px; }
.form-msg.is-ok  { background: #eef7d6; border: 1px solid #cfe89a; color: #3f5a10; }
.form-msg.is-err { background: #fdecec; border: 1px solid #f6c9c9; color: #8f2020; }

/* The honeypot: off-screen rather than display:none, because some bots skip
   fields that are not rendered at all. */
.hp { position: absolute; left: -5000px; width: 1px; height: 1px; overflow: hidden; }

/* -------------------------------- footer ------------------------------- */
.foot { background: var(--navy-deep); color: rgba(255,255,255,.72); padding: 60px 0 26px; }
.foot-inner {
    display: grid;
    grid-template-columns: minmax(0, 1.4fr) repeat(3, minmax(0, 1fr));
    gap: 32px;
}
.foot-brand .lockup { margin-bottom: 16px; }
.foot-brand p { max-width: 30ch; font-size: 15px; color: rgba(255,255,255,.6); }
.foot-col h4 { margin-bottom: 12px; font-size: 12px; letter-spacing: .1em;
               text-transform: uppercase; color: var(--accent); }
.foot-col a { display: block; margin-bottom: 8px; font-size: 14.5px;
              text-decoration: none; color: rgba(255,255,255,.72); }
.foot-col a:hover { color: #fff; }
.foot-legal {
    margin-top: 44px; padding-top: 20px;
    border-top: 1px solid rgba(255,255,255,.10);
    font-size: 13px; color: rgba(255,255,255,.45);
}

/* ------------------------------ responsive ----------------------------- */
@media (max-width: 900px) {
    /* The flow direction is the content, so the arrows rotate instead of
       disappearing. */
    .flow { flex-direction: column; }
    .flow-arrow { justify-content: center; transform: rotate(90deg); }
    .hero-inner { grid-template-columns: 1fr; }
    .hero-art { order: -1; max-width: 360px; margin: 0 auto; }
    .stats { grid-template-columns: 1fr; }
    .solve { grid-template-columns: 1fr; }
    .book { grid-template-columns: 1fr; }
    .book-intro { position: static; }
    .foot-inner { grid-template-columns: 1fr 1fr; }
}

/* Its own breakpoint, wider than the layout one: five translated labels plus
   the toggle plus the CTA stop fitting well before the page needs to reflow.
   The toggle and the CTA are what has to survive - they are the only two
   things in that bar a visitor cannot get to by scrolling. */
@media (max-width: 1120px) {
    .nav-links { display: none; }
}
@media (max-width: 560px) {
    .nav-inner { height: 64px; gap: 12px; }
    .lockup-logo { height: 34px; }   /* the nav is 8px shorter here */
    .nav-cta { display: none; }

    /* Touch targets. On a phone these three are the only controls in the bar,
       and at 40x30 they were the smallest thing on the page to hit - under the
       44px Apple and Google both recommend, and a miss switches language
       instead of doing nothing. Widening the pill rather than the font keeps
       the bar's proportions. Three 44px targets plus the logo still leave room
       at 320px, the narrowest phone in use. */
    .langs { gap: 0; padding: 2px; }
    .lang  { min-width: 44px; min-height: 44px; padding: 5px 8px; font-size: 13px; }
    .foot-inner { grid-template-columns: 1fr; }
}

@media (prefers-reduced-motion: reduce) {
    html { scroll-behavior: auto; }
    * { transition: none !important; }
    /* The scene is decorative and loops forever - it is exactly what this
       preference is for. Stopped at the frame that reads best rather than
       hidden: the drawing still explains the product standing still. */
    .scene * { animation: none !important; }
    .scene .wave, .scene .phone .screen { opacity: .9; }
    .scene .packet, .scene .send { opacity: 1; }
    .scene .dbfill { transform: translateY(22px); }
    .scene .s1 { transform: translate(64px, 378px); }
    .scene .s2 { transform: translate(396px, 378px); }
    .scene .s3 { transform: translate(230px, 392px); }
    .scene .k1 { transform: translate(150px, 232px); }
    .scene .k2 { transform: translate(230px, 240px); }
    .scene .k3 { transform: translate(310px, 232px); }
}
