/*
 * Better Pricing Mothership theme.
 *
 * Load order is MDB -> Dark.css -> this file. Dark.css is a verbatim copy of the Better
 * Pricing app's stylesheet so both sites share one palette; keep it untouched so it can be
 * re-copied when the app's version changes, and put every Mothership-specific adjustment
 * here instead.
 *
 * Dark.css was written for the app, which is a logged-in tool with a fixed-top navbar and
 * puts nearly all of its content inside .card. A marketing page has neither, so the rules
 * below fill the gaps: full-bleed section backgrounds, and text colour for headings and
 * copy that sit directly on the page rather than in a card.
 */

/* Dark.css offsets the page gradient by the height of the app's fixed-top navbar. The
   marketing navbar is sticky rather than fixed, so it takes its own space in the flow and
   that offset would leave a bare strip above the gradient. */
html {
    background-position-y: 0;
}

:root {
    /* The height of the bar, named because the hero is sized against it: the first screen is
       the bar plus a hero that fills what is left, and nothing else. Enforced as a
       min-height on the navbar below, so the two cannot drift apart. */
    --bp-header-height: 4.5rem;
}

/* An in-page link lands under the sticky navbar without this — #plans from the hero button
   put the heading behind the bar. */
html {
    scroll-behavior: smooth;
    scroll-padding-top: var(--bp-header-height);
}

@media (prefers-reduced-motion: reduce) {
    html {
        scroll-behavior: auto;
    }
}

main {
    min-height: 60vh;
}

/* MDB's tertiary background is a light grey used to separate sections. On the dark palette
   it reads as a bright band, so alternate sections get a subtle lift instead. */
.bg-body-tertiary {
    background-color: rgb(18 19 30) !important;
}

/* Copy outside a .card gets no colour from Dark.css. */
body,
main h1,
main h2,
main h3,
main h4,
main h5,
main h6,
main p,
main li,
.navbar-brand {
    color: #e6e6ea;
}

main .text-muted {
    color: #8b8fa3 !important;
}

/* Navbar. Dark.css restyles header nav.bg-white, but the .nav-link colours come from
   Bootstrap's navbar-light and would be near-black on that dark bar. */

/* Sticky rather than static: the hero is a whole screen tall, so on a scrolled page the way
   in — the login and signup buttons — would otherwise be a screen or more behind the
   visitor. Sticky and not fixed, so the bar still takes its own space at the top and the
   first screen is exactly the bar plus the hero.

   The z-index is above the positioned sections below it (.hero, .plans) rather than merely
   above the page: Dark.css gives the bar a drop shadow, and a positioned section painted
   over it. 1030 is Bootstrap's own sticky level, so MDB's dropdowns and modals still land
   on top of it. */
header {
    position: sticky;
    top: 0;
    z-index: 1030;
}

/* .bg-white for the specificity to beat Dark.css's `header nav.bg-white`, which sets the
   colour and a heavy shadow meant for a bar with the whole app under it. Translucent with a
   blur behind it instead: the hero photo travels under the bar as the page scrolls, which
   reads as one surface rather than as a lid. */
header .navbar.bg-white {
    min-height: var(--bp-header-height);
    background-color: rgba(16, 17, 30, 0.78) !important;
    -webkit-backdrop-filter: blur(14px);
    backdrop-filter: blur(14px);
    border-bottom: 1px solid rgba(255, 255, 255, 0.07);
    box-shadow: 0 10px 30px rgba(0, 0, 0, 0.35);
}

/* No blur to hide behind, so the bar has to be opaque or the hero shows through it. */
@supports not (backdrop-filter: blur(1px)) {
    header .navbar.bg-white {
        background-color: rgb(16 17 30) !important;
    }
}

header .navbar .nav-link {
    color: #c3c6d4;
}

header .navbar .nav-link:hover,
header .navbar .nav-link:focus,
header .navbar .nav-link.active {
    color: #ffffff;
}

/* The current page, marked by something other than a shade of grey. Under the link rather
   than around it, so the bar keeps its one line of text.

   Only once the menu is a row: in the collapsed menu the links are full-width blocks, and an
   underline across the whole panel reads as a divider between two groups of links rather
   than as a mark on one of them. Left border there instead. */
@media (min-width: 992px) {
    header .navbar .nav-item .nav-link.active {
        box-shadow: inset 0 -2px 0 var(--contrast-color-light, #15a44d);
        text-decoration: none;
    }
}

@media (max-width: 991.98px) {
    header .navbar .nav-item .nav-link.active {
        box-shadow: inset 2px 0 0 var(--contrast-color-light, #15a44d);
        padding-left: 0.75rem;
        text-decoration: none;
    }
}

header .navbar-toggler {
    border-color: rgba(255, 255, 255, 0.25);
    color: #e6e6ea;
}

header .navbar-toggler:hover,
header .navbar-toggler:focus {
    border-color: rgba(255, 255, 255, 0.45);
    color: #ffffff;
}

/* !important for the same reason as the trust and benefit icons: Dark.css paints every
   i.fas white, which is close enough here, but the hover state has to be able to win. */
header .navbar-toggler i {
    color: inherit !important;
}

.navbar-brand img {
    display: block;
}

/* Login and signup. Sized to sit on one line with the menu without making the bar taller
   than the menu needs. */
.nav-cta {
    padding: 0.5rem 1.1rem;
    font-size: 0.85rem;
    font-weight: 600;
}

.nav-cta--ghost,
.nav-cta--ghost:focus {
    border: 1px solid rgba(255, 255, 255, 0.18);
    background-color: rgba(255, 255, 255, 0.04);
    color: #e6e6ea;
}

.nav-cta--ghost:hover {
    border-color: rgba(255, 255, 255, 0.32);
    background-color: rgba(255, 255, 255, 0.08);
    color: #ffffff;
}

/* Side by side on the wide layout, and full-width one under the other in the collapsed
   menu, where a row of half-width buttons is harder to hit than a stack of whole ones. */
.navbar-nav--actions {
    gap: 0.5rem;
}

@media (max-width: 991.98px) {
    .navbar-nav--actions {
        margin-top: 0.75rem;
        padding-bottom: 0.5rem;
    }

    .navbar-nav--actions .nav-cta {
        display: block;
        width: 100%;
        text-align: center;
    }

    .locale-switcher {
        margin-bottom: 0.25rem;
    }

    /* Full width like the two buttons under it, so the collapsed menu is a stack of
       equal rows rather than a short button above two long ones. */
    .locale-switcher__toggle {
        width: 100%;
    }
}

/* ---------------------------------------------------------------------------
   Hero

   Headline first. It used to open with logo-large.png at 460px, which said the
   company's name — already in the navbar two lines above — at four times the size
   of the sentence that says what it sells.

   The photo is still the backdrop, on a ::before layer as the app does it with
   #promotion, but at a lower opacity and under a vignette: at 25% with nothing
   over it the price tables ran straight through the headline. A second layer
   darkens the edges and fades the bottom into the benefits section below, so the
   two meet without a seam.
   --------------------------------------------------------------------------- */

/* The first screen is the navbar and this, and nothing else: the sections below start
   exactly at the fold, so the page opens on one statement rather than on the top third of
   four things at once.

   min-height rather than height, because the hero grows past a screen when a screenshot has
   been uploaded or the browser's text is set large, and a fixed height would crop it.

   svh, not vh: on a phone vh is the viewport with the browser's toolbars hidden, so with vh
   alone the benefits section peeks over the bottom until you scroll. svh is the viewport
   with the toolbars shown, which is what a visitor arriving actually has. The vh line before
   it is the fallback for browsers that do not know svh. */
.hero {
    position: relative;
    display: grid;
    align-items: center;
    min-height: calc(100vh - var(--bp-header-height));
    min-height: calc(100svh - var(--bp-header-height));
    background-image: linear-gradient(rgb(22 24 40), rgb(10 11 20));
    overflow: hidden;
}

.hero::before {
    content: "";
    background-image: url('../images/promotions/promotion_dk.webp');
    background-size: cover;
    background-position: center;
    background-repeat: no-repeat;
    position: absolute;
    inset: 0;
    opacity: 0.12;
}

/* Vignette and bottom fade. Two gradients on one layer: the first pulls the
   corners down so the copy sits on something even, the second lands on the
   colour the next section starts with. */
.hero::after {
    content: "";
    position: absolute;
    inset: 0;
    pointer-events: none;
    background-image:
        /* Directly behind the copy, so the price tables in the photo stop running
           through the headline. */
        radial-gradient(65% 50% at 50% 42%, rgba(4, 5, 12, 0.72) 0%, transparent 75%),
        radial-gradient(120% 90% at 50% 35%, transparent 30%, rgba(4, 5, 12, 0.8) 100%),
        linear-gradient(to bottom, transparent 55%, rgb(18 19 30) 100%);
}

/* The photo and the vignette are both layers of the section, so the content
   needs its own stacking context to sit above them. */
.hero__inner {
    position: relative;
    /* Above the vignette, not merely above the photo. ::after is the section's
       last child, so with both at z-index auto it painted over the copy and the
       headline came out grey. */
    z-index: 1;
    padding-top: clamp(3.5rem, 8vw, 6rem);
    padding-bottom: clamp(3.5rem, 8vw, 6rem);
}

.hero__badge {
    display: inline-flex;
    align-items: center;
    gap: 0.55rem;
    margin-bottom: 1.5rem;
    padding: 0.4rem 0.9rem;
    border: 1px solid rgba(255, 255, 255, 0.14);
    border-radius: 999px;
    background-color: rgba(255, 255, 255, 0.04);
    color: #c3c6d4;
    font-size: 0.85rem;
}

.hero__badge-dot {
    width: 0.45rem;
    height: 0.45rem;
    border-radius: 50%;
    background-color: var(--contrast-color-light, #15a44d);
    /* The ring is what makes it read as a status light rather than a bullet. */
    box-shadow: 0 0 0 4px rgba(21, 164, 77, 0.18);
}

.hero__title {
    max-width: 56rem;
    margin: 0 auto 1.25rem;
    font-size: clamp(2.4rem, 6vw, 4.2rem);
    font-weight: 700;
    line-height: 1.05;
    letter-spacing: -0.03em;
    color: #ffffff;
    /* Keeps the last line of a two-line headline from being one short word. */
    text-wrap: balance;
}

.hero__lead {
    max-width: 44rem;
    margin: 0 auto 1rem;
    font-size: 1.15rem;
    color: #c3c6d4;
}

.hero__content {
    max-width: 42rem;
    margin: 0 auto;
}

.hero__content p {
    color: #8b8fa3 !important;
    margin-bottom: 0.5rem;
}

.hero__actions {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 0.75rem;
    margin-top: 2rem;
}

.hero__cta {
    padding: 0.85rem 2rem;
    font-size: 0.95rem;
    font-weight: 600;
}

.hero__cta--ghost,
.hero__cta--ghost:focus {
    border: 1px solid rgba(255, 255, 255, 0.18);
    background-color: rgba(255, 255, 255, 0.04);
    color: #e6e6ea;
}

.hero__cta--ghost:hover {
    border-color: rgba(255, 255, 255, 0.32);
    background-color: rgba(255, 255, 255, 0.08);
    color: #ffffff;
}

.hero__trust {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 0.75rem 1.75rem;
    margin: 2rem 0 0;
    padding: 0;
    list-style: none;
}

.hero__trust li {
    color: #8b8fa3 !important;
    font-size: 0.9rem;
}

/* !important because Dark.css paints every i.fas white — see the note on the
   benefits icons. */
.hero__trust i {
    margin-right: 0.5rem;
    color: var(--contrast-color-light, #15a44d) !important;
}

/* Only rendered when an image has been uploaded, so this is the framed shot and
   not a fallback. Same frame as the benefits section. */
.hero__shot {
    margin-top: 3rem;
    padding: 0.5rem;
    border-radius: 22px;
    background-color: rgba(255, 255, 255, 0.04);
    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.12);
}

.hero__shot-image {
    display: block;
    width: 100%;
    aspect-ratio: 16 / 9;
    object-fit: cover;
    object-position: center top;
    border-radius: 16px;
}

/* ---------------------------------------------------------------------------
   Benefits — heading, one large screenshot, then the feature list

   The section leads with the product rather than with six boxes: centred intro,
   a wide framed screenshot, and the benefits underneath as an inline list —
   icon, bold term, description running on in the same line — so six of them
   take up a fraction of the height they did as cards.

   The screenshot fades out at the bottom with a mask rather than by laying a
   gradient in the section's background colour over it. The section has no
   background of its own — the page gradient shows through — so there is no
   colour to match a gradient to, and a mask fades to whatever is actually
   behind it.
   --------------------------------------------------------------------------- */

.benefits__eyebrow {
    color: var(--contrast-color-light, #15a44d);
    font-size: 0.8rem;
    font-weight: 600;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    margin-bottom: 0.5rem;
}

.benefits__title {
    font-size: clamp(1.9rem, 4vw, 2.9rem);
    font-weight: 700;
    letter-spacing: -0.02em;
    color: #ffffff;
    margin-bottom: 0.75rem;
}

.benefits__lead {
    max-width: 42rem;
    margin: 0 auto;
    color: #8b8fa3;
}

/* The screenshot sits in a padded frame, as in the section this follows — a thin
   lit edge around a slightly lifted plate, so the image reads as a screenshot of
   something rather than as a photo dropped on the page.

   The fade is on the frame, not on the image: masking only the image would leave
   the frame's own bottom edge drawn across it. -8% bottom margin then pulls the
   feature list up into the faded part. */
.benefits__shot {
    margin-top: 3rem;
    margin-bottom: -8%;
    padding: 0.5rem;
    border-radius: 22px;
    background-color: rgba(255, 255, 255, 0.03);
    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.1);
    -webkit-mask-image: linear-gradient(to bottom, #000 62%, transparent 100%);
    mask-image: linear-gradient(to bottom, #000 62%, transparent 100%);
}

.benefits__shot-image {
    display: block;
    width: 100%;
    /* Cropped to a wide band rather than shown at its own proportions: an editor
       can upload anything, and a tall image would push the benefits themselves
       off the bottom of the screen. */
    aspect-ratio: 16 / 9;
    object-fit: cover;
    object-position: center top;
    border-radius: 16px;
    box-shadow: 0 32px 64px -32px rgba(0, 0, 0, 0.9);
}

.benefits__features {
    display: grid;
    gap: 2.25rem 3rem;
    /* Clear of the faded bottom of the screenshot above. */
    padding-top: 10%;
    margin-bottom: 0;
}

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

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

/* Icon hung in the margin, term and description stacked beside it. Nothing drawn
   round any of it: chips behind the icons put a box round every benefit and
   turned the list back into the grid of cards it replaced, and a rule over each
   one drew the same grid in thinner lines. The colour and the indent are enough
   to separate them. */
.benefits__feature {
    position: relative;
    padding-left: 2.25rem;
}

/* Every colour here is !important, and has to be. Dark.css carries
   `i.fas { color: white !important }` — the app paints its icons white and never
   wanted them any other colour — so an ordinary rule loses to it no matter how
   specific it is, and the icon renders white however the hue is set. Dark.css is
   a verbatim copy and stays untouched, so the override lives here. */
.benefits__icon {
    position: absolute;
    left: 0;
    top: 0.25rem;
    /* Large enough for the colour to survive antialiasing: at 1rem the violet
       and the amber both came out grey. */
    font-size: 1.2rem;
    line-height: 1;
    color: var(--contrast-color-light, #15a44d) !important;
}

/* And the glyph has to be told to follow its wrapper. Dark.css sets the colour on
   the `i` itself, and a declaration on the element beats an inherited one however
   the ancestor is coloured — so colouring only the wrapper leaves a white icon
   sitting in it. */
.benefits__icon i {
    color: inherit !important;
}

.benefits__term {
    font-weight: 600;
    color: #ffffff;
    margin-bottom: 0.3rem;
}

.benefits__description {
    margin: 0;
    color: #8b8fa3;
    font-size: 0.95rem;
    line-height: 1.6;
}

/* One hue per benefit, repeating every six. Six identical green icons read as a
   pattern rather than as six different things; the palette is the brand green
   plus tones already used elsewhere on the page — the glow's blue, and cooler
   neighbours of both — so it stays one family. */
.benefits__feature:nth-child(6n + 1) .benefits__icon { color: #22c55e !important; }
.benefits__feature:nth-child(6n + 2) .benefits__icon { color: #4d86e8 !important; }
.benefits__feature:nth-child(6n + 3) .benefits__icon { color: #2dd4bf !important; }
.benefits__feature:nth-child(6n + 4) .benefits__icon { color: #a78bfa !important; }
.benefits__feature:nth-child(6n + 5) .benefits__icon { color: #38bdf8 !important; }
.benefits__feature:nth-child(6n + 6) .benefits__icon { color: #fbbf24 !important; }

/* ---------------------------------------------------------------------------
   Plans

   Modelled on the Tailwind Plus pricing section: one dark panel per tier, the
   featured tier lifted out of the row and ringed in the brand green, the price
   set large with the period beside it rather than under it, and a tick list
   under the description so the tiers can be compared by reading down.

   The cards are deliberately not MDB .card. Dark.css styles that class for the
   app, where a card is a container for tables and forms, and its padding,
   radius and heading colours all fight this layout.

   The monthly/yearly toggle is two radios and :has(), the same trick the signup
   choices use, so no script is needed for it. Where :has() is missing the
   monthly cards stay and the toggle does nothing — the default is truthful,
   rather than both sets of prices at once.
   --------------------------------------------------------------------------- */

/* The glow behind the cards. Same construction as the section it is modelled
   on: one wide gradient, cut to an irregular shape and blurred until the shape
   itself is gone, leaving colour that falls off unevenly — which a radial
   gradient cannot do.

   It goes on a ::before layer with the content lifted above it, exactly as the
   hero handles its photo, so the section's own background colour still paints
   underneath and nothing has to fight a negative z-index. */
.plans {
    position: relative;
    overflow: hidden;
}

/* The blur lives on the wrapper. It cannot go on the shape itself: clip-path is
   applied to the filtered result, so an element that is both blurred and clipped
   has its blur cut back to a hard edge — which renders as a set of sharp spikes
   in the corner and reads as a bug. */
.plans__glow {
    position: absolute;
    /* Clear of the top edge by more than the blur radius. The section clips its
       own overflow, so a glow hung above the top — or even level with it — has
       its upper falloff sliced off, and what should be light fading in becomes a
       hard line across the full width of the page. */
    top: 9rem;
    left: 50%;
    /* Held well inside the section, so the blur's tail fades out before it
       reaches either edge. Run out to the edges and the glow stops looking like
       light behind the cards and starts looking like a coloured band across the
       page. The 96px blur reaches roughly 150px past the shape, which is what
       the margin either side leaves room for. */
    width: min(56rem, 72%);
    transform: translateX(-50%);
    filter: blur(96px);
    pointer-events: none;
}

.plans__glow-shape {
    width: 100%;
    aspect-ratio: 1155 / 678;
    /* Brighter than the brand green and the navbar blue they are drawn from: at
       this opacity, over a background this dark, the palette colours themselves
       come out as grey. */
    background-image: linear-gradient(115deg, #1ddc63 15%, #4d86e8 85%);
    clip-path: polygon(
        74.1% 44.1%, 100% 61.6%, 97.5% 26.9%, 85.5% 0.1%, 80.7% 2%, 72.5% 32.5%,
        60.2% 62.4%, 52.4% 68.1%, 47.5% 58.3%, 45.2% 34.5%, 27.5% 76.7%, 0.1% 64.9%,
        17.9% 100%, 27.6% 76.8%, 76.1% 97.7%
    );
    /* A little stronger than it needed to be when it started above the section:
       sitting lower, more of it falls behind the cards. */
    opacity: 0.46;
}

/* The glow is absolutely positioned and comes first in the markup, so the
   section's content needs to be positioned too in order to paint above it. */
.plans > .container {
    position: relative;
}

.plans__eyebrow {
    color: var(--contrast-color-light, #15a44d);
    font-size: 0.8rem;
    font-weight: 600;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    margin-bottom: 0.5rem;
}

.plans__title {
    font-size: clamp(1.9rem, 4vw, 2.9rem);
    font-weight: 700;
    letter-spacing: -0.02em;
    color: #ffffff;
    margin-bottom: 0.75rem;
}

.plans__lead {
    max-width: 42rem;
    margin: 0 auto;
    color: #8b8fa3;
}

.plans__toggle {
    display: flex;
    justify-content: center;
    gap: 0.25rem;
    width: fit-content;
    margin: 2rem auto 0;
    padding: 0.25rem;
    border: 1px solid rgba(255, 255, 255, 0.12);
    border-radius: 999px;
}

/* Kept in the accessibility tree and focusable — only the native dot is out of
   the way, since the pill it sits behind is what the customer sees. */
.plans__toggle-input {
    position: absolute;
    width: 1px;
    height: 1px;
    opacity: 0;
    pointer-events: none;
}

.plans__toggle-option {
    padding: 0.4rem 1.25rem;
    border-radius: 999px;
    color: #8b8fa3;
    font-size: 0.9rem;
    font-weight: 500;
    cursor: pointer;
    transition: background-color 0.15s ease-in-out, color 0.15s ease-in-out;
}

.plans__toggle-option:hover {
    color: #e6e6ea;
}

.plans__toggle-input:checked + .plans__toggle-option {
    background-color: var(--contrast-color-light, #15a44d);
    color: #ffffff;
}

/* The label is the visible control, so the focus ring belongs on it. */
.plans__toggle-input:focus-visible + .plans__toggle-option {
    outline: 2px solid var(--contrast-color-light, #15a44d);
    outline-offset: 2px;
}

.plans__group {
    margin-top: 3rem;
}

/* The small print under the cards. Same muted colour as the section lead above them, and
   centred on the same measure, so the section is bracketed by two lines of the same voice. */
.plans__note {
    max-width: 42rem;
    margin: 2rem auto 0;
    color: #8b8fa3;
    font-size: 0.9rem;
    text-align: center;
}

.plans__group--year {
    display: none;
}

.plans:has(#plans-interval-year:checked) .plans__group--year {
    display: block;
}

.plans:has(#plans-interval-year:checked) .plans__group--month {
    display: none;
}

/* Cards */
.plan-card {
    display: flex;
    flex-direction: column;
    width: 100%;
    padding: 2rem;
    border: 1px solid rgba(255, 255, 255, 0.08);
    border-radius: 20px;
    background-color: #12131e;
    transition: border-color 0.15s ease-in-out, transform 0.15s ease-in-out;
}

.plan-card:hover {
    border-color: rgba(255, 255, 255, 0.2);
}

.plan-card--featured {
    background-color: #171928;
    border-color: transparent;
    /* A ring rather than a 2px border, so the featured card is not a pixel wider
       than the two beside it. */
    box-shadow: 0 0 0 2px var(--contrast-color-light, #15a44d),
        0 24px 48px -24px rgba(0, 0, 0, 0.9);
}

.plan-card--featured:hover {
    border-color: transparent;
}

/* Only once the cards are side by side: lifting a card out of a single column
   just leaves a gap. */
@media (min-width: 992px) {
    .plan-card--featured {
        transform: translateY(-0.75rem);
    }
}

.plan-card__head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.75rem;
    margin-bottom: 0.25rem;
}

.plan-card__name {
    font-size: 1.1rem;
    font-weight: 600;
    color: #ffffff;
    margin: 0;
}

/* The featured tier's name carries the brand colour, as in the section this is
   modelled on — one more thing marking it out without another border. */
.plan-card--featured .plan-card__name {
    color: var(--contrast-color-light, #15a44d);
}

.plan-card__badge {
    flex-shrink: 0;
    padding: 0.25rem 0.65rem;
    border-radius: 999px;
    background-color: rgba(21, 164, 77, 0.15);
    color: #4ade80;
    font-size: 0.75rem;
    font-weight: 600;
}

.plan-card__users {
    color: #8b8fa3;
    font-size: 0.9rem;
    margin-bottom: 1.25rem;
}

/* Amount and period on one baseline, as in the Tailwind section: the period is
   part of the price, not a caption under it. */
.plan-card__price {
    display: flex;
    align-items: baseline;
    flex-wrap: wrap;
    gap: 0.5rem;
    margin-bottom: 1rem;
}

.plan-card__amount {
    font-size: 2.6rem;
    font-weight: 700;
    letter-spacing: -0.02em;
    color: #ffffff;
    line-height: 1.1;
}

.plan-card__period {
    color: #8b8fa3;
    font-size: 0.9rem;
}

.plan-card__desc {
    color: #c3c6d4;
    margin-bottom: 1.5rem;
}

.plan-card__features {
    list-style: none;
    padding: 0;
    margin: 0 0 2rem;
}

.plan-card__features li {
    position: relative;
    padding-left: 1.75rem;
    margin-bottom: 0.6rem;
    color: #c3c6d4;
    font-size: 0.95rem;
}

.plan-card__features li:last-child {
    margin-bottom: 0;
}

/* !important for the same reason as the benefits icons: Dark.css forces every
   `i.fas` white, so without it the ticks were white too — which is why they read
   as bullet points rather than as ticks in the brand colour. */
.plan-card__features i {
    position: absolute;
    left: 0;
    top: 0.3rem;
    color: var(--contrast-color-light, #15a44d) !important;
    font-size: 0.85rem;
}

/* Pushed to the bottom so the buttons line up across cards whose lists are of
   different lengths. */
.plan-card__action {
    margin-top: auto;
}

.plan-card__cta {
    display: block;
    width: 100%;
    padding-top: 0.7rem;
    padding-bottom: 0.7rem;
    font-weight: 600;
}

/* The unfeatured tiers get an outline button, so the featured one is the only
   filled target in the row. */
.plan-card__cta--ghost,
.plan-card__cta--ghost:hover,
.plan-card__cta--ghost:focus {
    background-color: transparent;
    border: 1px solid rgba(255, 255, 255, 0.16);
    color: #e6e6ea;
}

.plan-card__cta--ghost:hover {
    background-color: rgba(255, 255, 255, 0.06);
    border-color: rgba(255, 255, 255, 0.3);
    color: #ffffff;
}

.plan-card__cta--ghost:disabled {
    color: #8b8fa3;
}

/* ---------------------------------------------------------------------------
   Integrations

   A tile per accounting system rather than a row of bare logos. The logos come
   from third parties and are nearly all dark-on-light, so each one needs a light
   plate behind it — and a plate floating on a dark page looks like a mistake
   unless something holds it. The tile is that something, and it also gives the
   systems with no logo uploaded yet somewhere to put their name.
   --------------------------------------------------------------------------- */

.integrations__eyebrow {
    color: var(--contrast-color-light, #15a44d);
    font-size: 0.8rem;
    font-weight: 600;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    margin-bottom: 0.5rem;
}

.integrations__title {
    font-size: clamp(1.7rem, 3.4vw, 2.4rem);
    font-weight: 700;
    letter-spacing: -0.02em;
    color: #ffffff;
    margin-bottom: 0.75rem;
}

.integrations__lead {
    max-width: 40rem;
    margin: 0 auto;
    color: #8b8fa3;
}

.integrations__list {
    display: grid;
    /* Fits as many as the width allows rather than a fixed column count: the
       list is CMS-editable and a fourth system should not force a second row of
       one. */
    grid-template-columns: repeat(auto-fit, minmax(13rem, 1fr));
    gap: 1rem;
    margin: 2.5rem 0 0;
    padding: 0;
    list-style: none;
}

.integrations__tile {
    display: flex;
    align-items: center;
    justify-content: center;
    height: 6.5rem;
    padding: 1.25rem;
    border: 1px solid rgba(255, 255, 255, 0.08);
    border-radius: 16px;
    background-color: rgba(255, 255, 255, 0.02);
    text-decoration: none;
    transition: border-color 0.15s ease-in-out, background-color 0.15s ease-in-out,
        transform 0.15s ease-in-out;
}

a.integrations__tile:hover,
a.integrations__tile:focus-visible {
    border-color: rgba(255, 255, 255, 0.24);
    background-color: rgba(255, 255, 255, 0.05);
    transform: translateY(-2px);
}

/* The plate, on the logo itself rather than on the tile, so a transparent PNG
   keeps its contrast without the tile turning white. */
.integrations__logo {
    max-width: 100%;
    max-height: 3rem;
    background-color: #ffffff;
    border-radius: 8px;
    padding: 0.5rem 0.75rem;
}

.integrations__name {
    color: #e6e6ea;
    font-size: 1.05rem;
    font-weight: 600;
    text-align: center;
}

a.integrations__tile:hover .integrations__name {
    color: #ffffff;
}

/* ---------------------------------------------------------------------------
   FAQ

   Heading in its own column beside the questions, and the accordion stripped
   back to a list: no panel, no boxes, just a rule between one question and the
   next. Dark.css styles .accordion for the app, where it is a card — hence the
   !important on the background and the border.
   --------------------------------------------------------------------------- */

.faq__eyebrow {
    color: var(--contrast-color-light, #15a44d);
    font-size: 0.8rem;
    font-weight: 600;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    margin-bottom: 0.5rem;
}

.faq__title {
    font-size: clamp(1.7rem, 3.4vw, 2.4rem);
    font-weight: 700;
    letter-spacing: -0.02em;
    color: #ffffff;
    margin-bottom: 0.75rem;
}

.faq__lead {
    color: #8b8fa3;
}

@media (min-width: 992px) {
    /* Follows the questions down when the list is long enough to scroll past. */
    .faq__intro {
        position: sticky;
        top: 3rem;
    }
}

.faq__list,
.faq__item {
    background-color: transparent !important;
    border: 0 !important;
    border-radius: 0 !important;
}

/* Between the questions, not around them. */
.faq__item + .faq__item {
    border-top: 1px solid rgba(255, 255, 255, 0.09) !important;
}

/* The same padding open and closed, deliberately. It used to lose half a rem of
   bottom padding the moment it opened, which the class change applies instantly
   while the answer below it is still growing — so every question jumped upwards
   as its own answer came out. The room the open state wanted belongs to the
   answer, and is given to it there. */
.faq__question,
.faq__question:not(.collapsed) {
    padding: 1.4rem 0;
    background-color: transparent !important;
    box-shadow: none;
    color: #ffffff !important;
    font-size: 1.05rem;
    font-weight: 600;
}

/* The pale bar under an open question.
   MDB draws a near-white inset line under a focused accordion button — #e0e0e0,
   a colour for a white page — and a question is focused for as long as it is the
   one that was last clicked. So opening an answer left a bright rule across the
   page, and it stayed there. */
.faq__question:focus,
.faq__question:not(.collapsed):focus {
    box-shadow: none;
}

/* Which still leaves keyboard focus to show, and MDB has just been told not to
   draw it. Only for keyboard focus: a mouse click already says where it landed
   by opening the answer. */
.faq__question:focus-visible {
    outline: 2px solid var(--contrast-color-light, #15a44d);
    outline-offset: -2px;
}

.faq__question:hover {
    color: #ffffff !important;
}

/* The marker.
   MDB draws two images — a near-black chevron and a blue one for the open state —
   and swaps them at the moment the panel opens. The old rule inverted whichever
   was showing to get something light out of it, which meant the open state was a
   different colour arrived at by accident.

   One glyph in both states instead, in the muted grey the rest of the section's
   secondary text uses, and the brand green once the answer is out. Same geometry
   in both, so what the eye follows is the rotation rather than a substitution. */
.faq__question {
    --mdb-accordion-btn-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%238b8fa3' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 6l4 4 4-4'/%3E%3C/svg%3E");
    --mdb-accordion-btn-active-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%234ade80' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 6l4 4 4-4'/%3E%3C/svg%3E");
}

/* MDB sets `transition: none` on the marker, so the chevron used to arrive at
   its new angle in one frame while the panel below it moved. */
.faq__question::after {
    filter: none;
    opacity: 0.8;
    transition: transform 0.3s ease, opacity 0.15s ease-in-out;
}

.faq__question:hover::after,
.faq__question:not(.collapsed)::after {
    opacity: 1;
}

/* MDB ships `.collapsing { transition: none }`, which is what made opening an
   answer a jump rather than a movement: Bootstrap's collapse sets the height in
   pixels and expects the transition to carry it, and with none there the whole
   panel appeared at once and shoved everything below it down. Restored here
   rather than globally, since this is the only accordion on the site. */
.faq .accordion-collapse.collapsing {
    transition: height 0.3s ease;
}

/* And the answer itself comes up with it rather than being there from the first
   frame, which is what made a half-open panel look like text sliding out from
   under the question. */
.faq__answer,
.faq__answer p {
    padding-left: 0;
    padding-right: 0;
    color: #8b8fa3 !important;
}

.faq__answer {
    padding-top: 0;
    padding-bottom: 1.6rem;
    /* The width a line of text can be read at, rather than the width of the
       column: the answers are one or two sentences and the column is two thirds
       of the page. */
    max-width: 40rem;
    opacity: 0;
    transform: translateY(-0.25rem);
    transition: opacity 0.3s ease, transform 0.3s ease;
}

.faq .accordion-collapse.show .faq__answer {
    opacity: 1;
    transform: none;
}

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

/* Nothing above is load-bearing: with movement turned off the answer is simply
   there or not, which is what an accordion is for. */
@media (prefers-reduced-motion: reduce) {
    .faq .accordion-collapse.collapsing {
        transition: none;
    }

    .faq__question::after,
    .faq__answer {
        transition: none;
    }

    .faq__answer {
        opacity: 1;
        transform: none;
    }
}

/* ---------------------------------------------------------------------------
   Footer

   It was a light grey band with one line of copyright on it, which on this palette read as
   the page ending in a mistake and gave a visitor at the bottom of a long marketing page
   nowhere to go but back up.

   Now: the mark and what the product is, then the columns of links the site already knows
   about, then the small print on a rule of its own.
   --------------------------------------------------------------------------- */

.footer {
    margin-top: 0;
    border-top: 1px solid rgba(255, 255, 255, 0.07);
    background-color: rgb(14 15 24);
}

.footer p {
    color: #8b8fa3;
}

/* One column on a phone, the brand over a row of link columns from medium up. The brand
   column is wider than the rest: it holds a sentence, not a list. */
.footer__inner {
    display: grid;
    gap: 2rem;
    padding-top: 3.5rem;
    padding-bottom: 2.5rem;
}

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

    .footer__brand {
        grid-column: 1 / -1;
    }
}

@media (min-width: 992px) {
    .footer__inner {
        grid-template-columns: minmax(0, 1.6fr) repeat(3, minmax(0, 1fr));
        gap: 2.5rem;
    }

    .footer__brand {
        grid-column: auto;
    }
}

.footer__logo {
    display: inline-block;
    margin-bottom: 1rem;
}

.footer__logo img {
    display: block;
}

.footer__tagline {
    max-width: 22rem;
    margin-bottom: 0;
    font-size: 0.95rem;
}

/* Small, spaced and quiet: a column heading here labels four links, it does not compete
   with the headings in the page above. */
.footer__heading {
    margin-bottom: 0.9rem;
    color: #e6e6ea;
    font-size: 0.8rem;
    font-weight: 600;
    letter-spacing: 0.08em;
    text-transform: uppercase;
}

.footer__links {
    margin: 0;
    padding: 0;
    list-style: none;
}

.footer__links li + li {
    margin-top: 0.5rem;
}

.footer__links a {
    color: #8b8fa3;
    font-size: 0.95rem;
    text-decoration: none;
    transition: color 0.15s ease-in-out;
}

.footer__links a:hover,
.footer__links a:focus {
    color: #ffffff;
}

/* The language being read, marked without colour alone — as in the navbar, since following
   it only reloads the page you are on. */
.footer__links a.active {
    color: #e6e6ea;
    font-weight: 600;
}

/* Copyright and small print, on a rule so they read as the end of the page rather than as a
   fifth column. Side by side where there is room. */
.footer__bottom {
    display: flex;
    flex-wrap: wrap;
    justify-content: space-between;
    gap: 0.25rem 1.5rem;
    padding-top: 1.5rem;
    padding-bottom: 2rem;
    border-top: 1px solid rgba(255, 255, 255, 0.07);
}

.footer__copyright,
.footer__rights {
    margin-bottom: 0;
    font-size: 0.85rem;
}

/* ---------------------------------------------------------------------------
   Signup

   The page a plan card leads to, built out of the same parts as the sections it
   is reached from: the eyebrow-title-lead opening, the panels of .plan-card, and
   the pricing section's glow behind them. It used to be an h1 over a stack of
   MDB cards, which is what the app looks like — so paying for the product began
   by leaving the site that sells it.

   The step numbers are drawn by a counter rather than written into the markup,
   so adding or reordering a step cannot leave the numbering wrong.
   --------------------------------------------------------------------------- */

.signup {
    position: relative;
    counter-reset: signup-step;
    padding-top: clamp(2.5rem, 5vw, 4rem);
    padding-bottom: clamp(4rem, 8vw, 6rem);
}

/* The glow, near the top where the heading and the first step are, since that is
   what it is lighting. Same construction as .plans__glow — see the note there
   for why the blur has to be on an ancestor of the clipped shape rather than on
   the shape itself.

   One element more than the pricing section needs, though: there the section
   clips its own overflow, and here it cannot. The order summary beside the form
   is sticky, and overflow on any ancestor of a sticky element makes that
   ancestor its scroll container — one that never scrolls, so the summary would
   simply sit still. The clipping happens here instead. */
.signup__glow {
    position: absolute;
    inset: 0;
    overflow: hidden;
    pointer-events: none;
}

.signup__glow-blur {
    position: absolute;
    top: 2rem;
    left: 50%;
    width: min(60rem, 80%);
    transform: translateX(-50%);
    filter: blur(96px);
}

.signup__glow-shape {
    width: 100%;
    aspect-ratio: 1155 / 678;
    background-image: linear-gradient(115deg, #1ddc63 15%, #4d86e8 85%);
    clip-path: polygon(
        74.1% 44.1%, 100% 61.6%, 97.5% 26.9%, 85.5% 0.1%, 80.7% 2%, 72.5% 32.5%,
        60.2% 62.4%, 52.4% 68.1%, 47.5% 58.3%, 45.2% 34.5%, 27.5% 76.7%, 0.1% 64.9%,
        17.9% 100%, 27.6% 76.8%, 76.1% 97.7%
    );
    /* Weaker than the pricing section's: there the glow sits behind three cards
       and nothing else, here it sits behind text that has to stay readable. */
    opacity: 0.3;
}

/* The glow is absolutely positioned and comes first in the markup, so the
   content needs to be positioned too in order to paint above it. */
.signup__inner {
    position: relative;
}

.signup__intro {
    max-width: 46rem;
    margin: 0 auto clamp(2.5rem, 5vw, 3.5rem);
}

.signup__eyebrow {
    color: var(--contrast-color-light, #15a44d);
    font-size: 0.8rem;
    font-weight: 600;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    margin-bottom: 0.5rem;
}

.signup__title {
    font-size: clamp(1.9rem, 4vw, 2.9rem);
    font-weight: 700;
    letter-spacing: -0.02em;
    color: #ffffff;
    margin-bottom: 0.75rem;
    text-wrap: balance;
}

.signup__lead {
    color: #8b8fa3;
    margin-bottom: 0;
}

/* The step panel. Same surface, border and radius as a plan card, so the four
   steps read as the row of cards the customer just came from rather than as the
   app's own form. */
.signup-step {
    counter-increment: signup-step;
    padding: clamp(1.5rem, 3vw, 2rem);
    margin-bottom: 1.5rem;
    border: 1px solid rgba(255, 255, 255, 0.08);
    border-radius: 20px;
    background-color: #12131e;
    transition: border-color 0.15s ease-in-out;
}

/* The step being filled in, marked without moving anything. */
.signup-step:focus-within {
    border-color: rgba(255, 255, 255, 0.18);
}

.signup-step__head {
    display: flex;
    align-items: flex-start;
    gap: 1rem;
    margin-bottom: 1.75rem;
}

/* A ring rather than a filled green disc: four solid brand-coloured circles down
   the page pulled harder than the one thing on it that should — the button at
   the bottom. */
.signup-step__number {
    flex: 0 0 2.25rem;
    height: 2.25rem;
    border-radius: 50%;
    background-color: rgba(21, 164, 77, 0.14);
    box-shadow: inset 0 0 0 1px rgba(21, 164, 77, 0.4);
    color: #4ade80;
    font-size: 0.95rem;
    font-weight: 600;
    display: inline-flex;
    align-items: center;
    justify-content: center;
}

.signup-step__number::before {
    content: counter(signup-step);
}

.signup-step__title {
    font-size: 1.15rem;
    font-weight: 600;
    color: #ffffff;
    margin-bottom: 0.35rem;
}

.signup-step__desc {
    margin-bottom: 0;
    color: #8b8fa3;
    font-size: 0.92rem;
    line-height: 1.6;
}

/* Fields. Shared with the login and password forms — see the Authentication
   section at the foot of this file — since a customer meets both, and a field
   drawn one way on the form they buy through and another on the form they come
   back through is two designs for one control.

   MDB's inputs come out of Dark.css wearing the app's dark green outline, which
   on these pages is a second brand colour competing with the button. They get
   the same hairline every other surface here has instead, and the brand green
   only on the field being typed in.

   The focus colour is set as MDB's own custom property rather than by
   overriding the rules that read it: MDB draws the focused notch in four rules
   whose box-shadows carry the colour as well as the borders, and all four
   inherit this. */
.signup .form-outline,
.auth .form-outline {
    --mdb-input-focus-border-color: var(--contrast-color-light, #15a44d);
}

.signup .form-outline .form-control,
.auth .form-outline .form-control {
    background-color: rgba(255, 255, 255, 0.03);
    border-radius: 0.25rem;
}

.signup .form-outline .form-control ~ .form-notch div,
.auth .form-outline .form-control ~ .form-notch div {
    border-color: rgba(255, 255, 255, 0.14);
}

/* Not while it is focused, where MDB's own rules paint the notch green. */
.signup .form-outline:hover .form-control:not(:focus) ~ .form-notch div,
.auth .form-outline:hover .form-control:not(:focus) ~ .form-notch div {
    border-color: rgba(255, 255, 255, 0.26);
}

.signup .form-label,
.auth .form-label {
    color: #c3c6d4;
}

/* Every field carries mb-4 from the holder template, which under the last one in
   a panel lands on top of the panel's own padding and leaves the step looking
   bottom-heavy.

   Deliberately not `.signup-step .field:last-child`: the fields inside a
   two-column row are each the last child of their own column, and stripping
   their margin would close the gap between that row and the field under it. The
   second selector is for the step whose last field is inside a wrapper — the
   e-conomic token. */
.signup-step > .field:last-child,
.signup-step > :last-child > .field:last-child {
    /* mb-4 is a Bootstrap utility, and those carry !important, so nothing else
       can outrank it. */
    margin-bottom: 0 !important;
}

.signup .form-text.text-muted,
.auth .form-text.text-muted {
    color: #8b8fa3 !important;
}

/* Selects are not .form-outline and get none of the above. MDB styles them for a
   light page — white plate, near-black caret — so on this palette an untouched
   dropdown was the one bright rectangle on the form. */
.signup .form-select {
    background-color: rgba(255, 255, 255, 0.03);
    border: 1px solid rgba(255, 255, 255, 0.14);
    color: #ffffff;
    /* MDB's caret is drawn in a colour meant for a white field. Redrawn in the
       muted grey the rest of the form's secondary text uses. */
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%238b8fa3' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 6l4 4 4-4'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: right 0.75rem center;
    background-size: 16px 16px;
}

.signup .form-select:hover {
    border-color: rgba(255, 255, 255, 0.26);
}

.signup .form-select:focus {
    border-color: var(--contrast-color-light, #15a44d);
    box-shadow: 0 0 0 1px var(--contrast-color-light, #15a44d);
}

/* The list itself is drawn by the operating system, which knows nothing about
   the page: without this the options are black on white behind a dark field. */
.signup .form-select option {
    background-color: #12131e;
    color: #e6e6ea;
}

/* Selectable cards for the accounting system and the language. The label covers
   the card, which is what makes the whole thing clickable without any
   JavaScript. */
.signup-choice {
    position: relative;
    display: flex;
    align-items: center;
    padding: 1rem 1rem 1rem 2.75rem;
    border: 1px solid rgba(255, 255, 255, 0.1);
    border-radius: 14px;
    background-color: rgba(255, 255, 255, 0.02);
    transition: border-color 0.15s ease-in-out, background-color 0.15s ease-in-out;
}

.signup-choice:hover {
    border-color: rgba(255, 255, 255, 0.26);
    background-color: rgba(255, 255, 255, 0.05);
}

/* :has lets the card react to its own radio without a change handler. */
.signup-choice:has(input:checked) {
    border-color: transparent;
    background-color: rgba(21, 164, 77, 0.1);
    /* A ring rather than a thicker border, so the chosen card is not a pixel
       wider than the one beside it. */
    box-shadow: 0 0 0 1px var(--contrast-color-light, #15a44d);
}

.signup-choice .form-check-input {
    position: absolute;
    left: 1rem;
    margin: 0;
    flex-shrink: 0;
}

.signup-choice__label {
    margin: 0;
    color: #e6e6ea;
    font-weight: 500;
    cursor: pointer;
    /* Stretched over the card so the whole card is the hit area */
    position: static;
}

.signup-choice:has(input:checked) .signup-choice__label {
    color: #ffffff;
}

.signup-choice__label::after {
    content: "";
    position: absolute;
    inset: 0;
}

/* Order summary. Follows the form down on a wide screen, sits inline below it
   on anything narrower — a sticky block on a phone just eats the viewport. */
@media (min-width: 992px) {
    .signup-summary {
        position: sticky;
        top: calc(var(--bp-header-height) + 1.5rem);
    }
}

/* The featured plan card, standing on its own: same surface and radius. */
.signup-summary__card {
    padding: 1.75rem;
    border-radius: 20px;
    background-color: #171928;
    box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.08),
        0 24px 48px -24px rgba(0, 0, 0, 0.9);
}

/* The green ring only once there is a plan in it: it marks the one thing on this
   page that is already decided, and an empty summary has decided nothing. */
.signup-summary__card--chosen {
    box-shadow: 0 0 0 1px rgba(21, 164, 77, 0.45),
        0 24px 48px -24px rgba(0, 0, 0, 0.9);
}

.signup-summary__eyebrow {
    color: var(--contrast-color-light, #15a44d);
    font-size: 0.75rem;
    font-weight: 600;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    margin-bottom: 1rem;
}

.signup-summary__head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.75rem;
    margin-bottom: 0.25rem;
}

.signup-summary__name {
    font-size: 1.25rem;
    font-weight: 600;
    color: #ffffff;
    margin: 0;
}

.signup-summary__users {
    color: #8b8fa3;
    font-size: 0.9rem;
    margin-bottom: 1rem;
}

/* Amount and period on one baseline, as on the plan cards: the period is part of
   the price, not a caption under it. */
.signup-summary__price {
    display: flex;
    align-items: baseline;
    flex-wrap: wrap;
    gap: 0.5rem;
    margin-bottom: 1.5rem;
}

.signup-summary__amount {
    font-size: 2.2rem;
    font-weight: 700;
    letter-spacing: -0.02em;
    line-height: 1.1;
    color: #ffffff;
}

.signup-summary__period {
    color: #8b8fa3;
    font-size: 0.9rem;
}

.signup-summary__list {
    list-style: none;
    padding: 0;
    margin: 0 0 1.5rem;
    border-top: 1px solid rgba(255, 255, 255, 0.09);
    padding-top: 1.25rem;
}

.signup-summary__list li {
    position: relative;
    padding-left: 1.75rem;
    margin-bottom: 0.6rem;
    color: #c3c6d4;
    font-size: 0.9rem;
    line-height: 1.5;
}

.signup-summary__list li:last-child {
    margin-bottom: 0;
}

/* !important for the same reason as the plan cards' ticks: Dark.css forces every
   i.fas white, so without it these read as bullet points. */
.signup-summary__list i {
    position: absolute;
    left: 0;
    top: 0.3rem;
    font-size: 0.8rem;
    color: var(--contrast-color-light, #15a44d) !important;
}

/* A link, not a button: changing your mind about the plan is a way back to the
   page you came from, not a second thing to do here. */
.signup-summary__change {
    color: #8b8fa3;
    font-size: 0.9rem;
    text-decoration: none;
    border-bottom: 1px solid rgba(255, 255, 255, 0.2);
    transition: color 0.15s ease-in-out, border-color 0.15s ease-in-out;
}

.signup-summary__change:hover,
.signup-summary__change:focus {
    color: #ffffff;
    border-color: rgba(255, 255, 255, 0.5);
}

.signup-summary__empty {
    color: #c3c6d4;
    margin-bottom: 1.25rem;
}

/* The one case where the summary has something to be done in it, so here it is a
   button — the ghost one the unfeatured plan cards use. */
.signup-summary__cta,
.signup-summary__cta:focus {
    display: block;
    width: 100%;
    padding-top: 0.65rem;
    padding-bottom: 0.65rem;
    border: 1px solid rgba(255, 255, 255, 0.16);
    background-color: transparent;
    color: #e6e6ea;
    font-weight: 600;
}

.signup-summary__cta:hover {
    border-color: rgba(255, 255, 255, 0.3);
    background-color: rgba(255, 255, 255, 0.06);
    color: #ffffff;
}

.signup-summary__note {
    display: flex;
    align-items: flex-start;
    gap: 0.5rem;
    margin: 1.25rem 0 0;
    color: #8b8fa3;
    font-size: 0.85rem;
    line-height: 1.5;
}

.signup-summary__note i {
    margin-top: 0.2rem;
    font-size: 0.8rem;
    color: #8b8fa3 !important;
}

/* The submit sits below the last step, and is the only filled target on the
   page. Full width at every size: it is the end of the form, and a button that
   ends where the last field ends is easier to aim at than one floating under
   the left of it. */
.signup .btn-toolbar {
    display: block;
    margin-top: 2rem;
}

.signup .btn-toolbar .action {
    width: 100%;
    padding: 0.9rem 2rem;
    font-size: 0.95rem;
    font-weight: 600;
}

/* Hidden by signup.js, not by CSS: see the note in that file about failing open. */
.js-show-for-economic[hidden] {
    display: none;
}

/* Rejections. Shared with the login and password forms, where the same markup carries
   "e-mail eller adgangskode passer ikke".

   SilverStripe emits class="message bad" for a message that belongs to the form and
   class="form-text bad" for one attached to a field, and neither Bootstrap nor MDB
   styles either — so "firmanavnet er optaget" read as ordinary body copy and was easy
   to walk straight past, which is half of why a rejected signup felt like the form had
   simply reset itself.

   The tones are the ones Dark.css gives .alert-danger, so this stays one palette rather
   than introducing a second red. An empty message carries an inline display:none from
   the form template, so nothing is drawn when there is nothing to say. */
.signup .message,
.auth .message {
    padding: 0.9rem 1.1rem;
    margin-bottom: 1.5rem;
    border: 1px solid rgba(255, 181, 193, 0.25);
    border-radius: 14px;
    background-color: rgba(121, 28, 44, 0.35);
    color: #ffb5c1;
}

/* Set directly on the form rather than through the session: payment not being configured
   is not the customer's mistake, so it should not look like one. */
.signup .message.warning,
.auth .message.warning {
    border-color: rgba(255, 214, 143, 0.25);
    background-color: rgba(121, 84, 28, 0.35);
    color: #ffd68f;
}

/* The framework also has a good news message, on the page that says a password reset mail
   has been sent. Nothing styles that either, and in the red above it would have read as a
   failure. The tones are Dark.css's .alert-success. */
.auth .message.good {
    border-color: rgba(155, 240, 187, 0.25);
    background-color: rgba(21, 121, 60, 0.35);
    color: #9bf0bb;
}

/* Under the field it belongs to. .form-text is also MDB's help text, which is muted grey,
   so the error has to out-rank the description sitting right next to it. */
.signup .field .form-text.bad,
.auth .field .form-text.bad {
    color: #ffb5c1;
}

/* The address field: one box holding two things. The subdomain is a real input, the base
   domain is text, and the box draws the border once so the pair reads as a single address
   rather than as a field standing next to a stray word.

   Everything is scoped to .signup rather than dressing .form-control globally, since the
   input keeps that class for MDB's typography and sizing and only gives up its own frame. */
.signup .subdomain-field {
    display: flex;
    align-items: stretch;
    /* The same hairline the MDB inputs above it are given, rather than the app's
       dark green outline — one field on the form drawn in a different colour
       reads as one field in a different state. */
    border: 1px solid rgba(255, 255, 255, 0.14);
    border-radius: 0.25rem;
    background-color: rgba(255, 255, 255, 0.03);
    overflow: hidden;
    transition: border-color 0.15s ease-in-out;
}

.signup .subdomain-field:hover {
    border-color: rgba(255, 255, 255, 0.26);
}

/* The input no longer has a border of its own to show focus on, so the box shows it. */
.signup .subdomain-field:focus-within {
    border-color: var(--contrast-color-light, #15a44d);
    box-shadow: 0 0 0 1px var(--contrast-color-light, #15a44d);
}

.signup .subdomain-field .form-control,
.signup .subdomain-field .form-control:focus {
    flex: 1 1 auto;
    /* Without this a long company name makes the box wider than its column instead of
       scrolling inside the input. */
    min-width: 0;
    border: 0;
    border-radius: 0;
    background-color: transparent;
    box-shadow: none;
    /* Dark.css whitens input text through .form-outline input, and this input is not in a
       .form-outline. Without saying so here, the address the customer is choosing comes out
       in MDB's light-theme surface colour — barely brighter than its own placeholder. */
    color: #ffffff;
}

/* Which then has to be dimmer than the value, or the suggestion and the choice look the
   same. */
.signup .subdomain-field .form-control::placeholder {
    color: var(--bp-card-label, #8b8fa3);
    opacity: 1;
}

/* The half that is not on offer, in the tone Dark.css gives a disabled input — so it looks
   like the same thing it is, rather than like text that failed to become a field. The
   hairline is what keeps it from reading as part of what the customer typed. */
.signup .subdomain-field__base {
    display: flex;
    align-items: center;
    flex: 0 0 auto;
    padding: 0.375rem 0.75rem;
    border-left: 1px solid rgba(255, 255, 255, 0.08);
    background-color: var(--primary-color-medium, #1c1e35);
    color: var(--bp-card-label, #8b8fa3);
    white-space: nowrap;
    /* Clicking it selects nothing and does nothing, which is the point */
    user-select: none;
    cursor: not-allowed;
}

/* Room for both halves on a phone, where the base domain is most of the width. */
@media (max-width: 400px) {
    .signup .subdomain-field .form-control,
    .signup .subdomain-field__base {
        padding-left: 0.5rem;
        padding-right: 0.5rem;
        font-size: 0.875rem;
    }
}

/* The one thing on this form that cannot be undone, so it is not left as muted help text
   alongside the rest. The amber is the tone Dark.css gives a warning, so this stays one
   palette.

   The lock icon comes out white regardless, from i.fas in Dark.css — see the note on the
   benefits icons. */
.signup .subdomain-field__lock {
    color: #ffd68f;
}

.signup .subdomain-field__lock i {
    color: inherit !important;
}

/* ---------------------------------------------------------------------------
   Authentication

   /Security/login, the password pages either side of it, and the /login
   outcomes that stop rather than hand over.

   All of it was falling back to Layout/Page.ss — an h1 and $Form in a bare
   container — so the screen every paying customer passes through every day was
   the last part of the site that still looked like an unstyled form, reached
   from a navbar and a hero that do not.

   Built out of the same parts as everything else here: the eyebrow-title-lead
   opening, one panel with the surface and radius of a plan card, and the
   pricing section's glow behind it. The fields, the messages and the error
   colours are shared outright with the signup form — see the Fields and
   Rejections notes in the Signup section above.

   One card, narrow and centred: there is a single thing to do on this page, and
   a form the width of the container would have the eye travelling across empty
   space to find two inputs.
   --------------------------------------------------------------------------- */

.auth {
    position: relative;
    padding-top: clamp(2.5rem, 5vw, 4rem);
    padding-bottom: clamp(4rem, 8vw, 6rem);
}

/* Same construction as .signup__glow — see the note there for why the blur sits
   on an ancestor of the clipped shape rather than on the shape itself. Nothing
   on these pages is sticky, so the clipping could have gone on the section, but
   keeping the three elements identical means one shape to maintain. */
.auth__glow {
    position: absolute;
    inset: 0;
    overflow: hidden;
    pointer-events: none;
}

.auth__glow-blur {
    position: absolute;
    top: 1rem;
    left: 50%;
    width: min(52rem, 90%);
    transform: translateX(-50%);
    filter: blur(96px);
}

.auth__glow-shape {
    width: 100%;
    aspect-ratio: 1155 / 678;
    background-image: linear-gradient(115deg, #1ddc63 15%, #4d86e8 85%);
    clip-path: polygon(
        74.1% 44.1%, 100% 61.6%, 97.5% 26.9%, 85.5% 0.1%, 80.7% 2%, 72.5% 32.5%,
        60.2% 62.4%, 52.4% 68.1%, 47.5% 58.3%, 45.2% 34.5%, 27.5% 76.7%, 0.1% 64.9%,
        17.9% 100%, 27.6% 76.8%, 76.1% 97.7%
    );
    /* The same strength as the signup page's rather than the pricing section's:
       there is text over this too, and it has to stay readable. */
    opacity: 0.3;
}

/* The glow is absolutely positioned and comes first in the markup, so the
   content needs to be positioned too in order to paint above it. */
.auth__inner {
    position: relative;
}

.auth__intro {
    max-width: 34rem;
    margin: 0 auto clamp(1.75rem, 4vw, 2.5rem);
}

.auth__eyebrow {
    color: var(--contrast-color-light, #15a44d);
    font-size: 0.8rem;
    font-weight: 600;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    margin-bottom: 0.5rem;
}

/* A step down from the signup page's: that heading opens a form four panels
   long, this one opens a card with two fields in it. */
.auth__title {
    font-size: clamp(1.7rem, 3.5vw, 2.4rem);
    font-weight: 700;
    letter-spacing: -0.02em;
    color: #ffffff;
    margin-bottom: 0.75rem;
    text-wrap: balance;
}

.auth__lead {
    color: #8b8fa3;
    margin-bottom: 0;
}

/* The panel. Same surface, border and radius as a plan card and a signup step. */
.auth__card {
    max-width: 27rem;
    margin: 0 auto;
    padding: clamp(1.5rem, 3vw, 2.25rem);
    border: 1px solid rgba(255, 255, 255, 0.08);
    border-radius: 20px;
    background-color: #12131e;
}

/* Whatever sent the customer here, and on the outcome pages the whole of what
   there is to say. Framework copy, so it arrives as paragraphs and the odd
   <strong> and gets no colour of its own from Dark.css. */
.auth__content {
    color: #c3c6d4;
}

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

.auth__content strong {
    color: #ffffff;
}

/* "Husk mig". MDB draws the box for a white page, so unchecked it was a hairline
   nobody could see; checked, Dark.css already fills it with the brand green. */
.auth .form-check-input {
    border-color: rgba(255, 255, 255, 0.24);
    background-color: rgba(255, 255, 255, 0.03);
}

.auth .form-check-label {
    color: #c3c6d4;
    font-size: 0.9rem;
}

/* The submit, full width: it is the end of the form, and a button that ends
   where the fields end is easier to aim at than one floating under the left of
   them. As on the signup page. */
.auth .btn-toolbar {
    display: block;
    margin-top: 0.5rem;
}

.auth .btn-toolbar .action {
    width: 100%;
    padding: 0.8rem 1.5rem;
    font-size: 0.95rem;
    font-weight: 600;
    /* Bootstrap keeps a button on one line. "Send mig linket til at nulstille
       kodeord" does not fit on one line in a card this narrow, and was being cut
       off mid-word at the edge of the button. */
    white-space: normal;
}

/* "Jeg har glemt mit kodeord" is a LiteralField in the form's actions, so it
   renders inside the toolbar beside the button. Quiet and centred under it: it
   is a way out of a problem, not the thing the page is for.

   Dark.css styles this id for the app, where it sits under the app's own login
   box: a flex row, which is why text-align alone did not centre it, and a link
   in the dark brand green, which on this card was a second green competing with
   the button while being the harder of the two to read. Both have to be taken
   back, and the colour carries !important because Dark.css's does. */
.auth .btn-toolbar #ForgotPassword {
    display: block;
    margin: 1rem 0 0;
    text-align: center;
    font-size: 0.88rem;
}

.auth .btn-toolbar #ForgotPassword a {
    color: #8b8fa3 !important;
    text-decoration: none;
}

.auth .btn-toolbar #ForgotPassword a:hover,
.auth .btn-toolbar #ForgotPassword a:focus {
    color: #ffffff !important;
    text-decoration: underline;
}

/* Waiting.
   None of these forms can answer quickly — the framework pads a login attempt and a
   password-reset request to at least a second so that the time it takes cannot be
   used to tell whether an address has an account, and the answer is then a redirect
   rather than a page. auth.js marks the button and writes a line under it; this is
   what the two look like. */
.auth .btn-toolbar .action.is-busy {
    /* Not :disabled: a disabled submit is not sent, and Silverstripe routes a form by
       the name of the button that sent it — see the note in auth.js. */
    opacity: 0.65;
    pointer-events: none;
}

.auth__busy {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 0.5rem;
    margin: 0.9rem 0 0;
    color: #c3c6d4;
    font-size: 0.88rem;
}

.auth__spinner {
    flex: 0 0 0.9rem;
    width: 0.9rem;
    height: 0.9rem;
    border: 2px solid rgba(255, 255, 255, 0.2);
    border-top-color: var(--contrast-color-light, #15a44d);
    border-radius: 50%;
    animation: auth-spin 0.7s linear infinite;
}

@keyframes auth-spin {
    to {
        transform: rotate(360deg);
    }
}

/* The sentence beside it is the part that matters; the spinner only says it is still
   going. Somebody who has asked not to be shown movement keeps the sentence and gets
   a ring that stands still. */
@media (prefers-reduced-motion: reduce) {
    .auth__spinner {
        animation: none;
    }
}

/* What happens next, on the page that says the mail is on its way. Same ticked list as
   the plan cards and the order summary. */
.auth__list {
    list-style: none;
    padding: 0;
    margin: 0 0 1.5rem;
}

.auth__list li {
    display: flex;
    align-items: flex-start;
    gap: 0.6rem;
    margin-bottom: 0.6rem;
    color: #c3c6d4;
    font-size: 0.92rem;
    line-height: 1.5;
}

.auth__list li:last-child {
    margin-bottom: 0;
}

/* !important for the same reason as the plan cards' ticks: Dark.css forces every
   i.fas white. */
.auth__list i {
    margin-top: 0.3rem;
    font-size: 0.8rem;
    color: #4ade80 !important;
}

/* The button on the pages that have no form to put one in — the "check your mail"
   page and the /login outcomes. Given a floor on its width: on its own in the
   middle of a card, sized to two words, it read as an afterthought rather than as
   the way on. */
.auth__cta {
    min-width: 12rem;
    margin-top: 1.5rem;
    padding: 0.8rem 2rem;
    font-weight: 600;
}

/* Under the card: what happens after logging in, and the way out for somebody
   who has landed here without an account. Outside the panel on purpose — the
   panel is the form, and hanging small print inside it would make the card look
   longer than the work it holds. */
.auth__note {
    display: flex;
    align-items: flex-start;
    justify-content: center;
    gap: 0.5rem;
    max-width: 27rem;
    margin: 1.25rem auto 0;
    color: #8b8fa3;
    font-size: 0.85rem;
    line-height: 1.5;
}

/* !important because Dark.css paints every i.fas white — see the note on the
   hero's trust list. */
.auth__note i {
    margin-top: 0.2rem;
    font-size: 0.8rem;
    color: #8b8fa3 !important;
}

.auth__alt {
    margin: 1rem 0 0;
    text-align: center;
    color: #8b8fa3;
    font-size: 0.9rem;
}

.auth__alt a {
    color: #e6e6ea;
    font-weight: 600;
    text-decoration: none;
}

.auth__alt a:hover,
.auth__alt a:focus {
    color: #ffffff;
    text-decoration: underline;
}

/* The language chooser, in the navbar next to "Log ind".

   A dropdown on the shape of the Tailwind Plus menu: a bordered button that names the
   language being read, a chevron that turns when it opens, and a rounded panel under it
   with one row per language and a tick against the current one. It replaced two links side
   by side, which read as a pair of unrelated words rather than as a choice, and which only
   worked at all while there were exactly two languages.

   MDB's dropdown does the opening, the click-outside and the arrow keys — hence
   data-mdb-dropdown-init on the button. Inside a navbar Bootstrap skips Popper and lets CSS
   place the panel, which is why the collapsed menu can drop it into the flow below.

   Almost every rule here is heavier than it looks like it needs to be, and every one of
   them is !important. Dark.css dresses dropdowns as the filter menus of a dashboard — a
   blue panel, white text, a green fill on hover — with !important on all of it and a tag in
   the selector. Answering that takes both: the !important to tie, and one more class than
   Dark.css has to win the tie. The alternative is editing Dark.css, which is copied verbatim
   from the app and has to stay that way.
   --------------------------------------------------------------------------- */

/* Deliberately shaped like .nav-cta--ghost next to it: three controls in one row that are
   all the same kind of thing until pressed. .btn for MDB's reset, not for its colours —
   including its uppercasing, which the buttons beside it wear but a language does not: the
   names are in their own languages, and shouting them is a liberty to take with "Log ind",
   not with the word a visitor is looking for their own tongue in. */
.locale-switcher .locale-switcher__toggle,
.locale-switcher .locale-switcher__toggle:focus {
    display: inline-flex;
    align-items: center;
    gap: 0.45rem;
    padding: 0.5rem 0.8rem;
    border: 1px solid rgba(255, 255, 255, 0.18);
    background-color: rgba(255, 255, 255, 0.04);
    color: #e6e6ea;
    font-size: 0.85rem;
    font-weight: 600;
    text-transform: none;
    letter-spacing: normal;
}

.locale-switcher .locale-switcher__toggle:hover,
.locale-switcher .locale-switcher__toggle[aria-expanded="true"] {
    border-color: rgba(255, 255, 255, 0.32);
    background-color: rgba(255, 255, 255, 0.08);
    color: #ffffff;
}

/* The globe says "language" without spending a word on it, which matters because the
   button's own word is the name of a language and not the label of the control. Behind the
   text rather than beside it in the same ink — hence dimmer than Dark.css paints an icon. */
.locale-switcher i.locale-switcher__globe,
.locale-switcher i.locale-switcher__chevron {
    color: rgba(255, 255, 255, 0.55) !important;
    font-size: 0.75rem;
}

.locale-switcher .locale-switcher__toggle:hover i.locale-switcher__globe,
.locale-switcher .locale-switcher__toggle:hover i.locale-switcher__chevron,
.locale-switcher .locale-switcher__toggle[aria-expanded="true"] i.locale-switcher__globe,
.locale-switcher .locale-switcher__toggle[aria-expanded="true"] i.locale-switcher__chevron {
    color: rgba(255, 255, 255, 0.8) !important;
}

.locale-switcher i.locale-switcher__chevron {
    font-size: 0.6rem;
    transition: transform 0.15s ease-in-out;
}

/* Pointing at the panel while the panel is there. */
.locale-switcher .locale-switcher__toggle[aria-expanded="true"] i.locale-switcher__chevron {
    transform: rotate(180deg);
}

/* No .dropdown-toggle on the button, so no Bootstrap caret to hide — the chevron above is
   the only one. The panel is translucent and blurred like the bar it hangs from. */
.locale-switcher ul.locale-switcher__menu {
    min-width: 11rem;
    margin-top: 0.5rem;
    padding: 0.35rem;
    border: 1px solid rgba(255, 255, 255, 0.1) !important;
    border-radius: 0.75rem !important;
    background-color: rgba(20, 21, 34, 0.96) !important;
    -webkit-backdrop-filter: blur(14px);
    backdrop-filter: blur(14px);
    box-shadow: 0 12px 34px rgba(0, 0, 0, 0.45) !important;
}

.locale-switcher .locale-switcher__item {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1.5rem;
    padding: 0.5rem 0.7rem;
    /* !important because MDB rounds the first and last row to the panel's own corners with a
       shorthand, which zeroes the other two: these rows are separate pills inside a padded
       panel, not slices of it. */
    border-radius: 0.5rem !important;
    color: #c3c6d4 !important;
    font-size: 0.85rem;
}

/* A row you are only passing over, so it lifts rather than lights up: Dark.css fills every
   .dropdown-item state with the accent green, which belongs on a button you have decided to
   press. */
.locale-switcher .locale-switcher__item:hover,
.locale-switcher .locale-switcher__item:focus,
.locale-switcher .locale-switcher__item:active {
    background-color: rgba(255, 255, 255, 0.08) !important;
    color: #ffffff !important;
}

/* The language being read. Marked by weight and the tick rather than by the fill Bootstrap
   gives .active — it is the row you are already on, not the one you are about to choose. */
.locale-switcher .locale-switcher__item.active {
    background-color: transparent !important;
    color: #ffffff !important;
    font-weight: 600;
}

.locale-switcher .locale-switcher__item.active:hover,
.locale-switcher .locale-switcher__item.active:focus {
    background-color: rgba(255, 255, 255, 0.08) !important;
}

.locale-switcher i.locale-switcher__check {
    color: var(--contrast-color-light, #15a44d) !important;
    font-size: 0.7rem;
}

/* In the collapsed menu the panel drops into the flow instead of hanging over the page.
   Static rather than absolute: hanging, it covered "Log ind" and "Kom i gang" — the two
   things the bar is there for — and there is nothing to hang over anyway, because on a
   phone the open menu is the page. Nothing to lift off it either, so no blur and no
   shadow. */
@media (max-width: 991.98px) {
    .locale-switcher ul.locale-switcher__menu {
        position: static;
        width: 100%;
        margin-top: 0.35rem;
        -webkit-backdrop-filter: none;
        backdrop-filter: none;
        box-shadow: none !important;
    }
}


/* ---------------------------------------------------------------------------
   Deployment status — the page a customer lands on the moment they have paid.

   The install takes minutes, and until this page existed those minutes were a
   thank-you note and silence. So it is a page about waiting, and the whole of it
   hangs off two things: the state attribute on the section, which the poll in
   deployment.js moves, and --deploy-progress, a bare number from 0 to 100 that
   both the progress bar's width and the lorry's position along the road are
   worked out from. One number, so the two cannot disagree.

   Each state also sets its own accent. The queue is deliberately colourless:
   nothing is happening yet, and a page that goes green before the work starts is
   a page that looks like it is lying the first time somebody watches it closely.
   --------------------------------------------------------------------------- */

.deploy {
    position: relative;
    padding-top: clamp(2.5rem, 5vw, 4rem);
    padding-bottom: clamp(4rem, 8vw, 6rem);

    /* Set again by deployment.js before the first poll answers, from the value the
       template rendered into the markup. Declared here so the page is drawn
       correctly with scripting off as well. */
    --deploy-progress: 0;

    --deploy-accent: #8b8fa3;
    --deploy-glow-from: #3c4055;
    --deploy-glow-to: #4d5064;
}

/* Nothing has started. Grey, and the only states where the bar carries stripes
   going nowhere instead of a fill. */
.deploy[data-state="queued"],
.deploy[data-state="pending"],
.deploy[data-state="unknown"] {
    --deploy-accent: #8b8fa3;
}

/* Under way. The same green-into-blue the pricing and signup sections are lit by,
   because this is the same site and this is the good part. */
.deploy[data-state="running"] {
    --deploy-accent: #1ddc63;
    --deploy-glow-from: #1ddc63;
    --deploy-glow-to: #4d86e8;
}

.deploy[data-state="ready"] {
    --deploy-accent: #4ade80;
    --deploy-glow-from: #1ddc63;
    --deploy-glow-to: #22c55e;
}

/* Amber rather than red. Nothing has been lost — the pipeline stops at the first
   failure, the mail has already gone, and somebody is looking at it. Red tells the
   customer to do something, and there is nothing for them to do. */
.deploy[data-state="failed"] {
    --deploy-accent: #f0a33d;
    --deploy-glow-from: #f0a33d;
    --deploy-glow-to: #e8734d;
}

/* Same three-element construction as .signup__glow — see the note there for why
   the blur has to sit on an ancestor of the clipped shape. */
.deploy__glow {
    position: absolute;
    inset: 0;
    overflow: hidden;
    pointer-events: none;
}

.deploy__glow-blur {
    position: absolute;
    top: 2rem;
    left: 50%;
    width: min(60rem, 80%);
    transform: translateX(-50%);
    filter: blur(96px);
}

.deploy__glow-shape {
    width: 100%;
    aspect-ratio: 1155 / 678;
    background-image: linear-gradient(115deg, var(--deploy-glow-from) 15%, var(--deploy-glow-to) 85%);
    clip-path: polygon(
        74.1% 44.1%, 100% 61.6%, 97.5% 26.9%, 85.5% 0.1%, 80.7% 2%, 72.5% 32.5%,
        60.2% 62.4%, 52.4% 68.1%, 47.5% 58.3%, 45.2% 34.5%, 27.5% 76.7%, 0.1% 64.9%,
        17.9% 100%, 27.6% 76.8%, 76.1% 97.7%
    );
    opacity: 0.28;
}

.deploy__inner {
    position: relative;
}

.deploy__intro {
    max-width: 46rem;
    margin: 0 auto clamp(2rem, 4vw, 3rem);
}

.deploy__eyebrow {
    color: var(--contrast-color-light, #15a44d);
    font-size: 0.8rem;
    font-weight: 600;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    margin-bottom: 0.5rem;
}

.deploy__title {
    font-size: clamp(1.9rem, 4vw, 2.9rem);
    font-weight: 700;
    letter-spacing: -0.02em;
    color: #ffffff;
    margin-bottom: 0.75rem;
    text-wrap: balance;
}

.deploy__lead {
    color: #8b8fa3;
    margin-bottom: 0;
}

/* The card. Same surface, border and radius as a plan card and the login panel, so
   the page reads as part of the site the customer has just bought from. */
.deploy-card {
    max-width: 40rem;
    margin: 0 auto;
    padding: clamp(1.25rem, 3vw, 2rem);
    border: 1px solid rgba(255, 255, 255, 0.08);
    border-radius: 20px;
    background-color: #12131e;
    text-align: center;
}

/* ---------------------------------------------------------------------------
   The drive.

   A lorry on a road with their own installation at the end of it. Its position is
   the progress: translated along by --deploy-progress, so the same number that
   fills the bar drives it up to the building. 2.9 user units per percent takes it
   from where it is drawn to just short of the building at a hundred.
   --------------------------------------------------------------------------- */

.deploy-scene {
    margin: 0 auto 1.5rem;
    max-width: 30rem;
}

.deploy-scene__svg {
    display: block;
    width: 100%;
    height: auto;
}

.deploy-scene__kerb {
    stroke: rgba(255, 255, 255, 0.09);
    stroke-width: 3;
}

/* The dashes move, not the road. Standing still and driving are otherwise the same
   picture at nought percent. */
.deploy-scene__dashes {
    stroke: rgba(255, 255, 255, 0.22);
    stroke-width: 3;
    stroke-dasharray: 16 14;
}

.deploy[data-state="running"] .deploy-scene__dashes {
    stroke: rgba(29, 220, 99, 0.45);
    animation: deploy-road 0.8s linear infinite;
}

@keyframes deploy-road {
    to {
        stroke-dashoffset: -30;
    }
}

.deploy-scene__building {
    fill: #1b1d2c;
    stroke: rgba(255, 255, 255, 0.12);
    stroke-width: 2;
    transition: stroke 0.5s ease-in-out;
}

.deploy-scene__window {
    fill: rgba(255, 255, 255, 0.12);
    transition: fill 0.5s ease-in-out;
}

/* Their installation, lit up because it is now theirs. */
.deploy[data-state="ready"] .deploy-scene__building {
    stroke: rgba(74, 222, 128, 0.5);
}

.deploy[data-state="ready"] .deploy-scene__window {
    fill: #4ade80;
}

/* The tick over the roof. The scale property rather than transform, because the
   group already carries a transform attribute placing it and the css transform
   property would replace that outright; the individual properties combine with it
   instead. Same reason as the wheels below. */
.deploy-scene__tick {
    opacity: 0;
    scale: 0.4;
    transform-box: fill-box;
    transform-origin: 50% 50%;
    fill: #4ade80;
    stroke: #0b0c14;
}

.deploy[data-state="ready"] .deploy-scene__tick {
    animation: deploy-pop 0.5s cubic-bezier(0.34, 1.56, 0.64, 1) forwards;
}

@keyframes deploy-pop {
    to {
        opacity: 1;
        scale: 1;
    }
}

.deploy-scene__truck {
    transform: translate(calc(var(--deploy-progress) * 2.9px), 0);
    /* Slower than the poll interval, so a step completing looks like the lorry
       driving there rather than appearing there. */
    transition: transform 1.1s cubic-bezier(0.22, 0.61, 0.36, 1);
}

/* Idling in the queue: a lorry loaded and waiting, not one broken down. The
   horizontal position is repeated inside the keyframes because an animation on
   transform replaces the property outright — leave it out and the lorry jumps back
   to the start for as long as it idles. */
.deploy[data-state="queued"] .deploy-scene__truck,
.deploy[data-state="pending"] .deploy-scene__truck {
    animation: deploy-idle 2.6s ease-in-out infinite;
}

@keyframes deploy-idle {
    0%,
    100% {
        transform: translate(calc(var(--deploy-progress) * 2.9px), 0);
    }
    50% {
        transform: translate(calc(var(--deploy-progress) * 2.9px), -3px);
    }
}

/* Driving: the same trick, less of it, faster. */
.deploy[data-state="running"] .deploy-scene__truck {
    animation: deploy-drive 0.32s linear infinite;
}

@keyframes deploy-drive {
    0%,
    100% {
        transform: translate(calc(var(--deploy-progress) * 2.9px), 0);
    }
    50% {
        transform: translate(calc(var(--deploy-progress) * 2.9px), -1px);
    }
}

.deploy-scene__cargo {
    fill: #2a2d3f;
    stroke: rgba(255, 255, 255, 0.14);
    stroke-width: 2;
}

.deploy-scene__cab {
    fill: #363a51;
    transition: fill 0.5s ease-in-out;
}

.deploy-scene__windscreen {
    fill: rgba(255, 255, 255, 0.18);
}

/* The one bit of colour on the lorry, and what turns green when the build starts. */
.deploy-scene__stripe {
    fill: var(--deploy-accent);
    opacity: 0.75;
    transition: fill 0.5s ease-in-out;
}

.deploy[data-state="running"] .deploy-scene__cab,
.deploy[data-state="ready"] .deploy-scene__cab {
    fill: #3d4a63;
}

.deploy-scene__tyre {
    fill: #0e0f18;
    stroke: rgba(255, 255, 255, 0.25);
    stroke-width: 2;
}

.deploy-scene__hub {
    fill: rgba(255, 255, 255, 0.35);
}

.deploy-scene__spokes {
    stroke: rgba(255, 255, 255, 0.25);
}

/* The rotate property rather than transform, for the same reason as the tick: the
   wheels are placed by a transform attribute, and rotate combines with it rather
   than replacing it. */
.deploy-scene__wheel {
    transform-box: fill-box;
    transform-origin: 50% 50%;
}

.deploy[data-state="running"] .deploy-scene__wheel {
    animation: deploy-roll 0.5s linear infinite;
}

@keyframes deploy-roll {
    to {
        rotate: 360deg;
    }
}

.deploy-scene__smoke {
    fill: rgba(255, 255, 255, 0.16);
    opacity: 0;
}

.deploy[data-state="running"] .deploy-scene__smoke {
    animation: deploy-smoke 1.4s ease-out infinite;
}

@keyframes deploy-smoke {
    0% {
        opacity: 0.5;
        translate: 0 0;
    }
    100% {
        opacity: 0;
        translate: -14px -14px;
    }
}

/* A lorry sitting still needs a reason, or the stopped state reads as though it is
   still going and the customer waits for something that is not coming. */
.deploy-scene__hazard {
    opacity: 0;
    fill: #f0a33d;
    stroke: #f0a33d;
}

.deploy[data-state="failed"] .deploy-scene__hazard {
    animation: deploy-hazard 1.6s ease-in-out infinite;
}

@keyframes deploy-hazard {
    0%,
    100% {
        opacity: 0.55;
    }
    50% {
        opacity: 1;
    }
}

/* Nothing to show a lorry driving towards, and nothing to measure. */
.deploy[data-state="unknown"] .deploy-scene,
.deploy[data-state="unknown"] .deploy-card__progress,
.deploy[data-state="unknown"] .deploy-card__address {
    display: none;
}

/* ---------------------------------------------------------------------------
   The bar and the steps.
   --------------------------------------------------------------------------- */

.deploy-card__head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.75rem;
    margin-bottom: 0.75rem;
}

.deploy-badge {
    display: inline-flex;
    align-items: center;
    gap: 0.45rem;
    padding: 0.3rem 0.7rem;
    border: 1px solid rgba(255, 255, 255, 0.1);
    border-radius: 999px;
    color: #c3c6d4;
    font-size: 0.78rem;
    font-weight: 600;
}

.deploy-badge__dot {
    width: 0.5rem;
    height: 0.5rem;
    border-radius: 50%;
    background-color: var(--deploy-accent);
    transition: background-color 0.5s ease-in-out;
}

/* Still going, and saying so without a word. Only while something actually is — a
   pulsing dot on a finished install is noise. */
.deploy[data-state="running"] .deploy-badge__dot,
.deploy[data-state="queued"] .deploy-badge__dot,
.deploy[data-state="pending"] .deploy-badge__dot {
    animation: deploy-blink 1.6s ease-in-out infinite;
}

@keyframes deploy-blink {
    0%,
    100% {
        opacity: 1;
    }
    50% {
        opacity: 0.45;
    }
}

.deploy-card__count {
    margin: 0;
    color: #8b8fa3;
    font-size: 0.82rem;
}

.deploy-bar {
    height: 0.5rem;
    border-radius: 999px;
    background-color: rgba(255, 255, 255, 0.07);
    overflow: hidden;
}

.deploy-bar__fill {
    width: calc(var(--deploy-progress) * 1%);
    height: 100%;
    border-radius: inherit;
    background-color: var(--deploy-accent);
    /* Same duration as the lorry, so the two arrive together. */
    transition: width 1.1s cubic-bezier(0.22, 0.61, 0.36, 1), background-color 0.5s ease-in-out;
}

/* Nothing has started, so there is nothing to measure. Stripes going nowhere at a
   fraction of the contrast of a real fill: the bar says "waiting" without claiming
   a position the install has not reached. */
.deploy[data-state="queued"] .deploy-bar__fill,
.deploy[data-state="pending"] .deploy-bar__fill {
    width: 100%;
    background-color: rgba(255, 255, 255, 0.04);
    background-image: repeating-linear-gradient(
        115deg,
        rgba(255, 255, 255, 0.13) 0 10px,
        rgba(255, 255, 255, 0) 10px 22px
    );
    animation: deploy-stripes 1.1s linear infinite;
}

@keyframes deploy-stripes {
    to {
        background-position: 48px 0;
    }
}

.deploy-card__steps-title {
    margin: 1.5rem 0 0.75rem;
    color: #ffffff;
    font-size: 0.95rem;
    font-weight: 600;
    text-align: left;
}

.deploy-steps {
    list-style: none;
    padding: 0;
    margin: 0;
    text-align: left;
}

.deploy-step {
    display: flex;
    align-items: flex-start;
    gap: 0.75rem;
    padding: 0.65rem 0;
    border-top: 1px solid rgba(255, 255, 255, 0.05);
    transition: opacity 0.4s ease-in-out;
}

.deploy-step:first-child {
    border-top: 0;
}

/* Ahead of where the install has got to. Dimmed rather than hidden: the point of
   the list is that the customer can see what is left. */
.deploy-step[data-step-state="waiting"] {
    opacity: 0.45;
}

.deploy-step__marker {
    position: relative;
    flex: 0 0 2rem;
    width: 2rem;
    height: 2rem;
    display: flex;
    align-items: center;
    justify-content: center;
    border: 1px solid rgba(255, 255, 255, 0.12);
    border-radius: 50%;
    color: #8b8fa3;
    font-size: 0.8rem;
    transition: color 0.4s ease-in-out, border-color 0.4s ease-in-out, background-color 0.4s ease-in-out;
}

/* !important because Dark.css paints every i.fas white — the same reason the plan
   cards' ticks need it. */
.deploy-step__icon {
    color: inherit !important;
    font-size: 0.8rem;
}

.deploy-step__dot {
    width: 0.45rem;
    height: 0.45rem;
    border-radius: 50%;
    background-color: currentColor;
}

.deploy-step[data-step-state="done"] .deploy-step__marker {
    color: #4ade80;
    border-color: rgba(74, 222, 128, 0.45);
    background-color: rgba(74, 222, 128, 0.12);
}

/* The tick sits beside the step's own icon rather than replacing it, so a finished
   row still says which step it was. */
.deploy-step[data-step-state="done"] .deploy-step__marker::after {
    content: "\f00c";
    font-family: "Font Awesome 6 Free";
    font-weight: 900;
    position: absolute;
    right: -0.2rem;
    bottom: -0.2rem;
    width: 0.95rem;
    height: 0.95rem;
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: 50%;
    background-color: #4ade80;
    color: #0b0c14;
    font-size: 0.5rem;
}

.deploy-step[data-step-state="active"] .deploy-step__marker {
    color: #1ddc63;
    border-color: rgba(29, 220, 99, 0.6);
    background-color: rgba(29, 220, 99, 0.1);
}

/* The step being worked on, as a ring going round it. The same spinner as the login
   button's, on a bigger radius. */
.deploy-step[data-step-state="active"] .deploy-step__marker::before {
    content: "";
    position: absolute;
    inset: -0.28rem;
    border: 2px solid rgba(29, 220, 99, 0.18);
    border-top-color: #1ddc63;
    border-radius: 50%;
    animation: deploy-spin 0.9s linear infinite;
}

@keyframes deploy-spin {
    to {
        transform: rotate(360deg);
    }
}

.deploy-step[data-step-state="stopped"] .deploy-step__marker {
    color: #f0a33d;
    border-color: rgba(240, 163, 61, 0.5);
    background-color: rgba(240, 163, 61, 0.12);
}

.deploy-step__body {
    display: flex;
    flex-direction: column;
    gap: 0.15rem;
}

.deploy-step__title {
    color: #e6e6ea;
    font-size: 0.92rem;
    font-weight: 600;
}

.deploy-step__description {
    color: #8b8fa3;
    font-size: 0.82rem;
    line-height: 1.45;
}

/* Their own address: the thing they were sold, and the thing they will be typing in
   tomorrow. Worth showing while they wait for it. */
.deploy-card__address {
    display: flex;
    flex-direction: column;
    gap: 0.15rem;
    margin: 1.5rem 0 0;
    padding-top: 1.25rem;
    border-top: 1px solid rgba(255, 255, 255, 0.06);
}

.deploy-card__address-label {
    color: #8b8fa3;
    font-size: 0.78rem;
    letter-spacing: 0.04em;
    text-transform: uppercase;
}

.deploy-card__address-value {
    color: #ffffff;
    font-size: 1.05rem;
    font-weight: 600;
    word-break: break-all;
}

/* Both buttons are in the markup from the start and uncovered by the state, so
   neither is a button drawn in by a script that might not run. Given a floor on the
   width for the same reason as the login pages' — alone in the middle of a card,
   sized to three words, it reads as an afterthought. */
.deploy-card__cta,
.deploy-card__login {
    display: none;
    min-width: 14rem;
    margin-top: 1.5rem;
    padding: 0.8rem 2rem;
    font-weight: 600;
}

.deploy[data-state="ready"] .deploy-card__cta,
.deploy[data-state="unknown"] .deploy-card__login {
    display: inline-block;
    background-color: var(--contrast-color-light, #15a44d);
    color: #ffffff;
}

.deploy__note {
    max-width: 34rem;
    margin: 1.25rem auto 0;
    color: #8b8fa3;
    font-size: 0.85rem;
    line-height: 1.5;
    text-align: center;
}

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

.deploy__noscript {
    max-width: 34rem;
    margin: 1rem auto 0;
    color: #8b8fa3;
    font-size: 0.85rem;
    text-align: center;
}

/* Somebody who has asked not to be shown movement keeps every word and every
   colour, and the bar and the lorry still sit where the install has got to — they
   arrive there instead of driving there. */
@media (prefers-reduced-motion: reduce) {
    .deploy-scene__dashes,
    .deploy-scene__truck,
    .deploy-scene__wheel,
    .deploy-scene__smoke,
    .deploy-scene__hazard,
    .deploy-scene__tick,
    .deploy-badge__dot,
    .deploy-bar__fill,
    .deploy-step[data-step-state="active"] .deploy-step__marker::before {
        animation: none;
    }

    .deploy-scene__truck,
    .deploy-bar__fill {
        transition: none;
    }

    /* Without its animation the tick would never be revealed, since revealing it is
       what the animation does. */
    .deploy[data-state="ready"] .deploy-scene__tick {
        opacity: 1;
        scale: 1;
    }

    .deploy[data-state="failed"] .deploy-scene__hazard {
        opacity: 1;
    }
}

/* ---------------------------------------------------------------------------
   Standard content pages — about us, contact, terms

   Layout/Page.ss opens on a band with nothing but the title on it, so a page
   reached from the menu begins the way the front page begins rather than with an
   h1 dropped on the page gradient.

   It is the hero's shape, not the hero: no photograph, no min-height of a
   screen, no buttons. What lights it is the glow the pricing and signup sections
   share, so the three lit surfaces on the site are lit by the same thing.

   The content underneath is a single narrow column, left-aligned. The band is
   centred because a headline is two lines; the body is not, because an about
   page is not.
   --------------------------------------------------------------------------- */

.page-banner {
    position: relative;
    padding-top: clamp(3rem, 7vw, 5.5rem);
    padding-bottom: clamp(2rem, 4vw, 3rem);
}

/* Clipped, blurred, shaped — three elements as on the signup page, because
   clip-path is applied after filter and the blur therefore has to sit on an
   ancestor of the shape rather than on the shape itself. */
.page-banner__glow {
    position: absolute;
    inset: 0;
    overflow: hidden;
    pointer-events: none;
}

.page-banner__glow-blur {
    position: absolute;
    top: 1rem;
    left: 50%;
    width: min(60rem, 85%);
    transform: translateX(-50%);
    filter: blur(96px);
}

.page-banner__glow-shape {
    width: 100%;
    aspect-ratio: 1155 / 678;
    background-image: linear-gradient(115deg, #1ddc63 15%, #4d86e8 85%);
    clip-path: polygon(
        74.1% 44.1%, 100% 61.6%, 97.5% 26.9%, 85.5% 0.1%, 80.7% 2%, 72.5% 32.5%,
        60.2% 62.4%, 52.4% 68.1%, 47.5% 58.3%, 45.2% 34.5%, 27.5% 76.7%, 0.1% 64.9%,
        17.9% 100%, 27.6% 76.8%, 76.1% 97.7%
    );
    /* Weaker than the signup page's, which lights a heading with a form under it.
       Here there is nothing but the title, and the glow is the only thing on the
       band that could compete with it. */
    opacity: 0.22;
}

/* The glow is absolutely positioned and comes first in the markup, so the copy
   needs to be positioned too in order to paint above it. */
.page-banner__inner {
    position: relative;
    max-width: 52rem;
}

.page-banner__eyebrow {
    color: var(--contrast-color-light, #15a44d);
    font-size: 0.8rem;
    font-weight: 600;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    margin-bottom: 0.5rem;
}

/* Between the hero's headline and a section heading: this is the page's one
   title, so it is bigger than a section's, and it is not the sentence the site
   opens on, so it is smaller than the hero's. */
.page-banner__title {
    margin: 0;
    font-size: clamp(2.1rem, 5vw, 3.4rem);
    font-weight: 700;
    line-height: 1.1;
    letter-spacing: -0.03em;
    color: #ffffff;
    /* Keeps the last line of a two-line title from being one short word. */
    text-wrap: balance;
}

/* The band's padding already separates it from the copy, so the body only has to
   keep the page off the footer. */
.page-body {
    padding-top: clamp(1.5rem, 3vw, 2.25rem);
    padding-bottom: clamp(4rem, 8vw, 6rem);
}

.page-body__content {
    max-width: 44rem;
    margin: 0 auto;
    font-size: 1.05rem;
    line-height: 1.75;
}

.page-body__content > :first-child {
    margin-top: 0;
}

.page-body__content > :last-child {
    margin-bottom: 0;
}

/* The CMS editor writes h2 and h3 into the content, and Dark.css sizes headings
   for the app's cards. Sized against the body copy instead, and given space
   above so a long page reads as sections. */
.page-body__content h2 {
    margin-top: 2.5rem;
    margin-bottom: 0.75rem;
    font-size: 1.6rem;
    font-weight: 700;
    letter-spacing: -0.01em;
    color: #ffffff;
}

.page-body__content h3 {
    margin-top: 2rem;
    margin-bottom: 0.5rem;
    font-size: 1.25rem;
    font-weight: 600;
    color: #ffffff;
}

.page-body__content p,
.page-body__content ul,
.page-body__content ol {
    margin-bottom: 1.25rem;
}

/* The opening paragraph carries on from the title, so it is the lead. Larger and
   nothing else: dimming it, the way the hero dims the copy under its headline,
   would put the quietest text at the top of the page instead of the loudest. */
.page-body__content > p:first-of-type {
    font-size: 1.15rem;
}

.page-body__content li {
    margin-bottom: 0.35rem;
}

.page-body__content a:not(.btn) {
    color: var(--contrast-color-light, #15a44d);
    text-decoration: underline;
    text-underline-offset: 0.2em;
}

.page-body__content a:not(.btn):hover,
.page-body__content a:not(.btn):focus {
    color: #28b55f;
}

/* Editors paste tables and images into the content, and both overflow a narrow
   column left to themselves. */
.page-body__content img {
    max-width: 100%;
    height: auto;
    border-radius: 16px;
}

.page-body__content table {
    width: 100%;
    margin-bottom: 1.25rem;
}

.page-body__content blockquote {
    margin: 2rem 0;
    padding-left: 1.25rem;
    border-left: 2px solid rgba(255, 255, 255, 0.14);
    color: #c3c6d4;
}

/* ---------------------------------------------------------------------------
   Friendlier deployment experience.

   The original scene showed a lorry driving towards a server. This version shows
   the product itself gently coming to life. The visual language is the landing
   page's: a framed product preview, soft green-to-blue light, and small benefit
   icons. None of the motion is required to understand the state.
   --------------------------------------------------------------------------- */

.deploy {
    min-height: calc(100svh - var(--bp-header-height));
    background-image:
        radial-gradient(55% 34% at 50% 15%, rgba(77, 134, 232, 0.08), transparent 100%),
        linear-gradient(rgb(18 19 30), rgb(10 11 20));
}

.deploy__intro {
    margin-bottom: clamp(1.75rem, 3vw, 2.5rem);
}

.deploy__lead {
    max-width: 39rem;
    margin-right: auto;
    margin-left: auto;
    color: #a5a8b8;
    font-size: 1.05rem;
    line-height: 1.65;
}

.deploy-card {
    max-width: 48rem;
    padding: clamp(1.25rem, 4vw, 2.5rem);
    border-color: rgba(255, 255, 255, 0.11);
    border-radius: 24px;
    background:
        linear-gradient(145deg, rgba(255, 255, 255, 0.035), transparent 45%),
        #12131e;
    box-shadow: 0 28px 80px rgba(0, 0, 0, 0.28);
}

.deploy-scene {
    max-width: 36rem;
    margin-bottom: clamp(1.5rem, 3vw, 2.25rem);
}

.deploy-scene__halo {
    fill: url("#deploy-screen-glow");
    opacity: 0.055;
    transform-box: fill-box;
    transform-origin: center;
}

.deploy-scene__frame {
    fill: #181a29;
    stroke: rgba(255, 255, 255, 0.14);
    stroke-width: 2;
}

.deploy-scene__topbar {
    fill: #202232;
}

.deploy-scene__window-dot {
    fill: rgba(255, 255, 255, 0.18);
}

.deploy-scene__success path {
    fill: none;
    stroke: #ffffff;
    stroke-width: 3;
    stroke-linecap: round;
    stroke-linejoin: round;
}

/* A note. Cash green, but the site's green rather than a dollar one, so the money
   in the picture belongs to the page it is on.

   Opaque, and that is the whole trick: a stack is notes hiding the notes under them,
   and a translucent note turns five of them into one green smear. */
.deploy-scene__note-body {
    fill: #16291d;
    stroke: rgba(29, 220, 99, 0.5);
    stroke-width: 2;
}

.deploy-scene__note-mark {
    fill: rgba(255, 255, 255, 0.1);
}

.deploy-scene__note-tick {
    fill: rgba(29, 220, 99, 0.3);
}

.deploy-scene__stack--waiting {
    transition: opacity 0.6s ease-in-out;
}

/* The top two of the counted stack. Held back so the stack is visibly taller at the
   end than it was while the counting was going on. */
.deploy-scene__note--last {
    opacity: 0;
    transition: opacity 0.5s ease-in-out;
}

.deploy-scene__counter {
    fill: #181a29;
    stroke: rgba(255, 255, 255, 0.14);
    stroke-width: 2;
}

.deploy-scene__display {
    fill: #0d0e17;
    stroke: rgba(255, 255, 255, 0.06);
    stroke-width: 1.5;
}

.deploy-scene__wheel-cell {
    fill: rgba(255, 255, 255, 0.04);
}

/* The digits themselves, on a strip six long that is wound past its window. Every
   wheel carries the accent, so the counter goes grey while nothing is happening and
   amber when we have stopped, along with the rest of the page. */
.deploy-scene__wheel-strip rect {
    fill: var(--deploy-accent);
    opacity: 0.85;
}

.deploy-scene__led {
    fill: var(--deploy-accent);
    opacity: 0.45;
}

/* Nothing in the air until there is something to count. */
.deploy-scene__fly {
    opacity: 0;
    transform-box: fill-box;
    transform-origin: center;
}

.deploy-scene__bubble-disc {
    fill: #1d2030;
    stroke: rgba(255, 255, 255, 0.13);
    stroke-width: 2;
}

.deploy-scene__percent {
    fill: none;
    stroke: #4d86e8;
    stroke-width: 2.5;
}

.deploy-scene__percent-slash {
    fill: none;
    stroke: #4d86e8;
    stroke-width: 2.5;
    stroke-linecap: round;
}

.deploy-scene__bubble-tag {
    fill: rgba(29, 220, 99, 0.16);
    stroke: #1ddc63;
    stroke-width: 2;
    stroke-linejoin: round;
}

.deploy-scene__bubble-hole {
    fill: #1d2030;
    stroke: #1ddc63;
    stroke-width: 2;
}

.deploy-scene__success {
    opacity: 0;
    transform-box: fill-box;
    transform-origin: center;
}

.deploy-scene__success circle {
    fill: #22c55e;
    filter: drop-shadow(0 6px 16px rgba(34, 197, 94, 0.35));
}

.deploy-scene__pause {
    opacity: 0;
}

.deploy-scene__pause circle {
    fill: #292516;
    stroke: #f0a33d;
    stroke-width: 2;
}

.deploy-scene__pause path {
    fill: none;
    stroke: #f0a33d;
    stroke-width: 4;
    stroke-linecap: round;
}

.deploy[data-state="pending"] .deploy-scene__app,
.deploy[data-state="queued"] .deploy-scene__app {
    opacity: 0.72;
}

.deploy[data-state="running"] .deploy-scene__app {
    animation: deploy-workspace-float 4s ease-in-out infinite;
}

.deploy[data-state="running"] .deploy-scene__halo {
    animation: deploy-halo 2.8s ease-in-out infinite;
}

/* Four wheels, each an order slower than the one to its right, which is what makes
   a number climbing out of four things turning. The steps() is the point: a digit
   is either in the window or it is not, never halfway past it. */
.deploy[data-state="running"] .deploy-scene__wheel-strip--1 {
    animation: deploy-wheel 6s steps(6) infinite;
}

.deploy[data-state="running"] .deploy-scene__wheel-strip--2 {
    animation: deploy-wheel 2.4s steps(6) infinite;
}

.deploy[data-state="running"] .deploy-scene__wheel-strip--3 {
    animation: deploy-wheel 0.9s steps(6) infinite;
}

.deploy[data-state="running"] .deploy-scene__wheel-strip--4 {
    animation: deploy-wheel 0.32s steps(6) infinite;
}

.deploy[data-state="running"] .deploy-scene__led {
    animation: deploy-led 1.1s ease-in-out infinite;
}

/* Three notes in the air, a third of the cycle apart, so one is always leaving the
   stack while another is landing. */
.deploy[data-state="running"] .deploy-scene__fly {
    animation: deploy-fly 1.5s linear infinite;
}

.deploy[data-state="running"] .deploy-scene__fly--2 {
    animation-delay: 0.5s;
}

.deploy[data-state="running"] .deploy-scene__fly--3 {
    animation-delay: 1s;
}

.deploy[data-state="running"] .deploy-scene__bubble--factor {
    animation: deploy-bubble-float 3.4s ease-in-out infinite;
}

.deploy[data-state="running"] .deploy-scene__bubble--tag {
    animation: deploy-bubble-float 3.4s 0.8s ease-in-out infinite;
}

/* Counted: everything is on the right-hand stack, and what is left on the left is
   left behind rather than removed — a stack that vanishes reads as money gone. */
.deploy[data-state="ready"] .deploy-scene__note--last {
    opacity: 1;
}

.deploy[data-state="ready"] .deploy-scene__stack--waiting {
    opacity: 0.25;
}

.deploy[data-state="ready"] .deploy-scene__led {
    opacity: 1;
}

.deploy[data-state="ready"] .deploy-scene__success {
    animation: deploy-success-pop 0.55s cubic-bezier(0.34, 1.56, 0.64, 1) forwards;
}

.deploy[data-state="failed"] .deploy-scene__pause {
    opacity: 1;
}

.deploy[data-state="failed"] .deploy-scene__app {
    opacity: 0.48;
}

@keyframes deploy-workspace-float {
    0%, 100% { transform: translateY(0); }
    50% { transform: translateY(-4px); }
}

@keyframes deploy-bubble-float {
    0%, 100% { translate: 0 0; }
    50% { translate: 0 -7px; }
}

@keyframes deploy-halo {
    0%, 100% { opacity: 0.045; scale: 0.96; }
    50% { opacity: 0.1; scale: 1.03; }
}

/* Six digits, eighteen user units apart, wound past the window once per cycle. */
@keyframes deploy-wheel {
    to { translate: 0 -108px; }
}

@keyframes deploy-led {
    0%, 100% { opacity: 0.35; }
    50% { opacity: 1; }
}

/* Off the top of the waiting stack, over the counter, onto the counted one. The
   fade at both ends is what hides the jump back to the start. */
@keyframes deploy-fly {
    0% { translate: 0 0; rotate: -2deg; opacity: 0; }
    12% { opacity: 1; }
    50% { translate: 114px -28px; rotate: -8deg; }
    88% { opacity: 1; }
    100% { translate: 228px 8px; rotate: 5deg; opacity: 0; }
}

@keyframes deploy-success-pop {
    from { opacity: 0; scale: 0.35; }
    to { opacity: 1; scale: 1; }
}

.deploy-card__head {
    align-items: flex-end;
    margin-bottom: 0.85rem;
}

.deploy-badge {
    padding: 0.38rem 0.8rem;
    background-color: rgba(255, 255, 255, 0.035);
    font-size: 0.82rem;
}

.deploy-badge__dot {
    box-shadow: 0 0 0 4px color-mix(in srgb, var(--deploy-accent) 18%, transparent);
}

.deploy-card__count {
    display: flex;
    align-items: baseline;
    gap: 0.65rem;
}

.deploy-card__count strong {
    color: #ffffff;
    font-size: 1rem;
    font-weight: 700;
}

.deploy-bar {
    height: 0.85rem;
    padding: 2px;
    border: 1px solid rgba(255, 255, 255, 0.08);
    background-color: rgba(255, 255, 255, 0.045);
    box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.28);
}

.deploy-bar__fill {
    position: relative;
    width: calc(var(--deploy-progress) * 1%);
    overflow: hidden;
    background-image: linear-gradient(90deg, #1ddc63, #2dd4bf 56%, #4d86e8);
    box-shadow: 0 0 20px rgba(29, 220, 99, 0.22);
}

.deploy-bar__shine {
    position: absolute;
    inset: 0;
    background-image: linear-gradient(100deg, transparent 15%, rgba(255, 255, 255, 0.42) 48%, transparent 82%);
    transform: translateX(-120%);
}

.deploy[data-state="running"] .deploy-bar__shine {
    animation: deploy-bar-shine 2.2s ease-in-out infinite;
}

.deploy[data-state="queued"] .deploy-bar__fill,
.deploy[data-state="pending"] .deploy-bar__fill {
    width: 38%;
    background-image: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.18), transparent);
    animation: deploy-bar-waiting 1.8s ease-in-out infinite;
}

@keyframes deploy-bar-shine {
    55%, 100% { transform: translateX(120%); }
}

@keyframes deploy-bar-waiting {
    from { transform: translateX(-115%); }
    to { transform: translateX(300%); }
}

.deploy-card__steps-title {
    margin-top: 1.75rem;
    margin-bottom: 0.9rem;
    font-size: 0.88rem;
    letter-spacing: 0.06em;
    text-transform: uppercase;
}

.deploy-steps {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 0.45rem 1.5rem;
}

.deploy-step {
    min-width: 0;
    padding: 0.75rem 0;
    border-top-color: rgba(255, 255, 255, 0.055);
}

.deploy-step:nth-child(2) {
    border-top: 0;
}

.deploy-step[data-step-state="waiting"] {
    opacity: 0.55;
}

.deploy-step[data-step-state="active"] {
    opacity: 1;
}

.deploy-step__marker {
    flex-basis: 2.15rem;
    width: 2.15rem;
    height: 2.15rem;
    background-color: rgba(255, 255, 255, 0.025);
}

.deploy-step__title {
    line-height: 1.35;
}

.deploy-step__description {
    margin-top: 0.1rem;
}

.deploy-card__address {
    margin-top: 1.75rem;
    padding: 1rem 1.1rem;
    border: 1px solid rgba(255, 255, 255, 0.07);
    border-radius: 12px;
    background-color: rgba(255, 255, 255, 0.025);
}

@media (max-width: 575.98px) {
    .deploy {
        padding-top: 2rem;
    }

    .deploy-card {
        border-radius: 18px;
    }

    .deploy-card__head {
        align-items: flex-start;
    }

    .deploy-card__count {
        flex-direction: column;
        align-items: flex-end;
        gap: 0.05rem;
    }

    .deploy-steps {
        grid-template-columns: 1fr;
    }

    .deploy-step:nth-child(2) {
        border-top: 1px solid rgba(255, 255, 255, 0.055);
    }
}

@media (prefers-reduced-motion: reduce) {
    .deploy-scene__app,
    .deploy-scene__halo,
    .deploy-scene__bubble,
    .deploy-scene__success,
    .deploy-scene__wheel-strip,
    .deploy-scene__fly,
    .deploy-scene__led,
    .deploy-bar__shine,
    .deploy[data-state="queued"] .deploy-bar__fill,
    .deploy[data-state="pending"] .deploy-bar__fill {
        animation: none;
    }

    .deploy-scene__note--last,
    .deploy-scene__stack--waiting {
        transition: none;
    }

    /* A note frozen in mid-air is a note somebody dropped. Without the flight there
       is still a counter with a number on it and two stacks either side of it. */
    .deploy-scene__fly {
        display: none;
    }

    .deploy[data-state="ready"] .deploy-scene__success {
        opacity: 1;
        scale: 1;
    }

    .deploy[data-state="queued"] .deploy-bar__fill,
    .deploy[data-state="pending"] .deploy-bar__fill {
        width: 100%;
        transform: none;
        opacity: 0.35;
    }
}

}

/* ---------------------------------------------------------------------------
   The manual

   Built on the standard content pages rather than beside them: the band, the
   glow and the prose styling are all .page-banner and .page-body__content, and
   what is added here is only the two things a manual has that an about page does
   not — a table of contents, and a page that knows where it sits in one.

   The front of the manual is a numbered list of chapters, each one a card with
   its articles inside it. Cards rather than rows because a chapter is a heading,
   a line of explanation and a handful of links, and three lines of different
   weight in a flat list read as one paragraph.

   A page of the manual is that same list down the left in a column that stays
   put, and the article in the middle. The column is the manual's one piece of
   furniture: it is what makes a page of a manual different from a page.
   --------------------------------------------------------------------------- */

/* The couple of sentences on the band, under the title. Centred with the title
   and dimmed, the way the hero dims the copy under its headline — here the
   headline is the loudest thing on the band and this is the caption to it. */
.docs-intro {
    max-width: 34rem;
    margin: 1rem auto 0;
    color: #c3c6d4;
    font-size: 1.05rem;
    line-height: 1.7;
}

.docs-intro > :last-child {
    margin-bottom: 0;
}

.docs-contents {
    padding-top: clamp(1.5rem, 3vw, 2.5rem);
    padding-bottom: clamp(4rem, 8vw, 6rem);
}

.docs-contents__head {
    max-width: 46rem;
    margin: 0 auto clamp(1.5rem, 3vw, 2.25rem);
    text-align: center;
}

.docs-contents__title {
    margin: 0;
    font-size: clamp(1.5rem, 3vw, 2rem);
    font-weight: 700;
    letter-spacing: -0.02em;
    color: #ffffff;
}

.docs-contents__lead {
    margin: 0.6rem 0 0;
    color: #c3c6d4;
    line-height: 1.7;
}

.docs-contents__empty {
    max-width: 46rem;
    margin: 0 auto;
    text-align: center;
    color: #c3c6d4;
}

/* The numbers are drawn by .docs-chapter__number from $Pos, so the list marker
   itself is off. Two numbers per chapter is one too many. */
.docs-contents__list {
    max-width: 58rem;
    margin: 0 auto;
    padding: 0;
    list-style: none;
    display: grid;
    gap: 1rem;
}

.docs-chapter {
    border: 1px solid rgba(255, 255, 255, 0.08);
    border-radius: 20px;
    background: rgba(255, 255, 255, 0.02);
    overflow: hidden;
}

/* The whole head is one link — number, icon, title and summary. Grid rather than
   flex so the summary lines up under the title and not under the number. */
.docs-chapter__head {
    display: grid;
    grid-template-columns: auto 1fr;
    gap: 0 1rem;
    align-items: start;
    padding: 1.25rem 1.5rem;
    text-decoration: none;
    transition: background-color 0.15s ease-in-out;
}

.docs-chapter__head:hover,
.docs-chapter__head:focus-visible {
    background: rgba(255, 255, 255, 0.035);
    text-decoration: none;
}

/* The chapter number, on a plate of its own. Tabular figures so a two-digit
   chapter does not shift the titles below it. */
.docs-chapter__number {
    display: grid;
    place-items: center;
    width: 2rem;
    height: 2rem;
    border-radius: 10px;
    background: rgba(255, 255, 255, 0.06);
    color: #c3c6d4;
    font-size: 0.85rem;
    font-weight: 600;
    font-variant-numeric: tabular-nums;
}

.docs-chapter__text {
    display: block;
    min-width: 0;
}

.docs-chapter__title {
    display: block;
    color: #ffffff;
    font-size: 1.15rem;
    font-weight: 600;
    letter-spacing: -0.01em;
    line-height: 2rem;
}

/* !important for the same reason as the benefit and step icons: Dark.css paints
   every i.fas white, on the class rather than on anything this could outrank. */
.docs-chapter__icon {
    margin-right: 0.5rem;
    color: var(--contrast-color-light, #15a44d) !important;
    font-size: 0.95rem;
}

.docs-chapter__summary {
    display: block;
    margin-top: 0.15rem;
    color: #c3c6d4;
    font-size: 0.95rem;
    line-height: 1.6;
}

/* The articles inside their chapter, on a rule under the head so they read as
   belonging to it rather than as a second list. Indented to clear the number. */
.docs-chapter__articles {
    margin: 0;
    padding: 0.35rem 1.5rem 1.1rem calc(1.5rem + 2rem + 1rem);
    list-style: none;
    border-top: 1px solid rgba(255, 255, 255, 0.055);
}

.docs-chapter__articles a {
    display: block;
    padding: 0.5rem 0;
    text-decoration: none;
}

.docs-chapter__article-title {
    display: block;
    color: #e6e8f0;
    font-weight: 500;
}

.docs-chapter__articles a:hover .docs-chapter__article-title,
.docs-chapter__articles a:focus-visible .docs-chapter__article-title {
    color: var(--contrast-color-light, #15a44d);
}

.docs-chapter__article-summary {
    display: block;
    color: #9ca0b3;
    font-size: 0.9rem;
    line-height: 1.55;
}

/* The summary of an article, on the band under its title. Wider than the manual's
   own intro because it is one line rather than a paragraph. */
.docs-article__summary {
    max-width: 40rem;
    margin: 1rem auto 0;
    color: #c3c6d4;
    font-size: 1.1rem;
    line-height: 1.6;
}

/* One column on a phone: the sidebar is a dozen links, so it goes above the
   article rather than into a drawer with a control to explain. */
.docs-layout {
    display: grid;
    grid-template-columns: 1fr;
    gap: clamp(1.5rem, 4vw, 2.5rem);
    padding-top: clamp(1.5rem, 3vw, 2.25rem);
    padding-bottom: clamp(4rem, 8vw, 6rem);
}

.docs-sidebar {
    align-self: start;
    border: 1px solid rgba(255, 255, 255, 0.08);
    border-radius: 20px;
    background: rgba(255, 255, 255, 0.02);
    padding: 1.1rem 1.25rem;
}

.docs-sidebar__heading {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    margin-bottom: 0.75rem;
    padding-bottom: 0.75rem;
    border-bottom: 1px solid rgba(255, 255, 255, 0.055);
    color: #ffffff;
    font-size: 0.9rem;
    font-weight: 600;
    letter-spacing: 0.02em;
    text-decoration: none;
}

.docs-sidebar__heading:hover,
.docs-sidebar__heading:focus-visible {
    color: var(--contrast-color-light, #15a44d);
    text-decoration: none;
}

.docs-sidebar__heading-icon {
    color: var(--contrast-color-light, #15a44d) !important;
    font-size: 0.85rem;
}

/* Numbered to match the table of contents, since it is the same list. The
   counter is drawn by ::before rather than by the marker so it can be positioned
   against the link's own padding. */
.docs-sidebar__chapters {
    margin: 0;
    padding: 0;
    list-style: none;
    counter-reset: docs-chapter;
}

.docs-sidebar__chapter {
    counter-increment: docs-chapter;
}

.docs-sidebar__chapter > .docs-sidebar__link::before {
    content: counter(docs-chapter) ".";
    display: inline-block;
    min-width: 1.25rem;
    margin-right: 0.35rem;
    color: #6f7488;
    font-variant-numeric: tabular-nums;
}

.docs-sidebar__link {
    display: block;
    padding: 0.4rem 0.5rem;
    border-radius: 8px;
    color: #c3c6d4;
    font-size: 0.95rem;
    line-height: 1.45;
    text-decoration: none;
}

.docs-sidebar__link:hover,
.docs-sidebar__link:focus-visible {
    background: rgba(255, 255, 255, 0.04);
    color: #ffffff;
    text-decoration: none;
}

/* The page being read, marked by a bar down its left as well as by colour — the
   same rule the rest of the site follows about not using colour alone. */
.docs-sidebar__link--current {
    background: rgba(29, 220, 99, 0.08);
    box-shadow: inset 2px 0 0 var(--contrast-color-light, #15a44d);
    color: #ffffff;
    font-weight: 600;
}

.docs-sidebar__articles {
    margin: 0.15rem 0 0.35rem;
    padding-left: 1.6rem;
    list-style: none;
    border-left: 1px solid rgba(255, 255, 255, 0.055);
}

.docs-sidebar__articles .docs-sidebar__link {
    font-size: 0.9rem;
}

.docs-main {
    min-width: 0;
}

/* The page's own sections, above the article. A panel rather than a plain list,
   because it sits directly above prose that also begins with a heading. */
.docs-onthispage {
    margin-bottom: clamp(1.75rem, 4vw, 2.5rem);
    padding: 1rem 1.25rem;
    border: 1px solid rgba(255, 255, 255, 0.08);
    border-radius: 16px;
    background: rgba(255, 255, 255, 0.02);
}

.docs-onthispage__heading {
    margin: 0 0 0.5rem;
    color: #9ca0b3;
    font-size: 0.75rem;
    font-weight: 600;
    letter-spacing: 0.08em;
    text-transform: uppercase;
}

.docs-onthispage__list {
    margin: 0;
    padding-left: 1.2rem;
    color: #6f7488;
}

.docs-onthispage__list li {
    margin-bottom: 0.25rem;
}

.docs-onthispage__list a {
    color: #c3c6d4;
    text-decoration: none;
}

.docs-onthispage__list a:hover,
.docs-onthispage__list a:focus-visible {
    color: var(--contrast-color-light, #15a44d);
    text-decoration: underline;
    text-underline-offset: 0.2em;
}

/* The article itself borrows .page-body__content, which centres a 44rem column.
   Here the column is already the middle of a two-column layout, so it fills what
   it is given and only keeps its measure on a wide screen. */
.docs-body {
    max-width: 46rem;
    margin: 0;
}

.docs-children {
    margin-top: clamp(2.5rem, 5vw, 3.5rem);
    padding-top: clamp(1.5rem, 3vw, 2rem);
    border-top: 1px solid rgba(255, 255, 255, 0.055);
}

.docs-children__heading {
    margin: 0 0 0.9rem;
    color: #9ca0b3;
    font-size: 0.75rem;
    font-weight: 600;
    letter-spacing: 0.08em;
    text-transform: uppercase;
}

.docs-children__list {
    margin: 0;
    padding: 0;
    list-style: none;
    display: grid;
    gap: 0.6rem;
}

.docs-children__item {
    display: block;
    padding: 0.85rem 1.1rem;
    border: 1px solid rgba(255, 255, 255, 0.08);
    border-radius: 14px;
    background: rgba(255, 255, 255, 0.02);
    text-decoration: none;
    transition: background-color 0.15s ease-in-out;
}

.docs-children__item:hover,
.docs-children__item:focus-visible {
    background: rgba(255, 255, 255, 0.045);
    text-decoration: none;
}

.docs-children__title {
    display: block;
    color: #ffffff;
    font-weight: 600;
}

.docs-children__icon {
    margin-right: 0.45rem;
    color: var(--contrast-color-light, #15a44d) !important;
    font-size: 0.9rem;
}

.docs-children__summary {
    display: block;
    margin-top: 0.1rem;
    color: #9ca0b3;
    font-size: 0.9rem;
    line-height: 1.55;
}

/* Previous and next. Two columns even when one of them is empty, so the next
   link is on the right on every page — including the first, which is the one
   page where a reader is most likely to be looking for it. */
.docs-pager {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 0.75rem;
    margin-top: clamp(2.5rem, 5vw, 3.5rem);
    padding-top: clamp(1.5rem, 3vw, 2rem);
    border-top: 1px solid rgba(255, 255, 255, 0.055);
}

.docs-pager__link {
    display: block;
    padding: 0.85rem 1.1rem;
    border: 1px solid rgba(255, 255, 255, 0.08);
    border-radius: 14px;
    background: rgba(255, 255, 255, 0.02);
    text-decoration: none;
    transition: background-color 0.15s ease-in-out;
}

.docs-pager__link:hover,
.docs-pager__link:focus-visible {
    background: rgba(255, 255, 255, 0.045);
    text-decoration: none;
}

.docs-pager__link--next {
    grid-column: 2;
    text-align: right;
}

.docs-pager__label {
    display: block;
    color: #9ca0b3;
    font-size: 0.75rem;
    font-weight: 600;
    letter-spacing: 0.06em;
    text-transform: uppercase;
}

.docs-pager__label i {
    color: #9ca0b3 !important;
    font-size: 0.7rem;
}

.docs-pager__title {
    display: block;
    margin-top: 0.15rem;
    color: #ffffff;
    font-weight: 600;
    line-height: 1.4;
}

/* From large up the sidebar becomes a column of its own and follows the reader
   down the page. Sticky rather than fixed so it still scrolls with a manual page
   longer than the viewport, and its own overflow so a very long manual does not
   run past the bottom of the window with no way to reach the end of it. */
@media (min-width: 992px) {
    .docs-layout {
        grid-template-columns: 17rem minmax(0, 1fr);
        align-items: start;
    }

    .docs-sidebar {
        position: sticky;
        top: calc(var(--bp-header-height) + 1rem);
        max-height: calc(100vh - var(--bp-header-height) - 2.5rem);
        overflow-y: auto;
    }
}

@media (max-width: 575.98px) {
    /* Number and text stacked would put the summary under a 2rem plate with
       nothing beside it, so the number goes and the icon carries the row. */
    .docs-chapter__number {
        display: none;
    }

    .docs-chapter__head {
        grid-template-columns: 1fr;
    }

    .docs-chapter__articles {
        padding-left: 1.5rem;
    }

    /* One under the other, previous first. */
    .docs-pager {
        grid-template-columns: 1fr;
    }

    .docs-pager__link--next {
        grid-column: 1;
    }
}
