@layer components {
/* Height of the footer, modeled term-by-term from the rule below (border +
   padding + button rows + powered-by subtitle + padding + safe-area). Pages
   reserve scroll space above the fixed footer with
   calc(var(--psw-footer-height) + <gap>) — 24px of content-to-footer air on
   mobile. */
:root {
    /* The buttons block: n × 48px rows, their (n − 1) 12px flex gaps, and the
       12px gap down to the subtitle — which is n × 60px. Defaults to one CTA;
       the :has() rules below adjust it for the footers that render more, and
       zero it for the ones that render none. */
    --psw-footer-buttons: calc(48px + var(--space-3));
    --psw-footer-height: calc(
        var(--border-width-sm) + var(--space-3) + var(--psw-footer-buttons) +
        var(--text-paragraph-sm--line-height) + var(--space-3) +
        env(safe-area-inset-bottom)
    );
}

/* A branding-only footer (the landing pages, the read-only record view, the
   categories step, a non-client pay page) renders no .psw-footer__buttons at
   all, so neither the button row nor the 12px flex gap down to the subtitle
   exists — the one-CTA default over-reserved 60px on every one of them. */
:root:has(.psw-footer):not(:has(.psw-footer__buttons)) {
    --psw-footer-buttons: 0px;
}

/* A column footer's extra rows are real height the one-CTA model didn't carry,
   so every consumer under-reserved by 60px per extra button and the last of the
   page's content sat under the bar — 36px of it on the two-CTA states (gift's
   transfer, estimate's add-method + download, and the three pay summary pages'
   signed-out pair).

   The count has to reach an ANCESTOR of each scroll container, and a custom
   property set on .psw-footer can only travel down. Matching from :root instead
   costs one rule here rather than a modifier threaded through seven page
   sheets and their templates — where the CTA count is decided in a branch far
   below the element that needs it, and would drift out of step the first time
   a branch gained a button. Row layouts stay one row tall at any count, and so
   match neither rule. */
:root:has(.psw-footer__buttons--column > :nth-child(2)) {
    --psw-footer-buttons: calc(2 * (48px + var(--space-3)));
}
:root:has(.psw-footer__buttons--column > :nth-child(3)) {
    --psw-footer-buttons: calc(3 * (48px + var(--space-3)));
}

/* Fixed to the viewport; pages that render it must add enough bottom padding
   to their main scroll area for the chosen CTA count + safe-area inset. */
.psw-footer {
    position: fixed;
    bottom: 0;
    left: 0;
    right: 0;
    z-index: 10;
    background: var(--color-white);
    border-top: var(--border-width-sm) solid var(--color-border-default);
    padding: var(--space-3) var(--space-4) calc(var(--space-3) + env(safe-area-inset-bottom));
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
}

@media (min-width: 769px) {
    .psw-footer {
        display: none;
    }

    /* Keep desktop-width Storybook examples visible; the gallery renders
       mobile-sized frames to preview this mobile-only component. */
    .dbg-gallery .psw-footer {
        display: flex;
    }
}

.psw-footer__buttons {
    display: flex;
    gap: var(--space-3);
}

.psw-footer__buttons--column {
    flex-direction: column;
}

.psw-footer__buttons--row {
    flex-direction: row;
}

/* Equal-width row buttons. block=True gives each button width: 100% within
   its flex cell; flex: 1 1 0 makes the cells themselves equal. */
.psw-footer__buttons--row > * {
    flex: 1 1 0;
    min-width: 0;
}
}
