@layer components {
.psw-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--space-2);                 /* Figma: Padding/padding-small (8px) between icon + label */
    border: 1px solid transparent;
    border-radius: var(--radius-lg);     /* Figma: Radius/radius-medium (8px) */
    /* Figma: Label/Medium (16/20) — DM Sans, normal, 700. Size + line-height
       come from the paired Label tokens so a future ramp tweak in tokens.css
       flows through automatically. .psw-btn--sm overrides both with the
       Label/Small (14/16) pair. */
    font-family: var(--font-sans);
    font-style: normal;
    font-weight: var(--font-weight-bold);
    font-size: var(--text-label-md);
    line-height: var(--text-label-md--line-height);
    text-align: center;
    cursor: pointer;
    text-decoration: none;
    user-select: none;
    /* Rapid taps on a button must never read as iOS's double-tap-to-zoom —
       the gratuity dialog's −/+ stepper zoomed the viewport when tapped
       repeatedly. Pinch zoom is unaffected. */
    touch-action: manipulation;
    transition: background-color 120ms ease, border-color 120ms ease, color 120ms ease;
}

/* Figma: Label/Small (14/16) — both size and line-height come from the
   paired tokens so the small button matches the spec, not the inherited
   Label/Medium line-height (20px) it was using before. */
.psw-btn--sm { padding: 8px 12px;  font-size: var(--text-label-sm); line-height: var(--text-label-sm--line-height); height: 36px; }
.psw-btn--md { padding: 14px 16px; font-size: var(--text-label-md); line-height: var(--text-label-md--line-height); height: 48px; }

/* Icon-only layout (also used by icon_button). Width/height are equal, while
   the inner icon keeps the size mapping from the component template. */
.psw-btn--icon-only {
    flex: 0 0 auto;
    gap: 0;
    padding: 0;
}
.psw-btn--icon-only.psw-btn--sm { width: 36px; height: 36px; }
.psw-btn--icon-only.psw-btn--md { width: 48px; }
.psw-btn--icon-shape-circle { border-radius: var(--radius-max); }
.psw-btn--icon-shape-square { border-radius: var(--radius-lg); }

.psw-btn--primary {
    /* Background/border read from --theme-primary — a Pro's primary_color when
       set, otherwise --theme-primary-default (Cobalt 500) via :root in
       tokens.css. The literal fallback below is that same alias token. */
    background-color: var(--theme-primary, var(--theme-primary-default));
    color: var(--color-content-inverse);              /* Figma: Content/content-inverse (#FFF) */
    border-color: var(--theme-primary, var(--theme-primary-default));
}
/* Hover washes are gated on (hover: hover) throughout: touch browsers keep
   :hover latched on the last-tapped element, which left the just-selected
   slot button stuck a shade darker than its resting state. */
@media (hover: hover) {
    .psw-btn--primary:hover {
        /* Figma hover: 10% black overlay on base fill */
        background-image: linear-gradient(rgba(0, 0, 0, 0.1), rgba(0, 0, 0, 0.1));
    }
}
.psw-btn--primary:active {
    /* Figma pressed: 20% black overlay on base fill */
    background-image: linear-gradient(rgba(0, 0, 0, 0.2), rgba(0, 0, 0, 0.2));
}
.psw-btn--primary:focus-visible {
    /* Figma focus: 2px solid Gray700 ring; outline with negative offset keeps layout stable */
    outline: 2px solid var(--color-gray-700);
    outline-offset: 2px;
}

/* Secondary — Figma nodes 1952:20483..20487 + 2142:28420. Outlined button on
   a white fill with brand-blue text. Hover/pressed darken via a near-black
   gray-700 overlay (matches Figma's 4%/8% rgba(15,15,15,…) gradients).
   Disabled keeps the white fill (NOT the universal gray) and just lightens
   the border. */
.psw-btn--secondary {
    background-color: var(--color-white);                              /* Figma: Background/bg-base */
    color: var(--theme-primary, var(--theme-primary-default));                /* themed; fallback Cobalt 500 */
    border-color: var(--color-border-default);                         /* Figma: Border/border-medium (#e2e2e2) */
}
@media (hover: hover) {
    .psw-btn--secondary:hover {
        background-image: linear-gradient(rgba(15, 15, 15, 0.04), rgba(15, 15, 15, 0.04));
    }
}
.psw-btn--secondary:active {
    background-image: linear-gradient(rgba(15, 15, 15, 0.08), rgba(15, 15, 15, 0.08));
}
.psw-btn--secondary:focus-visible {
    outline: var(--border-width-md) solid var(--color-gray-700);
    outline-offset: calc(1 * var(--border-width-md));
}
.psw-btn.psw-btn--secondary[disabled],
.psw-btn.psw-btn--secondary[aria-disabled="true"],
.psw-btn.psw-btn--secondary.psw-btn--loading {
    /* Override the universal disabled gray bg with white; only the border
       lightens. Text color stays content-disabled from the universal rule. */
    background-color: var(--color-white);            /* Figma: Background/bg-base */
    border-color: var(--color-border-disabled);      /* Figma: Border/border-disabled (#f0f0f0) */
}

/* Tertiary — Figma 1952:20746..20750 + 2142:28433. Padded link-styled button:
   white fill, info-400 underlined text, no visible border. Same dark-overlay
   hover/pressed treatment as secondary. Disabled keeps white bg and fades
   the text to content-disabled (underline preserved). */
.psw-btn--tertiary {
    background-color: var(--color-white);                              /* Figma: Background/bg-base */
    color: var(--theme-primary, var(--theme-primary-default));                /* themed; fallback Cobalt 500 */
    border-color: transparent;
    text-decoration: underline;
}
@media (hover: hover) {
    .psw-btn--tertiary:hover {
        background-image: linear-gradient(rgba(15, 15, 15, 0.04), rgba(15, 15, 15, 0.04));
    }
}
.psw-btn--tertiary:active {
    background-image: linear-gradient(rgba(15, 15, 15, 0.08), rgba(15, 15, 15, 0.08));
}
.psw-btn--tertiary:focus-visible {
    outline: var(--border-width-md) solid var(--color-gray-700);
    outline-offset: calc(1 * var(--border-width-md));
}
.psw-btn.psw-btn--tertiary[disabled],
.psw-btn.psw-btn--tertiary[aria-disabled="true"],
.psw-btn.psw-btn--tertiary.psw-btn--loading {
    /* Override the universal disabled gray bg/border. Text color stays as
       content-disabled from the universal disabled rule. */
    background-color: var(--color-white);
    border-color: transparent;
}

/* tertiaryLink — Figma 1952:20974..20978 + 2142:28442. Inline text-link
   affordance, distinct from tertiary: NO padding, NO fill, NO border in
   default state — sits inline within flowing copy. Underlined info-400
   text. Hover/pressed darken the primary text with a 20%/30% black
   overlay (Figma-updated). Focus draws a 2px gray-700 outline 2px outside
   the text (positive outline-offset), mirroring Figma's "2px border + 2px
   padding" focus visual without layout shift. Disabled/loading fade text
   via the universal disabled rule (content-disabled). */
.psw-btn--tertiary-link {
    background: transparent;
    border-color: transparent;
    padding: 0;
    height: auto;
    color: var(--theme-primary, var(--theme-primary-default));   /* themed; fallback Cobalt 500 */
    text-decoration: underline;
}
@media (hover: hover) {
    .psw-btn--tertiary-link:hover {
        /* Figma: primary color + 20% black overlay */
        color: color-mix(in srgb, var(--theme-primary, var(--theme-primary-default)), black 20%);
    }
}
.psw-btn--tertiary-link:active {
    /* Figma: primary color + 30% black overlay */
    color: color-mix(in srgb, var(--theme-primary, var(--theme-primary-default)), black 30%);
}
.psw-btn--tertiary-link:focus-visible {
    outline: var(--border-width-md) solid var(--color-gray-700);
    outline-offset: var(--border-width-md);      /* positive offset: ring sits outside the text */
}
.psw-btn.psw-btn--tertiary-link[disabled],
.psw-btn.psw-btn--tertiary-link[aria-disabled="true"],
.psw-btn.psw-btn--tertiary-link.psw-btn--loading {
    /* Override the universal disabled gray bg/border with transparent so
       the link stays inline-styled. Text color stays as content-disabled
       from the universal disabled rule. */
    background: transparent;
    border-color: transparent;
}

/* Destructive modifier — combines with any variant via paired selectors so
   the variant's shape (filled/outlined/transparent) is preserved while the
   color palette swaps to danger tokens. */

/* All destructive buttons use Figma's Content/content-inverse (white) text in
   every state, including disabled. Selectors are doubled with `.psw-btn` so
   the disabled/loading variants reach specificity (0,2,1) and cleanly beat
   the universal `.psw-btn[disabled] { color: content-disabled }` rule
   regardless of source order. */
.psw-btn.psw-btn--destructive,
.psw-btn.psw-btn--destructive[disabled],
.psw-btn.psw-btn--destructive[aria-disabled="true"],
.psw-btn.psw-btn--destructive.psw-btn--loading {
    color: var(--color-content-inverse);
}

/* Primary destructive — Figma node 1952:19205..19208. Hover/pressed use a
   WHITE overlay (lightens red), opposite of primary's black overlay (darkens
   blue). Disabled keeps the destructive identity via bg-negative-low instead
   of falling back to the universal bg-disabled gray. */
.psw-btn--primary.psw-btn--destructive {
    background-color: var(--color-bg-negative);    /* Figma: Status/bg-negative (#e11900) */
    border-color: var(--color-bg-negative);
}
@media (hover: hover) {
    .psw-btn--primary.psw-btn--destructive:hover {
        background-image: linear-gradient(rgba(255, 255, 255, 0.1), rgba(255, 255, 255, 0.1));
    }
}
.psw-btn--primary.psw-btn--destructive:active {
    background-image: linear-gradient(rgba(255, 255, 255, 0.2), rgba(255, 255, 255, 0.2));
}
.psw-btn--primary.psw-btn--destructive[disabled],
.psw-btn--primary.psw-btn--destructive[aria-disabled="true"],
.psw-btn--primary.psw-btn--destructive.psw-btn--loading {
    /* Override the universal disabled bg with the destructive's low-emphasis
       tint. Specificity (0,3,1) beats the universal (0,1,1). */
    background-color: var(--color-bg-negative-low);  /* Figma: Status/bg-negative-low (#ffdbd6) */
    border-color: var(--color-bg-negative-low);
}

/* Secondary destructive — Figma 1952:20489..20491 (default inferred from the
   surrounding states). Same shape as regular secondary (white fill, gray-300
   border, 4%/8% dark overlay on hover/pressed) but text swaps to danger red.
   Disabled keeps the default border color (NOT the lighter `border-disabled`
   used by regular secondary disabled) and fades the text to negative-low. */
.psw-btn.psw-btn--secondary.psw-btn--destructive {
    color: var(--color-content-negative);            /* Figma: Status/content-negative (#e11900) */
}
.psw-btn.psw-btn--secondary.psw-btn--destructive[disabled],
.psw-btn.psw-btn--secondary.psw-btn--destructive[aria-disabled="true"],
.psw-btn.psw-btn--secondary.psw-btn--destructive.psw-btn--loading {
    color: var(--color-content-negative-low);        /* Figma: Status/content-negative-low (#ffdbd6) */
    border-color: var(--color-border-default);       /* override the lighter `border-disabled` from secondary disabled */
}

/* Tertiary + tertiaryLink destructive — Figma 1952:20752..20755 for tertiary.
   tertiaryLink destructive inherits the same treatment since the two are now
   visually unified. Same padded shape as regular tertiary; text swaps to
   danger red, fades to negative-low for disabled/loading. */
.psw-btn.psw-btn--tertiary.psw-btn--destructive,
.psw-btn.psw-btn--tertiary-link.psw-btn--destructive {
    color: var(--color-content-negative);           /* Figma: Status/content-negative (#e11900) */
}
.psw-btn.psw-btn--tertiary.psw-btn--destructive[disabled],
.psw-btn.psw-btn--tertiary.psw-btn--destructive[aria-disabled="true"],
.psw-btn.psw-btn--tertiary.psw-btn--destructive.psw-btn--loading,
.psw-btn.psw-btn--tertiary-link.psw-btn--destructive[disabled],
.psw-btn.psw-btn--tertiary-link.psw-btn--destructive[aria-disabled="true"],
.psw-btn.psw-btn--tertiary-link.psw-btn--destructive.psw-btn--loading {
    color: var(--color-content-negative-low);       /* Figma: Status/content-negative-low (#ffdbd6) */
}

.psw-btn--block { display: flex; width: 100%; }

/* Disabled & loading share the same universal Figma treatment (bg-disabled +
   content-disabled tokens). These selectors win over variant fills via
   specificity (attribute selectors and the --loading class beat the variant
   class on its own). */
.psw-btn[disabled],
.psw-btn[aria-disabled="true"],
.psw-btn--loading {
    background-color: var(--color-bg-disabled);   /* Figma: Background/bg-disabled */
    background-image: none;                       /* drop any hover/active overlay */
    color: var(--color-content-disabled);         /* Figma: Content/content-disabled */
    border-color: var(--color-bg-disabled);
    cursor: not-allowed;
    pointer-events: none;
}
.psw-btn--loading { cursor: progress; }

/* Spinner: inlined as <svg> inside the button partial when state="loading".
   We can't use a background-image SVG here because external SVGs are isolated
   from the parent's CSS variables — inline SVG lets the path `fill` values
   read `var(--theme-primary, ...)` directly. The button partial picks the
   ring/arc fills per variant (destructive vs not). */
.psw-btn__spinner {
    flex-shrink: 0;
    width: 20px;                                /* Figma: 20×20 spinner */
    height: 20px;
    animation: psw-spin 1.2s linear infinite;
}

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

/* JS-driven busy state (form submit): the inline <svg> spinner only exists on
   server-rendered state="loading" buttons, so a script (psw-source.js)
   toggles .psw-btn--busy to draw an equivalent themed ring via ::after. */
.psw-btn--busy::after {
    content: "";
    flex-shrink: 0;
    width: 20px;                                /* matches the 20×20 SVG spinner */
    height: 20px;
    border-radius: 50%;
    border: 2px solid var(--color-border-default);
    border-top-color: var(--theme-primary, var(--theme-primary-default));
    animation: psw-spin 1.2s linear infinite;
}
.psw-btn--sm.psw-btn--busy::after { width: 16px; height: 16px; }
}
