/* =========================================================
   PRICING PAGE — plan grid, add-ons, billing FAQ.
   Loaded after public.css (tokens/nav/footer/buttons) and landing.css
   (hero, section shells, feature cards), whose vocabulary this page shares
   with the homepage. Everything here is either page-scoped layout or a
   pricing-specific component.

   Presentation only. There is no amount, no currency and no plan name in
   this file: every one of those comes from /api/public/pricing at runtime,
   and a test asserts this stylesheet generates no content containing a
   number either.
   ========================================================= */

/* =========================================================
   PAGE SHELL

   The section shells come from landing.css at a fixed 24px inline padding.
   Pricing runs wider content (up to four plan columns), so it takes a fluid
   gutter instead — comfortable on a desktop, never touching the edge on a
   phone. Scoped to .page-pricing so the homepage keeps its own spacing.
   ========================================================= */

.page-pricing .hero,
.page-pricing .section,
.page-pricing .section--muted > .section {
    padding-inline: clamp(20px, 4vw, 48px);
}

/* One vertical rhythm for every band on the page. */
.page-pricing .section,
.page-pricing .section--muted > .section {
    padding-block: clamp(56px, 7vw, 88px);
}

/* Matched to the homepage, measured rather than guessed: its hero is
   96px/88px and the section below adds 72px, so the gap between the last
   line of the hero and the next heading is 160px. Zeroing the bottom here
   made that gap 88px — noticeably tighter than every other page. */
.hero--compact {
    padding-block: clamp(64px, 8vw, 96px) clamp(32px, 5vw, 72px);
}

/* =========================================================
   PLAN GRID
   ========================================================= */

.plan-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(248px, 1fr));
    gap: 18px;
    /* Cards size to their own content. Stretching them to a common height
       is the obvious choice and it is wrong here: the catalog gives Free 23
       feature lines and Enterprise 43, so a shared height left 720px of
       empty card between Free's last feature and its button. The call to
       action is lifted above the list instead (see .plan-card__cta), which
       is what actually needs to line up across the row. */
    align-items: start;
}

.plan-card {
    /* Declared once so the reservation rule below can be derived from them
       rather than restating two numbers that would drift apart. */
    --card-gap: 12px;
    --note-line: calc(13.5px * 1.6);

    display: flex;
    flex-direction: column;
    gap: var(--card-gap);
    padding: 26px 24px;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
}

.plan-card--featured {
    border-color: var(--accent);
    background: var(--bg-elevated);
    box-shadow: var(--shadow-md);
}

.plan-card__name {
    margin: 0;
    font-size: 16.5px;
    font-weight: 600;
    letter-spacing: 0.01em;
    color: var(--text);
}

.plan-card__price {
    font-size: clamp(30px, 4vw, 38px);
    font-weight: 700;
    line-height: 1.1;
    letter-spacing: -0.02em;
    color: var(--text);
    /* Digits line up between cards. */
    font-variant-numeric: tabular-nums;
}

.plan-card__price--custom {
    font-size: clamp(22px, 3vw, 26px);
}

.plan-card__interval {
    font-size: 15px;
    font-weight: 500;
    color: var(--text-faint);
    letter-spacing: 0;
    margin-inline-start: 4px;
}

/* The computed "N months free" label — only ever shown beside the YEARLY
   headline (see priceBlock() in pricing.js). BLOCK, not inline: it sits on
   its own line directly under the price, left-aligned with it, at every
   width — living inline after the price/interval text meant it wrapped
   onto its own line only on narrow cards anyway, and carried its inline
   margin down with it when it did, landing indented under nothing.

   COMPOUNDED with .plan-card__badge, not standalone, on purpose: both
   classes sit on the same element (see priceBlock() in pricing.js), and
   a bare `.plan-card__badge--inline` selector ties in specificity with
   `.plan-card__badge` — whichever rule happened to sit later in this file
   would then win outright, silently overriding this rule's declarations.
   A compound selector is strictly more specific, so this rule wins
   regardless of source order. A test in public-pricing.test.js refuses a
   standalone selector from coming back.

   Every property below is restated explicitly rather than left to fall
   through from .plan-card__badge, even where the values now match its
   "Most popular" look — relying on that fallthrough is exactly the
   fragile coupling that caused this rule to lose its padding in the
   first place, and a future change to the setup badge must not be able
   to silently reach this one. */
.plan-card__badge.plan-card__badge--inline {
    display: block;
    width: fit-content;
    margin-inline-start: 0;
    margin-block-start: 4px;
    padding: 4px 10px;
    border-radius: 999px;
    background: var(--accent);
    color: var(--accent-contrast);
    font-size: 10.5px;
    font-weight: 700;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    white-space: nowrap;
}

/* Monthly / Yearly. A plain two-option toggle, not a form control — see
   web/tests/public-pricing.test.js's "no form, no field" scan, which this
   must never trip. */
.pricing-interval-toggle {
    display: flex;
    width: fit-content;
    /* Was inline-flex with no horizontal centering of its own — a block
       this narrow just sat at .section's left edge. A fit-content block
       centers with ordinary margin auto, no wrapper markup needed. */
    margin-inline: auto;
    gap: 2px;
    padding: 3px;
    margin-block-end: 22px;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 999px;
}

.pricing-interval-toggle__option {
    border: 0;
    background: transparent;
    color: var(--text-muted);
    font: inherit;
    font-size: 14px;
    font-weight: 600;
    padding: 7px 16px;
    border-radius: 999px;
    cursor: pointer;
}

.pricing-interval-toggle__option.is-active {
    background: var(--accent);
    color: var(--accent-contrast);
    box-shadow: var(--shadow-sm);
}

.plan-card__blurb,
.plan-card__note {
    margin: 0;
    color: var(--text-muted);
    font-size: 14.5px;
    line-height: 1.6;
}

.plan-card__note {
    font-size: 13.5px;
    /* --text-faint on --surface is about 4:1, under AA for text this size,
       and this line carries the yearly price and the "priced per
       organization" explanation — both things a reader is trying to read. */
    color: var(--text-muted);
}

/* Two lines' worth, so a one-line blurb does not lift its card's button
   above its neighbours'. It only ever ADDS space, so a longer description
   still sets its own height. */
.plan-card__blurb {
    min-height: 3.2em;
}

/* A free plan renders no yearly note (see priceBlock in pricing.js), which
   makes its card exactly one note-line shorter than its neighbours and
   lifts its button out of the row. That line is reserved instead.
   :has() is progressive here: where it is unsupported the card simply keeps
   the small offset it would have had anyway — nothing breaks.

   The reservation is for the YEARLY PRICE LINE, so it is scoped to the cards
   that can actually render one. A setup package never does — see setupCard()
   — so without :not(.plan-card--setup) all three of those cards reserved a
   line none of them has, which lined nothing up and left 33.6px of empty card
   between every price and its description. */
.plan-card:not(.plan-card--setup):not(:has(.plan-card__note)) .plan-card__price {
    padding-block-end: calc(var(--note-line) + var(--card-gap));
}

.plan-card__features {
    list-style: none;
    margin: 4px 0 0;
    padding: 16px 0 0;
    border-top: 1px solid var(--border);
    display: grid;
    gap: 10px;
    font-size: 14.5px;
    line-height: 1.5;
    color: var(--text-muted);
}

.plan-card__features li {
    position: relative;
    padding-inline-start: 22px;
}

.plan-card__features li::before {
    content: "✓";
    position: absolute;
    inset-inline-start: 0;
    color: var(--accent);
    font-size: 13px;
    line-height: 1.6;
}

/* ORDER, not source order. The call to action is rendered after the
   feature list and shown before it, so the four buttons sit at the same
   height across the row — a plan with twice the features does not push its
   button half a screen further down the page. */
.plan-card__features { order: 2; }

.plan-card__cta {
    order: 1;
    margin-block-start: 4px;
    align-self: stretch;
}

/* An add-on is bought alongside a plan rather than instead of one, so its
   card is quieter: no featured state and no call to action of its own. */
.plan-card--addon .plan-card__price {
    font-size: clamp(24px, 3vw, 28px);
}

/* There are two add-ons and the container is wide, so a 1fr track made each
   card 523px of mostly empty surface. They are capped and centred instead,
   which also keeps them the size of a plan card rather than twice it. */
#pricing-addons {
    grid-template-columns: repeat(auto-fit, minmax(248px, 340px));
    justify-content: center;
}

/* =========================================================
   LOADING AND EMPTY STATES

   Both are states the reader is meant to understand, so both are composed
   rather than left as a line of text. The skeleton mirrors the plan card it
   is standing in for; the unavailable state borrows the dashed frame the
   homepage uses when it has no reviews to show.
   ========================================================= */

.plan-skeleton {
    min-height: 268px;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    background: linear-gradient(90deg, var(--surface) 25%, var(--surface-hover) 37%, var(--surface) 63%);
    background-size: 400% 100%;
    animation: pricing-shimmer 1.4s ease infinite;
}

@keyframes pricing-shimmer {
    0% { background-position: 100% 50%; }
    100% { background-position: 0 50%; }
}

/* Announced, not shown — the skeleton above is the visual state. */
.pricing-loading {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
    border: 0;
}

.pricing-empty {
    grid-column: 1 / -1;
    display: grid;
    justify-items: center;
    gap: 18px;
    margin: 0;
    padding: 40px 24px;
    text-align: center;
    color: var(--text-muted);
    font-size: 14.5px;
    line-height: 1.6;
    border: 1px dashed var(--border-strong);
    border-radius: var(--radius);
}

.pricing-empty p {
    margin: 0;
    max-width: 46ch;
}

.pricing-note {
    margin: 24px 0 0;
    text-align: center;
    color: var(--text-muted);
    font-size: 13.5px;
    line-height: 1.6;
}

/* =========================================================
   BILLING FAQ

   Built on landing.css's feature cards so it matches the homepage, with the
   question/answer hierarchy the cards there do not need. They are read, not
   operated, so the accent hover a feature card carries is taken back off.
   ========================================================= */

.faq-grid {
    gap: 16px;
}

.faq-card {
    padding: 24px;
}

.faq-card:hover {
    border-color: var(--border);
    background: var(--surface);
}

.faq-card h3 {
    margin: 0 0 10px;
    font-size: 16px;
    font-weight: 600;
    line-height: 1.4;
    color: var(--text);
}

.faq-card p {
    margin: 0;
    color: var(--text-muted);
    font-size: 14.5px;
    line-height: 1.65;
}

/* The global rule is `a { color: inherit }`, which would leave these
   reading as body text. Inside an answer a link has to look like one. */
.faq-card a {
    color: var(--accent);
    text-decoration: none;
}

.faq-card a:hover {
    text-decoration: underline;
}

/* =========================================================
   RESPONSIVE
   ========================================================= */

@media (max-width: 560px) {
    .plan-grid { grid-template-columns: 1fr; }
    .plan-card { padding: 22px 20px; }
    .faq-card { padding: 20px; }
    .plan-skeleton { min-height: 200px; }
}

@media (prefers-reduced-motion: no-preference) {
    .plan-card,
    .faq-card {
        transition: border-color 0.15s ease, background 0.15s ease;
    }
}

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

/* =========================================================
   MANAGED CONFIGURATION
   A manually arranged service. These rules add no content —
   no `content:` property here puts a price, a package name or a badge
   word on the page, because all of that is server data rendered by
   assets/pricing.js. The stylesheet only lays it out.
   ========================================================= */

.plan-card--setup {
    /* Same card shape as a plan. Nothing here is conditional on which
       package it is, and no rule adds text — the price, the interval
       wording and the badge are all server data. */
    gap: var(--card-gap);

    /* Declared here so the reservation rule below is derived from the badge's
       own metrics rather than restating numbers that would drift from them —
       the same treatment --note-line already gets on .plan-card above. */
    --badge-pad-block: 3px;
    --badge-line: calc(11.5px * 1.25);
}

.plan-card__badge {
    margin: 0;
    align-self: flex-start;
    /* Real fallbacks, not just a definition on .plan-card--setup above —
       any element carrying this class outside that one scope (a stray
       reuse, a future badge on a plain .plan-card) would otherwise
       resolve an undefined var() to nothing, which for `padding` is a
       silent, invisible collapse to zero rather than a visible error.
       These match .plan-card--setup's own values exactly, so nothing
       about the setup card's badge changes. */
    padding: var(--badge-pad-block, 3px) 9px;
    border-radius: 999px;
    background: var(--accent);
    /* --accent-contrast is the token public.css actually defines for text on
       the accent, and the one .btn--primary already uses. The first draft
       named --on-accent, which is defined nowhere on this site, so every
       badge silently took the fallback: white on #35d6e6 is 1.76:1, well
       under AA for 11.5px text and visibly washed out. */
    color: var(--accent-contrast);
    font-size: 11.5px;
    /* Explicit, so the reservation below is exact rather than dependent on
       whatever "normal" resolves to for the system font. */
    line-height: var(--badge-line, calc(11.5px * 1.25));
    font-weight: 650;
    letter-spacing: 0.04em;
    text-transform: uppercase;
}

/* A package carrying no badge is exactly one badge-row shorter than the one
   that does, which lifted its price, its description and its button clear of
   the row — the three "How to request this" buttons stopped lining up, by
   32px. That row is reserved instead, which is the same answer
   .plan-card__note already gets above; :has() is progressive here in the same
   way, since unsupported the card simply keeps the offset it would have had
   anyway. The badge is the card's first child, so the space is reserved above
   the name rather than below the price. */
.plan-card--setup:not(:has(.plan-card__badge)) .plan-card__name {
    padding-block-start: calc(var(--badge-line) + (var(--badge-pad-block) * 2) + var(--card-gap));
}

.setup-extras {
    margin-top: 22px;
    display: flex;
    flex-direction: column;
    gap: 14px;
}

.setup-extras__line,
.setup-extras__note {
    margin: 0;
    color: var(--text-muted);
    font-size: 14px;
    line-height: 1.6;
}

.setup-extras__block {
    padding: 16px 18px;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
}

.setup-extras__title {
    margin: 0 0 8px;
    font-size: 14.5px;
    font-weight: 600;
    color: var(--text);
}

.setup-extras__list {
    margin: 0;
    padding-left: 18px;
    display: grid;
    gap: 6px;
    color: var(--text-muted);
    font-size: 14px;
    line-height: 1.55;
}

/* Mobile: the cards already stack through .plan-grid; this keeps the
   extras readable rather than letting the block padding crowd them. */
@media (max-width: 560px) {
    .setup-extras__block { padding: 14px; }
    .setup-extras__list { padding-left: 16px; }

    /* .plan-grid collapses to a single column here, so no two cards share a
       row and there is nothing for the reserved badge row to line up with —
       it would just be 32px of empty card above every title but Complete's.
       Released at exactly the breakpoint that stacks them. */
    .plan-card--setup:not(:has(.plan-card__badge)) .plan-card__name {
        padding-block-start: 0;
    }
}
