/* ==========================================================================
   Fibercity — design system

   Direction: the brand is deep navy and white, taken straight from the mark
   itself — pure white strokes with two cooler tints, #A4B3DE and #E4E7FF,
   sitting on a night-blue ground. The site is built from exactly that and
   nothing else: the accent is the navy of the masthead itself. On paper it
   prints dark — rules, ticks, icons, filled buttons — and on the navy field
   it prints white, so the two are the same one accent seen on two grounds.

   Surfaces: the masthead and the opening field are one continuous navy block,
   so the white logotype always sits on its proper ground. Below it the page
   turns to pale blue-white paper, and the tariff sheet crosses the seam
   between the two. Navy returns for the featured plan, the verdict and the
   footer — and the page closes on a second white sheet that crosses the seam
   into that footer, mirroring the one it opened with.

   Every colour comes from the design tokens. Tailwind utilities do layout and
   spacing; this file holds the components and the motion. The page opens with
   one orchestrated sequence — the network draws itself, the headline arrives
   line by line and the three speeds measure themselves out — and from there
   each section arrives as it is reached, in that same drawn language.
   ========================================================================== */

:root {
    --font-display: 'Geologica', 'Golos Text', system-ui, sans-serif;
    --font-body: 'Golos Text', system-ui, sans-serif;

    /* The two cooler tints of the logotype, used for the quiet voice on navy */
    --sky: 231 100% 95%;
    --haze: 226 44% 76%;

    /* The accent as it reads on the navy ground. On paper the accent is the
       navy itself; on the navy it can only be its opposite, so it is the pure
       white of the logotype. One accent, two grounds — never a third colour. */
    --beam: 0 0% 100%;
}

/* --------------------------------------------------------------------------
   0. The page frame

   The document holds itself: it scrolls up and down freely, but never
   sideways, never rubber-bands past its own two ends, and cannot be pinched
   or zoomed. The scrollbar is drawn in the colours of the site — a bare navy
   bar on glass, nothing else — and nothing that belongs to the interface can be dragged
   off the page or caught in a selection: photographs, the logotype, the icons
   and every control behave like interface, while the words themselves stay
   selectable and the phone number and address stay copyable.
   -------------------------------------------------------------------------- */
/* The page scrolls up and down exactly as it should. It simply never scrolls
   sideways, never carries on past its own two ends, and cannot be pinched or
   zoomed — both pans stay open, so scrolling itself is never touched. Only
   the root carries an overflow: the moment the root and the body are both
   clipped, the browser clips the viewport itself and the page stops
   scrolling altogether. */
html {
    overflow-x: hidden;
    overflow-y: auto;
    overscroll-behavior: none;
    touch-action: pan-x pan-y;
    -webkit-text-size-adjust: 100%;
    text-size-adjust: 100%;
}

body {
    max-width: 100%;
    -webkit-tap-highlight-color: transparent;
}

/* Nothing overflows the frame sideways, whatever it is. */
img,
svg,
video,
iframe,
table {
    max-width: 100%;
}

/* While the mobile menu is open the page underneath stays exactly where it
   was, instead of scrolling away behind the panel. */
html.is-locked {
    overflow: hidden;
}

/* --------------------------------------------------------------------------
   0a. The scrollbar, drawn in the colours of the site

   Nothing but the position itself: no gutter, no tray, no empty grey band —
   the track is glass, so whatever the page is showing carries straight
   through it. The slug is a plain square bar in the navy of the mark, with
   no rounded ends, and it deepens as it is taken hold of. Blink and WebKit
   are given the real parts; Firefox, which has no such parts, is given the
   two colours it does understand — and only Firefox, because the moment
   those two properties are set in Blink it drops the drawn scrollbar and
   hands back the default one.
   -------------------------------------------------------------------------- */
::-webkit-scrollbar {
    width: 9px;
    height: 9px;
    background: transparent;
}

::-webkit-scrollbar-track,
::-webkit-scrollbar-track-piece {
    background: transparent;
    border: 0;
    box-shadow: none;
}

::-webkit-scrollbar-thumb {
    border: 0;
    border-radius: 0;
    background-color: hsl(var(--primary) / 0.45);
    transition: background-color 0.2s ease;
}

::-webkit-scrollbar-thumb:hover {
    background-color: hsl(var(--primary) / 0.7);
}

::-webkit-scrollbar-thumb:active {
    background-color: hsl(var(--primary));
}

/* The two ends stay empty: no buttons, no corner block. */
::-webkit-scrollbar-button {
    display: none;
    height: 0;
    width: 0;
}

::-webkit-scrollbar-corner {
    background: transparent;
}

@supports (scrollbar-color: red blue) and (not selector(::-webkit-scrollbar)) {
    html,
    textarea,
    .lang-menu {
        scrollbar-width: thin;
        scrollbar-color: hsl(var(--primary) / 0.45) transparent;
    }
}

/* --------------------------------------------------------------------------
   0a-ii. The indicator the site draws itself

   On anything with a pointer, the browser bar is taken away altogether — no
   gutter, no tray, no reserved band of any kind — and the page runs the full
   width of the window. In its place the site draws the one thing that was
   ever wanted: the position. A slim square bar, floating over the page on
   nothing at all, so whatever is behind it carries straight through. It
   prints dark on the paper and white over the navy fields, the same one
   accent on its two grounds, and it deepens as it is taken hold of.
   -------------------------------------------------------------------------- */
html.has-rail {
    scrollbar-width: none;
}

html.has-rail::-webkit-scrollbar {
    display: none;
    width: 0;
    height: 0;
}

.scroll-rail {
    position: fixed;
    top: 0;
    right: 0;
    bottom: 0;
    z-index: 80;
    width: 9px;
    background: none;
    pointer-events: none;
    opacity: 0;
    transition: opacity 0.25s ease;
}

.scroll-rail.is-ready {
    opacity: 1;
}

.scroll-rail-bar {
    position: absolute;
    top: 0;
    right: 2px;
    width: 5px;
    background: hsl(var(--foreground) / 0.32);
    pointer-events: auto;
    transition: background-color 0.2s ease;
}

.scroll-rail-bar:hover,
.scroll-rail.is-held .scroll-rail-bar {
    background: hsl(var(--foreground) / 0.72);
}

/* Over the navy fields the indicator turns over, exactly as the accent does. */
.scroll-rail.is-on-dark .scroll-rail-bar {
    background: hsl(var(--background) / 0.42);
}

.scroll-rail.is-on-dark .scroll-rail-bar:hover,
.scroll-rail.is-on-dark.is-held .scroll-rail-bar {
    background: hsl(var(--background) / 0.9);
}

/* --------------------------------------------------------------------------
   0b. Interface, not content

   Photographs, the logotype, icons and every control behave like interface:
   they cannot be dragged off the page, caught in a stray selection or held
   down for a save menu. The words themselves — headings, paragraphs, answers
   and the phone number and address — stay selectable and copyable.
   -------------------------------------------------------------------------- */
body {
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
}

p,
h1,
h2,
h3,
h4,
h5,
h6,
blockquote,
li,
dd,
dt,
address,
figcaption,
input,
textarea,
select,
option,
[data-selectable] {
    -webkit-user-select: text;
    -moz-user-select: text;
    user-select: text;
}

/* Controls come last, so a heading or a label inside one is interface too. */
a,
button,
summary,
label,
nav,
.btn,
.icon-btn,
.navlink,
.menu-link,
.lang-toggle,
.lang-option,
.social,
.footer-link,
.plan-tag,
.measure-row,
.plant .cap,
.closing-eyebrow,
[role='img'],
a *,
button *,
summary *,
label * {
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
}

/* Except the two things people genuinely copy. */
a[href^='tel:']:not(.btn),
a[href^='mailto:']:not(.btn),
a[href^='tel:']:not(.btn) *,
a[href^='mailto:']:not(.btn) * {
    -webkit-user-select: text;
    -moz-user-select: text;
    user-select: text;
}

img,
svg,
a {
    -webkit-user-drag: none;
}

img {
    -webkit-touch-callout: none;
    pointer-events: none;
}

/* A photograph inside a link stays clickable, it simply cannot be dragged. */
a img,
button img {
    pointer-events: auto;
}

::selection {
    background: hsl(var(--primary));
    color: hsl(var(--primary-foreground));
}

/* --------------------------------------------------------------------------
   Base typography
   -------------------------------------------------------------------------- */
h1,
h2,
h3,
h4 {
    font-family: var(--font-display);
    overflow-wrap: break-word;
}

h1 {
    letter-spacing: -0.03em;
}

h2 {
    letter-spacing: -0.025em;
}

h3,
h4 {
    letter-spacing: -0.015em;
}

h1,
h2,
h3 {
    text-wrap: balance;
}

p {
    text-wrap: pretty;
    overflow-wrap: break-word;
}

/* Measured values never jitter between rows. */
.num {
    font-family: var(--font-display);
    font-variant-numeric: tabular-nums;
    letter-spacing: -0.02em;
}

.unit {
    font-family: var(--font-body);
    font-size: 0.5em;
    font-weight: 500;
    letter-spacing: 0;
    color: hsl(var(--muted-foreground));
}

/* Reading measure: body copy never runs past a comfortable line. */
.lede {
    max-width: 46ch;
    font-size: 1.0625rem;
    line-height: 1.7;
    color: hsl(var(--muted-foreground));
}

@media (min-width: 640px) {
    .lede {
        font-size: 1.15rem;
    }
}

/* Section heading, used on paper and on navy alike. */
.head {
    font-size: clamp(1.75rem, 4vw, 2.75rem);
    font-weight: 600;
    line-height: 1.1;
}

/* A hairline that opens a section, with a short heavy segment in navy. */
.rule {
    position: relative;
    height: 1px;
    background: hsl(var(--border));
}

.rule::before {
    content: '';
    position: absolute;
    left: 0;
    top: -1px;
    height: 3px;
    width: 3.5rem;
    background: hsl(var(--primary));
}

/* --------------------------------------------------------------------------
   1. Buttons
   Square-shouldered, 4px radius, no gradients and no glow. The filled button
   carries the one accent of the site: on paper it is navy with white type,
   and on the navy field it turns over — white ground, navy type — so a
   visitor is always asked to act on the same one colour.
   -------------------------------------------------------------------------- */
.btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0.55rem;
    min-height: 2.75rem;
    border-radius: var(--radius);
    padding: 0.9rem 1.4rem;
    text-align: center;
    font-family: var(--font-body);
    font-size: 0.95rem;
    font-weight: 600;
    line-height: 1;
    border: 1px solid transparent;
    transition:
        background-color 0.2s ease,
        border-color 0.2s ease,
        color 0.2s ease,
        transform 0.12s ease;
}

.btn svg {
    height: 1.05rem;
    width: 1.05rem;
    flex: none;
}

.btn-signal {
    background: hsl(var(--primary));
    color: hsl(var(--primary-foreground));
}

.btn-signal:hover {
    background: hsl(var(--accent));
}

.btn-ghost {
    border-color: hsl(var(--foreground) / 0.25);
    color: hsl(var(--foreground));
}

.btn-ghost:hover {
    border-color: hsl(var(--foreground));
    background: hsl(var(--foreground));
    color: hsl(var(--background));
}

/* On a navy field the outline flips to light. */
.btn-onink {
    border-color: hsl(var(--background) / 0.32);
    color: hsl(var(--background));
}

/* On a navy field the filled button flips: white ground, navy type. It is the
   same accent as the dark button on paper, simply printed on the other
   ground — and it cools a shade under the pointer instead of deepening. */
.masthead .btn-signal,
.hero .btn-signal,
.plan-pick .btn-signal,
.vs-verdict .btn-signal,
.site-footer .btn-signal {
    background: hsl(var(--beam));
    color: hsl(var(--foreground));
}

.masthead .btn-signal:hover,
.hero .btn-signal:hover,
.plan-pick .btn-signal:hover,
.vs-verdict .btn-signal:hover,
.site-footer .btn-signal:hover {
    background: hsl(var(--sky));
    color: hsl(var(--foreground));
}

/* On a navy field the outline button fills white as it is reached. */
.btn-onink:hover {
    border-color: hsl(var(--beam));
    background: hsl(var(--beam));
    color: hsl(var(--foreground));
}

/* The compact size matches the height of the other header controls. */
.btn-sm {
    height: 2.75rem;
    padding: 0 1.05rem;
    font-size: 0.875rem;
}

/* The last ask on the page carries the largest button on it. */
.btn-lg {
    padding: 1.05rem 1.8rem;
    font-size: 1rem;
}

/* --------------------------------------------------------------------------
   2. Masthead
   Always navy, so the white logotype sits on its proper ground and runs
   straight into the opening field below it.
   -------------------------------------------------------------------------- */
.masthead {
    background: hsl(var(--foreground));
}

/* Once the page has moved, the masthead is underlined with a hairline. */
.masthead.is-scrolled {
    box-shadow: 0 1px 0 hsl(var(--beam) / 0.3);
}

.logo {
    display: inline-flex;
    flex: none;
    align-items: center;
}

.logo img {
    display: block;
    height: 1.6rem;
    width: auto;
}

.logo-lg img {
    height: 2rem;
}

@media (min-width: 640px) {
    .logo img {
        height: 1.8rem;
    }

    .logo-lg img {
        height: 2.35rem;
    }
}

/* Navigation: a rule under the link, not a pill around it. */
.navlink {
    position: relative;
    padding: 0.35rem 0;
    font-size: 0.95rem;
    font-weight: 500;
    color: hsl(var(--haze));
    transition: color 0.2s ease;
}

.navlink::after {
    content: '';
    position: absolute;
    left: 0;
    right: 0;
    bottom: -0.15rem;
    height: 2px;
    background: hsl(var(--beam));
    transform: scaleX(0);
    transform-origin: left;
    transition: transform 0.25s ease;
}

.navlink:hover,
.navlink.is-active {
    color: hsl(var(--background));
}

.navlink:hover::after,
.navlink.is-active::after {
    transform: scaleX(1);
}

/* Mobile panel */
.menu-panel {
    border-top: 1px solid hsl(var(--background) / 0.14);
    background: hsl(var(--foreground));
}

/* Comfortable to hit with a thumb, and marked in white as it is touched. */
.menu-link {
    position: relative;
    display: block;
    padding: 1.05rem 0 1.05rem 0.9rem;
    border-bottom: 1px solid hsl(var(--background) / 0.1);
    font-size: 1.0625rem;
    font-weight: 500;
    color: hsl(var(--haze));
    transition:
        color 0.2s ease,
        padding-left 0.2s ease;
}

.menu-link::before {
    content: '';
    position: absolute;
    left: 0;
    top: 50%;
    height: 1.15rem;
    width: 3px;
    background: hsl(var(--beam));
    transform: translateY(-50%) scaleY(0);
    transform-origin: center;
    transition: transform 0.2s ease;
}

.menu-link:last-child {
    border-bottom: 0;
}

.menu-link:hover,
.menu-link:focus-visible {
    color: hsl(var(--background));
    padding-left: 1.15rem;
}

.menu-link:hover::before,
.menu-link:focus-visible::before {
    transform: translateY(-50%) scaleY(1);
}

.icon-btn {
    display: inline-grid;
    place-items: center;
    height: 2.75rem;
    width: 2.75rem;
    flex: none;
    border-radius: var(--radius);
    border: 1px solid hsl(var(--background) / 0.28);
    color: hsl(var(--background));
    transition:
        border-color 0.2s ease,
        background 0.2s ease,
        color 0.2s ease;
}

.icon-btn:hover {
    border-color: hsl(var(--beam));
    background: hsl(var(--beam) / 0.16);
    color: hsl(var(--background));
}

.icon-btn[aria-expanded='true'] {
    border-color: hsl(var(--beam));
    background: hsl(var(--beam));
    color: hsl(var(--foreground));
}

/* --------------------------------------------------------------------------
   3. Language switcher
   The pages are written in Macedonian. When a visitor has chosen another
   language the document is marked while the text is swapped, so the change is
   never visible as a flash.
   -------------------------------------------------------------------------- */
html[data-lang-loading] body {
    opacity: 0;
}

body {
    transition: opacity 0.16s ease;
}

.lang {
    position: relative;
    flex: none;
}

.lang-toggle {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    height: 2.75rem;
    padding: 0 0.7rem;
    border-radius: var(--radius);
    border: 1px solid hsl(var(--background) / 0.28);
    color: hsl(var(--background));
    font-size: 0.85rem;
    font-weight: 600;
    transition:
        border-color 0.2s ease,
        background 0.2s ease;
}

.lang-toggle:hover,
.lang.is-open .lang-toggle {
    border-color: hsl(var(--beam));
    background: hsl(var(--beam) / 0.16);
}

.lang-globe {
    height: 1rem;
    width: 1rem;
    flex: none;
    opacity: 0.8;
}

.lang-caret {
    height: 0.7rem;
    width: 0.7rem;
    flex: none;
    opacity: 0.75;
    transition: transform 0.2s ease;
}

.lang.is-open .lang-caret {
    transform: rotate(180deg);
}

.lang-menu {
    position: absolute;
    right: 0;
    top: calc(100% + 0.5rem);
    z-index: 60;
    display: grid;
    min-width: 12rem;
    max-width: calc(100vw - 2rem);
    padding: 0.3rem;
    border-radius: var(--radius);
    border: 1px solid hsl(var(--border));
    border-top: 3px solid hsl(var(--primary));
    background: hsl(var(--card));
    box-shadow: 0 18px 40px -24px hsl(var(--foreground) / 0.5);
}

.lang-menu[hidden] {
    display: none;
}

.lang-option {
    display: flex;
    width: 100%;
    min-height: 2.75rem;
    align-items: center;
    gap: 0.6rem;
    padding: 0.6rem 0.65rem;
    border-radius: 2px;
    text-align: left;
    font-size: 0.95rem;
    color: hsl(var(--muted-foreground));
    transition:
        background 0.15s ease,
        color 0.15s ease;
}

.lang-option:hover {
    background: hsl(var(--muted));
    color: hsl(var(--foreground));
}

.lang-code {
    flex: none;
    width: 1.75rem;
    font-family: var(--font-display);
    font-size: 0.75rem;
    font-weight: 600;
    color: hsl(var(--foreground) / 0.55);
}

.lang-check {
    margin-left: auto;
    height: 1rem;
    width: 1rem;
    flex: none;
    opacity: 0;
    color: hsl(var(--primary));
}

.lang-option[aria-checked='true'] {
    background: hsl(var(--muted));
    color: hsl(var(--foreground));
    font-weight: 500;
}

.lang-option[aria-checked='true'] .lang-code {
    color: hsl(var(--primary));
}

.lang-option[aria-checked='true'] .lang-check {
    opacity: 1;
}

/* --------------------------------------------------------------------------
   4. The opening field
   The masthead and the opening run together as one navy block, headline in
   white, second voice in the pale blue of the mark. Behind it, drawn in
   hairlines, is the thing the business actually sells: a network — a wire
   globe with real routes running between its nodes.
   -------------------------------------------------------------------------- */
.hero {
    position: relative;
    isolation: isolate;
    overflow: hidden;
    background: hsl(var(--foreground));
    color: hsl(var(--background));
    padding-top: 7.5rem;
    padding-bottom: 8rem;
}

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

@media (min-width: 640px) {
    .hero {
        padding-top: 10rem;
        padding-bottom: 11rem;
    }
}

/* A shorter opening for the inner pages. */
.hero-compact {
    padding-bottom: 7.5rem;
}

@media (min-width: 640px) {
    .hero-compact {
        padding-bottom: 10rem;
    }
}

/* The network behind the headline. Hairlines only, held to the right edge of
   the field and masked from its own centre outwards, so it has dissolved
   completely long before it reaches a word of type. Once drawn it never
   stops: traffic keeps running the routes, a point of light keeps circling
   the equator, the nodes keep pinging and the whole sphere breathes. */
.hero-art {
    position: absolute;
    z-index: 0;
    top: 1rem;
    right: -9rem;
    width: 26rem;
    max-width: 86vw;
    opacity: 0.45;
    pointer-events: none;
    -webkit-mask-image: radial-gradient(
        closest-side at 66% 50%,
        #000 32%,
        transparent 84%
    );
    mask-image: radial-gradient(
        closest-side at 66% 50%,
        #000 32%,
        transparent 84%
    );
}

@media (min-width: 1024px) {
    .hero-art {
        top: 50%;
        right: -13rem;
        width: 41rem;
        opacity: 0.92;
        transform: translateY(-48%);
    }
}

.hero-art svg {
    display: block;
    width: 100%;
    height: auto;
    animation: hero-drift 24s ease-in-out infinite;
}

/* A soft field of brand light behind the sphere, so the network sits in
   depth instead of lying flat on the navy. */
.hero-halo {
    position: absolute;
    inset: 10%;
    border-radius: 50%;
    background: radial-gradient(
        circle at 50% 50%,
        hsl(var(--haze) / 0.24),
        hsl(var(--haze) / 0.08) 46%,
        transparent 72%
    );
    animation: hero-breathe 11s ease-in-out infinite;
}

/* The sphere: parallels and meridians, the quietest layer. */
.hero-globe {
    fill: none;
    stroke: hsl(var(--beam) / 0.18);
    stroke-width: 1;
}

/* One point of light circling the equator, without pause. */
.hero-orbit ellipse {
    fill: none;
    stroke: hsl(var(--background));
    stroke-width: 5.5;
    stroke-linecap: round;
    stroke-dasharray: 0.01 99.99;
    animation: hero-orbit 17s linear infinite;
}

/* The routes between the nodes, and the traffic that keeps moving on them. */
.hero-routes {
    fill: none;
    stroke: hsl(var(--haze) / 0.45);
    stroke-width: 1.4;
    stroke-linecap: round;
}

.hero-flow {
    fill: none;
    stroke: hsl(var(--beam));
    stroke-width: 2.2;
    stroke-linecap: round;
}

.hero-flow path {
    stroke-dasharray: 13 87;
    animation: hero-packet 3.9s linear infinite;
    animation-delay: calc(var(--i, 0) * 430ms + 2.2s);
}

.hero-nodes circle {
    fill: hsl(var(--haze));
}

.hero-nodes circle:not(.halo) {
    animation: hero-twinkle 5.6s ease-in-out infinite;
    animation-delay: calc(var(--i, 0) * 620ms + 1.9s);
}

.hero-nodes circle.is-hub {
    fill: hsl(var(--background));
    animation: none;
}

.hero-nodes .halo {
    fill: none;
    stroke: hsl(var(--beam) / 0.5);
    stroke-width: 1;
    transform-box: fill-box;
    transform-origin: center;
    animation: hero-ping 4.4s ease-out infinite;
    animation-delay: calc(var(--i, 0) * 1.2s + 2.4s);
}

@keyframes hero-drift {
    0%,
    100% {
        transform: translate3d(0, -0.7%, 0);
    }

    50% {
        transform: translate3d(0, 0.7%, 0);
    }
}

@keyframes hero-breathe {
    0%,
    100% {
        opacity: 0.5;
        transform: scale(0.94);
    }

    50% {
        opacity: 1;
        transform: scale(1.05);
    }
}

@keyframes hero-orbit {
    from {
        stroke-dashoffset: 100;
    }

    to {
        stroke-dashoffset: 0;
    }
}

@keyframes hero-packet {
    0% {
        stroke-dashoffset: 100;
        opacity: 0;
    }

    14% {
        opacity: 1;
    }

    86% {
        opacity: 1;
    }

    100% {
        stroke-dashoffset: 0;
        opacity: 0;
    }
}

@keyframes hero-twinkle {
    0%,
    100% {
        opacity: 1;
    }

    50% {
        opacity: 0.4;
    }
}

@keyframes hero-ping {
    0% {
        transform: scale(0.5);
        opacity: 0.85;
    }

    65%,
    100% {
        transform: scale(2);
        opacity: 0;
    }
}

.hero-title {
    font-size: clamp(2.35rem, 6vw, 4.35rem);
    font-weight: 600;
    line-height: 1.03;
    letter-spacing: -0.035em;
    color: hsl(var(--background));
}

.hero .lede {
    color: hsl(var(--haze));
}

/* One quiet line of practical facts, kept out of the button row. */
.hero-note {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.65rem;
    margin-top: 1.85rem;
    padding-top: 1.25rem;
    border-top: 1px solid hsl(var(--background) / 0.16);
    font-size: 0.875rem;
    color: hsl(var(--haze));
}

.hero-note .sep {
    color: hsl(var(--beam));
    opacity: 1;
}

/* The sheet that crosses the seam between navy and paper. */
.hero-sheet {
    position: relative;
    z-index: 10;
    margin-top: -5rem;
}

@media (min-width: 640px) {
    .hero-sheet {
        margin-top: -8rem;
    }
}

.hero-sheet .sheet {
    box-shadow: 0 34px 64px -44px hsl(var(--foreground) / 0.65);
}

/* --------------------------------------------------------------------------
   5. The measure — the whole offer drawn to scale
   Three real speeds against their real price, inside a sheet with drafting
   corner ticks.
   -------------------------------------------------------------------------- */
.sheet {
    position: relative;
    border: 1px solid hsl(var(--border));
    border-radius: var(--radius);
    background: hsl(var(--card));
}

/* Drafting corner ticks, the single ornament the page allows itself. */
.sheet::before,
.sheet::after {
    content: '';
    position: absolute;
    height: 0.6rem;
    width: 0.6rem;
    border: 1px solid hsl(var(--primary));
    pointer-events: none;
}

.sheet::before {
    left: -1px;
    top: -1px;
    border-right: 0;
    border-bottom: 0;
}

.sheet::after {
    right: -1px;
    bottom: -1px;
    border-left: 0;
    border-top: 0;
}

.measure {
    padding: 1.35rem 1.25rem 1.5rem;
}

@media (min-width: 640px) {
    .measure {
        padding: 1.85rem 2.25rem 2rem;
    }
}

.measure-head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 1rem;
    padding-bottom: 0.9rem;
    border-bottom: 1px solid hsl(var(--border));
    font-size: 0.8rem;
    color: hsl(var(--muted-foreground));
}

.measure-row {
    display: grid;
    grid-template-columns: 1fr auto;
    grid-template-areas:
        'label price'
        'track track';
    align-items: center;
    gap: 0.55rem 1rem;
    padding: 1.05rem 0;
    border-bottom: 1px solid hsl(var(--border));
}

.measure-label {
    grid-area: label;
    display: grid;
    gap: 0.2rem;
}

.measure-track {
    grid-area: track;
}

.measure-price {
    grid-area: price;
}

.measure-row:last-of-type {
    border-bottom: 0;
}

.measure-name {
    font-size: 0.9rem;
    font-weight: 500;
    color: hsl(var(--muted-foreground));
    transition: color 0.2s ease;
}

.measure-row:hover .measure-name {
    color: hsl(var(--foreground));
}

.measure-speed {
    font-size: 1.6rem;
    font-weight: 600;
    line-height: 1;
    color: hsl(var(--foreground));
}

.measure-speed .unit {
    font-size: 0.8rem;
    margin-left: 0.3rem;
}

.measure-price {
    justify-self: end;
    font-size: 1.35rem;
    font-weight: 600;
    color: hsl(var(--foreground));
}

.measure-price .unit {
    font-size: 0.72rem;
    margin-left: 0.25rem;
}

.measure-track {
    height: 0.5rem;
    background: hsl(var(--muted));
    border-radius: 1px;
    overflow: hidden;
}

.measure-bar {
    display: block;
    height: 100%;
    width: var(--len, 100%);
    background: hsl(var(--primary));
    transform-origin: left center;
}

.measure-row:nth-of-type(2) .measure-bar {
    background: hsl(var(--primary) / 0.8);
}

.measure-row:nth-of-type(1) .measure-bar {
    background: hsl(var(--primary) / 0.6);
}

.measure-foot {
    padding-top: 1.1rem;
    border-top: 1px solid hsl(var(--border));
    font-size: 0.85rem;
    color: hsl(var(--muted-foreground));
}

@media (min-width: 768px) {
    .measure-row {
        grid-template-columns: 12rem 1fr auto;
        grid-template-areas: 'label track price';
        gap: 2rem;
        padding: 1.3rem 0;
    }

    /* The two column labels line up with the columns they describe. */
    .measure-head {
        display: grid;
        grid-template-columns: 12rem 1fr auto;
        gap: 2rem;
    }

    .measure-head span:last-child {
        grid-column: 3;
        justify-self: end;
    }

    .measure-speed {
        font-size: 1.75rem;
    }

    .measure-price {
        font-size: 1.5rem;
    }
}

/* --------------------------------------------------------------------------
   5b. The one orchestrated moment
   As the page opens: the routes of the network draw themselves, its nodes
   arrive, and the three speed bars measure themselves out. It happens once,
   on load, and nowhere else on the site. The finished state is the plain
   default — the script only arms the starting state — so nothing can ever
   stay hidden if scripting never runs.
   -------------------------------------------------------------------------- */
.hero-art.is-armed .hero-routes path {
    stroke-dasharray: 100;
    stroke-dashoffset: 100;
    transition: none;
}

.hero-art.is-armed .hero-nodes > * {
    opacity: 0;
    transition: none;
}

.hero-art.is-armed .hero-globe,
.hero-art.is-armed .hero-orbit {
    opacity: 0;
    transition: none;
}

.hero-art.is-drawn .hero-globe,
.hero-art.is-drawn .hero-orbit {
    opacity: 1;
    transition: opacity 1.1s ease;
}

.hero-art.is-drawn .hero-routes path {
    stroke-dashoffset: 0;
    transition: stroke-dashoffset 1.5s cubic-bezier(0.33, 1, 0.68, 1);
    transition-delay: calc(var(--i, 0) * 110ms + 260ms);
}

.hero-art.is-drawn .hero-nodes > * {
    opacity: 1;
    transition: opacity 0.5s ease;
    transition-delay: calc(var(--i, 0) * 110ms + 700ms);
}

.measure.is-armed .measure-bar {
    transform: scaleX(0);
    transition: none;
}

.measure.is-armed .measure-price,
.measure.is-armed .measure-speed {
    opacity: 0;
    transition: none;
}

.measure.is-drawn .measure-bar {
    transform: scaleX(1);
    transition: transform 0.9s cubic-bezier(0.22, 1, 0.36, 1);
    transition-delay: calc(var(--i, 0) * 130ms + 620ms);
}

.measure.is-drawn .measure-price,
.measure.is-drawn .measure-speed {
    opacity: 1;
    transition: opacity 0.5s ease;
    transition-delay: calc(var(--i, 0) * 130ms + 800ms);
}

/* The headline, its second voice and the two ways to act arrive with the
   network behind them, one line after another. */
.hero.is-armed .hero-title,
.hero.is-armed .lede,
.hero.is-armed .hero-note,
.hero.is-armed .btn {
    opacity: 0;
}

.hero.is-drawn .hero-title,
.hero.is-drawn .lede,
.hero.is-drawn .hero-note,
.hero.is-drawn .btn {
    animation: rv-up 0.85s cubic-bezier(0.22, 1, 0.36, 1) both;
    animation-delay: calc(var(--i, 0) * 90ms + 120ms);
}

/* Then the tariff sheet itself rises into the seam, and only once it is in
   place do the three speeds measure themselves out inside it. */
.measure.is-armed {
    opacity: 0;
}

.measure.is-drawn {
    animation: rv-rise 0.85s cubic-bezier(0.22, 1, 0.36, 1) both;
    animation-delay: 300ms;
}

/* --------------------------------------------------------------------------
   6. Facts row — four measured facts about the network
   -------------------------------------------------------------------------- */
.facts {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    margin: 0;
    padding: 0;
    list-style: none;
    border-top: 1px solid hsl(var(--border));
}

.facts li {
    padding: 1.35rem 0.5rem 1.35rem 0;
    border-bottom: 1px solid hsl(var(--border));
}

/* Hairlines sit between the columns, never at the start of a row. */
.facts li:nth-child(even) {
    padding-left: 1.25rem;
    border-left: 1px solid hsl(var(--border));
}

.facts strong {
    display: block;
    font-family: var(--font-display);
    font-size: 1.75rem;
    font-weight: 600;
    font-variant-numeric: tabular-nums;
    letter-spacing: -0.03em;
    color: hsl(var(--foreground));
}

.facts span {
    display: block;
    margin-top: 0.4rem;
    font-size: 0.85rem;
    line-height: 1.45;
    color: hsl(var(--muted-foreground));
}

@media (min-width: 768px) {
    .facts {
        grid-template-columns: repeat(4, minmax(0, 1fr));
    }

    .facts li:not(:first-child) {
        padding-left: 1.25rem;
        border-left: 1px solid hsl(var(--border));
    }

    .facts strong {
        font-size: 2.1rem;
    }
}

/* --------------------------------------------------------------------------
   7. Plant — the photographs of the real network
   -------------------------------------------------------------------------- */
.plant {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: 1px;
    margin: 0;
    padding: 0;
    list-style: none;
    background: hsl(var(--border));
    border: 1px solid hsl(var(--border));
    border-radius: var(--radius);
    overflow: hidden;
}

.plant li {
    position: relative;
    background: hsl(var(--card));
}

.plant img {
    display: block;
    width: 100%;
    height: auto;
    aspect-ratio: 4 / 3;
    object-fit: cover;
}

.plant figcaption,
.plant .cap {
    position: absolute;
    left: 0;
    bottom: 0;
    padding: 0.45rem 0.7rem;
    background: hsl(var(--primary));
    color: hsl(var(--primary-foreground));
    font-size: 0.75rem;
    font-weight: 500;
}

@media (min-width: 640px) {
    .plant {
        grid-template-columns: repeat(3, minmax(0, 1fr));
    }
}

/* --------------------------------------------------------------------------
   8. Advantages — a ruled specification list, not a card kit
   -------------------------------------------------------------------------- */
.spec-list {
    display: grid;
    gap: 0;
    border-top: 1px solid hsl(var(--border));
}

.spec-item {
    display: grid;
    grid-template-columns: auto 1fr;
    gap: 0.35rem 1.1rem;
    padding: 1.6rem 0;
    border-bottom: 1px solid hsl(var(--border));
}

.spec-item svg {
    height: 1.35rem;
    width: 1.35rem;
    grid-row: span 2;
    margin-top: 0.15rem;
    color: hsl(var(--primary));
}

.spec-item h3 {
    font-size: 1.1rem;
    font-weight: 600;
    color: hsl(var(--foreground));
}

.spec-item p {
    grid-column: 2;
    max-width: 44ch;
    font-size: 0.95rem;
    line-height: 1.65;
    color: hsl(var(--muted-foreground));
}

@media (min-width: 768px) {
    .spec-list {
        grid-template-columns: repeat(2, minmax(0, 1fr));
        column-gap: 3.5rem;
    }
}

/* --------------------------------------------------------------------------
   9. Comparison — one plain table, our column first
   The reader meets what they would get from us before they read what they
   would get elsewhere, and the section closes on a plain conclusion.
   -------------------------------------------------------------------------- */
.vs {
    border: 1px solid hsl(var(--border));
    border-radius: var(--radius);
    background: hsl(var(--card));
    overflow: hidden;
}

.vs-head,
.vs-row {
    display: grid;
    grid-template-columns: 1fr;
}

.vs-head {
    border-bottom: 1px solid hsl(var(--border));
}

.vs-head > * {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 0.75rem;
    padding: 1.1rem 1.25rem;
    text-align: center;
}

.vs-head-us {
    background: hsl(var(--foreground));
}

.vs-head-them {
    font-family: var(--font-display);
    font-size: 1rem;
    font-weight: 600;
    color: hsl(var(--muted-foreground));
}

.vs-row {
    border-bottom: 1px solid hsl(var(--border));
}

/* The table closes on the conclusion, so the row that runs into it lets go of
   its own hairline: the dark block is its own edge, and no doubled line is
   left stranded at the foot of the table. */
.vs-row:last-child {
    border-bottom: 0;
}

.vs-row:has(+ .vs-verdict) {
    border-bottom: 0;
}

.vs-them,
.vs-us {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 0.7rem;
    padding: 1rem 1.25rem;
    text-align: center;
    font-size: 0.95rem;
    line-height: 1.5;
}

.vs-us {
    background: hsl(var(--primary) / 0.06);
    color: hsl(var(--foreground));
    font-weight: 500;
}

.vs-them {
    border-top: 1px solid hsl(var(--border));
    color: hsl(var(--muted-foreground));
}

.vs-ico {
    height: 1.05rem;
    width: 1.05rem;
    flex: none;
}

.vs-them .vs-ico {
    color: hsl(var(--muted-foreground) / 0.55);
}

.vs-us .vs-ico {
    color: hsl(var(--primary));
}

/* The conclusion the nine rows add up to, stated once, with the way on. */
.vs-verdict {
    display: grid;
    gap: 1.25rem;
    padding: 1.6rem 1.25rem;
    background: hsl(var(--foreground));
    color: hsl(var(--background));
}

.vs-verdict p {
    max-width: 62ch;
    font-size: 1rem;
    line-height: 1.65;
    color: hsl(var(--sky));
}

.vs-verdict .btn {
    justify-self: start;
}

@media (min-width: 768px) {
    .vs-head,
    .vs-row {
        grid-template-columns: 1fr 1fr;
    }

    .vs-head-us {
        border-right: 1px solid hsl(var(--foreground));
    }

    .vs-head-them {
        font-size: 1.15rem;
    }

    .vs-them {
        border-top: 0;
        border-left: 1px solid hsl(var(--border));
    }

    .vs-verdict {
        grid-template-columns: 1fr auto;
        align-items: center;
        gap: 2rem;
        padding: 1.75rem 2rem;
    }

    .vs-verdict .btn {
        justify-self: end;
    }
}

/* --------------------------------------------------------------------------
   10. Plans — a tariff sheet: what differs per plan, what every plan shares
   stated once, and a line of guidance for anyone still deciding
   -------------------------------------------------------------------------- */
.plan {
    position: relative;
    display: flex;
    flex-direction: column;
    padding: 1.75rem 1.5rem 1.6rem;
    border: 1px solid hsl(var(--border));
    border-radius: var(--radius);
    background: hsl(var(--card));
}

.plan-pick {
    background: hsl(var(--foreground));
    border-color: hsl(var(--foreground));
    color: hsl(var(--background));
}

/* The badge rides on the name line, so the three plans stay in step: every
   name, price and speed sits on exactly the same line across all three. */
.plan-head {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 0.75rem;
    min-height: 1.8rem;
}

.plan-tag {
    flex: none;
    margin-top: 0.05rem;
    padding: 0.25rem 0.55rem;
    border-radius: 2px;
    background: hsl(var(--beam));
    color: hsl(var(--foreground));
    font-size: 0.72rem;
    font-weight: 600;
    line-height: 1.35;
}

.plan-name {
    font-size: 1.15rem;
    font-weight: 600;
}

.plan-note {
    margin-top: 0.4rem;
    font-size: 0.9rem;
    line-height: 1.6;
    color: hsl(var(--muted-foreground));
}

.plan-price {
    margin-top: 1.35rem;
    font-size: 2.75rem;
    font-weight: 600;
    line-height: 1;
}

.plan-price .unit {
    font-size: 0.85rem;
    margin-left: 0.35rem;
}

.plan-pick .plan-price .unit,
.plan-pick .plan-speed span,
.plan-pick .plan-note,
.plan-pick .plan-fit p {
    color: hsl(var(--haze));
}

.plan-term {
    margin-top: 0.5rem;
    font-size: 0.85rem;
    color: hsl(var(--muted-foreground));
}

.plan-pick .plan-term {
    color: hsl(var(--haze));
}

.plan-speed {
    margin-top: 1.4rem;
    padding-top: 1.1rem;
    border-top: 1px solid hsl(var(--border));
    display: grid;
    gap: 0.55rem;
}

.plan-pick .plan-speed,
.plan-pick .plan-fit {
    border-color: hsl(var(--background) / 0.2);
}

.plan-speed div {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 1rem;
    font-size: 0.95rem;
}

.plan-speed span {
    color: hsl(var(--muted-foreground));
}

.plan-speed strong {
    font-family: var(--font-display);
    font-weight: 600;
    font-variant-numeric: tabular-nums;
}

/* Who each speed is actually for — the one thing that helps someone decide. */
.plan-fit {
    margin-top: 1.25rem;
    padding-top: 1.1rem;
    border-top: 1px solid hsl(var(--border));
}

.plan-fit h4 {
    font-size: 0.75rem;
    font-weight: 600;
    color: hsl(var(--primary));
}

.plan-pick .plan-fit h4 {
    color: hsl(var(--beam));
}

.plan-fit p {
    margin-top: 0.4rem;
    font-size: 0.9rem;
    line-height: 1.6;
    color: hsl(var(--muted-foreground));
}

/* However long the copy above runs, the three buttons close the three cards
   on one line, at the very bottom, full width. */
.plan-foot {
    margin-top: auto;
    padding-top: 1.7rem;
}

.plan-foot .btn {
    width: 100%;
}

/* What every plan includes, stated once instead of three times. */
.incl {
    display: grid;
    gap: 0.85rem 2rem;
    margin: 0;
    padding: 0;
    list-style: none;
}

.incl li {
    display: flex;
    align-items: flex-start;
    gap: 0.65rem;
    font-size: 0.95rem;
    color: hsl(var(--foreground));
}

.incl svg {
    height: 1.05rem;
    width: 1.05rem;
    flex: none;
    margin-top: 0.22rem;
    color: hsl(var(--primary));
}

@media (min-width: 640px) {
    .incl {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }
}

@media (min-width: 1024px) {
    .incl {
        grid-template-columns: repeat(3, minmax(0, 1fr));
    }
}

/* The line for anyone still undecided, with both ways to ask. */
.plans-help {
    display: grid;
    gap: 1.1rem;
    margin-top: 1rem;
    padding: 1.5rem;
    border: 1px solid hsl(var(--border));
    border-left: 3px solid hsl(var(--primary));
    background: hsl(var(--card));
}

.plans-help p {
    max-width: 60ch;
    font-size: 0.95rem;
    line-height: 1.65;
    color: hsl(var(--muted-foreground));
}

.plans-help div {
    display: flex;
    flex-wrap: wrap;
    gap: 0.6rem;
}

@media (min-width: 900px) {
    .plans-help {
        grid-template-columns: 1fr auto;
        align-items: center;
        gap: 2rem;
        padding: 1.5rem 1.75rem;
    }
}

/* --------------------------------------------------------------------------
   10b. The two tools, announced as a section of their own

   They are given exactly the treatment the plans get — a card each on the
   same tariff sheet — with a drafted mark at the head, the three plain facts
   about each tool as a ruled list, and the way in closing the card at its
   foot, so both tools stand at the full weight of an offer.
   -------------------------------------------------------------------------- */
.tool-mark {
    display: inline-grid;
    place-items: center;
    height: 2.85rem;
    width: 2.85rem;
    margin-bottom: 1.15rem;
    border: 1px solid hsl(var(--border));
    border-radius: var(--radius);
    background: hsl(var(--muted));
    color: hsl(var(--primary));
}

.tool-mark svg {
    height: 1.4rem;
    width: 1.4rem;
}

.tool-card .plan-note {
    max-width: 46ch;
}

/* Inside a card the three facts read as one column, however wide the screen. */
.tool-card .tool-incl {
    grid-template-columns: minmax(0, 1fr);
    gap: 0.75rem;
    margin-top: 1.4rem;
    padding-top: 1.25rem;
    border-top: 1px solid hsl(var(--border));
}

/* The one line that holds for both of them, stated once under the two cards. */
.tools-foot {
    display: flex;
    align-items: center;
    gap: 0.7rem;
    margin-top: 1rem;
    padding: 1rem 1.25rem;
    border: 1px solid hsl(var(--border));
    border-left: 3px solid hsl(var(--primary));
    background: hsl(var(--card));
    font-size: 0.9rem;
    color: hsl(var(--muted-foreground));
}

.tools-foot svg {
    height: 1rem;
    width: 1rem;
    flex: none;
    color: hsl(var(--primary));
}

/* --------------------------------------------------------------------------
   11. Questions — one ruled document, read straight through
   A single unbroken list in one column, so opening an answer never leaves a
   hole beside it, and the answer itself unfolds instead of appearing.
   -------------------------------------------------------------------------- */
.faq-list {
    border-top: 1px solid hsl(var(--border));
}

.faq {
    border-bottom: 1px solid hsl(var(--border));
}

.faq summary {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 1.25rem;
    padding: 1.15rem 0;
    cursor: pointer;
    list-style: none;
    font-family: var(--font-display);
    font-size: 1rem;
    font-weight: 500;
    color: hsl(var(--foreground));
    transition: color 0.2s ease;
}

.faq summary:hover {
    color: hsl(var(--accent));
}

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

.faq-mark {
    position: relative;
    flex: none;
    height: 1.25rem;
    width: 1.25rem;
    margin-top: 0.15rem;
    color: hsl(var(--primary));
}

.faq-mark::before,
.faq-mark::after {
    content: '';
    position: absolute;
    left: 50%;
    top: 50%;
    background: currentColor;
}

.faq-mark::before {
    height: 1.5px;
    width: 100%;
    transform: translate(-50%, -50%);
}

.faq-mark::after {
    height: 100%;
    width: 1.5px;
    transform: translate(-50%, -50%);
    transition: transform 0.25s ease;
}

/* The answer unfolds: the row grows from nothing to its natural height. */
.faq-wrap {
    display: grid;
    grid-template-rows: 0fr;
    transition: grid-template-rows 0.34s cubic-bezier(0.22, 1, 0.36, 1);
}

.faq-wrap > div {
    overflow: hidden;
}

.faq-body {
    padding: 0 0 1.4rem;
    max-width: 68ch;
    font-size: 0.95rem;
    line-height: 1.75;
    overflow-wrap: break-word;
    color: hsl(var(--muted-foreground));
    opacity: 0;
    transition: opacity 0.25s ease;
}

/* Without scripting the answer simply opens, instantly and completely. */
.faq[open] .faq-wrap {
    grid-template-rows: 1fr;
}

.faq[open] .faq-body {
    opacity: 1;
}

.faq[open] .faq-mark::after {
    transform: translate(-50%, -50%) scaleY(0);
}

/* With scripting the same states are driven by the class, so that closing is
   animated too and not just opening. */
html.js .faq[open] .faq-wrap {
    grid-template-rows: 0fr;
}

html.js .faq[open] .faq-body {
    opacity: 0;
}

html.js .faq[open] .faq-mark::after {
    transform: translate(-50%, -50%);
}

html.js .faq.is-open .faq-wrap {
    grid-template-rows: 1fr;
}

html.js .faq.is-open .faq-body {
    opacity: 1;
    transition-delay: 0.08s;
}

html.js .faq.is-open .faq-mark::after {
    transform: translate(-50%, -50%) scaleY(0);
}

@media (min-width: 768px) {
    .faq summary {
        font-size: 1.0625rem;
        padding: 1.25rem 0;
    }
}

/* --------------------------------------------------------------------------
   13. The closing sheet
   The page opens with a white sheet crossing down from the navy field onto
   the paper. It closes with the same move in reverse: a white sheet that
   crosses from the paper down into the navy footer, carrying the last ask.
   White, so the final page of the document is the brightest thing on screen
   and never merges into the dark footer beneath it.
   -------------------------------------------------------------------------- */
.closing {
    padding-top: 4rem;
    padding-bottom: 0;
}

@media (min-width: 640px) {
    .closing {
        padding-top: 6rem;
    }
}

.closing-card {
    position: relative;
    z-index: 5;
    margin-bottom: -3rem;
    padding: 1.75rem 1.35rem 0;
    box-shadow: 0 34px 64px -44px hsl(var(--foreground) / 0.65);
}

@media (min-width: 640px) {
    .closing-card {
        margin-bottom: -4.5rem;
        padding: 2.75rem 2.5rem 0;
    }
}

.closing-body {
    display: grid;
    gap: 1.4rem;
    padding-bottom: 1.9rem;
}

/* The label that opens the closing sheet, in the language of the section
   rules above it. */
.closing-eyebrow {
    display: flex;
    align-items: center;
    gap: 0.7rem;
    margin-bottom: 0.95rem;
    font-family: var(--font-display);
    font-size: 0.78rem;
    font-weight: 600;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: hsl(var(--primary));
}

.closing-eyebrow::before {
    content: '';
    flex: none;
    height: 3px;
    width: 2.5rem;
    background: hsl(var(--primary));
}

.closing-title {
    font-size: clamp(1.9rem, 4.4vw, 2.95rem);
    font-weight: 600;
    line-height: 1.06;
    letter-spacing: -0.03em;
}

.closing-actions {
    display: flex;
    flex-wrap: wrap;
    gap: 0.7rem;
    margin-top: 1.75rem;
}

@media (min-width: 900px) {
    .closing-body {
        grid-template-columns: 1.05fr 0.95fr;
        align-items: end;
        gap: 3rem;
        padding-bottom: 2.4rem;
    }
}

/* The three plain facts the last ask rests on. */
.closing-facts {
    display: grid;
    margin: 0;
    padding: 0;
    list-style: none;
    border-top: 1px solid hsl(var(--border));
}

.closing-facts li {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    padding: 0.95rem 0;
    border-bottom: 1px solid hsl(var(--border));
    font-size: 0.9rem;
    color: hsl(var(--muted-foreground));
}

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

.closing-facts svg {
    height: 1rem;
    width: 1rem;
    flex: none;
    color: hsl(var(--primary));
}

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

    .closing-facts li {
        padding: 1.15rem 1.25rem 1.15rem 0;
        border-bottom: 0;
    }

    .closing-facts li:not(:first-child) {
        padding-left: 1.5rem;
        border-left: 1px solid hsl(var(--border));
    }
}

/* The last ask is also where the page says how to reach us: the single-target
   map plate beside the hours, both set inside the closing sheet, since that
   sheet is the last thing the page says and the only place a contact is
   needed. */
.closing-split {
    display: grid;
    gap: 1.25rem;
    margin-bottom: 1.6rem;
}

.closing-map {
    margin-bottom: 0;
}

.closing-map .map-frame {
    aspect-ratio: 16 / 9;
    height: auto;
    min-height: 0;
}

/* The hours sit on the pale ground of the page, ruled open in navy like every
   other section, so they read as a panel inside the white sheet. */
.closing-hours {
    padding: 1.4rem 1.35rem 1.5rem;
    border: 1px solid hsl(var(--border));
    border-top: 3px solid hsl(var(--primary));
    background: hsl(var(--muted) / 0.65);
}

.closing-hours h3 {
    font-size: 1.0625rem;
    font-weight: 600;
}

.closing-hours .hours {
    margin-top: 1.1rem;
}

.hours-note {
    margin-top: 1rem;
    font-size: 0.85rem;
    line-height: 1.6;
    color: hsl(var(--muted-foreground));
}

@media (min-width: 640px) {
    .closing-split {
        margin-bottom: 2rem;
    }

    .closing-hours {
        padding: 1.6rem 1.6rem 1.75rem;
    }
}

@media (min-width: 900px) {
    .closing-split {
        grid-template-columns: 1.15fr 0.85fr;
        gap: 1.5rem;
    }

    .closing-map .map-frame {
        aspect-ratio: auto;
        height: 100%;
        min-height: 21rem;
    }
}

/* --------------------------------------------------------------------------
   14. Footer
   -------------------------------------------------------------------------- */
.site-footer {
    background: hsl(var(--foreground));
    color: hsl(var(--background));
}

/* The closing sheet hangs into the footer, so there the footer opens lower. */
.site-footer.has-closing .footer-grid {
    padding-top: 6rem;
}

@media (min-width: 640px) {
    .site-footer.has-closing .footer-grid {
        padding-top: 8.5rem;
    }
}

/* Where to find us away from the site: the marks alone, square and equal,
   named only for a screen reader. They fill with the accent as they are
   reached, the same white the navy field gives everything else. */
.social {
    display: inline-grid;
    place-items: center;
    height: 2.75rem;
    width: 2.75rem;
    flex: none;
    border-radius: var(--radius);
    border: 1px solid hsl(var(--background) / 0.28);
    color: hsl(var(--background));
    transition:
        border-color 0.2s ease,
        background 0.2s ease,
        color 0.2s ease;
}

.social svg {
    height: 1.1rem;
    width: 1.1rem;
    flex: none;
}

.social:hover {
    border-color: hsl(var(--beam));
    background: hsl(var(--beam));
    color: hsl(var(--foreground));
}

.footer-title {
    position: relative;
    padding-top: 0.85rem;
    font-family: var(--font-display);
    font-size: 0.9rem;
    font-weight: 600;
    color: hsl(var(--background));
}

.footer-title::before {
    content: '';
    position: absolute;
    left: 0;
    top: 0;
    height: 3px;
    width: 2rem;
    background: hsl(var(--beam));
}

.footer-link {
    display: inline-block;
    padding: 0.15rem 0;
    font-size: 0.95rem;
    color: hsl(var(--haze));
    transition: color 0.2s ease;
}

.footer-link:hover {
    color: hsl(var(--beam));
}

.footer-bottom {
    display: flex;
    flex-direction: column;
    gap: 0.6rem;
    padding: 1.75rem 0;
    border-top: 1px solid hsl(var(--background) / 0.14);
    font-size: 0.85rem;
    color: hsl(var(--haze) / 0.8);
}

@media (min-width: 640px) {
    .footer-bottom {
        flex-direction: row;
        align-items: center;
        justify-content: space-between;
    }
}

/* --------------------------------------------------------------------------
   15. Forms
   -------------------------------------------------------------------------- */
.field {
    display: block;
    margin-bottom: 0.4rem;
    font-size: 0.85rem;
    font-weight: 500;
    color: hsl(var(--foreground));
}

.input {
    width: 100%;
    border-radius: var(--radius);
    border: 1px solid hsl(var(--border));
    background: hsl(var(--card));
    padding: 0.8rem 0.95rem;
    font-family: var(--font-body);
    font-size: 0.95rem;
    color: hsl(var(--foreground));
    transition:
        border-color 0.2s ease,
        box-shadow 0.2s ease;
}

.input::placeholder {
    color: hsl(var(--muted-foreground) / 0.7);
}

.input:focus {
    outline: none;
    border-color: hsl(var(--primary));
    box-shadow: inset 0 0 0 1px hsl(var(--primary));
}

/* --------------------------------------------------------------------------
   15b. Where we are, and when

   The map is one single target: the whole plate is the link, so a tap opens
   the location in the maps application instead of trapping a finger inside a
   frame it then has to fight its way out of. It sits back in the palette of
   the page until it is reached, and comes to full colour under the pointer.
   Beside it the hours are a plain ruled table, closed by the one line that
   never changes: the network is watched around the clock.
   -------------------------------------------------------------------------- */
.map-card {
    position: relative;
    display: block;
    overflow: hidden;
    border: 1px solid hsl(var(--border));
    border-radius: var(--radius);
    background: hsl(var(--muted));
    transition: border-color 0.2s ease;
}

.map-card:hover {
    border-color: hsl(var(--primary));
}

.map-frame {
    display: block;
    position: relative;
    aspect-ratio: 4 / 3;
    background-color: hsl(var(--muted));
    background-image: linear-gradient(hsl(var(--border)) 1px, transparent 1px),
        linear-gradient(90deg, hsl(var(--border)) 1px, transparent 1px);
    background-size: 3.5rem 3.5rem;
}

/* The place is marked on the plate itself, under the map, so the card reads
   as a location from the first moment and never as an empty box. */
.map-pin {
    position: absolute;
    left: 50%;
    top: 50%;
    height: 2.5rem;
    width: 2.5rem;
    transform: translate(-50%, -60%);
    color: hsl(var(--primary));
}

@media (min-width: 640px) {
    .map-frame {
        aspect-ratio: 16 / 9;
    }
}

@media (min-width: 1024px) {
    .map-frame {
        aspect-ratio: auto;
        height: 100%;
        min-height: 25rem;
    }
}

/* The frame is a picture of the place, never a control: every press on it
   belongs to the link that carries it. */
.map-card iframe {
    position: absolute;
    inset: 0;
    display: block;
    height: 100%;
    width: 100%;
    border: 0;
    pointer-events: none;
    filter: grayscale(0.6) contrast(1.04);
    transition: filter 0.35s ease;
}

.map-card:hover iframe,
.map-card:focus-visible iframe {
    filter: none;
}

/* The plate says plainly what a press on it does. */
.map-flag {
    position: absolute;
    left: 0;
    bottom: 0;
    display: inline-flex;
    align-items: center;
    gap: 0.55rem;
    padding: 0.6rem 0.9rem;
    background: hsl(var(--primary));
    color: hsl(var(--primary-foreground));
    font-size: 0.8rem;
    font-weight: 600;
}

.map-flag svg {
    height: 0.9rem;
    width: 0.9rem;
    flex: none;
    transition: transform 0.2s ease;
}

.map-card:hover .map-flag svg,
.map-card:focus-visible .map-flag svg {
    transform: translate(2px, -2px);
}

/* The hours themselves: one ruled table, day against time. */
.hours {
    display: grid;
    margin: 0;
    padding: 0;
    border-top: 1px solid hsl(var(--border));
}

.hours > div {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 1rem;
    padding: 0.85rem 0;
    border-bottom: 1px solid hsl(var(--border));
}

.hours dt {
    font-size: 0.95rem;
    color: hsl(var(--muted-foreground));
}

.hours dd {
    margin: 0;
    font-family: var(--font-display);
    font-size: 0.95rem;
    font-weight: 600;
    font-variant-numeric: tabular-nums;
    letter-spacing: -0.01em;
    color: hsl(var(--foreground));
    text-align: right;
}

/* A day we are closed is stated, not stressed. */
.hours .is-off dd {
    font-weight: 500;
    color: hsl(var(--muted-foreground));
}

/* The one line that never changes, on the navy of the mark. */
.hours-support {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    margin-top: 1.4rem;
    padding: 0.95rem 1.1rem;
    background: hsl(var(--foreground));
    color: hsl(var(--background));
    font-size: 0.9rem;
    font-weight: 600;
}

.dot-live {
    position: relative;
    flex: none;
    height: 0.5rem;
    width: 0.5rem;
    border-radius: 50%;
    background: hsl(var(--beam));
}

.dot-live::after {
    content: '';
    position: absolute;
    inset: 0;
    border-radius: 50%;
    background: hsl(var(--beam));
    animation: dot-pulse 2.6s ease-out infinite;
}

@keyframes dot-pulse {
    0% {
        opacity: 0.7;
        transform: scale(1);
    }

    70%,
    100% {
        opacity: 0;
        transform: scale(3.2);
    }
}

/* The hours ride on the plate itself, so the one question a map is ever
   asked — are they open right now — is answered on the map. The mark is
   live: it reads the clock in Skopje, not the clock of whoever is looking,
   and goes quiet outside the hours. */
.map-hours {
    position: absolute;
    right: 0.65rem;
    top: 0.65rem;
    display: grid;
    gap: 0.15rem;
    padding: 0.55rem 0.8rem;
    border: 1px solid hsl(var(--border));
    border-radius: var(--radius);
    background: hsl(var(--card) / 0.93);
    backdrop-filter: blur(6px);
    -webkit-backdrop-filter: blur(6px);
}

.map-hours-state {
    display: flex;
    align-items: center;
    gap: 0.45rem;
    font-family: var(--font-display);
    font-size: 0.78rem;
    font-weight: 600;
    color: hsl(var(--primary));
}

.map-hours-time {
    font-size: 0.72rem;
    font-variant-numeric: tabular-nums;
    color: hsl(var(--muted-foreground));
}

/* On the white chip the live mark prints navy, the accent as it reads on
   paper, instead of the white it carries on the navy strip. */
.map-hours .dot-live,
.map-hours .dot-live::after {
    background: hsl(var(--primary));
}

.map-hours.is-closed .map-hours-state {
    color: hsl(var(--muted-foreground));
}

.map-hours.is-closed .dot-live,
.map-hours.is-closed .dot-live::after {
    background: hsl(var(--muted-foreground));
}

.map-hours.is-closed .dot-live::after {
    animation: none;
    opacity: 0;
}

/* If the clock cannot be read at all, the plate simply states the hours. */
.map-hours.is-plain .map-hours-state {
    display: none;
}

/* --------------------------------------------------------------------------
   15c. The tools a customer actually uses

   Two things anyone with an internet connection wants to check for
   themselves: how fast the line really is, and which address the internet
   sees them by. Each one gets a page of its own, at the full width of the
   screen; the home page only announces them and points the way, and the
   three quick links sit under the two cards.
   -------------------------------------------------------------------------- */
/* The measurement the site runs itself: a drafted dial in the navy of the
   mark, the four readings beside it as a ruled table, and one button. The
   needle follows what is actually arriving on the line, so the gauge is a
   picture of the measurement and never an ornament. */
.st {
    display: grid;
    gap: 1.5rem;
}

.st-main {
    display: grid;
    gap: 1.75rem;
    align-items: center;
}

@media (min-width: 900px) {
    .st-main {
        grid-template-columns: minmax(0, 1.1fr) minmax(0, 0.9fr);
        gap: 3rem;
    }
}

.st-gauge {
    display: block;
    width: 100%;
    max-width: 30rem;
    height: auto;
    margin: 0 auto;
}

/* The scale: hairline ticks and plain numbers, drafted rather than styled. */
.st-ticks line {
    stroke: hsl(var(--foreground) / 0.3);
    stroke-width: 1.4;
}

.st-scale text {
    fill: hsl(var(--muted-foreground));
    font-family: var(--font-body);
    font-size: 10px;
    font-variant-numeric: tabular-nums;
    text-anchor: middle;
    dominant-baseline: middle;
}

.st-track,
.st-arc {
    fill: none;
    stroke-width: 9;
    stroke-linecap: butt;
}

.st-track {
    stroke: hsl(var(--muted));
}

.st-arc {
    stroke: hsl(var(--primary));
    stroke-dasharray: 352;
    stroke-dashoffset: 352;
    transition: stroke-dashoffset 0.2s linear;
}

.st-needle {
    transform-box: view-box;
    transform-origin: 150px 150px;
    transform: rotate(-90deg);
    transition: transform 0.24s cubic-bezier(0.22, 1, 0.36, 1);
}

.st-needle line {
    stroke: hsl(var(--foreground));
    stroke-width: 2.4;
    stroke-linecap: round;
}

.st-hub {
    fill: hsl(var(--foreground));
}

/* The reading itself, under the dial and at the scale of a headline. */
.st-read {
    margin-top: 0.4rem;
    text-align: center;
}

.st-phase {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 0.5rem;
    font-family: var(--font-display);
    font-size: 0.78rem;
    font-weight: 600;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: hsl(var(--primary));
}

/* The live mark shows only while a measurement is actually running, and on
   the white sheet it prints navy, the accent as it reads on paper. */
.st-live {
    display: none;
}

.st.is-busy .st-live {
    display: block;
}

.st-phase .dot-live,
.st-phase .dot-live::after {
    background: hsl(var(--primary));
}

.st-value {
    margin-top: 0.3rem;
    font-family: var(--font-display);
    font-size: clamp(2.6rem, 9vw, 3.75rem);
    font-weight: 600;
    font-variant-numeric: tabular-nums;
    letter-spacing: -0.035em;
    line-height: 1;
    color: hsl(var(--foreground));
}

.st-value .st-unit {
    margin-left: 0.4rem;
    font-family: var(--font-body);
    font-size: 0.9rem;
    font-weight: 500;
    letter-spacing: 0;
    color: hsl(var(--muted-foreground));
}

/* The four readings, as a ruled table rather than four more cards. */
.st-rows {
    display: grid;
    margin: 0;
    border-top: 1px solid hsl(var(--border));
}

.st-rows > div {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 1rem;
    padding: 0.85rem 0;
    border-bottom: 1px solid hsl(var(--border));
}

.st-rows dt {
    font-size: 0.92rem;
    color: hsl(var(--muted-foreground));
    transition: color 0.2s ease;
}

.st-rows dd {
    margin: 0;
    font-family: var(--font-display);
    font-size: 1.05rem;
    font-weight: 600;
    font-variant-numeric: tabular-nums;
    letter-spacing: -0.01em;
    color: hsl(var(--foreground));
}

/* The reading being taken right now is marked, so it is always clear which
   number the needle is moving for. */
.st-rows > div.is-live dt,
.st-rows > div.is-live dd {
    color: hsl(var(--primary));
}

.st-bar {
    margin-top: 1.35rem;
    height: 0.3rem;
    background: hsl(var(--muted));
}

.st-bar span {
    display: block;
    height: 100%;
    background: hsl(var(--primary));
    transform: scaleX(0);
    transform-origin: left center;
    transition: transform 0.25s linear;
}

/* One line that says what is happening, kept at a fixed height so the panel
   never jumps as the words change. */
.st-state {
    margin-top: 0.9rem;
    min-height: 3.2em;
    font-size: 0.88rem;
    line-height: 1.6;
    color: hsl(var(--muted-foreground));
}

.st-state.is-error {
    font-weight: 500;
    color: hsl(0 72% 33%);
}

.st-go {
    display: flex;
    flex-wrap: wrap;
    gap: 0.6rem;
}

.st-go .btn {
    flex: 1 1 14rem;
}

/* Without scripting the dial simply sits at rest, and the page says why. */
.st-nojs {
    margin-top: 0.9rem;
    font-size: 0.85rem;
    line-height: 1.6;
    color: hsl(var(--muted-foreground));
}

html.js .st-nojs {
    display: none;
}

/* What the result is meant to be measured against: the three real speeds.
   On a phone they read one under another, as a ruled list, because three
   columns on a narrow screen would break the names across four lines each;
   from the small screen up they stand side by side as three columns. */
.speed-marks {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    margin: 0;
    padding: 0;
    list-style: none;
    border-top: 1px solid hsl(var(--border));
}

.speed-marks a {
    display: grid;
    gap: 0.15rem;
    height: 100%;
    padding: 0.95rem 1rem;
    transition: background 0.2s ease;
}

.speed-marks li:not(:first-child) a {
    border-top: 1px solid hsl(var(--border));
}

/* Stacked, each speed is one line: the number, then who it is for. */
@media (max-width: 639px) {
    .speed-marks a {
        display: flex;
        flex-wrap: wrap;
        align-items: baseline;
        gap: 0.2rem 0.65rem;
    }
}

@media (min-width: 640px) {
    .speed-marks {
        grid-template-columns: repeat(3, minmax(0, 1fr));
    }

    .speed-marks li:not(:first-child) a {
        border-top: 0;
        border-left: 1px solid hsl(var(--border));
    }
}

.speed-marks a:hover {
    background: hsl(var(--muted));
}

.speed-marks strong {
    font-family: var(--font-display);
    font-size: 1.05rem;
    font-weight: 600;
    font-variant-numeric: tabular-nums;
    letter-spacing: -0.02em;
    color: hsl(var(--foreground));
}

.speed-marks span {
    font-size: 0.76rem;
    line-height: 1.4;
    color: hsl(var(--muted-foreground));
}

/* Once a measurement is finished, the speed it lands on is marked on the
   three real speeds, so the result is read against the offer itself. */
.speed-marks li.is-hit a {
    background: hsl(var(--primary) / 0.07);
}

.speed-marks li.is-hit strong {
    color: hsl(var(--primary));
}

.speed-hit {
    display: none;
    margin-top: 0.25rem;
    font-family: var(--font-display);
    font-size: 0.68rem;
    font-weight: 600;
    letter-spacing: 0.07em;
    text-transform: uppercase;
    color: hsl(var(--primary));
}

.speed-marks li.is-hit .speed-hit {
    display: block;
}

/* On one line the mark sits out at the end of that line, not under it. */
@media (max-width: 639px) {
    .speed-marks li.is-hit .speed-hit {
        margin-top: 0;
        margin-left: auto;
    }
}

/* The three ways on, as a ruled list rather than three more cards. */
.tool-links {
    margin: 0;
    padding: 0;
    list-style: none;
}

.tool-links li {
    border-top: 1px solid hsl(var(--border));
}

.tool-links a {
    display: flex;
    align-items: center;
    gap: 0.8rem;
    padding: 1rem 1.35rem;
    font-size: 0.95rem;
    font-weight: 500;
    color: hsl(var(--foreground));
    transition: background 0.2s ease;
}

.tool-links a:hover {
    background: hsl(var(--muted));
}

.tool-links .tool-ico {
    height: 1.1rem;
    width: 1.1rem;
    flex: none;
    color: hsl(var(--primary));
}

.tool-links .tool-go {
    margin-left: auto;
    height: 0.85rem;
    width: 0.85rem;
    flex: none;
    color: hsl(var(--muted-foreground));
    transition: transform 0.2s ease;
}

.tool-links a:hover .tool-go {
    transform: translateX(3px);
}

/* The three ways on, as one ruled strip. */
.tool-strip {
    margin-top: 1.25rem;
    border: 1px solid hsl(var(--border));
    border-radius: var(--radius);
    background: hsl(var(--card));
    overflow: hidden;
}

.tool-strip .tool-links li:first-child {
    border-top: 0;
}

@media (min-width: 768px) {
    .tool-strip .tool-links {
        display: grid;
        grid-template-columns: repeat(3, minmax(0, 1fr));
    }

    .tool-strip .tool-links li {
        border-top: 0;
    }

    .tool-strip .tool-links li:not(:first-child) {
        border-left: 1px solid hsl(var(--border));
    }
}

/* --------------------------------------------------------------------------
   15d. The tool pages

   Each tool gets the whole screen: the measurement runs at full width inside
   the sheet that crosses the seam out of the opening, exactly as the tariff
   sheet does on the home page, and the address is printed as large as a
   headline because it is the one thing the page exists to say.
   -------------------------------------------------------------------------- */
.crumbs {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.5rem;
    margin-bottom: 1.35rem;
    font-size: 0.82rem;
    color: hsl(var(--haze));
}

.crumbs a {
    color: hsl(var(--haze));
    transition: color 0.2s ease;
}

.crumbs a:hover {
    color: hsl(var(--background));
}

.crumbs .is-here {
    color: hsl(var(--background));
    font-weight: 500;
}

.crumbs svg {
    height: 0.7rem;
    width: 0.7rem;
    flex: none;
    opacity: 0.55;
}

.tool-sheet {
    padding: 1rem;
}

@media (min-width: 640px) {
    .tool-sheet {
        padding: 1.35rem;
    }
}

/* Inside the sheet the three speeds are a bordered block of their own: one
   ruled column on a phone, three panels side by side from the small screen
   up, with no doubled hairline between them either way. */
.tool-sheet .speed-marks {
    border-top: 0;
    margin-top: 1rem;
}

.tool-sheet .speed-marks li a {
    border: 1px solid hsl(var(--border));
}

.tool-sheet .speed-marks li:not(:first-child) a {
    border-top: 0;
}

@media (min-width: 640px) {
    .tool-sheet .speed-marks li:not(:first-child) a {
        border-top: 1px solid hsl(var(--border));
        border-left: 0;
    }
}

/* The address itself, printed at the scale of a headline. */
.ipx {
    display: grid;
    gap: 1.4rem;
    padding: 1.6rem 1.35rem 1.75rem;
}

@media (min-width: 640px) {
    .ipx {
        padding: 2.25rem 2.5rem 2.4rem;
    }
}

.ipx-label {
    display: flex;
    align-items: center;
    gap: 0.7rem;
    font-family: var(--font-display);
    font-size: 0.78rem;
    font-weight: 600;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: hsl(var(--primary));
}

.ipx-label::before {
    content: '';
    flex: none;
    height: 3px;
    width: 2.5rem;
    background: hsl(var(--primary));
}

.ipx-value {
    font-family: var(--font-display);
    font-size: clamp(1.85rem, 7vw, 3.5rem);
    font-weight: 600;
    font-variant-numeric: tabular-nums;
    letter-spacing: -0.035em;
    line-height: 1.05;
    word-break: break-all;
    color: hsl(var(--foreground));
}

.ipx-actions {
    display: flex;
    flex-wrap: wrap;
    gap: 0.6rem;
}

.ipx-actions .btn[hidden] {
    display: none;
}

.ipx-note {
    padding-top: 1.35rem;
    border-top: 1px solid hsl(var(--border));
    max-width: 62ch;
    font-size: 0.9rem;
    line-height: 1.65;
    color: hsl(var(--muted-foreground));
}

@media (max-width: 639px) {
    .ipx-actions .btn {
        width: 100%;
    }
}

/* The same plate takes any other address: the field sits under the reading,
   so checking someone else's address is the same gesture as reading your own. */
.ipx-form {
    display: grid;
    gap: 0.75rem;
    padding-top: 1.35rem;
    border-top: 1px solid hsl(var(--border));
}

.ipx-form .field {
    margin-bottom: 0;
}

.ipx-row {
    display: grid;
    gap: 0.6rem;
}

.ipx-row .input {
    font-family: var(--font-display);
    font-variant-numeric: tabular-nums;
    letter-spacing: -0.01em;
}

@media (min-width: 640px) {
    .ipx-row {
        grid-template-columns: minmax(0, 1fr) auto auto;
        align-items: center;
    }
}

.ipx-hint {
    font-size: 0.85rem;
    line-height: 1.6;
    color: hsl(var(--muted-foreground));
}

.ipx-hint.is-error {
    font-weight: 500;
    color: hsl(0 72% 33%);
}

/* What stands behind the address: a plain ruled table of facts, with the
   place itself drawn underneath it. */
.ipgeo {
    border: 1px solid hsl(var(--border));
    border-top: 3px solid hsl(var(--primary));
    border-radius: var(--radius);
    background: hsl(var(--card));
    overflow: hidden;
}

.ipgeo-head {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    justify-content: space-between;
    gap: 0.4rem 1.25rem;
    padding: 1.05rem 1.35rem;
    border-bottom: 1px solid hsl(var(--border));
}

.ipgeo-for {
    font-size: 0.9rem;
    color: hsl(var(--muted-foreground));
}

.ipgeo-for strong {
    font-family: var(--font-display);
    font-variant-numeric: tabular-nums;
    color: hsl(var(--foreground));
    word-break: break-all;
}

.ipgeo-state {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    font-size: 0.82rem;
    color: hsl(var(--muted-foreground));
}

.ipgeo-state.is-error {
    color: hsl(0 72% 33%);
}

.ipgeo-grid {
    display: grid;
    margin: 0;
    padding: 0;
}

.ipgeo-grid > div {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 1rem;
    padding: 0.85rem 1.35rem;
    border-bottom: 1px solid hsl(var(--border));
}

.ipgeo-grid dt {
    font-size: 0.9rem;
    color: hsl(var(--muted-foreground));
}

.ipgeo-grid dd {
    margin: 0;
    font-family: var(--font-display);
    font-size: 0.92rem;
    font-weight: 500;
    font-variant-numeric: tabular-nums;
    letter-spacing: -0.01em;
    text-align: right;
    overflow-wrap: anywhere;
    color: hsl(var(--foreground));
}

/* On a phone a long operator name or a set of coordinates would be squeezed
   against its own label, so the reading sits under it instead of beside it. */
@media (max-width: 639px) {
    .ipgeo-grid > div {
        flex-direction: column;
        align-items: flex-start;
        gap: 0.2rem;
    }

    .ipgeo-grid dd {
        text-align: left;
    }
}

@media (min-width: 768px) {
    .ipgeo-grid {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }

    .ipgeo-grid > div:nth-child(even) {
        border-left: 1px solid hsl(var(--border));
    }
}

/* The map rides inside the same plate, so it reads as part of the answer. */
.ipgeo-map {
    border: 0;
    border-top: 1px solid hsl(var(--border));
    border-radius: 0;
}

.ipgeo-map[hidden] {
    display: none;
}

.ipgeo-map .map-frame {
    aspect-ratio: 16 / 9;
    height: auto;
    min-height: 0;
}

@media (min-width: 768px) {
    .ipgeo-map .map-frame {
        aspect-ratio: 21 / 9;
    }
}

.ipgeo-note {
    padding: 1rem 1.35rem;
    font-size: 0.82rem;
    line-height: 1.65;
    color: hsl(var(--muted-foreground));
}

/* A plain word of caution, where one is owed. */
.notice {
    display: flex;
    gap: 0.85rem;
    margin-top: 1rem;
    padding: 1rem 1.15rem;
    border: 1px solid hsl(var(--border));
    border-left: 3px solid hsl(var(--primary));
    background: hsl(var(--muted) / 0.6);
}

.notice svg {
    height: 1.15rem;
    width: 1.15rem;
    flex: none;
    margin-top: 0.15rem;
    color: hsl(var(--primary));
}

.notice p {
    max-width: 74ch;
    font-size: 0.88rem;
    line-height: 1.65;
    color: hsl(var(--muted-foreground));
}

.notice p + p {
    margin-top: 0.35rem;
}

.notice .notice-title {
    font-family: var(--font-display);
    font-size: 0.92rem;
    font-weight: 600;
    color: hsl(var(--foreground));
}

/* --------------------------------------------------------------------------
   16. Section reveals

   Every section arrives in the same language the page is drawn in: a rule
   rules itself out from the left, rows print in one after another, the
   photographs develop from their top edge down, and the sheets rise into
   place. The arrived state is the plain default of each element — the script
   arms the starting state only at the moment it is able to release it, and
   clears both again once the piece is in place, so nothing on the page can
   ever be left hidden.
   -------------------------------------------------------------------------- */
@keyframes rv-up {
    from {
        opacity: 0;
        transform: translate3d(0, 1.5rem, 0);
    }

    to {
        opacity: 1;
        transform: none;
    }
}

@keyframes rv-rise {
    from {
        opacity: 0;
        transform: translate3d(0, 2.75rem, 0);
    }

    to {
        opacity: 1;
        transform: none;
    }
}

@keyframes rv-row {
    from {
        opacity: 0;
        transform: translate3d(-0.85rem, 0, 0);
    }

    to {
        opacity: 1;
        transform: none;
    }
}

@keyframes rv-fade {
    from {
        opacity: 0;
    }

    to {
        opacity: 1;
    }
}

@keyframes rv-line {
    from {
        transform: scaleX(0);
    }

    to {
        transform: scaleX(1);
    }
}

@keyframes rv-wipe {
    from {
        opacity: 0;
        clip-path: inset(0 0 34% 0);
        transform: scale(1.02);
    }

    to {
        opacity: 1;
        clip-path: inset(0 0 0 0);
        transform: none;
    }
}

/* Armed: the starting state, held only between the moment the script takes
   charge of a piece and the moment that piece arrives. */
.rv-arm {
    opacity: 0;
}

.rv-arm[data-rv='line'] {
    opacity: 1;
    transform: scaleX(0);
    transform-origin: left center;
}

.rv-in {
    animation-duration: 0.8s;
    animation-timing-function: cubic-bezier(0.22, 1, 0.36, 1);
    animation-fill-mode: both;
    animation-delay: var(--rv-d, 0ms);
}

.rv-in[data-rv='up'] {
    animation-name: rv-up;
}

.rv-in[data-rv='rise'] {
    animation-name: rv-rise;
    animation-duration: 0.9s;
}

.rv-in[data-rv='row'] {
    animation-name: rv-row;
    animation-duration: 0.7s;
}

.rv-in[data-rv='fade'] {
    animation-name: rv-fade;
}

.rv-in[data-rv='line'] {
    animation-name: rv-line;
    animation-duration: 0.9s;
}

.rv-in[data-rv='wipe'] {
    animation-name: rv-wipe;
    animation-duration: 0.95s;
}

/* --------------------------------------------------------------------------
   17. The phone first

   The site is built for a thumb on a narrow screen and grows from there:
   every control is at least a comfortable 44px, every ask runs the full
   width of the screen where there is no room for two side by side, and a
   form field is set at a size the phone never decides to zoom into. On a
   dark field the focus ring turns white, the accent as it reads there.
   -------------------------------------------------------------------------- */
.masthead :focus-visible,
.hero :focus-visible,
.plan-pick :focus-visible,
.vs-verdict :focus-visible,
.site-footer :focus-visible {
    outline: 2px solid hsl(var(--beam));
    outline-offset: 2px;
}

/* Jumping to a section never lands behind the masthead. With scripting the
   page draws the journey itself, a frame at a time; this is what holds when
   scripting never runs. */
html {
    scroll-padding-top: 5.5rem;
}

/* A tap on a control acts at once, with no waiting for a second one. */
a,
button,
summary,
label,
input,
select,
textarea,
.btn,
.icon-btn {
    touch-action: manipulation;
}

@media (max-width: 639px) {
    .input {
        font-size: 1rem;
        padding: 0.85rem 0.95rem;
    }

    /* One ask per line, the whole width of the screen. */
    .hero .btn,
    .vs-verdict .btn,
    .plans-help div .btn,
    .closing-actions .btn,
    .site-footer .btn {
        width: 100%;
    }

    .btn-lg {
        padding: 1rem 1.3rem;
    }

    .closing-actions {
        gap: 0.6rem;
    }

    /* The plans and the closing sheet breathe a little tighter. */
    .plan {
        padding: 1.5rem 1.25rem 1.4rem;
    }

    .plans-help {
        padding: 1.25rem;
    }

    .facts strong {
        font-size: 1.55rem;
    }

    .measure-speed {
        font-size: 1.45rem;
    }

    .measure-price {
        font-size: 1.2rem;
    }
}

/* A pointer that cannot hover — a finger — never needs a hover state, so
   the mark arrives on press instead of lingering after a tap. */
@media (hover: none) {
    .btn:active,
    .icon-btn:active,
    .lang-toggle:active,
    .social:active {
        transform: translateY(1px);
    }

    .menu-link:hover {
        padding-left: 0.9rem;
    }

    .menu-link:hover::before {
        transform: translateY(-50%) scaleY(0);
    }

    .menu-link:active {
        color: hsl(var(--background));
    }

    .menu-link:active::before {
        transform: translateY(-50%) scaleY(1);
    }
}

/* --------------------------------------------------------------------------
   18. Reduced motion
   -------------------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
    /* Jumping to a section happens at once, without the page gliding there.
       The page is answered by name here, so the preference of the visitor
       always outranks the smooth scrolling the document asks for. */
    html,
    html.js,
    html.scroll-smooth {
        scroll-behavior: auto;
    }

    .rv-arm,
    .rv-in {
        opacity: 1 !important;
        transform: none !important;
        clip-path: none !important;
        animation: none !important;
    }

    .hero.is-armed .hero-title,
    .hero.is-armed .lede,
    .hero.is-armed .hero-note,
    .hero.is-armed .btn,
    .measure.is-armed,
    .measure.is-drawn {
        opacity: 1 !important;
        transform: none !important;
        animation: none !important;
    }

    .measure .measure-bar,
    .measure .measure-price,
    .measure .measure-speed {
        transform: none !important;
        opacity: 1 !important;
        transition: none !important;
    }

    /* The network is drawn, lit and still: nothing on it moves. */
    .hero-art svg,
    .hero-halo,
    .hero-art .hero-globe,
    .hero-art .hero-orbit,
    .hero-art .hero-orbit ellipse,
    .hero-art .hero-routes path,
    .hero-art .hero-nodes > *,
    .hero-art .hero-nodes circle {
        opacity: 1 !important;
        stroke-dashoffset: 0 !important;
        transform: none !important;
        transition: none !important;
        animation: none !important;
    }

    .hero-flow {
        display: none !important;
    }

    .faq-wrap,
    .faq-body,
    .navlink::after,
    .faq-mark::after,
    .lang-caret {
        transition: none;
    }

    /* The map is simply shown, and the live mark simply sits there. */
    .map-card iframe,
    .map-flag svg {
        transition: none !important;
    }

    /* The dial still measures and still reads out: the needle simply moves
       to each reading instead of sweeping there. */
    .st-arc,
    .st-needle,
    .st-bar span {
        transition: none !important;
    }

    .dot-live::after {
        animation: none !important;
        opacity: 0 !important;
    }
}
