/* =============================================================================
   cst-public.css — the public / Tier A component system

   Phase 3 Step 2 (docs/decisions.md D18): every comp class now carries the
   `cst-` prefix and the `.cst-page` scope is gone. Components are therefore
   collision-free and usable anywhere, not only inside a comp page wrapper.

   The nine classes that collided with real Tabler components — btn, card,
   grid, steps, tag, avatar, carousel, lead, stars — were the reason the scope
   existed. See docs/style-guide/06-migration.md for the full rename map.

   THE ELEMENT RESETS ARE NOW CLASSES
     .cst-h1 .cst-h2 .cst-h3 .cst-h4   were bare h1-h4
     .cst-p                             was bare p
     .cst-link-plain                    was bare a
     .cst-btn-reset                     was bare button
     .cst-media                         was bare img, svg
     .cst-typography                    was the .cst-page rule itself — the
                                        comp type context (17px Roboto/1.6).
                                        Nothing selects through it.
   `* { box-sizing }` was deleted — Tabler already sets it. `:focus-visible`
   and the reduced-motion block are now global; both are correct site-wide and
   neither can override an explicit style already in the tree.

   Generated by docs/tools/rename-comp-classes.py. Regenerating overwrites this
   file, so edit the script rather than the output while the alias block lives.
   ============================================================================= */

.cst-typography { -webkit-text-size-adjust:100%; background:var(--cst-surface); color:var(--cst-ink); font-family:Roboto,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif; font-size:17px; line-height:1.6; -webkit-font-smoothing:antialiased }
.cst-media { display:block }

/* --- Mobile gutter ----------------------------------------------------------
   Tabler drops --tblr-page-padding from 1rem to 0.5rem below 992px, and every
   section on these pages takes its side padding from it through .container-xl
   (padding-inline: calc(--tblr-gutter-x * .5), where the gutter is that token
   doubled). 8px either side reads as no margin at all on a phone: headings and
   card edges sit against the bezel.

   Raising the token on the wrapper rather than restyling .container-xl keeps
   this inside Tabler's own mechanism - anything that reads the token inside
   <main> follows - and scopes it to the four pages that carry .cst-typography
   (home, /IACET/, /team-enrollment/, /onboarding/). The admin and account
   layouts are outside this wrapper and keep Tabler's value.

   1rem, i.e. Tabler's own desktop value, not a larger invented one: the column
   is already narrow at this width and the content should not be squeezed
   further than it needs to be. */
@media (max-width: 991.98px) {
	.cst-typography { --tblr-page-padding: 1rem; }
}

/* The guard against any full-bleed breakout turning into a horizontal scroll.
   c-theme.css carries the identical rule for its pages, with the same
   reasoning: overflow-x:clip behaves like hidden but does NOT establish a
   scroll container, so sticky positioning elsewhere still works. This file had
   no equivalent, which is why the navbar's over-wide brand lockup (see
   .cst-brand-logo in cst-components.css, fixed at source) was free to drag the
   whole page sideways on a phone. Belt and braces - the overflow itself is
   fixed, this stops the next one being a user-visible bug. */
body { overflow-x: clip; }

/* --- .cst-typography bare-element resets (D18 / Phase 4 Tier A) -------------
   The D18 rename turned the .cst-page bare-element rules into standalone
   classes (.cst-h1, .cst-p, .cst-media, .cst-link-plain, .cst-btn-reset). The
   Tier A pages use semantic elements, not those classes, so re-scope the same
   resets under .cst-typography — the wrapper that replaces .cst-page. Values
   are identical to the ALIAS block's .cst-page rules, so the swap is visually
   a no-op; this lets that block be deleted once all three Tier A pages carry
   .cst-typography instead of .cst-page. */
.cst-typography img, .cst-typography svg { display:block }
.cst-typography a { color:inherit; text-decoration:none }
.cst-typography button { font:inherit; color:inherit; border:0; background:none; cursor:pointer }
.cst-typography h1, .cst-typography h2, .cst-typography h3, .cst-typography h4 { margin:0; letter-spacing:0; line-height:1.28; font-weight:700; text-wrap:balance }
.cst-typography h1 { font-size:34px; font-weight:900; line-height:1.22 }
.cst-typography h2 { font-size:27px; font-weight:900 }
.cst-typography h3 { font-size:18px; font-weight:700; letter-spacing:0 }
.cst-typography p { margin:0 }
@media(min-width:64rem){
	.cst-typography h1 { font-size:44px }
	.cst-typography h2 { font-size:31px }
}
.cst-link-plain { color:inherit;text-decoration:none }
.cst-btn-reset { font:inherit;color:inherit;border:0;background:none;cursor:pointer }
:focus-visible { outline:2px solid var(--cst-accent); outline-offset:2px; border-radius:2px }
/* padding-block, NOT the `56px 0` shorthand it used to be. Most sections put
   .cst-sec on the band and .container-xl on a div inside it, where the two never
   met - but the home page also writes <section class="cst-sec container-xl">
   ("What operators get"), and there the shorthand's horizontal 0 overwrote the
   container's own gutter, because this file loads after tabler.min.css. That
   section ran flush to both screen edges. Vertical-only padding leaves the
   band-plus-inner-div case byte-identical (horizontal padding stays 0 there,
   which is what `0` was setting anyway) and lets the container keep its gutter
   when the two classes share an element. Same fix on .cst-hero below. */
.cst-sec { padding-block:56px }
.cst-band { background:var(--cst-band); border-top:1px solid var(--cst-border-subtle); border-bottom:1px solid var(--cst-border-subtle) }
.cst-band--tint { background:var(--cst-accent-pale); border-color:var(--cst-tint-band-border) }
.cst-band--sand { background:var(--cst-sand); border-color:var(--cst-sand-line) }
.cst-dark { background:var(--cst-ink); color:var(--cst-surface); border:0 }
.cst-dark--green { background:var(--cst-accent) }
.cst-dark--green .cst-card { background:var(--cst-dark-green-card);border-color:var(--cst-dark-green-border) }
.cst-dark--green .cst-bar { background:var(--cst-dark-green-border) }
.cst-dark--green .cst-eyebrow { color:var(--cst-badge) }
.cst-dark--green .cst-ico { color:var(--cst-badge) }
.cst-dark--green .cst-stat span { color:var(--cst-dark-green-stat) }
.cst-dark--green p { color:var(--cst-dark-green-text) }
.cst-dark--green .cst-statrow { border-top-color:var(--cst-dark-green-border) }
.cst-dark--green .cst-priceline { border-color:var(--cst-badge) }
.cst-band--accent { background:var(--cst-accent); color:var(--cst-surface); border:0 }
.cst-dark h2, .cst-band--accent h2, .cst-dark h3, .cst-band--accent h3, .cst-dark h4 { color:var(--cst-surface) }
.cst-dark p, .cst-band--accent p { color:var(--cst-dark-body-text) }
.cst-dark .cst-sub, .cst-band--accent .cst-sub { color:var(--cst-dark-sub-text) }
.cst-band--accent .cst-eyebrow { color:var(--cst-badge) }
.cst-dark .cst-card { background:var(--cst-dark-surface); border-color:var(--cst-ink-soft) }
.cst-dark .cst-card--hov:hover { box-shadow:0 4px 14px rgb(0 0 0 / 45%) }
.cst-dark .cst-card h3 { color:var(--cst-surface) }
.cst-dark .cst-card p { color:var(--cst-dark-card-text) }
.cst-dark .cst-kicker, .cst-dark .cst-role, .cst-dark .cst-meta, .cst-dark .cst-by, .cst-dark .cst-railcap, .cst-dark .cst-mcard p { color:var(--cst-dark-muted-text) }
.cst-dark .cst-ico { color:var(--cst-dark-icon) }
.cst-dark .cst-bar { background:var(--cst-ink-soft) }
.cst-dark .cst-tag { color:var(--cst-badge);background:transparent;border-color:var(--cst-gold) }
.cst-dark .cst-divider-line { background:var(--cst-ink-soft) }
.cst-band--tint .cst-card { background:var(--cst-surface);border-color:var(--cst-tint-band-border) }
.cst-band--sand .cst-card { background:var(--cst-surface);border-color:var(--cst-sand-line) }
.cst-band--sand .cst-step { border-top-color:var(--cst-sand-line) }
.cst-h1, .cst-h2, .cst-h3, .cst-h4 { margin:0; letter-spacing:0; line-height:1.28; font-weight:700; text-wrap:balance }
.cst-h1 { font-size:34px;font-weight:900;line-height:1.22 }
.cst-h2 { font-size:27px;font-weight:900 }
.cst-h3 { font-size:18px; font-weight:700; letter-spacing:0 }
.cst-p { margin:0 }
.cst-lead { font-size:18px; color:var(--cst-ink-soft); line-height:1.55; text-wrap:balance }
.cst-sub { font-size:17px;line-height:1.6; font-weight:500; color:var(--cst-ink-soft); margin-top:12px; max-width:none; text-wrap:balance }
.cst-eyebrow { font-size:13px; font-weight:700; letter-spacing:.06em; text-transform:uppercase; color:var(--cst-accent); margin-bottom:10px }
.cst-dark .cst-eyebrow { color:var(--cst-eyebrow-green) }
.cst-accent-text { color:var(--cst-accent) }
.cst-tnum { font-variant-numeric:tabular-nums }
.cst-head { margin-bottom:28px }
.cst-ico { width:24px;height:24px;fill:none;stroke:currentColor;stroke-width:1.6;stroke-linecap:round;stroke-linejoin:round;flex:none }
.cst-ico--sm { width:16px;height:16px;stroke-width:1.8 }
.cst-ico--20 { width:20px;height:20px }
.cst-ico--star { width:14px;height:14px;fill:var(--cst-terracotta);stroke:none }
/* border:0 belongs on the component, not on a page wrapper. Until the catalog
   cards, every .cst-btn in the codebase was an <a>, which has no UA border, so
   the missing declaration never showed. On a <button> it does — and the reset
   that used to cover it (.cst-typography button) is deliberately scoped, since
   making it global would strip .btn / .btn-close / .navbar-toggler site-wide.
   The variants that want a border declare their own below. */
.cst-btn { display:inline-flex;align-items:center;justify-content:center;gap:8px;padding:13px 20px;border:0;border-radius:var(--cst-radius);font-weight:700;font-size:16px;transition:background .15s,color .15s,border-color .15s }
.cst-btn--p { background:var(--cst-accent);color:var(--cst-surface) }
.cst-btn--p:hover { background:var(--cst-accent-hover) }
.cst-btn--s { background:var(--cst-surface);color:var(--cst-accent);border:1px solid var(--cst-accent) }
.cst-btn--s:hover { background:var(--cst-accent-pale) }
.cst-btn--g { padding:10px 12px;font-weight:700 }
.cst-btn--g:hover { color:var(--cst-accent) }
.cst-btn--onDark { background:transparent;color:var(--cst-surface);border:1px solid var(--cst-surface) }
.cst-btn--onDark:hover { background:rgb(255 255 255 / 12%) }
.cst-btn--sm { padding:10px 16px;font-size:15px }
/* The wrapper element resets — .cst-typography a / .cst-oc-page a { color:inherit }
   and .cst-typography button { color:inherit;background:none } — are (0,1,1),
   which outranks the single-class .cst-btn--* rules above. Inside those wrappers
   a primary button kept its green fill but drew its label in the inherited body
   colour instead of white (and a <button> lost the fill outright). Re-assert fill
   and label with an element qualifier: (0,1,1) beats the resets, and still loses
   to the two-class band overrides below (.cst-band--accent / .cst-oc-final-cta),
   so the inverted-on-accent buttons are unaffected. Hover needs no twin — the
   :hover rules above are already (0,2,0). */
a.cst-btn--p, button.cst-btn--p { background:var(--cst-accent);color:var(--cst-surface) }
a.cst-btn--s, button.cst-btn--s { background:var(--cst-surface);color:var(--cst-accent) }
a.cst-btn--onDark, button.cst-btn--onDark { background:transparent;color:var(--cst-surface) }
/* Link inside a sentence. The same wrapper resets strip colour and underline
   from every anchor — right for cards and buttons, but it leaves a prose link
   indistinguishable from the text around it. Element-qualified for the same
   specificity reason as the buttons above. */
a.cst-inline-link { color:var(--cst-accent);text-decoration:underline;text-underline-offset:2px }
a.cst-inline-link:hover { color:var(--cst-accent-hover) }
.cst-card { background:var(--cst-surface);border:1px solid var(--cst-border);border-radius:var(--cst-radius) }
.cst-card--hov { transition:box-shadow .15s }
.cst-card--hov:hover { box-shadow:var(--cst-shadow-hover) }
.cst-pill { display:inline-flex;align-items:center;gap:5px;font-size:13px;font-weight:500;padding:4px 9px;border-radius:2px;letter-spacing:.01em }
.cst-pill--badge { background:var(--cst-badge);color:var(--cst-badge-pill-text) }
.cst-pill--accent { background:var(--cst-accent-pale);color:var(--cst-accent) }
.cst-pill--warn { background:var(--cst-terracotta-pale);color:var(--cst-warm-text) }
.cst-tag { display:inline-block;font-size:12px;font-weight:500;letter-spacing:.04em;text-transform:uppercase;color:var(--cst-ink);background:var(--cst-terracotta-pale);border:1px dashed var(--cst-terracotta);padding:2px 6px;border-radius:2px;vertical-align:middle }
.cst-ph { position:relative;overflow:hidden;border-radius:var(--cst-radius); background: radial-gradient(120% 90% at 0% 0%, rgb(255 255 255 / 55%) 0%, rgb(255 255 255 / 0%) 45%), radial-gradient(120% 110% at 100% 100%, rgb(28 29 31 / 55%) 0%, rgb(28 29 31 / 0%) 55%), linear-gradient(135deg, var(--cst-accent-pale) 0%, var(--cst-accent) 100%); }
.cst-ph::after { content:"";position:absolute;inset:0;opacity:.12;mix-blend-mode:overlay;pointer-events:none; background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E"); }
.cst-ph__mark { position:absolute;inset:0;display:flex;align-items:center;justify-content:center }
.cst-ph__mark svg { width:64px;height:64px;stroke:var(--cst-surface);opacity:.3;stroke-width:1.2;fill:none }
.cst-ph--sm .cst-ph__mark svg { width:40px;height:40px }
.cst-ph__cap { position:absolute;left:12px;bottom:12px;right:56px;background:rgb(28 29 31 / 78%);color:var(--cst-surface);font-size:12px;line-height:1.35;padding:7px 10px;border-radius:2px }
.cst-ph__flag { position:absolute;top:10px;right:10px;background:var(--cst-ink);color:var(--cst-terracotta);font-size:12px;font-weight:700;letter-spacing:.04em;padding:4px 8px;border-radius:2px;z-index:2 }
.cst-r-16-9 { aspect-ratio:16/9 }
.cst-r-16-10 { aspect-ratio:16/10 }
.cst-r-4-3 { aspect-ratio:4/3 }
.cst-mockbar { background:var(--cst-terracotta);color:var(--cst-ink);font-size:12px;font-weight:600;text-align:center;padding:9px 16px;letter-spacing:.01em }
.cst-hero-band { background:linear-gradient(180deg,var(--cst-hero-band-bottom) 0%,var(--cst-hero-band-top) 100%);border-bottom:1px solid var(--cst-hero-band-border) }
/* Vertical only - see the note on .cst-sec. The hero is the one element on the
   home page written as <div class="cst-hero container-xl">, so the old
   `44px 0 52px` zeroed its gutter and the h1, the lead and the CTA buttons all
   started at x=0 on a phone. */
.cst-hero { padding-block:44px 52px }
.cst-hero__grid { display:grid;gap:34px }
.cst-hero h1 { margin-bottom:16px }
.cst-hero .cst-lead { max-width:56ch }
.cst-hero__cta { display:flex;flex-wrap:wrap;gap:12px;margin-top:24px }
.cst-trustline { display:flex;flex-wrap:wrap;align-items:center;gap:10px 18px;margin-top:24px;font-size:15px;font-weight:500;color:var(--cst-muted) }
.cst-trustline span { display:inline-flex;align-items:center;gap:7px }
.cst-trustline i { width:1px;height:14px;background:var(--cst-border);display:none }
@media(min-width:48rem) {
	.cst-trustline i { display:block }
}
.cst-hero__media { position:relative }
.cst-dashcard { display:none;position:absolute;left:16px;bottom:16px;width:262px;background:var(--cst-surface);border:1px solid var(--cst-border);border-radius:var(--cst-radius);padding:14px }
.cst-dashcard h4 { font-size:14px;font-weight:700;letter-spacing:0;margin-bottom:10px }
.cst-drow { display:flex;align-items:center;gap:8px;margin-bottom:9px;font-size:13px;color:var(--cst-muted) }
.cst-drow b { color:var(--cst-ink);font-size:13px;margin-left:auto;font-variant-numeric:tabular-nums }
.cst-drow .cst-lbl { width:64px;flex:none }
.cst-bar { flex:1;height:4px;background:var(--cst-border-subtle);border-radius:2px;overflow:hidden }
.cst-bar i { display:block;height:100%;background:var(--cst-accent);border-radius:2px }
.cst-bar i.cst-warn { background:var(--cst-terracotta) }
.cst-dashcard .cst-note { font-size:12px;color:var(--cst-muted);margin-top:4px }
/* Image variant: the card is one graphic rather than built rows, so it carries
   no padding and the image fills the box edge to edge inside the border. The
   caption keeps its own padding below the image and is divided off with the same
   hairline the card's own border uses.

   No line-height:0 on the card to kill the inline-image gap - that would flatten
   the caption too. `display:block` on the img does the same job locally.

   The card no longer takes .cst-dashcard's fixed 262px. It is shrink-to-fit, so
   it hugs whatever the graphic's natural width is and the file can be re-exported
   wider without touching CSS. The cap keeps it inside .cst-hero__media at the
   16px inset the `left` offset establishes. */
.cst-dashcard--img { width:auto;max-width:calc(100% - 32px);padding:0;overflow:hidden }
/* 100%, not auto: the card's width is max(graphic, caption). If the caption is
   the wider of the two, auto would leave the graphic short of the right edge
   with a band of card showing beside it. */
.cst-dashcard--img img { display:block;width:100%;height:auto }
/* nowrap: the caption is one line by design. Because the card above is
   shrink-to-fit, this also sets the card's floor - if the graphic is narrower
   than the caption, the card widens to the caption rather than wrapping it. */
.cst-dashcard__cap { margin:0;padding:9px 12px 10px;border-top:1px solid var(--cst-border);font-size:12px;line-height:1.35;color:var(--cst-muted);white-space:nowrap }
.cst-dashcard__cap b { color:var(--cst-ink);font-weight:700 }
@media(min-width:48rem) {
	.cst-dashcard { display:block }
}
@media(min-width:64rem) {
	.cst-hero__grid { grid-template-columns:1.05fr .95fr;align-items:center;gap:56px }
	.cst-h1 { font-size:44px }
	.cst-h2 { font-size:31px }
}
.cst-trustbar { padding:28px 0 }
.cst-trustbar p { text-align:center;font-size:16px;font-weight:500;color:var(--cst-muted) }
.cst-logos { display:flex;flex-wrap:wrap;justify-content:center;gap:14px 26px;margin-top:18px }
.cst-logoph { width:124px;height:44px;background:var(--cst-logo-placeholder);border-radius:2px;display:flex;align-items:center;justify-content:center;gap:6px;color:var(--cst-surface);font-size:12px;font-weight:500;letter-spacing:.06em }
.cst-logoph svg { width:16px;height:16px;stroke:var(--cst-surface);stroke-width:1.6;fill:none }
.cst-tabs { display:flex;gap:22px;overflow-x:auto;border-bottom:1px solid var(--cst-border);margin:26px 0 22px;scrollbar-width:none;-webkit-overflow-scrolling:touch }
.cst-tabs::-webkit-scrollbar { display:none }
.cst-tab { font-size:16px;font-weight:500;color:var(--cst-muted);padding:0 0 12px;white-space:nowrap;border-bottom:2px solid transparent;margin-bottom:-1px }
.cst-tab:hover { color:var(--cst-ink) }
.cst-tab[aria-selected="true"] { color:var(--cst-ink);font-weight:700;border-bottom-color:var(--cst-ink) }
.cst-carousel { position:relative }
.cst-track { display:grid;grid-auto-flow:column;grid-auto-columns:264px;gap:16px;overflow-x:auto;scroll-snap-type:x mandatory;padding-bottom:6px;scrollbar-width:none }
.cst-track::-webkit-scrollbar { display:none }
.cst-track>* { scroll-snap-align:start }
/* The doubled class is deliberate, not a typo. .cst-arrow is a <button> and the
   only page that uses it sits inside .cst-typography, whose
   `button { background:none; border:0 }` reset is a class-plus-element rule -
   specificity (0,1,1), which outranks a bare .cst-arrow at (0,1,0). The arrows
   therefore painted as naked chevrons floating over the cards. Repeating the
   class lifts this to (0,2,0) without naming the wrapper, so the rule holds
   wherever the component is used. Same root cause as the .cst-btn note above. */
.cst-arrow.cst-arrow { display:none;position:absolute;top:calc(50% - 22px);z-index:5;width:44px;height:44px;border-radius:999px;background:var(--cst-surface);border:1px solid var(--cst-border);align-items:center;justify-content:center;box-shadow:var(--cst-shadow-hover) }
.cst-arrow.cst-arrow:hover { background:var(--cst-band) }
/* The track is a single-line scroller, so an arrow sitting at a scroll limit has
   nothing to do. Say so, rather than leaving a live-looking control that ignores
   clicks - which is exactly how the arrows read before they had a handler. */
.cst-arrow.cst-arrow[disabled] { opacity:.35;cursor:default;box-shadow:none }
.cst-arrow.cst-arrow[disabled]:hover { background:var(--cst-surface) }
.cst-arrow--l { left:-14px }
.cst-arrow--r { right:-14px }
@media(min-width:48rem) {
	/* Doubled to match the base rule above - a single class would now lose to it
	   and the arrows would stay hidden at every width. */
	.cst-arrow.cst-arrow { display:flex }
}
.cst-ccard { display:flex;flex-direction:column }
.cst-ccard__body { padding:12px 12px 14px }
.cst-ccard h3 { font-size:16px;line-height:1.35;margin-bottom:5px;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden }
.cst-ccard .cst-by { font-size:14px;color:var(--cst-muted) }
.cst-rating { display:flex;align-items:center;gap:6px;margin-top:8px;font-size:13px }
.cst-rating b { color:var(--cst-gold);font-size:15px;font-variant-numeric:tabular-nums }
.cst-rating .cst-stars { display:flex;gap:1px }
.cst-rating .cst-cnt { color:var(--cst-muted);font-weight:500;font-size:13px }
.cst-meta { font-size:14px;color:var(--cst-muted);margin-top:8px }
.cst-badges { display:flex;flex-wrap:wrap;gap:6px;margin-top:9px }
.cst-price { margin-top:12px;font-size:17px;font-weight:700 }
.cst-price s { font-weight:400;font-size:14px;color:var(--cst-muted);margin-left:7px }
.cst-rail { margin-top:8px;background:var(--cst-surface);border:1px solid var(--cst-border);border-radius:var(--cst-radius);padding:26px 24px }
.cst-railrow { margin-bottom:28px }
.cst-railrow:last-of-type { margin-bottom:22px }
/* Label text is ink, not --cst-rail-label: the burnt-orange reads as a second
   warning colour next to the peach fill and terracotta border, which already
   carry the "without" signal. --cst-ink on --cst-terracotta-pale is 13.64:1
   (01-foundations.md contrast table). The token still drives the .cst-gap
   handoff markers below, where the warm colour is the point. This rule alone
   does not reach the homepage rail — see the .cst-dark .cst-rail block after
   .cst-railcap. */
.cst-raillabel { display:inline-flex;align-items:center;gap:8px;font-size:14px;font-weight:700;letter-spacing:.04em;text-transform:uppercase;color:var(--cst-ink);background:var(--cst-terracotta-pale);border:1px solid var(--cst-terracotta);border-radius:2px;padding:4px 10px;margin-bottom:14px }
.cst-raillabel.cst-on { color:var(--cst-surface);background:var(--cst-accent);border-color:var(--cst-accent) }
.cst-segs { display:flex;align-items:stretch;gap:0 }
.cst-seg { flex:1;border:2px solid;border-radius:var(--cst-radius);padding:14px 12px;display:flex;align-items:center;gap:9px;font-size:15px;font-weight:700;min-width:0 }
.cst-seg small { display:block;font-size:14px;font-weight:500;color:var(--cst-muted);margin-top:3px }
.cst-seg span { min-width:0 }
.cst-seg b { display:block;font-weight:700;line-height:1.25 }
.cst-seg--a { background:var(--cst-segment-a-bg);border-color:var(--cst-logo-blue);color:var(--cst-ink) }
.cst-seg--a small { color:var(--cst-segment-a-text) }
.cst-seg--b { background:var(--cst-terracotta-pale);border-color:var(--cst-terracotta);color:var(--cst-ink) }
.cst-seg--b small { color:var(--cst-warm-text) }
.cst-seg--c { background:var(--cst-segment-c-bg);border-color:var(--cst-segment-c-border);color:var(--cst-ink) }
.cst-seg--c small { color:var(--cst-segment-c-text) }
.cst-gap { width:78px;flex:none;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:4px;font-size:12px;font-weight:700;color:var(--cst-rail-label);text-align:center;line-height:1.15;position:relative }
.cst-gap::before { content:"";position:absolute;left:50%;top:8px;bottom:8px;width:0;border-left:2px dashed var(--cst-terracotta);transform:translateX(-50%);opacity:.55 }
.cst-gap svg { stroke:var(--cst-rail-label);position:relative;background:var(--cst-surface);border-radius:2px }
.cst-gap em { position:relative;background:var(--cst-surface);font-style:normal;padding:2px 3px }
.cst-cont { display:flex;border:2px solid var(--cst-accent);border-radius:var(--cst-radius);overflow:hidden;background:var(--cst-accent) }
.cst-cont .cst-seg { border:0;border-radius:0;background:transparent;color:var(--cst-surface) }
.cst-cont .cst-seg small { color:var(--cst-segment-contrast-text) }
.cst-cont .cst-seg+.cst-seg { border-left:2px solid rgb(255 255 255 / 35%) }
.cst-railcap { font-size:17px;line-height:1.6;font-weight:500;color:var(--cst-ink-soft);margin-top:16px;max-width:78ch;text-wrap:balance }
/* The rail is a WHITE card sitting inside the .cst-dark band, and the band's
   descendant rules assume everything under it is on dark: .cst-dark p (line 71)
   and .cst-dark .cst-railcap (line 78) are both two-class, so they outrank the
   one-class component rules above. The labels were painting #dbe2ec on peach
   and the captions #a9b6c9 on white — light-on-dark colours over a light
   surface. Re-assert the light-surface colours, scoped to the rail, at three
   classes. Anything in the rail that is not a <p> (the segments, the .cst-gap
   markers) never inherited the band colours and is left alone. */
.cst-dark .cst-rail .cst-raillabel { color:var(--cst-ink) }
.cst-dark .cst-rail .cst-raillabel.cst-on { color:var(--cst-surface) }
.cst-dark .cst-rail .cst-railcap { color:var(--cst-ink-soft) }
.cst-quotecard { background:var(--cst-surface);border:1px solid var(--cst-border);border-left:3px solid var(--cst-accent);border-radius:var(--cst-radius);padding:20px 22px;display:flex;gap:14px;margin-top:8px }
.cst-quotecard svg { stroke:var(--cst-accent);width:20px;height:20px;flex:none;margin-top:3px }
.cst-quotecard p { font-size:19px;line-height:1.55;font-weight:500;color:var(--cst-ink-soft);line-height:1.5 }
@media(max-width:47.99rem) {
	.cst-segs { flex-direction:column;gap:0 }
	.cst-gap { width:100%;flex-direction:row;padding:10px 0;gap:8px }
	.cst-gap::before { left:0;right:0;top:50%;bottom:auto;width:auto;height:0;border-left:0;border-top:2px dashed var(--cst-terracotta);transform:none }
	.cst-cont { flex-direction:column }
	.cst-cont .cst-seg+.cst-seg { border-left:0;border-top:1px solid rgb(22 38 60 / 22%) }
}
.cst-grid { display:grid;gap:20px }
@media(min-width:48rem) {
	.cst-g2 { grid-template-columns:repeat(2,1fr) }
	.cst-g3 { grid-template-columns:repeat(3,1fr) }
}
@media(min-width:64rem) {
	.cst-g4 { grid-template-columns:repeat(4,1fr) }
	.cst-g3 { grid-template-columns:repeat(3,1fr) }
}
@media(min-width:48rem) and (max-width:63.99rem) {
	.cst-g4 { grid-template-columns:repeat(2,1fr) }
}
.cst-bcard { padding:22px }
.cst-bcard .cst-ico { color:var(--cst-accent);margin-bottom:12px }
.cst-bcard .cst-kicker { font-size:13px;font-weight:700;letter-spacing:.05em;text-transform:uppercase;color:var(--cst-muted);margin-bottom:6px }
.cst-bcard p { font-size:16px;line-height:1.6;font-weight:400;color:var(--cst-ink-soft);margin-top:8px }
.cst-rcard { padding:22px }
.cst-rcard--lead { border-top:3px solid var(--cst-accent) }
.cst-rcard .cst-ico { color:var(--cst-accent);margin-bottom:12px }
.cst-rcard ul { list-style:none;margin:14px 0 0;padding:0 }
.cst-rcard li { display:flex;gap:10px;font-size:16px;color:var(--cst-ink-soft);margin-bottom:9px;line-height:1.45 }
.cst-rcard li svg { stroke:var(--cst-accent);flex:none;margin-top:3px }
.cst-rcard .cst-role { font-size:14px;color:var(--cst-muted);margin-top:4px }
.cst-qcard { padding:22px;display:flex;flex-direction:column }
.cst-qcard>svg { stroke:var(--cst-accent);width:22px;height:22px;margin-bottom:12px }
.cst-qcard p { font-size:17px;color:var(--cst-ink-soft);line-height:1.55 }
.cst-qcard .cst-who { display:flex;align-items:center;gap:11px;margin-top:auto;padding-top:18px }
.cst-avatar { width:48px;height:48px;border-radius:999px;flex:none;position:relative;overflow:hidden }
.cst-avatar .cst-ph__flag { display:none }
.cst-qcard .cst-name { font-size:15px;font-weight:700 }
.cst-qcard .cst-title { font-size:14px;color:var(--cst-muted) }
.cst-qcard--empty { border-style:dashed;opacity:.5;align-items:flex-start;justify-content:center;min-height:200px }
.cst-qcard--empty p { font-size:15px;font-weight:500;color:var(--cst-muted) }
.cst-tile { overflow:hidden;display:flex;flex-direction:column }
.cst-tile__body { padding:18px }
.cst-tile p { font-size:16px;line-height:1.6;font-weight:500;color:var(--cst-ink-soft);margin-top:7px }
.cst-tile a { display:inline-flex;align-items:center;gap:6px;color:var(--cst-logo-blue);font-weight:700;font-size:15px;margin-top:14px }
.cst-steps { display:grid;gap:26px;margin-top:8px }
.cst-step { padding-top:20px;border-top:1px solid var(--cst-border) }
.cst-step .cst-num { font-size:28px;font-weight:700;color:var(--cst-accent);letter-spacing:-.03em;line-height:1 }
.cst-step .cst-ico { color:var(--cst-accent);margin:12px 0 10px }
.cst-step p { font-size:16px;line-height:1.6;font-weight:500;color:var(--cst-ink-soft);margin-top:7px }
@media(min-width:48rem) {
	.cst-steps { grid-template-columns:repeat(3,1fr);gap:32px }
}
.cst-teams__grid { display:grid;gap:32px }
.cst-dark h2 { color:var(--cst-surface) }
.cst-dark p { color:var(--cst-dark-body-text) }
.cst-teams .cst-priceline { font-size:14px;color:var(--cst-surface);font-weight:600;margin-top:18px;padding:10px 14px;border:1px solid var(--cst-eyebrow-green);border-radius:var(--cst-radius);display:inline-block }
/* Link inside the price line. .cst-inline-link is accent green and would
   disappear against the green band, so this one takes the badge yellow the
   band already uses for the eyebrow and this pill's own border. */
.cst-teams .cst-priceline a { color:var(--cst-badge);text-decoration:underline;text-underline-offset:2px }
.cst-teams .cst-priceline a:hover { color:var(--cst-surface) }
.cst-teams__cta { display:flex;flex-wrap:wrap;gap:12px;margin-top:20px }
.cst-statrow { display:grid;gap:18px;margin-top:44px;padding-top:28px;border-top:1px solid var(--cst-ink-soft) }
.cst-stat b { display:block;font-size:30px;font-weight:700;letter-spacing:-.03em;color:var(--cst-surface);font-variant-numeric:tabular-nums }
.cst-stat span { font-size:15px;font-weight:500;color:var(--cst-dark-muted-text);display:block;margin-top:4px }
/* The stat row on a LIGHT band. It was built to close out the dark green Teams
   section, so its numbers are --cst-surface (white) and its labels are
   --cst-dark-muted-text: both vanish on --cst-accent-pale. It also carries a
   top border plus 44px/28px of separation, which earn their keep as a rule
   under the Teams content but read as a stray line when the row is a band of
   its own. Same context-override shape as the .cst-dark--green rules above.

   Flex rather than the inherited 4-column grid: there are three stats, so the
   grid left-shifted them into columns 1-3 and left a dead fourth. Flex with
   justify-content centres whatever number of stats the row actually holds, and
   wraps them instead of squeezing on a phone. */
.cst-band--tint .cst-statrow {
	margin-top:0;padding-top:0;border-top:0;
	display:flex;flex-wrap:wrap;justify-content:center;gap:28px 96px;text-align:center;
}
.cst-band--tint .cst-stat b { color:var(--cst-ink) }
.cst-band--tint .cst-stat span { color:var(--cst-ink-soft) }
@media(min-width:48rem) {
	.cst-teams__grid { grid-template-columns:1.1fr .9fr;align-items:center;gap:48px }
	.cst-statrow { grid-template-columns:repeat(4,1fr) }
}
.cst-mcard { padding:20px }
.cst-mcard__top { display:flex;align-items:flex-start;justify-content:space-between;gap:10px }
.cst-mcard .cst-big { font-size:32px;font-weight:700;letter-spacing:-.03em;font-variant-numeric:tabular-nums }
.cst-mcard__top .cst-ico { color:var(--cst-muted);opacity:.45 }
.cst-mcard h3 { font-size:17px;margin-top:6px }
.cst-mcard p { font-size:15px;line-height:1.55;font-weight:500;color:var(--cst-ink-soft);margin-top:6px }
.cst-mcard .cst-bar { margin-top:14px;height:4px }
.cst-mcard .cst-plabel { font-size:13px;color:var(--cst-terracotta-ink);font-weight:700;margin-top:10px }
.cst-final { text-align:center }
.cst-final p { margin:16px auto 0;max-width:60ch;color:var(--cst-ink-soft);font-size:19px;font-weight:500;line-height:1.6;text-wrap:balance }
.cst-final .cst-btn { margin-top:24px }
.cst-final .cst-direct { font-size:16px;font-weight:500;color:var(--cst-muted);margin-top:18px }
.cst-band--accent .cst-final p { color:var(--cst-accent-band-text) }
.cst-band--accent .cst-final .cst-direct { color:var(--cst-accent-band-lead) }
.cst-band--accent .cst-btn--p { background:var(--cst-surface);color:var(--cst-accent-hover) }
.cst-band--accent .cst-btn--p:hover { background:var(--cst-accent-band-btn-hover) }
.cst-band--accent { position:relative }
.cst-band--accent::before { content:"";position:absolute;inset:0;pointer-events:none;opacity:.16; background-image:radial-gradient(rgb(255 255 255 / 85%) 1px, transparent 1px); background-size:18px 18px }
.cst-band--accent .container-xl { position:relative;z-index:1 }
.cst-ftr { padding:48px 0 0 }
.cst-ftr__grid { display:grid;gap:30px }
.cst-ftr h4 { font-size:15px;font-weight:700;letter-spacing:.02em;color:var(--cst-surface);margin-bottom:12px }
.cst-ftr ul { list-style:none;margin:0;padding:0 }
.cst-ftr li { margin-bottom:9px }
.cst-ftr a { font-size:16px;font-weight:500;color:var(--cst-footer-link) }
.cst-ftr a:hover { color:var(--cst-surface);text-decoration:underline }
.cst-ftr .cst-blurb { font-size:16px;line-height:1.6;font-weight:500;color:var(--cst-footer-text);max-width:34ch;margin-top:10px }
.cst-ftr__bot { margin-top:38px;padding:20px 0;border-top:1px solid var(--cst-ink-soft);display:flex;flex-wrap:wrap;gap:10px;justify-content:space-between;font-size:15px;font-weight:500;color:var(--cst-footer-text) }
.cst-ftr__bot a { font-size:15px;font-weight:700 }
@media(min-width:48rem) {
	.cst-ftr__grid { grid-template-columns:1.4fr 1fr 1fr 1fr }
}
@media(prefers-reduced-motion:reduce) {
	* { transition:none!important;animation:none!important;scroll-behavior:auto!important }
	.cst-track { scroll-snap-type:none }
}
.cst-oc-page h1, .cst-oc-page h2, .cst-oc-page h3 { margin: 0 0 .5em; font-weight: 700; line-height: 1.15; font-family: 'Roboto', system-ui, sans-serif; }
.cst-oc-page p { margin: 0 0 1em; color: var(--cst-ink-soft); }
.cst-oc-page img { max-width: 100%; display: block; }
.cst-oc-page a { color: inherit; }
/* …except a button. The a.cst-btn--* rules near line 127 already re-assert the
   button colours over a wrapper reset, but they only beat .cst-typography a
   because that one is declared ABOVE them. This reset is declared BELOW, at
   identical specificity (0,1,1), so on .cst-oc-page it won instead — every
   primary button on /team-enrollment/ and /onboarding/ kept its green fill and
   drew its label in the inherited body ink rather than white. Two classes plus
   the element settles it. The inverted buttons on the accent band are restated
   at the same weight further down (.cst-oc-final-cta), after these. */
.cst-oc-page a.cst-btn--p { color: var(--cst-surface); }
.cst-oc-page a.cst-btn--s { color: var(--cst-accent); }
.cst-oc-wrap { max-width: 1120px; margin: 0 auto; padding: 0 24px; }
.cst-oc-eyebrow { display: inline-block; font-size: .78rem; font-weight: 700; letter-spacing: .08em; text-transform: uppercase; color: var(--cst-accent-hover); margin-bottom: .75em; }
.cst-oc-page .cst-oc-bleed { position: relative; isolation: isolate; }
.cst-oc-page .cst-oc-bleed::before { content: ''; position: absolute; inset-block: 0; left: calc(50% - 50vw); right: calc(50% - 50vw); z-index: -1; pointer-events: none; }
.cst-oc-stats-section::before { background: var(--cst-band); }
.cst-oc-section--alt::before { background: var(--cst-band); }
.cst-oc-final-cta::before { background: var(--cst-accent-hover); }
.cst-oc-hero { padding: 64px 0 48px; }
.cst-oc-hero .cst-oc-wrap { max-width: 760px; text-align: left; }
.cst-oc-hero h1 { font-size: clamp(2rem, 4.4vw, 3rem); color: var(--cst-ink); }
.cst-oc-hero h1 em { color: var(--cst-accent-hover); font-style: italic; }
.cst-oc-hero .cst-oc-lede { font-size: 1.15rem; max-width: 620px; }
/* Same problem the FAQ answers have, same fix. `.cst-oc-page a { color: inherit }`
   below is declared later at equal specificity, so a bare .cst-inline-link in the
   lede renders as plain body text. Two classes plus the element wins. */
.cst-oc-hero .cst-oc-lede a { color: var(--cst-accent-hover); text-decoration: underline; text-underline-offset: 2px; }
.cst-oc-hero .cst-oc-lede a:hover { color: var(--cst-accent); }
.cst-oc-hero-bullets { list-style: none; margin: 28px 0 32px; padding: 0; display: grid; gap: 14px; }
.cst-oc-hero-bullets li { position: relative; padding-left: 30px; font-size: 1rem; color: var(--cst-ink); font-weight: 500; }
.cst-oc-hero-bullets li::before { content: ''; position: absolute; left: 0; top: .35em; width: 16px; height: 16px; border-radius: 5px; background: var(--cst-accent); }
.cst-oc-btn-row { display: flex; flex-wrap: wrap; gap: 14px; }

/* DEPRECATED 2026-09-17, and unused. Use .cst-btn / --p / --s (line ~108).

   This was a parallel button system on two landing pages: a 999px pill against
   the styleguide's var(--cst-radius), its own padding and font size, and a
   lift-and-shadow hover nothing else in the site does. It also hard-coded
   rgba(127,190,65,.35) rather than reading a token.

   Kept rather than deleted, per the don't-decommission rule - but do not reach
   for it. Anything that needs a button on those pages should use .cst-btn, and
   on the final CTA band the .cst-oc-final-cta overrides below invert it the way
   .cst-band--accent does on the home page. */
.cst-oc-btn { display: inline-block; padding: 14px 28px; border-radius: 999px; font-weight: 700; font-size: .95rem; text-decoration: none; transition: transform .15s ease, box-shadow .15s ease; cursor: pointer; border: none; }
.cst-oc-btn--primary { background: var(--cst-accent); color: var(--cst-surface); }
.cst-oc-btn--primary:hover { transform: translateY(-2px); box-shadow: 0 10px 20px rgba(127,190,65,.35); color: var(--cst-surface); text-decoration: none; }
.cst-oc-btn--secondary { background: transparent; color: var(--cst-ink); border: 2px solid var(--cst-ink); }
.cst-oc-btn--secondary:hover { background: var(--cst-ink); color: var(--cst-surface); text-decoration: none; }
.cst-oc-stats-section { padding: 36px 0; }
.cst-oc-stats { display: grid; grid-template-columns: repeat(3, 1fr); gap: 20px; text-align: center; }
.cst-oc-stat b { display: block; font-size: 2rem; color: var(--cst-ink); font-weight: 700; }
.cst-oc-stat span { font-size: .85rem; color: var(--cst-ink-soft); }
.cst-oc-section { padding: 72px 0; }
.cst-oc-section-head { max-width: 680px; margin-bottom: 40px; }
.cst-oc-section-head h2 { font-size: clamp(1.6rem, 3vw, 2.2rem); color: var(--cst-ink); }
.cst-oc-course-groups { display: grid; grid-template-columns: repeat(2, 1fr); gap: 20px; }
.cst-oc-course-group { background: var(--cst-surface); border: 1px solid var(--cst-border-subtle); border-radius: var(--cst-radius); padding: 26px 28px; box-shadow: var(--cst-shadow-hover); }
.cst-oc-course-group h3 { font-size: .78rem; text-transform: uppercase; letter-spacing: .06em; color: var(--cst-accent-hover); font-weight: 700; margin-bottom: 14px; }
.cst-oc-course-group ul { list-style: none; margin: 0; padding: 0; display: grid; gap: 14px; }
.cst-oc-course-group li b { display: block; color: var(--cst-ink); font-size: 1rem; font-weight: 700; }
.cst-oc-course-group li span { font-size: .92rem; color: var(--cst-ink-soft); }
/* 28px put this hard against the last row of the course grid, where it read as a
   fourth course rather than a note about all twelve. 52px is enough of a break
   that it reads as its own thing without becoming a new section.

   TWO CLASSES, and that is the whole reason this works. As `.cst-oc-course-note`
   alone it is (0,1,0), and `.cst-oc-page p` at line 444 is (0,1,1) - so that
   rule won and its `margin: 0 0 1em` SHORTHAND reset margin-top to 0. Being
   later in the file does not help; specificity is settled before source order.
   The 28px this replaced had never applied either, for the same reason.

   Only margin-top is set here, so the 1em bottom margin `.cst-oc-page p` gives
   every paragraph on these pages still applies. */
.cst-oc-page .cst-oc-course-note { margin-top: 52px; }
.cst-oc-course-note { max-width: 680px; font-size: .95rem; }
.cst-oc-steps { display: grid; grid-template-columns: repeat(3, 1fr); gap: 28px; }
/* .cst-oc-steps carries no top margin of its own because on /onboarding/ it
   follows a .cst-oc-section-head, whose 40px margin-bottom is the gap. On
   /team-enrollment/ the steps sit straight under the pricing card with no head
   between them, so there was nothing to space them and 01/02/03 butted against
   the card. Same 40px, so both pages keep one rhythm. */
.cst-oc-price-card + .cst-oc-steps { margin-top: 40px; }
.cst-oc-step .cst-oc-num { font-size: .85rem; font-weight: 700; color: var(--cst-accent); letter-spacing: .05em; margin-bottom: 10px; display: block; }
.cst-oc-step h3 { font-size: 1.15rem; color: var(--cst-ink); }
.cst-oc-step p { font-size: .95rem; }
.cst-oc-price-card { background: var(--cst-ink); color: var(--cst-surface); border-radius: 20px; padding: 48px; display: grid; grid-template-columns: 1.1fr .9fr; gap: 40px; align-items: center; }
.cst-oc-price-card h2 { color: var(--cst-surface); }
/* The eyebrow above that h2. .cst-oc-eyebrow is --cst-accent-hover, a green
   picked to sit on the page's light ground; this card is --cst-ink, so it read
   as a dim green smudge over the heading it is supposed to label. White, the
   same token the h2 and the price take, so the three lines read as one block.
   Same move .cst-oc-final-cta makes for its eyebrow on the accent band. */
.cst-oc-price-card .cst-oc-eyebrow { color: var(--cst-surface); }
.cst-oc-price-card p { color: var(--cst-border); }
/* Buy Licenses, inverted for this card. .cst-btn--p is --cst-accent green on white
   text, which is built to sit on the page's light ground; on --cst-ink it was a
   dark green block on dark navy, so the one control the card exists to present
   was the hardest thing on it to see.

   Same inversion .cst-oc-final-cta makes on the accent band, and by the same
   rule: the button takes the surface colour, and its LABEL takes the band's own
   background - green there, navy here - so the button reads as the band turned
   inside out rather than as a second brand colour arriving on the card.

   The hover is the neutral band rather than the final CTA's pale green, which
   would pull a third hue onto a navy card for no reason. */
.cst-oc-price-card a.cst-btn--p { background: var(--cst-surface); color: var(--cst-ink); }
.cst-oc-price-card a.cst-btn--p:hover { background: var(--cst-band); color: var(--cst-ink); }
/* The seat calculator, sitting on the --cst-ink card. The white overlay was .06,
   which over #16263c lifts each channel by about 14 - close enough to the card
   that the panel edge was carried almost entirely by its border, and the two
   blues read as one surface with a line drawn on it. At .12 the lift is about
   28, so the panel is visibly its own plane while still clearly belonging to the
   card rather than being a separate colour.

   Kept as a white overlay rather than a literal hex, so the panel still tracks
   --cst-ink if that token is ever retuned. The border comes up with it: at .18
   against a lighter panel it was the weaker of the two edges. */
.cst-oc-price-box { background: rgba(255,255,255,.12); border: 1px solid rgba(255,255,255,.28); border-radius: var(--cst-radius); padding: 32px; text-align: center; }
/* White and bold, not muted grey: this sits inside .cst-oc-price-box on the dark
   .cst-oc-price-card, where --cst-muted is the colour of text meant to recede on
   a LIGHT surface and came out nearly illegible. The struck price is half the
   comparison the card is making, so it has to be readable. */
.cst-oc-price-old { font-size: 1.2rem; color: var(--cst-surface); font-weight: 700; text-decoration: line-through; }
.cst-oc-price-new { font-size: 3rem; font-weight: 700; color: var(--cst-surface); margin: 6px 0; }
.cst-oc-save-badge { display: inline-block; background: var(--cst-terracotta); color: var(--cst-ink); font-weight: 700; font-size: .82rem; border-radius: 999px; padding: 5px 14px; margin-bottom: 10px; }
.cst-oc-price-box .cst-oc-btn--primary { width: 100%; margin-top: 16px; display: block; text-align: center; }
.cst-oc-price-fine { font-size: .82rem; color: var(--cst-muted); margin-top: 14px; }
.cst-oc-price-footnote { margin-top: 28px; font-size: .92rem; color: var(--cst-ink-soft); }
.cst-oc-price-footnote a { color: var(--cst-accent-hover); font-weight: 700; text-decoration: underline; }
/* Team-enrollment row inside .cst-oc-price-card. Spans the card's two columns
   and re-splits on the same 1.1fr/.9fr ratio so its heading sits under the
   pricing copy and its text under the price box. The rule above it is the
   card's own hairline, repeated - the row is a second offer, not a footnote. */
.cst-oc-team-band { grid-column: 1 / -1; display: grid; grid-template-columns: 1.1fr .9fr; gap: 40px; align-items: center; margin-top: 8px; padding-top: 32px; border-top: 1px solid rgba(255,255,255,.18); }
/* Sized to match the card's h2 ("One price. Everything included.") so the two
   rows read as equal offers rather than an offer and a sub-note. The values are
   the .cst-typography h2 scale verbatim, including its 64rem step; it stays an
   h3 because it follows that h2 in the document. */
.cst-oc-team-band h3 { color: var(--cst-surface); font-size: 27px; margin: 0; }
@media (min-width: 64rem) {
	.cst-oc-team-band h3 { font-size: 31px; }
}
.cst-oc-team-band p { color: var(--cst-border); margin: 0 0 18px; }
/* The link sits on the dark card, where the footnote's --cst-accent-hover green
   is unreadable. Badge yellow is the treatment the other on-dark inline links
   already use. */
.cst-oc-team-band a:not(.cst-btn) { color: var(--cst-badge); font-weight: 700; text-decoration: underline; }
.cst-oc-faq { max-width: 760px; }
.cst-oc-faq details { border-bottom: 1px solid var(--cst-border-subtle); padding: 20px 0; }
.cst-oc-faq details summary { cursor: pointer; font-weight: 700; color: var(--cst-ink); list-style: none; display: flex; justify-content: space-between; align-items: center; font-size: 1.02rem; }
.cst-oc-faq details summary::-webkit-details-marker { display: none; }
.cst-oc-faq details summary::after { content: '+'; font-size: 1.4rem; color: var(--cst-accent); font-weight: 400; margin-left: 12px; flex-shrink: 0; }
.cst-oc-faq details[open] summary::after { content: '\2212'; }
.cst-oc-faq details p { margin-top: 14px; font-size: .95rem; }
/* Answer links have to look like links. The .cst-oc-page a { color: inherit }
   reset above sits at the same specificity as a.cst-inline-link but is declared
   later, so it wins — an inline link in an answer rendered as plain body text.
   Two classes plus the element settles it, same as the button rules do. */
.cst-oc-faq details p a { color: var(--cst-accent-hover); text-decoration: underline; text-underline-offset: 2px; }
.cst-oc-faq details p a:hover { color: var(--cst-accent); }
.cst-oc-final-cta { color: var(--cst-surface); }
/* Centred as a block: the closing band is a single short column with one
   action, not a reading column, so a left edge with nothing beneath it reads
   as a stray. text-align carries the eyebrow, the heading and the footnote;
   the button row is flex and needs its own justification. */
.cst-oc-final-cta .cst-oc-wrap { max-width: 700px; text-align: center; }
.cst-oc-final-cta .cst-oc-btn-row { justify-content: center; }
/* The footnote under the button gets its own air. .cst-oc-page p sets only a
   bottom margin, so without this the enterprise-pricing line sat tight against
   the CTA and read as part of the button block. */
.cst-oc-final-cta .cst-oc-btn-row + p { margin-top: 24px; }
.cst-oc-final-cta h2 { color: var(--cst-surface); font-size: clamp(1.6rem, 3.2vw, 2.3rem); }
.cst-oc-final-cta p { color: var(--cst-accent-pale); font-size: 1.05rem; }

/* The band is dark green, so a normal primary button would be green on green.
   These are the same two rules .cst-band--accent applies on the home page, and
   they replace a pair of inline styles that hand-rolled the inversion with
   `background:##fff;color:var(--oc-green-dark)`. --oc-green-dark is defined
   NOWHERE - the colour declaration was dropped by the browser and the label
   fell back to the band's inherited near-white, giving white text on a white
   button. That is the "can't see the text" case; the token, not the markup, was
   the bug.

   Same for the eyebrow: it was `color:var(--oc-yellow)`, equally undefined,
   which is why it rendered in the default green against dark green. */
/* Element-qualified to match the .cst-oc-page a.cst-btn--p rule added above: at
   two classes it would have lost to that one and the inverted button would have
   gone white-on-white. Same weight, declared later, so the inversion still
   wins on this band and nowhere else. */
.cst-oc-final-cta a.cst-btn--p { background: var(--cst-surface); color: var(--cst-accent-hover); }
.cst-oc-final-cta a.cst-btn--p:hover { background: var(--cst-accent-band-btn-hover); color: var(--cst-accent-hover); }
.cst-oc-final-cta .cst-oc-eyebrow { color: var(--cst-badge); }
@media (max-width: 900px) {
	.cst-oc-course-groups { grid-template-columns: 1fr; }
	.cst-oc-steps { grid-template-columns: 1fr; gap: 36px; }
	.cst-oc-price-card { grid-template-columns: 1fr; padding: 32px; }
	/* Stacks with the card: heading over copy over button, same as the two
	   blocks above it collapse. */
	.cst-oc-team-band { grid-template-columns: 1fr; gap: 20px; }
}
@media (max-width: 600px) {
	.cst-oc-stats { grid-template-columns: 1fr; gap: 24px; }
	.cst-oc-hero { padding: 40px 0 32px; }
	.cst-oc-section { padding: 52px 0; }
}
/* The .cst-oc-page landing pages (/team-enrollment/, /onboarding/): same column
   width as the home page, and a hero that starts at the page's left edge rather
   than centred.

   WIDTH. The home page's sections use Bootstrap/Tabler's .container-xl, which
   is 1140px from the xl breakpoint and 1320px from xxl (1400px), with
   --tblr-page-padding of gutter either side. .cst-oc-wrap is a flat 1120px with
   24px gutters, so on a wide screen this page ran ~200px narrower than the home
   page and read as a different, tighter layout. The values below are
   .container-xl's, restated rather than inherited because .cst-oc-wrap is not a
   Bootstrap container - if Tabler's container scale ever changes, this is the
   one place to follow it.

   LEFT EDGE. .cst-oc-hero .cst-oc-wrap narrows the wrap to 760px while
   .cst-oc-wrap still carries margin:0 auto, so the whole hero BLOCK was centred
   inside the column every other section uses. text-align:left made the text
   ragged-left within that floating block, which is why it read as almost right:
   the h1 simply did not line up with the section headings below it. The hero now
   takes the full column and the MEASURE is capped on the copy instead, so line
   length stays readable while the left edge agrees with the rest of the page.
   (.cst-oc-lede caps itself at 620px.)

   Both selectors are spelled out so the hero does not depend on source order
   against .cst-oc-hero .cst-oc-wrap above.

   Scoped to .cst-oc-page, which is exactly these two pages and nothing else.
   This started life on .te-page while only Team Enrollment was in scope; once
   Onboarding wanted the same thing, one shared rule beat two identical ones.
   The .te-page class is still on that page's <main> as a hook, it just no
   longer carries these declarations. */
.cst-oc-page .cst-oc-wrap,
.cst-oc-page .cst-oc-hero .cst-oc-wrap {
	max-width: 1140px;
	padding-inline: var(--tblr-page-padding, 1rem);
}
@media (min-width: 1400px) {
	.cst-oc-page .cst-oc-wrap,
	.cst-oc-page .cst-oc-hero .cst-oc-wrap { max-width: 1320px; }
}
.cst-oc-page .cst-oc-hero h1,
.cst-oc-page .cst-oc-hero .cst-oc-hero-bullets { max-width: 760px; }

.cst-te-included-grid { display: grid; grid-template-columns: 1.1fr .9fr; gap: 40px; align-items: start; }
.cst-te-included-list { list-style: none; margin: 0; padding: 0; }
.cst-te-included-list li { display: flex; gap: 12px; align-items: flex-start; padding: 10px 0; border-bottom: 1px solid var(--cst-border-subtle); font-size: 1.02rem; color: var(--cst-ink); }
.cst-te-included-list li:last-child { border-bottom: none; }
.cst-te-included-list li::before { content: '\2713'; color: var(--cst-accent); font-weight: 700; flex: 0 0 auto; }
.cst-te-journey { background: var(--cst-surface); border: 1px solid var(--cst-border-subtle); border-radius: var(--cst-radius); padding: 24px; box-shadow: var(--cst-shadow-hover); }
.cst-te-journey-label { font-size: .85rem; color: var(--cst-ink-soft); margin-bottom: 16px; }
.cst-te-journey-track { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
/* Numbered 1-12, so the track reads as the twelve courses rather than as
   decoration. Grown from 18px to 26px because "12" has to fit inside the
   circle at a legible size; the border and fill are unchanged. */
.cst-te-journey-dot { width: 26px; height: 26px; border-radius: 50%; background: var(--cst-accent-pale); border: 2px solid var(--cst-accent); flex: 0 0 auto; display: flex; align-items: center; justify-content: center; font-size: .72rem; font-weight: 700; line-height: 1; color: var(--cst-accent-hover); }
.cst-te-journey-arrow { color: var(--cst-ink-soft); margin: 0 6px; }
.cst-te-journey-badge { flex: 0 0 auto; width: 48px; height: 48px; border-radius: 50%; background: var(--cst-ink); color: var(--cst-surface); display: flex; align-items: center; justify-content: center; font-weight: 700; font-size: .68rem; text-align: center; line-height: 1.1; padding: 4px; }
.cst-te-journey p:last-child { margin-top: 16px; margin-bottom: 0; font-size: .9rem; }
.cst-te-callout { max-width: 780px; font-size: 1.02rem; color: var(--cst-ink); }
/* Air above the first callout only. It follows the included-list / journey-card
   grid, and .cst-oc-page p carries no top margin, so it was butting up against
   the bottom of that block; the second callout keeps its normal paragraph
   rhythm underneath. */
.cst-te-included-grid + .cst-te-callout { margin-top: 32px; }
.cst-te-course-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 4px 32px; margin-top: 8px; }
.cst-te-course-item { display: flex; gap: 12px; align-items: baseline; padding: 10px 0; border-bottom: 1px solid var(--cst-border-subtle); }
.cst-te-course-item .cst-te-n { font-weight: 700; color: var(--cst-accent-hover); font-size: 1rem; flex: 0 0 auto; min-width: 1.4rem; }
.cst-te-course-item .cst-te-t { font-size: 1rem; color: var(--cst-ink); }
.cst-te-toolkit-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 20px; }
.cst-te-toolkit-card { background: var(--cst-surface); border: 1px solid var(--cst-border-subtle); border-radius: var(--cst-radius); padding: 26px 28px; box-shadow: var(--cst-shadow-hover); }
.cst-te-toolkit-card h3 { font-size: 1.1rem; color: var(--cst-ink); margin-bottom: .4em; }
.cst-te-toolkit-card p { margin: 0; font-size: .96rem; }
.cst-te-pull { margin: 32px 0 0; padding: 20px 28px; border-left: 4px solid var(--cst-accent); background: var(--cst-accent-pale); border-radius: 0 var(--cst-radius) var(--cst-radius) 0; font-size: 1.08rem; color: var(--cst-ink); }
.cst-te-price-figure { font-size: 2.6rem; font-weight: 700; color: var(--cst-surface); }
.cst-te-price-figure span { font-size: 1.05rem; font-weight: 400; color: var(--cst-border); }
/* The seat calculator sits in the same .cst-oc-price-box panel the /onboarding/
   price block uses, but it was typeset two or three steps smaller throughout and
   so read as a cramped form dropped onto the dark card rather than as the price
   display it is. The sizes below are taken from the onboarding box: the running
   total matches .cst-oc-price-new at 3rem, and the label and field step up to
   match it. */
.cst-te-calc label { display: block; font-weight: 700; font-size: 1.05rem; margin-bottom: 14px; color: var(--cst-surface); }
/* Wraps because the total is now 3rem: "$9900" plus the field is wider than the
   box's content width once the card collapses to one column on mobile. Wrapping
   drops the total onto its own line there, which is how the onboarding box reads
   anyway; on desktop the pair still fits side by side. */
.cst-te-calc-row { display: flex; flex-wrap: wrap; align-items: center; justify-content: center; gap: 16px; }
/* The field's border was .28, the same value the panel around it now carries, so
   the two edges read at equal weight and the input stopped looking like a
   control. .40 keeps it the most defined edge in the box, which is what it
   should be - it is the only thing here anyone types into. */
.cst-te-calc-row input[type=number] { width: 6.5rem; padding: 12px 14px; font-size: 1.35rem; font-weight: 700; border: 1px solid rgba(255,255,255,.40); border-radius: 6px; background: rgba(255,255,255,.08); color: var(--cst-surface); }
.cst-te-calc-total { font-size: 3rem; font-weight: 700; color: var(--cst-surface); line-height: 1.1; }
/* Not --cst-muted. That token is #4f5d70, a dark slate tuned to recede on a
   LIGHT surface; on this panel it is near-invisible against the background. It
   is the same mistake already caught and written up for .cst-oc-price-old above.
   --cst-border (#d5d5c8) is what .cst-oc-price-card p already uses for secondary
   copy on this card, so the note now matches the rest of it. */
.cst-te-calc-note { font-size: .92rem; color: var(--cst-border); margin: 16px 0 0; }
.cst-te-calc-note--warn { color: var(--cst-terracotta); font-weight: 700; }
@media (max-width: 900px) {
	.cst-te-included-grid { grid-template-columns: 1fr; }
	.cst-te-toolkit-grid { grid-template-columns: 1fr; }
	.cst-te-course-grid { grid-template-columns: 1fr; }
}

/* --- Catalog card (/menu/) --------------------------------------------------
   The home page's course card (.cst-ccard, above) reused as the catalog's
   product tile, replacing the bordered table the catalog used to render. The
   body above the price is unchanged; these rules add only what a real product
   needs and the home page comp did not have — a product image in place of the
   .cst-ph placeholder, and a footer holding the add-to-cart control.

   The two-class selectors are deliberate. /menu/ is a .c-theme page, and
   .c-theme p / .c-theme h3 are single-class-plus-element rules that would
   otherwise win the cascade and recolour the card's metadata. Anything that
   .c-theme also sets is therefore restated here at .cst-ccard--catalog X. */
.cst-ccard--catalog { height:100%;overflow:hidden }
.cst-ccard--catalog a { color:inherit;text-decoration:none }
/* A FIXED height, not an aspect-ratio box. Two reasons, both of which made
   product images render at a different size on every card:
     1. An aspect-ratio box has no definite height of its own, so the img's
        height:100% had nothing to resolve against and fell back to auto —
        each picture then sized itself from its own intrinsic proportions.
     2. The box is a flex item in a column card. Default flex-shrink let it
        compress whenever a stretched card redistributed space, so cards in
        the same row disagreed about how tall the image was.
   flex:0 0 auto plus a literal height settles both: identical box on every
   card, with object-fit cropping whatever the source image's shape is. */
/* Inset by the same 12px the body and the footer use, so the image, the text and
   the CTA all sit on one vertical edge instead of the image alone running full
   bleed. Height is 180 = the 168px picture the cards already had, plus the 12px
   that now sits above it, so insetting did not shrink the image.

   box-sizing:border-box is Tabler's, set site-wide; the padding therefore comes
   out of the 180 rather than adding to it, which is what keeps the picture at
   168 and every card in a row exactly as tall as its neighbours.

   The band background and the radius moved from the box to the img: with the
   picture inset, those belong to the picture, and the card's own surface is what
   shows in the margin around it. border-bottom went away with the same change -
   it existed to separate a full-bleed image from the body, and a rule running
   wider than the thing it underlines just reads as a mistake. */
.cst-ccard__media { display:block;flex:0 0 auto;height:180px;padding:12px 12px 0 }
.cst-ccard__media img { width:100%;height:100%;object-fit:cover;object-position:center;display:block;border-radius:var(--cst-radius);background:var(--cst-band) }
.cst-ccard--catalog .cst-ccard__body { flex:1 1 auto;display:flex;flex-direction:column }
.cst-ccard--catalog .cst-ccard__body h3 { font-size:16px;line-height:1.35;font-weight:700;color:var(--cst-ink) }
.cst-ccard--catalog .cst-by,
.cst-ccard--catalog .cst-meta { color:var(--cst-muted);line-height:1.45 }
/* The price moved out of the body and into the footer row, so it no longer needs
   margin-top:auto to reach the bottom of the card - the body's flex:1 1 auto
   above does that for the whole row, which is what keeps prices and CTAs aligned
   across cards whose titles wrap to different heights. */
.cst-ccard--catalog .cst-price { margin:0;color:var(--cst-ink);line-height:1.3 }
/* "Price" above the amount. Both spans are block so they stack inside the <p>
   without a <br>, and the label takes the muted treatment the card's other
   secondary text (.cst-by, .cst-meta) already uses, so it reads as a caption for
   the number rather than competing with it. */
.cst-price__label { display:block;font-size:var(--cst-text-sm);font-weight:500;color:var(--cst-muted);line-height:1.2 }
.cst-price__amt { display:block }
/* Price left, CTA right, on one line - with a real safety valve, because the CTA
   label is not fixed. These cards are 264px wide (240px inside the padding) and
   the button says anything from "Add to Cart" to "Add to My Courses", which is
   roughly 70px wider. The pair does not always fit.

   The button does not grow to fill the row - flex-grow:1 stretched it across
   whatever the price left behind and made a two-word CTA read as a banner. It
   also does not sit at bare content width, which left "Add to Cart" looking like
   an afterthought next to the price. min-width is the floor between those two:
   short labels are padded out to a deliberate button shape, long ones size to
   their own text and simply run wider. justify-content pushes it to the right
   edge either way.

   The floor is a FLOOR, not a width. Content wider than 8.75rem still wins, so
   adding a longer CTA later widens the button instead of truncating it - which
   is the failure a fixed width would have introduced.

   The wrap is driven by the button's own min-content width, not by a guessed
   breakpoint. white-space:nowrap makes min-content the full label, so when label
   + price + gap exceed the row the button drops to its own line intact. Nothing
   is ever squeezed, wrapped mid-label, or clipped: a truncated call to action is
   worse than a second line. Note the floor feeds into that calculation - raising
   it much past 9rem starts wrapping cards that fit today. */
/* Column gap is the space between the amount and the button and is set wider
   than the row gap on purpose - they are two different jobs. Row gap only
   applies once the button has wrapped onto its own line, where 10px sits it
   closer under the price than 18px would. */
.cst-ccard__foot { display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;gap:10px 18px;padding:0 12px 14px }
.cst-ccard__foot .cst-price { flex:0 0 auto }
.cst-ccard__cta { flex:0 0 auto;width:auto;min-width:8.75rem;white-space:nowrap }
.cst-ccard__cta[disabled] { background:var(--cst-band);color:var(--cst-muted);border:1px solid var(--cst-border);cursor:default }
.cst-ccard__cta[disabled]:hover { background:var(--cst-band) }

/* --- Catalog view switch (/menu/) -------------------------------------------
   Two icon buttons above the catalog, and the compact view they turn on. The
   compact view is the SAME card markup relaid as a row — there is no second
   rendering — so a change to the card cannot leave one of the two views behind.
   The .cst-viewtoggle__btn is a <button>, which /menu/ does not scope under
   .cst-typography, so it carries its own reset. */
.cst-viewtoggle { display:flex;justify-content:flex-end;gap:6px;margin-bottom:16px }
.cst-viewtoggle__btn { display:inline-flex;align-items:center;justify-content:center;width:38px;height:38px;padding:0;font-size:18px;line-height:1;cursor:pointer;background:var(--cst-surface);color:var(--cst-muted);border:1px solid var(--cst-border);border-radius:var(--cst-radius);transition:background .15s,color .15s,border-color .15s }
.cst-viewtoggle__btn:hover { color:var(--cst-accent);border-color:var(--cst-accent) }
.cst-viewtoggle__btn[aria-pressed="true"] { background:var(--cst-accent);border-color:var(--cst-accent);color:var(--cst-surface) }

/* One row per product. The grid stays a grid — only its track count changes —
   so the gap and the cards' own box model keep working. Two-class selectors
   throughout, same reason as the block above: .c-theme's element rules and the
   card's own one-class rules both have to be cleared. */
.cst-catalog--compact .cst-grid { grid-template-columns:1fr;gap:10px }
/* gap here is the one between the badge column and the price/CTA block, and it
   is wider than the card view's 14px on purpose: at full width those are three
   separate readings — what it covers, what it costs, what to do — and a tight
   gap runs them together. */
.cst-catalog--compact .cst-ccard--catalog { height:auto;flex-direction:row;align-items:center;gap:28px;padding:10px 12px }
/* No thumbnail in the compact view. It is display:none rather than removed from
   the markup because the card is rendered once and restyled — the card view
   still needs it. */
.cst-catalog--compact .cst-ccard__media { display:none }
/* The body becomes the scanning grid: the title and everything that belongs
   under it — .cst-by, and the .cst-meta line carrying minutes, CEUs and
   Certificate — stay stacked in a fluid first column. Only the .cst-badges
   group moves out, into a second column of its own.

   That column is auto-width, and the text column takes all the slack, so the
   badge group is pushed up against the price/CTA block and the pills end on a
   common right edge down the page.

   Every text child is pinned to column 1 explicitly. Without that, only the
   title landed there: auto-placement fills row by row, so with .cst-badges
   holding (row 1, column 2) the cursor wrapped to row 2, put .cst-by at
   (2,1) and then dropped .cst-meta into the next free cell — (2,2), directly
   under the badges. Pinning the column keeps minutes / CEU / Certificate under
   the title where they belong, whether or not .cst-by is present. */
.cst-catalog--compact .cst-ccard--catalog .cst-ccard__body { padding:0;min-width:0;display:grid;grid-template-columns:minmax(0,1fr) auto;align-items:center;column-gap:24px }
.cst-catalog--compact .cst-ccard__body > h3,
.cst-catalog--compact .cst-ccard__body > .cst-by,
.cst-catalog--compact .cst-ccard__body > .cst-meta { grid-column:1 }
/* Centred against the whole text stack, not pinned to the title's row.
   span 3 is the ceiling, not a guess: column 1 holds at most h3 + .cst-by +
   .cst-meta, and the last two are conditional. A product with fewer leaves an
   empty implicit row, which costs nothing — implicit rows are auto-sized and
   row-gap is 0, so an empty one is 0 tall. align-self then centres the pills
   across whatever the span actually resolved to. */
.cst-catalog--compact .cst-ccard__body > .cst-badges { grid-column:2;grid-row:1 / span 3;align-self:center;margin-top:0;flex-wrap:nowrap }
/* One row of pills, not a stack: .cst-badges wraps by default because the card
   view is 264px wide, and nothing here is. */
.cst-catalog--compact .cst-badges .cst-pill { white-space:nowrap }
/* One line per title here — the point of the view is scanning a list, and a
   card that wraps to two lines makes the rows disagree about their height. */
.cst-catalog--compact .cst-ccard h3 { -webkit-line-clamp:1;margin-bottom:2px }
/* Price and CTA stop being a footer row and become the right-hand end of the
   line. nowrap keeps them there: the wrap the card view needs at 264px wide is
   not needed at full width, and letting it happen would stagger the rows. */
.cst-catalog--compact .cst-ccard__foot { flex:0 0 auto;flex-wrap:nowrap;justify-content:flex-end;gap:28px;padding:0 }
.cst-catalog--compact .cst-ccard--catalog .cst-price { text-align:right }
@media(max-width:47.99rem) {
	/* Narrow screens: let the price/CTA pair drop under the text rather than
	   squeezing the title into a few characters. */
	.cst-catalog--compact .cst-ccard--catalog { flex-wrap:wrap }
	.cst-catalog--compact .cst-ccard__foot { flex:1 1 100% }
	/* There is no room for a pill column beside the text at this width, so the
	   badges go back under it, the grid collapses to one track, and they are
	   allowed to wrap again. */
	.cst-catalog--compact .cst-ccard--catalog .cst-ccard__body { grid-template-columns:minmax(0,1fr) }
	.cst-catalog--compact .cst-ccard__body > .cst-badges { grid-column:1;grid-row:auto;margin-top:9px;flex-wrap:wrap }
}

/* --- Certificate programme block (/menu/) -----------------------------------
   A certificate programme is not a course, and a 264px tile cannot answer the
   question a buyer actually has about one: what is IN it? So each programme
   gets a full-width block above the catalog grid instead of a card inside it -
   image, description, the whole course list, and the price and CTA, laid out as
   three columns: artwork, prose, buy rail.

   TWO-CLASS SELECTORS THROUGHOUT, for exactly the reason .cst-ccard--catalog
   above uses them: /menu/ is a .c-theme page, and `.c-theme p`, `.c-theme h2`,
   `.c-theme h3` are element-plus-class rules (0,1,1) that would otherwise win
   the cascade and recolour and resize everything in here. Anything c-theme also
   sets is restated at `.cst-certprog X` (0,2,0), which beats it.

   Literal px/rem rather than c-theme's --space-* tokens: this sheet is Tier A
   and must not start depending on tokens declared in the Tier B wrapper, which
   retires under docs/decisions.md D12.

   The block does not opt into the card/list view switch. That toggle relays a
   .cst-ccard into a row; there is no compact form of a programme, and a
   programme reduced to a row would be the tile this block exists to replace. */
/* A real section break under the programmes. The two halves of this page are
   different kinds of thing - programmes you commit to, and courses you buy
   singly - and with only whitespace between them the first course card read as
   the next item in the programme list. The rule is the same subtle border the
   cards use, so it separates without announcing itself. */
.cst-certprog-band { margin-bottom:32px;padding-bottom:32px;border-bottom:1px solid var(--cst-border) }
/* On /company/purchasing/buy/ the band is the whole page rather than a section
   above a course grid, so the rule underneath it would be closing off nothing. */
.cst-certprog-band:last-child { margin-bottom:0;padding-bottom:0;border-bottom:0 }
.cst-certprog + .cst-certprog { margin-top:24px }

/* Section heading, shared by the programme band and the course grid below it so
   the two read as siblings. Restated against .c-theme h2 / .c-theme p for the
   reason given above. */
.cst-cat-head { margin-bottom:18px }
.cst-cat-head__text h2 { font-size:22px;line-height:1.25;font-weight:700;color:var(--cst-ink);margin:0 0 6px }
.cst-cat-head__text p { font-size:15px;line-height:1.5;color:var(--cst-muted);margin:0 }
/* The course-grid heading shares its row with the card/list switch. flex-end
   aligns the switch to the BASELINE of the subheading rather than the middle of
   a two-line text block, and wrap drops it under the heading when the row is too
   narrow for both. The switch keeps its own bottom margin for the search case,
   where it is the only thing in here; inside a populated row that margin would
   push it out of alignment, so it is zeroed there. */
.cst-cat-head--row { display:flex;flex-wrap:wrap;align-items:flex-end;justify-content:space-between;gap:12px 20px }
.cst-cat-head--row .cst-cat-head__text { flex:1 1 16rem;min-width:0 }
.cst-cat-head--row .cst-cat-head__text + .cst-viewtoggle { margin-bottom:0 }

/* THREE columns on desktop: artwork, prose, and a narrow buy rail.

   The middle column is the point of the arrangement. Description and course
   list set at the full width of the block ran to 900px+ on a wide viewport,
   which is roughly twice a comfortable measure - the eye loses the line
   returning from the end of one row to the start of the next, and the course
   list in particular stopped reading as a list once each short title was
   stranded on its own 900px row. Boxing the prose between the image and the
   rail holds it near 60-70 characters without a max-width that would leave dead
   space on the right.

   minmax(0,…) on EVERY track: without the zero floor a long unbroken course
   title sets the content column's min-content width and pushes the grid wider
   than its container. */
.cst-certprog { display:grid;grid-template-columns:minmax(0,440px) minmax(0,1fr) minmax(0,16rem);overflow:hidden }
/* align-self:start, NOT the default stretch. The artwork is a fixed-ratio tile
   now, so letting the cell stretch to the height of the course list would only
   pad it out below.

   The padding is not a round number picked for looks - it is the same 24px
   .cst-certprog__body carries, which is what puts the top edge of the image on
   exactly the line the programme title starts on and gives the article one
   consistent gutter on all four sides. Change one and the other has to move with
   it or the two columns stop sharing a top edge.

   White behind the image, NOT --cst-band. The artwork in /images/products/ is
   authored on white and some of it is transparent PNG; the warm off-white band
   showed through those as a tinted rectangle and drew a visible seam around the
   ones that were already white. --cst-surface is the same token the card faces
   use, so the tile sits on the same ground they do. */
.cst-certprog__media { display:block;background:var(--cst-surface);padding:24px;align-self:start }
/* NO aspect-ratio. It was 1/1, and that is what defeated align-self:start on the
   wrapper above: the anchor sat at the top of the row correctly, but the img BOX
   it contained was forced to a 440px square while the picture inside it was
   landscape, and object-fit:contain centred that picture in the leftover. The
   image looked vertically centred because it WAS - inside a square box that
   happened to be white on a white tile, so nothing showed where the box ended
   and the picture began.

   With the ratio gone, height:auto sizes the box to the picture's own
   proportions at the full width of the column, so the top of the box and the top
   of the artwork are the same line - which is the line the title starts on.

   max-height is the guard the square used to provide. A portrait source at 440px
   wide would otherwise run 600px+ and tower over the text beside it; clamped, it
   fits to the cap and object-fit:contain pillarboxes it instead. For the
   landscape and square sources that clear the cap the property never applies.

   The radius is the same --cst-radius .cst-ccard__media img carries, so the
   programme artwork and the course artwork below it are cut the same way. It
   goes on the IMG, not the anchor: the anchor is a transparent white box with
   padding, and rounding that would round nothing anybody can see. */
.cst-certprog__media img { width:100%;height:auto;max-height:440px;min-height:0;object-fit:contain;object-position:center top;border-radius:var(--cst-radius);display:block }
.cst-certprog__body { padding:24px }

.cst-certprog__title { font-size:24px;line-height:1.2;font-weight:700;color:var(--cst-ink);margin:0 0 8px }
.cst-certprog__title a { color:inherit;text-decoration:none }
.cst-certprog__title a:hover { text-decoration:underline }
.cst-certprog__meta { font-size:15px;line-height:1.45;color:var(--cst-muted);margin:0 }
/* The badge row sits closer to the meta line above it than to whatever follows,
   because it qualifies the title block rather than opening a new one.

   The two adjacent-sibling rules tighten the gap BELOW it without touching the
   18px/20px those blocks take when there are no badges - the badges only render
   for an accredited or already-owned programme, so the common case has the
   description following the meta line directly and still wants the full step.
   Specificity (0,2,0) beats the single-class rules further down whatever order
   they end up in. */
.cst-certprog__badges { display:flex;flex-wrap:wrap;gap:6px;margin-top:9px }
.cst-certprog__badges + .cst-certprog__rt { margin-top:12px }
.cst-certprog__badges + .cst-certprog__courses { margin-top:14px }

/* The two rich-text blocks. Their inner markup is admin-authored, so the child
   selectors have to cover whatever the editor produced rather than assume a
   single <p>. */
.cst-certprog__rt { margin-top:18px }
.cst-certprog__rt h3 { font-size:15px;line-height:1.3;font-weight:700;color:var(--cst-ink);margin:0 0 6px }
.cst-certprog__rt p,
.cst-certprog__rt li,
.cst-certprog__rt div { font-size:15px;line-height:1.6;color:var(--cst-ink-soft) }
.cst-certprog__rt p { margin:0 0 8px }
.cst-certprog__rt ul,
.cst-certprog__rt ol { margin:0 0 8px;padding-left:1.25rem }

/* Course list. ONE column at every width, tightly set.

   It was two tracks (and before that auto-fill, which found room for three on a
   wide viewport). Both lost: a course title is long enough that half a row makes
   it wrap, and a wrapped entry in a multi-column list is harder to scan than a
   plain vertical run of seven. One column also lets the numbers and the titles
   line up on a single edge, which is the whole point of showing the list rather
   than a count.

   The row gap is deliberately smaller than the line-height: these are entries in
   one list, not paragraphs, so they should read as a block. */
/* --cst-sand, not --cst-band. The band is the page's own alternating surface and
   this panel sits on a white card in the middle of a white page, so a warm
   off-white read as a rendering artefact rather than a deliberate block. Sand is
   far enough from white to be unmistakably a block, and it is the one tint on
   the page that does not belong to a state - the accent tint reads as "good" and
   the peach tint as "attention", neither of which is what a table of contents
   means.

   --cst-sand-line is the border token declared FOR this background - see
   cst-tokens.css section 1. Do not pair sand with --cst-border; that is the
   general warm grey and it goes muddy against the sand fill. */
.cst-certprog__courses { margin-top:20px;padding:16px;background:var(--cst-sand);border:1px solid var(--cst-sand-line);border-radius:var(--cst-radius) }
.cst-certprog__courses h3 { font-size:15px;line-height:1.3;font-weight:700;color:var(--cst-ink);margin:0 0 8px }
.cst-certprog__courselist { list-style:none;margin:0;padding:0;display:grid;grid-template-columns:minmax(0,1fr);gap:3px }
.cst-certprog__course { display:flex;align-items:baseline;gap:9px;font-size:15px;line-height:1.3;color:var(--cst-ink-soft);margin:0 }
/* Fixed-width counter so the titles line up whether the number is 1 or 12.

   --cst-warm-text, not --cst-accent. The numerals used to echo the green tint
   this panel carried; on sand that pairing became green-on-peach, two families
   at once. The warm brown is the sand family's own text colour, so the counter
   now belongs to the panel it sits in rather than to the buttons elsewhere on
   the page. If the panel background changes again, this moves with it. */
.cst-certprog__num { flex:0 0 auto;min-width:1.5rem;font-variant-numeric:tabular-nums;font-weight:700;color:var(--cst-warm-text) }
.cst-certprog__cname { flex:1 1 auto;min-width:0;color:var(--cst-ink) }

/* The buy rail: price left, CTA right, both sitting on the bottom of the block.

   Same row arrangement and the same .cst-price parts as the course card's
   footer, so the two read as one family - the card's version just spans a tile
   instead of a column.

   No divider of any kind. The rule down the left edge drew a box around two
   short things and made the rail look like a sidebar rather than the block's
   own footer; the whitespace is enough separation at this width.

   The bottom alignment is doing two jobs at once, which is why both properties
   are here. The grid item stretches to the full height of the row, so the
   single flex line fills it and align-items:flex-end drops the pair to the
   bottom. If the rail is too narrow for price and button side by side they wrap
   to two lines - and align-content:flex-end is what keeps those lines packed at
   the bottom, since align-items only positions items WITHIN a line. */
.cst-certprog__foot { display:flex;flex-wrap:wrap;align-items:flex-end;align-content:flex-end;justify-content:space-between;gap:12px;padding:24px }
.cst-certprog__foot .cst-price { margin:0;color:var(--cst-ink);line-height:1.3;flex:0 0 auto }
.cst-certprog__foot .cst-price__amt { font-size:22px;font-weight:700 }
/* white-space:nowrap matters more here than on the card: the rail is narrow
   enough that "Already Completed" would otherwise break across two lines. */
.cst-certprog__cta { flex:0 0 auto;width:auto;white-space:nowrap;text-decoration:none }

/* The quantity box, which takes the CTA's place in "company" mode
   (/company/purchasing/buy/). It sits in the same slot and obeys the same
   flex:0 0 auto, so the rail's price-left/control-right arrangement is
   unchanged and the two modes cannot drift apart.

   The label is stacked above the field rather than beside it because the rail
   is only 16rem: inline, "Licenses" and a 5-wide number box together overflow
   and wrap the pair onto two lines anyway, just less tidily. Stacking also
   mirrors .cst-price, which puts its own label above its amount.

   Fixed 5.5rem width: wide enough for "5000", the ceiling
   insert_Company_Product_Purchase enforces, plus the spinner arrows. Left to
   auto it stretched to the whole rail and read as a text field. */
.cst-certprog__qty { flex:0 0 auto;display:flex;flex-direction:column;gap:3px;align-items:flex-end }
.cst-certprog__qtylabel { font-size:var(--cst-text-sm);font-weight:500;color:var(--cst-muted);line-height:1.2;margin:0 }
.cst-certprog__qtyinput { width:5.5rem;padding:6px 8px;font-size:var(--cst-text-base);font-family:inherit;font-variant-numeric:tabular-nums;text-align:right;color:var(--cst-ink);background:var(--cst-surface);border:1px solid var(--cst-border);border-radius:var(--cst-radius) }
.cst-certprog__qtyinput:focus-visible { outline:2px solid var(--cst-accent);outline-offset:1px;border-color:var(--cst-accent) }
/* A quantity above zero is a line on the order, so the card says so without
   needing the summary at the foot of the page to be in view. */
.cst-certprog__qtyinput[data-has-qty="1"] { border-color:var(--cst-accent);box-shadow:inset 0 0 0 1px var(--cst-accent) }

/* --- The running-total bar (/company/purchasing/buy/) ----------------------
   Sticky at the foot of the viewport because a programme card is tall - with
   three or four of them the Continue button sits several screens below the
   quantity somebody just typed, and a total they have to scroll to find is a
   total they will not check before paying.

   position:sticky and not fixed: sticky stays inside the normal flow, so the
   bar cannot overlap the page footer the way a fixed element would, and it
   needs no body padding to compensate. bottom:0 pins it while its own place in
   the document is still below the last card.

   z-index is low on purpose. It has to clear the cards it floats over and
   nothing else; Tabler's dropdowns (1000) and modals (1055) must stay above it,
   and the manager dropdown in the navbar opens right over this area. */
.cst-buybar { position:sticky;bottom:0;z-index:5;margin-top:24px;background:var(--cst-surface);border-top:1px solid var(--cst-border);box-shadow:var(--cst-shadow-overlay) }
.cst-buybar__in { display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;gap:12px 20px;padding:14px 16px }
.cst-buybar__sum { font-size:var(--cst-text-base);font-weight:700;color:var(--cst-ink);min-width:0 }

@media(max-width:35.99rem) {
	/* Stacked, and the button goes full width - at this size the summary and a
	   button beside it leave the button too narrow to be a comfortable target. */
	.cst-buybar__in { flex-direction:column;align-items:stretch;gap:10px }
	.cst-buybar__sum { text-align:center }
}

@media(max-width:74.99rem) {
	/* Two columns, and the rail unwinds back into a full-width footer under
	   them. Below about 1200px the three tracks are competing for the same
	   pixels and the middle column - the one the layout exists to protect -
	   is the one that loses; a 16rem rail holding two short things is not
	   worth the width it costs the course titles beside it. */
	.cst-certprog { grid-template-columns:minmax(0,360px) minmax(0,1fr) }
	/* Spanning both tracks it is no longer bottom-of-a-column but bottom-of-the
	   block, so the end alignment goes back to centring the pair on one row. */
	.cst-certprog__foot { grid-column:1 / -1;align-items:center;align-content:center;gap:12px 20px;padding:4px 24px 24px }
}

@media(max-width:61.99rem) {
	/* Image above the content rather than beside it, and pinned to a fixed height
	   rather than left to its own proportions: full-bleed at this width a natural
	   landscape source would be 300px+ of artwork before a single word.
	   object-fit:contain carries down from the base rule, so the image is fitted
	   to that height and centred across the width. object-position goes back to
	   centre for the same reason - there is no title beside it to align to. */
	.cst-certprog { grid-template-columns:minmax(0,1fr) }
	.cst-certprog__media { padding:20px;align-self:stretch }
	.cst-certprog__media img { height:200px;max-height:none;object-position:center }
	.cst-certprog__body { padding:20px }
	.cst-certprog__foot { padding:4px 20px 20px }
	.cst-certprog__title { font-size:21px }
}
@media(max-width:35.99rem) {
	/* Price and CTA stack: at this width the button cannot sit beside the amount
	   without one of the two being squeezed. */
	.cst-certprog__foot { justify-content:flex-start }
	.cst-certprog__cta { width:100% }
}
