/* The plan cards (premium direction 2026-11-11, decision 6: saas/DESIGN.md "Plan cards"): the plans as the pricing section the owner
   chose, for the home, /pricing and, in its round, the app's Billing page. It takes the place of shared/css/pricing-section.css
   wherever it is loaded: both sheets style the same `ps-` names, so a page loads one of them, never both.

   Where the look comes from. The owner's pick is "Pricing" by uilayout.contact on 21st.dev, whose page shows no licence: it was looked
   at and described (the heading on the left, the switch under it, the glossy pill and buttons, the price that rolls, the checked
   list) and nothing of its code, classes or colours is here. The pieces are rebuilt in plain CSS on this product's tokens after
   items that carry a licence (rows in saas/docs/design/21st-provenance.md, notices in shared/NOTICE.md):
     the tabs with a pill that slides      aymanch-03 "pricing-section" (MIT)
     the digits that roll                  barvian "Number Flow" (MIT), as "slider-number-flow" on 21st.dev
     the heading's words                   danielpetho "Vertical Cut Reveal" (MIT)
   The card itself is the product's glow card (v2/glow.css); the buttons read the --gloss-* tokens (v2/accents.css).

   Needs, loaded before this sheet: theme-a.css (the theme and the motion tokens), v2/accents.css, v2/glow.css. Nothing here depends
   on a site or an app selector. Behaviour: shared/js/plan-cards.js `initPlanCards(root)`; the light of the cards: shared/js/glow.js
   `initGlow()`, once per page.

   MARKUP CONTRACT (api/web_pricing.py `section_html` writes it for the site; the app writes the same from GET /billing)
     <div class="ps" data-ps>
       <div class="ps-switch" hidden>                                    shown by the script; without it every card shows both periods
         <div class="ps-tabs" role="radiogroup" aria-label="Billing period">
           <button type="button" class="ps-tab" role="radio" aria-checked="true" data-freq="month">Monthly</button>
           <button type="button" class="ps-tab" role="radio" aria-checked="false" data-freq="year" tabindex="-1">Yearly
             <span class="ps-save">Pay for 10 months</span></button>     optional; only a fact of the prices
         </div>
       </div>
       <div class="ps-grid" data-cols="4">                               data-cols: how many cards stand side by side when wide (3 or 4)
         <article class="ps-card ps-free glow glow-pad" aria-labelledby="ps-free"> ... </article>     optional: a calm row above
         <article class="ps-card glow glow-pad" aria-labelledby="ps-solo">
           <div class="ps-head">
             <h3 class="ps-name" id="ps-solo">Solo <span class="ps-badge">Recommended</span></h3>     the badge only with .is-rec
             <p class="ps-desc">One line.</p>
           </div>
           <div class="ps-cost">
             <div class="ps-price">                                      one per kind of buyer; add .ps-who and data-who where a page
               <p class="ps-row" data-period="month">                    switches between kinds itself (site/js/who-pick.js)
                 <span class="ps-amt v-m">€19</span> <span class="ps-per p-m">a month, excluding VAT</span>
                 <span class="ps-ind">One more line</span></p>           .ps-ind is optional: a line of this period's own
               <p class="ps-row" data-period="year">
                 <span class="ps-amt v-y">€190</span> <span class="ps-per p-y">a year, billed once, excluding VAT</span>
                 <span class="ps-ind">One more line</span></p>
             </div>
           </div>
           <a class="ps-cta" href="...">Choose Solo</a>                  a link or a button; .is-primary is the emerald one
           <ul class="ps-feats"><li><svg class="ps-check" viewBox="0 0 24 24" aria-hidden="true"><circle cx="12" cy="12" r="11"/>
             <path d="m7.5 12.5 3 3 6-6.5"/></svg><span>A fact of the plan</span></li> ... </ul>
         </article>
       </div>
     </div>
   A `.ps-tabs` group may also stand on its own, outside `.ps`, as a page's own two-way switch (the site's Business / Individual,
   api/web_pricing.py `WHO_SWITCH`): the same radio group of two `.ps-tab`, drawn by the same rules. The page's script keeps
   aria-checked on its tabs and writes `--ps-at` (0 or 1, the seat of the pill) on the group.
   Where a card's button differs by period (the app's Billing: "Choose Solo", "Switch to yearly", "Current plan"), `.ps-go` stands in
   the button's place and holds one `.ps-cta` per period, each (or its wrapper) marked data-period: both lie in one cell, the
   rule of one period at a time shows the chosen one, and the card keeps its height.
   A price with one row (the Free plan's) has one `.ps-row` and no data-period. Just before `.ps`, an element marked `data-ps-intro`
   (the section's heading and its lead) joins the entrance: its heading's words, then its paragraphs, then the switch, then the cards.

   STATES
     .ps[data-freq="month|year"]   the period shown (the script; none = month)
     .ps.is-live                   the script runs: one row of each price shows, the other keeps its place so no card changes height
     .ps-card.is-rec               the plan the page recommends: an emerald edge and a faint emerald face. One per grid at most, and
                                   only with a fact or the page's own word for it (decision 6: never "Popular" without sales data)
     .ps-cta.is-primary            the emerald button; one per grid (decision 5)
     .ps-price.has-roll            the script built `.ps-roll`, the digits that roll; the readable amounts stay for assistive technology
     .ps-wait, .ps-step, .is-wait > .ps-word  the entrance: a piece set aside, a piece coming in, a heading whose words wait (the
                                   script arms only a piece that starts below the screen; what is already seen is left as it is)

   WITHOUT THE SCRIPT the switch stays hidden and each card shows the month's row and the year's row, one under the other, each
   with its own line; where a page holds two kinds of buyer (`.ps-who`), the second shows under a rule, a step smaller. Where the
   browser says scripts run (`scripting: enabled`) the sheet already lays the rows out as the script will, so nothing shifts when
   it arrives.

   LAYOUT follows the width of `.ps` itself (a container), not of the window, so the same sheet fits a page and a panel:
     under 620 px   one column, the Free card first
     from 620 px    two columns, the Free card across both; of three plans the third lies across both too, its facts beside its price
     from 1040 px   data-cols columns, the Free card a slim row above them (from 900 px its facts sit beside its price)
   Rows line up across the cards of a row (subgrid): names, prices, buttons and lists start on the same lines.

   MOTION is transform and opacity only, each on a token (the theme's, or one of the durations below); with prefers-reduced-motion
   or data-motion="off" nothing rolls, slides or enters and the chosen period is simply shown; Calm keeps the fades and moves nothing. */

:root {
  --ps-roll: 650ms;        /* a digit turning to its new value */
  --ps-digit-gap: 35ms;    /* between two digits of one amount starting to turn */
  --ps-fade: 240ms;        /* the words of the period that is chosen coming in */
  --ps-enter: 500ms;       /* a piece of the section arriving */
  --ps-step-gap: 80ms;     /* between two pieces of the entrance */
  --ps-word: 600ms;        /* a word of the heading coming down into its line */
  --ps-word-gap: 60ms;     /* between two words */
  --ps-r-btn: var(--radius-md, 0.875rem);   /* the theme's button radius (theme-a.css; the site's and the app's --a-r-btn is this value): the
                              plan buttons are the product's one glossy button (decision 5), and the switch is built on the same curve */
}

.ps, .ps-tabs {   /* a group of tabs on its own reads the same values */
  --ps-ease: var(--motion-ease-sheet, cubic-bezier(0.32, 0.72, 0, 1));
  --ps-face: var(--glow-face, #ffffff);
  --ps-rule: var(--glow-line, #e6e6e8);
}
.ps {
  container: ps / inline-size; display: grid; grid-template-columns: minmax(0, 1fr); justify-items: start; gap: 24px; }
.ps [hidden] { display: none !important; }
.ps-status { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }

/* ==== the switch: two equal tabs and one glossy pill that slides under the chosen one. The tabs and the pill take the button's
   radius; the track is rounder by its own padding, so the two curves stay parallel ==== */
.ps-switch { max-width: 100%; }
@media (scripting: enabled) { .ps .ps-switch[hidden] { display: block !important; visibility: hidden; } }   /* its place is kept until the script shows it */
.ps-tabs { position: relative; isolation: isolate; display: inline-grid; grid-template-columns: repeat(2, minmax(0, 1fr)); max-width: 100%; padding: 4px;
  border-radius: calc(var(--ps-r-btn) + 4px); background: var(--muted, #f5f5f5); box-shadow: inset 0 0 0 1px var(--ps-rule); }
.ps-tabs::before { content: ""; position: absolute; z-index: -1; top: 4px; bottom: 4px; left: 4px; width: calc(50% - 4px); border-radius: var(--ps-r-btn);
  border: 1px solid var(--gloss-primary-edge); background: var(--gloss-primary-bg);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.45), 0 6px 14px -6px rgba(var(--acc-emerald-rgb), 0.6);
  transform: translateX(calc(var(--ps-at, 0) * 100%)); transition: transform var(--motion-sheet) var(--ps-ease); }
.ps[data-freq="year"] .ps-switch > .ps-tabs { --ps-at: 1; }
.ps-tab { display: inline-flex; align-items: center; justify-content: center; gap: 8px; min-height: 44px; padding: 0 18px; border: 0; border-radius: var(--ps-r-btn);
  background: none; color: var(--muted-foreground); font: inherit; font-size: 0.9375rem; font-weight: 600; line-height: 1.2; white-space: nowrap;
  cursor: pointer; }
.ps-tab[aria-checked="true"] { color: var(--gloss-primary-ink, #000000); }
@media (hover: hover) { .ps-tab[aria-checked="false"]:hover { color: var(--foreground); } }
.ps-tab:focus-visible { outline: 2px solid var(--ring); outline-offset: 2px; }
.ps-save { display: inline-flex; align-items: center; min-height: 22px; padding: 0 8px; border-radius: 999px; background: var(--background);
  color: var(--foreground); box-shadow: inset 0 0 0 1px var(--ps-rule); font-size: 0.75rem; font-weight: 600; }
@container ps (max-width: 459.98px) {
  .ps-switch, .ps-tabs { width: 100%; }
  .ps-tab { flex-direction: column; gap: 3px; min-height: 56px; padding: 6px 8px; }
}

/* ==== the grid ==== */
.ps-grid { display: grid; width: 100%; grid-template-columns: minmax(0, 1fr); gap: 16px; }
@container ps (min-width: 620px) {
  .ps-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .ps-grid > .ps-free { grid-column: 1 / -1; }
}
@container ps (min-width: 1040px) {
  .ps-grid { grid-template-columns: repeat(4, minmax(0, 1fr)); }
  .ps-grid[data-cols="3"] { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
@supports not (container-type: inline-size) {   /* an older browser: the window's width stands in for the container's */
  @media (min-width: 700px) { .ps-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } .ps-grid > .ps-free { grid-column: 1 / -1; } }
  @media (min-width: 1100px) { .ps-grid { grid-template-columns: repeat(4, minmax(0, 1fr)); } .ps-grid[data-cols="3"] { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
}

/* ==== a card: the glow card (glow.css owns its face, its edge and its light); this sheet lays out what stands in it ==== */
.ps-grid > .ps-card { min-width: 0; gap: 20px; color: var(--card-foreground, var(--foreground)); }
@supports (grid-template-rows: subgrid) {
  .ps-grid > .ps-card:not(.ps-free) { display: grid; grid-template-columns: minmax(0, 1fr); grid-template-rows: subgrid; grid-row: span 4; row-gap: 20px; }
}
.ps-card.is-rec { --glow-line: rgba(var(--acc-emerald-rgb), 0.6); --glow-face: color-mix(in srgb, rgb(var(--acc-emerald-rgb)) 6%, var(--ps-face)); }

.ps-head { display: grid; align-content: start; gap: 8px; }
.ps-name { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 6px 12px; margin: 0; color: var(--foreground);
  font-size: 1.375rem; font-weight: 600; line-height: 1.2; letter-spacing: -0.01em; }
.ps-badge { display: inline-flex; align-items: center; min-height: 24px; padding: 0 10px; border-radius: 999px; background: rgba(var(--acc-emerald-rgb), 0.12);
  color: color-mix(in srgb, var(--acc-emerald) 82%, var(--foreground)); box-shadow: inset 0 0 0 1px rgba(var(--acc-emerald-rgb), 0.32); font-size: 0.75rem; font-weight: 600; letter-spacing: 0; }
.ps-desc { margin: 0; color: var(--muted-foreground); font-size: 0.875rem; line-height: 1.5; }

/* the price: a row per period, the amount set large and its words under it */
.ps-cost { display: grid; align-content: start; gap: 8px; }
.ps-price { position: relative; display: grid; grid-template-columns: minmax(0, 1fr); gap: 8px; }
.ps-row { display: grid; gap: 4px; margin: 0; }
.ps-amt, .ps-roll { color: var(--foreground); font-size: 2.5rem; font-weight: 600; line-height: 1.15; letter-spacing: -0.02em; font-variant-numeric: tabular-nums; }
.ps-row[data-period="year"] .ps-amt { font-size: 1.25rem; }   /* without the script the year stands under the month, a step smaller */
.ps-per, .ps-ind { color: var(--muted-foreground); font-size: 0.8125rem; line-height: 1.45; text-wrap: balance; }   /* a sum that wraps never leaves its total alone on a line */
.ps-ind { margin-top: 2px; }
@media (scripting: none) { .ps .ps-who[hidden] { display: grid !important; } }   /* no script, so no Business / Individual switch: both show, each says its VAT */
@media (scripting: none) {
  /* ... and the second kind reads as the same price with its VAT, not as a second price: under the card's rule, a step smaller */
  .ps .ps-who[hidden] { margin-top: 4px; padding-top: 12px; border-top: 1px solid var(--ps-rule); }
  .ps .ps-who[hidden] .ps-row[data-period="month"] .ps-amt { font-size: 1.5rem; }
  .ps .ps-who[hidden] .ps-row[data-period="year"] .ps-amt { font-size: 1.125rem; }
}

/* one period at a time. Written twice on purpose: for a browser that tells the sheet scripts run (so the page is laid out this way
   from its first paint), and for the script's own mark on `.ps` (every browser). Both rows share one cell, so the cell is as tall as
   the taller of the two and a card keeps its height when the period changes. The row that is not chosen is `visibility: hidden`
   (gone for a screen reader too) at once; the chosen one fades in. */
.ps.is-live .ps-row { grid-area: 1 / 1; align-content: start; transition: opacity var(--ps-fade) var(--motion-ease-out, ease-out); }
.ps.is-live .ps-row[data-period="year"] .ps-amt { font-size: 2.5rem; }
.ps.is-live:not([data-freq="year"]) [data-period="year"], .ps.is-live[data-freq="year"] [data-period="month"] { visibility: hidden; opacity: 0; }
@media (scripting: enabled) {
  .ps .ps-row { grid-area: 1 / 1; align-content: start; transition: opacity var(--ps-fade) var(--motion-ease-out, ease-out); }
  .ps .ps-row[data-period="year"] .ps-amt { font-size: 2.5rem; }
  .ps:not([data-freq="year"]) [data-period="year"], .ps[data-freq="year"] [data-period="month"] { visibility: hidden; opacity: 0; }
}

/* the digits that roll (plan-cards.js builds `.ps-roll` over the amount's line; the amounts themselves stay, unseen, for a screen
   reader). A digit is a column of 0 to 9 moved to its value (--d); a digit that keeps its place value slides to its new seat (--x);
   one that arrives or leaves fades. */
.ps-price.has-roll .ps-amt { opacity: 0; }
.ps-roll { grid-area: 1 / 1; place-self: start; position: relative; display: flex; height: 1.15em; clip-path: inset(0 -100vw); pointer-events: none;
  -webkit-user-select: none; user-select: none; }   /* a selection copies the amount itself, never the columns of digits */
.ps-slot { flex: none; display: block; height: 1.15em; transform: translateX(var(--x, 0px));
  transition: transform var(--ps-roll) var(--ps-ease), opacity var(--ps-fade) var(--motion-ease-out, ease-out); }
.ps-reel { display: flex; flex-direction: column; transform: translateY(calc(var(--d, 0) * -1.15em));
  transition: transform var(--ps-roll) var(--ps-ease); transition-delay: calc(var(--i, 0) * var(--ps-digit-gap)); }
.ps-reel > span { display: block; height: 1.15em; }
.ps-slot.is-in, .ps-slot.is-out { opacity: 0; }
.ps-slot.is-gone { position: absolute; top: 0; left: var(--x0, 0px); }
.ps-roll.is-jump :is(.ps-slot, .ps-reel) { transition-duration: 0s; transition-delay: 0s; }   /* the start of a roll is set without a transition, then released */

/* the button: glossy neutral, and the glossy emerald on the plan the page recommends (the --gloss-* tokens of accents.css) */
.ps-cta { display: flex; align-items: center; justify-content: center; min-height: 48px; padding: 0 20px; border: 1px solid var(--gloss-neutral-edge);
  border-radius: var(--ps-r-btn); background: var(--gloss-neutral-bg); color: var(--gloss-neutral-ink); box-shadow: var(--gloss-neutral-shadow);
  font: inherit; font-size: 1rem; font-weight: 600; line-height: 1.2; text-align: center; text-decoration: none; cursor: pointer;
  transition: transform var(--motion-fast) var(--motion-ease-out, ease-out); }
.ps-cta.is-primary { border-color: var(--gloss-primary-edge); background: var(--gloss-primary-bg); color: var(--gloss-primary-ink); box-shadow: var(--gloss-primary-shadow); }
@media (hover: hover) {
  .ps-cta:hover { background: var(--gloss-neutral-bg-hover); color: var(--gloss-neutral-ink); text-decoration: none; }
  .ps-cta.is-primary:hover { background: var(--gloss-primary-bg-hover); color: var(--gloss-primary-ink); }
}
.ps-cta:active { transform: scale(var(--press-scale, 0.97)); }
.ps-cta:focus-visible { outline: 2px solid var(--ring); outline-offset: 2px; }

/* a button per period in the button's place: one cell, the chosen period's shows (the rule of one period at a time, above) */
.ps-go { display: grid; grid-template-columns: minmax(0, 1fr); align-content: start; }
.ps-go > * { grid-area: 1 / 1; min-width: 0; }

/* the checked list, under a rule */
.ps-card .ps-feats { display: grid; align-content: start; gap: 10px; margin: 0; padding: 20px 0 0; border-top: 1px solid var(--ps-rule); list-style: none; }
.ps-feats li { display: flex; align-items: flex-start; gap: 10px; color: var(--muted-foreground); font-size: 0.875rem; line-height: 1.45; }
.ps-check { flex: none; width: 20px; height: 20px; }
.ps-check circle { fill: rgba(var(--acc-rgb, var(--acc-emerald-rgb)), 0.12); stroke: rgba(var(--acc-rgb, var(--acc-emerald-rgb)), 0.45); stroke-width: 1; }
.ps-check path { fill: none; stroke: var(--acc, var(--acc-emerald)); stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }

/* ==== the Free card when there is room: a calm row above the plans on sale, its facts beside its price, its button at the end ==== */
@container ps (min-width: 620px) {
  .ps-grid > .ps-free { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1.2fr); grid-template-areas: "head feats" "cost feats" "cta feats";
    align-content: start; column-gap: 32px; row-gap: 16px; }
  .ps-free > .ps-head { grid-area: head; }
  .ps-free > .ps-cost { grid-area: cost; }
  .ps-free > :is(.ps-cta, .ps-go) { grid-area: cta; align-self: start; }
  .ps-grid > .ps-free > .ps-feats { grid-area: feats; padding: 0 0 0 32px; border-top: 0; border-left: 1px solid var(--ps-rule); }
  .ps-free .ps-row { display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 10px; }
}
@container ps (min-width: 900px) {
  .ps-grid > .ps-free { grid-template-columns: minmax(0, 17rem) minmax(0, 1fr) minmax(12rem, auto); grid-template-areas: "head feats cta" "cost feats cta";
    align-items: center; row-gap: 12px; }
  .ps-free > .ps-head { align-self: end; }
  .ps-free > .ps-cost { align-self: start; }
  .ps-free > .ps-cta { align-self: center; }
  .ps-grid > .ps-free > .ps-feats { grid-auto-flow: column; grid-template-columns: repeat(2, minmax(0, 1fr)); grid-template-rows: repeat(3, auto); column-gap: 24px;
    align-self: center; }   /* read down the first column, then the second */
}

/* three plans in two columns: the third would stand alone beside a hole, so it lies across both, laid out as the Free card is */
@container ps (min-width: 620px) and (max-width: 1039.98px) {
  .ps-grid[data-cols="3"] > .ps-card:not(.ps-free):last-child { grid-column: 1 / -1; grid-row: auto; display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1.2fr);
    grid-template-rows: none; grid-template-areas: "head feats" "cost feats" "cta feats"; align-content: start; column-gap: 32px; row-gap: 16px; }
  .ps-grid[data-cols="3"] > .ps-card:not(.ps-free):last-child > .ps-head { grid-area: head; }
  .ps-grid[data-cols="3"] > .ps-card:not(.ps-free):last-child > .ps-cost { grid-area: cost; }
  .ps-grid[data-cols="3"] > .ps-card:not(.ps-free):last-child > :is(.ps-cta, .ps-go) { grid-area: cta; align-self: start; }
  .ps-grid[data-cols="3"] > .ps-card:not(.ps-free):last-child > .ps-feats { grid-area: feats; padding: 0 0 0 32px; border-top: 0; border-left: 1px solid var(--ps-rule); }
}

/* ==== the entrance (armed by the script, piece by piece, and only for a piece that starts below the screen): the heading's words come down into
   their line one after another, then each piece of the section arrives in turn. Each ends where the page had it. ==== */
.ps-wait { opacity: 0; transform: translateY(-14px); }   /* set aside without a transition: nothing fades out below the screen */
.ps-step { transition: opacity var(--ps-enter) var(--motion-ease-out, ease-out), transform var(--ps-enter) var(--motion-ease-out, ease-out);
  transition-delay: calc(var(--ps-i, 0) * var(--ps-step-gap)); }
.ps-word { display: inline-block; clip-path: inset(0 -0.1em -0.25em); }
.ps-word > span { display: inline-block; }
.is-wait > .ps-word > span { transform: translateY(-115%); }
.is-play > .ps-word > span { transition: transform var(--ps-word) var(--motion-ease-out, cubic-bezier(0.23, 1, 0.32, 1));
  transition-delay: calc(var(--ps-i, 0) * var(--ps-word-gap)); }

/* ==== still: the system asks for less motion, or the page's motion is off. The script neither arms the entrance nor rolls a digit;
   these rules hold the same line for a setting that changes while the page is open. Calm (the app's middle setting): the fades stay,
   nothing moves. ==== */
@media (prefers-reduced-motion: reduce) {
  :root { --ps-roll: 0ms; --ps-digit-gap: 0ms; --ps-fade: 0ms; --ps-enter: 0ms; --ps-step-gap: 0ms; --ps-word: 0ms; --ps-word-gap: 0ms; }
  .ps-tabs::before, .ps-slot, .ps-reel, .ps-cta, .ps-step, .ps-word > span { transition-duration: 0s; transition-delay: 0s; }
  .ps-wait { opacity: 1; transform: none; }
  .is-wait > .ps-word > span { transform: none; }
}
:root[data-motion="off"] { --ps-roll: 0ms; --ps-digit-gap: 0ms; --ps-fade: 0ms; --ps-enter: 0ms; --ps-step-gap: 0ms; --ps-word: 0ms; --ps-word-gap: 0ms; }
:root[data-motion="off"] .ps-tabs::before, :root[data-motion="off"] :is(.ps-slot, .ps-reel, .ps-cta, .ps-step, .ps-word > span) { transition-duration: 0s; transition-delay: 0s; }
:root[data-motion="off"] .ps-wait { opacity: 1; transform: none; }
:root[data-motion="off"] .is-wait > .ps-word > span { transform: none; }
:root[data-motion="calm"] { --ps-roll: 0ms; --ps-digit-gap: 0ms; --ps-word: 0ms; --ps-word-gap: 0ms; }
:root[data-motion="calm"] .ps-tabs::before, :root[data-motion="calm"] :is(.ps-cta, .ps-word > span) { transition-duration: 0s; transition-delay: 0s; }
:root[data-motion="calm"] .ps-wait, :root[data-motion="calm"] .is-wait > .ps-word > span { transform: none; }

/* forced colours: the system draws the chosen tab and the buttons. Print: paper shows what is chosen, at rest. */
@media (forced-colors: active) {
  .ps-tabs::before { display: none; }
  .ps-tab[aria-checked="true"] { outline: 2px solid Highlight; outline-offset: -2px; color: ButtonText; }
  .ps-cta { border-color: ButtonText; }
  .ps-check circle, .ps-check path { stroke: CanvasText; }
}
@media print {
  .ps-switch { display: none !important; }
  .ps-wait { opacity: 1; transform: none; }
  .is-wait > .ps-word > span { transform: none; }
}
