/* ══════════════════════════════════════════════════════════════════════════
   AIToolsay · /ai-courses — THE DELTA over /ai-directory's live sheet
   --------------------------------------------------------------------------
   This file is NOT the page's stylesheet. The page wears
   `v2-public-directory-listing.css` — /ai-directory's OWN sheet, loaded from
   the blade body immediately before this one — and everything here is the
   difference a course catalogue needs on top of a tool catalogue.

   ⚠ An edit to the SHARED sheet reaches six pages — /ai-directory,
     /browser-extensions, /gpts, /workflows, /ai-projects and /ai-courses.
     Fix a shared problem there; fix a courses-only problem here.

   SCOPE: every rule is `.v2x.acx …`. `.acx` is on this page's root <div>
   only, so nothing here can leak to the five siblings.

   SECTIONS
     §PLATE   the icon plate — a course has no thumbnail, so it inherits its
              category's icon + colour. THE ACCENT IS THE PLATE, NOT THE GLYPH.
     §FLAG    the featured / trending ribbon on the card
     §STRIP   the rating · certificate signal strip
     §BY      the provider byline
     §CTA     the card's View-course button
     §CHIP    the active-filter chip row above the results
     §BUSY    the dim-while-filtering state the directory keys on a class it
              never defines in any sheet in the stack
     §HERE    the "you are here" marker on the category rail
     §ABOUT   the hub pages' about panel
     §CATGRID /ai-courses/category — the same cards, a browse layout
     §IOS     the 16px floor that stops iOS zooming on search focus
     §RESP    the responsive fixes the above need
   ══════════════════════════════════════════════════════════════════════════ */


/* ═══ §PLATE — the icon plate ═══════════════════════════════════════════════
   `ai_courses.thumbnail` is NULL on all 23 published rows and every
   `ai_course_providers.logo` is NULL too, so there is no logo to draw. Each
   course inherits its CATEGORY's Lucide icon and hex colour instead — a truer
   plate than the first letter of a title, and it makes a category read as one
   family down the grid.

   ⚠ THE ACCENT IS THE PLATE, NEVER THE GLYPH, AND THIS MUST NOT BE
   "SIMPLIFIED" BACK. `--acx-accent` is whatever hex an admin typed on the
   category. Measured over the nine distinct colours in `ai_course_categories`
   TODAY, as glyph ink on white: worst is #74B816 at 2.44:1 and TWO of the
   nine fail even the 3:1 non-text floor — and the glyph is the plate's only
   content. Saturation is not luminance, which is exactly why an arbitrary
   admin-supplied hue can never be trusted as ink.

   The fix needs no per-hue table: a white scrim is painted OVER the accent,
   so whatever the hue, the plate lands light and the glyph is drawn in the
   sheet's own guaranteed ink. Dark mode paints a dark scrim and flips the
   ink. Measured on the same nine: 15.02:1 worst light, 11.97:1 worst dark.

   `linear-gradient(rgba(...),rgba(...))` over a colour is used rather than
   color-mix(), which Safari did not ship until 16.2 — a plate that vanishes
   on an older iPhone is not a trade worth making for shorter CSS.

   ⚠ ANY AUDIT THAT READS `backgroundColor` WILL MISREAD THIS. The shorthand
   sets background-image (the scrim) AND background-color (the raw accent
   underneath); what is painted is the composite. Composite the
   backgroundImage before judging a plate. */
.v2x.acx .acx-plate{
  background:linear-gradient(rgba(255,255,255,.88),rgba(255,255,255,.88)),var(--acx-accent,#3680ED);
  color:var(--v2-ink);
  display:grid;place-items:center;overflow:hidden}
body.theme-dark .v2x.acx .acx-plate{
  background:linear-gradient(rgba(19,19,23,.82),rgba(19,19,23,.82)),var(--acx-accent,#3680ED);
  color:#EAF0FA}

/* Glyph sizing per placement. The plate BOXES come from the directory sheet
   (66px card, 52px list row, 34px rail); only the glyph inside them is ours.
   These are Lucide SVGs rendered through <x-lucide>, not <i> glyphs, so the
   lever is width/height — a font-size rule here would do nothing at all and
   the icon would sit at its intrinsic 24px everywhere. */
.v2x.acx .dir-tc-logo.acx-plate svg{width:27px;height:27px}
.v2x.acx .dir-lc-logo.acx-plate svg{width:21px;height:21px}
.v2x.acx .dir-tr-lg.acx-plate   svg{width:15px;height:15px}

/* Hero orbit tiles get the same treatment at a lighter scrim — they sit on
   the hero's tinted ground rather than on a card, so they can afford more
   hue. The directory floats four model LOGOS here; ours are the four
   featured categories. */
.v2x.acx .dir-hh-tile.acx-plate{
  background:linear-gradient(rgba(255,255,255,.9),rgba(255,255,255,.9)),var(--acx-accent,#3680ED);
  color:var(--v2-ink)}
.v2x.acx .dir-hh-tile.acx-plate svg{width:30px;height:30px}
body.theme-dark .v2x.acx .dir-hh-tile.acx-plate{
  background:linear-gradient(rgba(23,23,27,.86),rgba(23,23,27,.86)),var(--acx-accent,#3680ED);
  color:#EAF0FA}

/* The category rail card's icon is already tone-cycled by the directory
   sheet, so it is deliberately NOT re-painted — only sized, because the
   directory's cards carry Font Awesome <i> and ours carry Lucide <svg>. */
.v2x.acx .dir-cat-card-ico svg{width:22px;height:22px}
.v2x.acx .dir-hh-stat-ico svg{width:20px;height:20px}


/* ═══ §FLAG — featured / trending ribbon ════════════════════════════════════
   Absolute in the card's top-right. The directory has no equivalent, so this
   is additive rather than an override.

   Both tone pairs are MEASURED, not picked: #7A4A05 on #FEF3C7 is 6.71:1 and
   #9F1239 on #FFE4E6 is 6.68:1. Dark mode drops the wash to a translucent
   tint of the same hue and lifts the ink: 8.25:1 and 7.27:1 respectively. */
.v2x.acx .acx-flag{
  position:absolute;top:12px;right:12px;z-index:3;
  display:inline-flex;align-items:center;gap:4px;
  padding:4px 9px 4px 7px;border-radius:999px;
  font-size:10.5px;font-weight:760;letter-spacing:.01em;line-height:1;
  pointer-events:none}
.v2x.acx .acx-flag svg{width:11px;height:11px;flex:0 0 auto}
.v2x.acx .acx-flag.is-star{background:#FEF3C7;color:#7A4A05}
.v2x.acx .acx-flag.is-fire{background:#FFE4E6;color:#9F1239}
body.theme-dark .v2x.acx .acx-flag.is-star{background:rgba(245,158,11,.18);color:#FCD34D}
body.theme-dark .v2x.acx .acx-flag.is-fire{background:rgba(244,63,94,.18);color:#FDA4AF}

/* The rank chip and the flag both want the card's top-right. The rank moves
   to the LEFT here rather than the flag moving, because the rank is the same
   element on all six pages and a reader scanning two of them expects it in
   the same place. */
.v2x.acx .dir-tc .dir-tc-rank{right:auto;left:12px}


/* ═══ §STRIP — the signal strip ═════════════════════════════════════════════
   Rating · certificate. It was rating · enrolment · length · certificate
   until 2026-08-22, when the enrolment count and the running time came off
   both cards on request. `.acx-fig` stays general — it still dresses the
   certificate claim and, in list mode, the byline. Each figure drops
   individually at zero rather than printing a placeholder: a grey star row
   reads as "rated badly", not as "not yet rated". */
.v2x.acx .acx-strip{
  display:flex;flex-wrap:wrap;align-items:center;justify-content:center;
  gap:6px 10px;margin:10px 0 0;min-height:18px}
.v2x.acx .acx-fig{
  display:inline-flex;align-items:center;gap:4px;
  font-size:11.5px;font-weight:620;color:var(--v2-muted);white-space:nowrap}
.v2x.acx .acx-fig svg{width:12px;height:12px;flex:0 0 auto;opacity:.85}
.v2x.acx .acx-fig b{font-weight:760;color:var(--v2-ink);letter-spacing:-.005em}
/* §NMROW — the title row that carries the certificate chip     (2026-09-02)
   ─────────────────────────────────────────────────────────────────────────
   The chip used to sit in `.acx-strip` beside the rating and was moved up
   beside the title. It is a SIBLING of the `<h3 class="dir-tc-nm">`, never a
   child: inside the heading its "Certificate" label would join the heading
   text on 15 of the 24 cards this listing renders. The verified tick stays
   inside the h3 — it is an icon with a title attribute and contributes no
   text. Copied from the glossary card's `.glx-nmrow`.

   ⚠ `max-width:100%` is the load-bearing line, not `min-width:0`. This row is
   a flex ITEM of `.dir-tc`, a flex COLUMN with `align-items:center`, and a
   centred item is sized to its own content — never shrunk. Without the cap the
   row lays out at its natural width inside a narrower card and hangs over the
   edge, which is exactly the bug §GLXROW in public-dir-bands.css documents
   (8 overflowing glossary cards). `min-width:0` only starts mattering once the
   cap makes the row shrinkable, so both are needed, in that order. */
.v2x.acx .acx-nmrow{
  display:flex;align-items:center;justify-content:center;flex-wrap:wrap;
  gap:5px 6px;max-width:100%;min-width:0}
.v2x.acx .acx-nmrow .dir-tc-nm{min-width:0}

/* Certificate is the one figure that is a CLAIM rather than a number, so it
   gets the emerald the rest of the site uses for "yes, included". Measured:
   #047857 on #ECFDF5 is 5.21:1; dark #6EE7B7 on the tint is 8.42:1. */
.v2x.acx .acx-fig.is-cert{
  padding:2px 8px;border-radius:999px;background:#ECFDF5;color:#047857}
.v2x.acx .acx-fig.is-cert b{color:#047857;font-weight:700}
.v2x.acx .acx-fig.is-cert svg{opacity:1}
body.theme-dark .v2x.acx .acx-fig.is-cert{background:rgba(16,185,129,.16);color:#6EE7B7}
body.theme-dark .v2x.acx .acx-fig.is-cert b{color:#6EE7B7}

/* In list mode the strip's figures join the meta row rather than forming
   their own line — the row is already horizontal and a second strip inside it
   would read as a nested component. */
.v2x.acx .dir-lc .acx-fig{font-size:11px}
.v2x.acx .dir-lc-meta{flex-wrap:wrap;gap:6px 10px}


/* ═══ §BY — the provider byline ═════════════════════════════════════════════
   Below the strip, above the pills. Named the INSTRUCTOR until 2026-08-22;
   it now names the provider (Coursera, DeepLearning.AI, MIT), which is why
   the glyph beside it is a building rather than a person. Truncated with
   ellipsis rather than wrapped: two lines of a name pushes the button row
   out of alignment across the grid, and the card is already centred. */
.v2x.acx .acx-by{
  display:flex;align-items:center;justify-content:center;gap:5px;
  margin:8px 0 0;max-width:100%;
  font-size:11.5px;font-weight:600;color:var(--v2-muted)}
.v2x.acx .acx-by svg{width:12px;height:12px;flex:0 0 auto;opacity:.8}
.v2x.acx .acx-by span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}


/* ═══ §CTA — the card's button ══════════════════════════════════════════════
   A price used to sit beside this button inside an `.acx-cta` flex row. That
   wrapper is gone (2026-08-22) and so is the override it needed, because the
   reason it existed no longer applies:

   `.dir-tc-btn` in the SHARED sheet is `width:100%` + `margin-top:auto`, and
   that auto margin is what pins the button to the bottom of a flex card so a
   row of unequal cards still lines its CTAs up. Wrapping it broke both — the
   auto margin moved to the wrapper and 100% width left the price no room — so
   the wrapper took the margin back and the button dropped to auto width.
   Unwrapped, the button simply inherits the shared geometry and needs NO rule
   here. Do not re-add one: an override at this specificity is how the bottom
   alignment gets broken by accident.

   The right-hand column of the LIST row is the one thing still worth stating,
   because it is a column that holds a single item. */
.v2x.acx .dir-lc-side{display:flex;flex-direction:column;align-items:flex-end;gap:8px}


/* ═══ §CHIP — active-filter chips ═══════════════════════════════════════════
   One-tap removal above the results, so a visitor can undo a filter without
   reopening the rail. Same component as /ai-projects' `.apx-chip`, renamed to
   this page's scope so the two can diverge without a shared-sheet edit. */
.v2x.acx .acx-chips{
  display:flex;flex-wrap:wrap;align-items:center;gap:8px;margin:0 0 16px}
.v2x.acx .acx-chip{
  display:inline-flex;align-items:center;gap:6px;
  padding:5px 6px 5px 12px;border-radius:999px;
  background:var(--v2-accent-soft,#eaf1fe);border:1px solid rgba(54,128,237,.22);
  font-size:12.5px;font-weight:640;color:var(--brand-blue,#2060C0);line-height:1.3}
.v2x.acx .acx-chip button{
  display:grid;place-items:center;width:18px;height:18px;padding:0;
  border:0;border-radius:50%;background:rgba(54,128,237,.16);
  color:inherit;cursor:pointer;transition:background .16s ease,transform .16s ease}
.v2x.acx .acx-chip button svg{width:10px;height:10px}
.v2x.acx .acx-chip button:hover{background:rgba(54,128,237,.3);transform:scale(1.08)}
.v2x.acx .acx-chip-clear{
  padding:5px 12px;border:1px dashed var(--v2-line);border-radius:999px;
  background:transparent;color:var(--v2-muted);
  font-size:12.5px;font-weight:640;cursor:pointer;font-family:inherit;
  transition:color .16s ease,border-color .16s ease}
.v2x.acx .acx-chip-clear:hover{color:var(--v2-ink);border-color:var(--v2-ink)}
body.theme-dark .v2x.acx .acx-chip{
  background:rgba(54,128,237,.16);border-color:rgba(96,164,245,.28);color:#9DC4FA}
body.theme-dark .v2x.acx .acx-chip button{background:rgba(96,164,245,.2)}
body.theme-dark .v2x.acx .acx-chip button:hover{background:rgba(96,164,245,.34)}


/* ═══ §BUSY — dim while filtering ═══════════════════════════════════════════
   ⚠ `wire:loading.class="is-busy"` is on the results grid in every one of
   these listings, and `is-busy` is defined in NO sheet in the stack — not the
   directory's, not the token layer, not custom.*.css. Grepped: zero hits.
   Without this block the class lands and nothing happens, so a filter change
   looks frozen for the length of the round-trip. Fifth module to hit it. */
.v2x.acx .acx-results{transition:opacity .18s ease,filter .18s ease}
.v2x.acx .acx-results.is-busy{opacity:.45;filter:saturate(.6);pointer-events:none}


/* ═══ §HERE — "you are here" on the category rail ══════════════════════════
   The rail renders on the hubs too, so the card for the category you are
   already on gets a ring. The ring is currentColor and therefore already
   theme-correct; only the drop shadow needs a dark twin. */
.v2x.acx .dir-cat-card.is-here{
  box-shadow:inset 0 0 0 2px currentColor,0 10px 28px -18px rgba(16,24,40,.5)}
body.theme-dark .v2x.acx .dir-cat-card.is-here{
  box-shadow:inset 0 0 0 2px currentColor,0 10px 28px -18px rgba(0,0,0,.8)}

/* "View all …" footer link under a band. Geometry only here; the premium
   treatment is §ACXPRM-CTA at the foot of this file. */


/* ═══ §ABOUT — hub about panel ═════════════════════════════════════════════
   The taxonomy row's own description, shown under the results on a hub and
   suppressed on the index. */
.v2x.acx .acx-about{max-width:var(--seo-shell-max,1280px);margin:0 auto;padding:0 var(--seo-shell-pad,20px) 8px}
.v2x.acx .acx-about-box{
  padding:26px 28px;border:1px solid var(--v2-line);border-radius:20px;background:#fff;
  box-shadow:inset 0 1px 0 rgba(255,255,255,.7),0 1px 2px rgba(16,24,40,.04)}
.v2x.acx .acx-about-box h2{
  margin:0 0 10px;font-size:1.25rem;font-weight:800;letter-spacing:-.02em;color:var(--v2-ink)}
.v2x.acx .acx-about-box p{margin:0;font-size:.95rem;line-height:1.7;color:var(--v2-muted)}
body.theme-dark .v2x.acx .acx-about-box{
  background:rgba(29,29,34,.92);border-color:var(--dk-line,rgba(255,255,255,.10));
  box-shadow:inset 0 1px 0 rgba(255,255,255,.06),0 1px 2px rgba(0,0,0,.4)}


/* ═══ §CATGRID — /ai-courses/category ═══════════════════════════════════════
   The categories hub reuses `.dir-cat-card`, which in the rail is
   `flex:0 0 <width>`. In a grid track that fixed basis fights the column, so
   it is released here and the track does the sizing. */
.v2x.acx .acx-catgrid{
  display:grid;grid-template-columns:repeat(auto-fill,minmax(248px,1fr));gap:18px}
.v2x.acx .acx-catgrid .dir-cat-card{flex:1 1 auto;width:auto;min-width:0;scroll-snap-align:none}

/* ⚠️ THE FIVE BROWSE BANDS THAT USED TO BE DECLARED AT THIS LINE — the level
   and skill pills, the provider rows, the leaderboard / newest panels and the
   goal tiles — ARE NOW §ACXPRM AT THE FOOT OF THIS FILE. Nothing is declared
   here; one home for the values, and this note so the next reader does not go
   looking for a rule set that has moved rather than vanished.

   What they were: flat #fff boxes with a 1px `--v2-line` edge, one blue icon
   plate on every tile and a hover that changed the border colour and lifted
   2px. Correct, and nothing like the `.dir-cat-card` grid three bands above
   them on the SAME page — which is the whole reason for the rewrite. */


/* ═══ §IOS — the 16px focus-zoom floor ══════════════════════════════════════
   `.dir-hh-search input` is 15.5px in the SHARED sheet (14px under 820px), so
   iOS Safari zooms the viewport the moment the field takes focus and the page
   is left scrolled sideways. Confirmed by measuring /ai-directory itself:
   14px at 390 and 15.5px at 820.

   This is pinned to `.v2x.acx` ONLY. Raising it in the shared sheet is the
   real fix and would reflow five pages that have not been re-verified — the
   shared miss is real and still wants its own pass. */
.v2x.acx .dir-hh-search input,
.v2x.acx .dir-hh-search input::placeholder{font-size:16px}
@media (max-width:820px){
  .v2x.acx .dir-hh-search input,
  .v2x.acx .dir-hh-search input::placeholder{font-size:16px}
}


/* ═══ §RESP — responsive ════════════════════════════════════════════════════
   The shared sheet's breakpoint ladder, measured by frequency, is
   820 ×8 · 520 ×5 · 1180 ×5 · 640 ×3 · 900 ×2 · 1100 ×2. This file uses the
   SAME stops rather than Bootstrap's, so a page never reflows halfway. */

/* 1180, not 1100: the shared sheet's ladder is 400 420 480 520 560 640 680
   820 900 1180 1500 and does NOT contain 1100. Reflowing at a stop the rest
   of the page never uses makes the layout change twice on the way down. */
/* §ACXPRM owns the ladder for .acx-two, .acx-goals, .acx-provgrid and the
   pills — see §ACXPRM-RESP. The stops below are the ones this file still
   owns on its own. */

@media (max-width:820px){
  .v2x.acx .acx-catgrid{grid-template-columns:repeat(auto-fill,minmax(210px,1fr));gap:14px}
  .v2x.acx .acx-about{padding-inline:16px}
  .v2x.acx .acx-about-box{padding:20px 18px;border-radius:16px}
}

@media (max-width:640px){
  /* The list row's right column stops being a column: at this width the price
     and the CTA have more room side by side under the text than stacked
     beside it.

     ⚠️ "UNDER THE TEXT" NEEDS A WRAPPING ROW, AND THE SHARED SHEET DOES NOT
     GIVE US ONE. `.dir-lc` is `display:flex` with no `flex-wrap` — so `nowrap`
     by initial value — and at 680px the base restates it explicitly, under a
     comment that the row "stays as a single horizontal flex line". On top of
     that `.dir-lc-side` is `flex:0 0 auto`, so it cannot shrink back either.
     A full-width unshrinkable item on a single-line row therefore claimed the
     ENTIRE row: measured at 360px, `.dir-lc-mid` was squashed to 0px — no
     title, no description — and the side block ran to x=413 inside a row
     ending at 331, so the price and the CTA were cut off by `.dir-lc`'s own
     `overflow:hidden`. The rule was written for a layout it never got; the
     `flex-wrap` below is the half that was missing. /deals had the identical
     defect for the identical reason — see §LCWRAP in public-deals.css. */
  .v2x.acx .dir-lc{flex-wrap:wrap;row-gap:10px}
  .v2x.acx .dir-lc-side{flex-direction:row;align-items:center;justify-content:space-between;width:100%}

  /* `.dir-lc-mid` is `flex:1 1 auto`, so on a wrapping row its base size is
     its max-content and it takes a whole line to itself — which strands the
     rank chip and the logo plate on an empty line above it. A small basis
     keeps it beside them and lets it grow into whatever is left. Measured at
     360px: 290px wide and a 206px row without this, 204px and 193px with it. */
  .v2x.acx .dir-lc-mid{flex:1 1 120px}

  /* The side column is a full-width row here and, since the price came off,
     holds one item. `space-between` above would strand a compact button at
     the left of an otherwise empty row, so it stretches instead. */
  .v2x.acx .dir-lc-side .dir-tc-btn{flex:1 1 auto}
}

@media (max-width:520px){
  .v2x.acx .acx-catgrid{grid-template-columns:1fr}
  .v2x.acx .acx-strip{gap:5px 8px}
  .v2x.acx .acx-fig{font-size:11px}
  .v2x.acx .acx-flag span{display:none}
  .v2x.acx .acx-flag{padding:5px;gap:0}
  /* The chip row is the only horizontal-overflow risk on a 320px screen —
     the chips wrap, but a single long search term cannot, so it truncates. */
  .v2x.acx .acx-chip{max-width:100%;overflow:hidden}
}


/* ═══ REDUCED MOTION ════════════════════════════════════════════════════════
   Everything above that moves is a hover translate or an opacity fade; none
   of it carries meaning, so all of it goes. */
@media (prefers-reduced-motion:reduce){
  /* The five browse bands are handled in §ACXPRM-A11Y, which owns every
     layer it animates. What is left here is this file's own chrome. */
  .v2x.acx .acx-chip button,
  .v2x.acx .acx-results{transition:none}
  .v2x.acx .acx-chip button:hover{transform:none}
}


/* ═══════════════════════════════════════════════════════════════════════════
   §ACXPRM — the five browse bands, at §CATPRM parity            (2026-08-23)
   ═══════════════════════════════════════════════════════════════════════════
   /ai-courses/category carries SIX bands. The first of them — All Course
   Categories — is `.dir-cat-card`, and on 2026-08-18 that card was brought to
   the homepage's premium recipe (§CATPRM in public-dir-bands.css): a tone
   wash, a corner bloom, a tinted hairline, a tone-tinted lift and a masked
   conic ring that sweeps on hover.

   The five bands UNDER it were not. They rendered as flat #fff boxes with a
   `--v2-line` hairline, one blue icon plate on every tile regardless of what
   it was, and a hover that moved the border colour and lifted 2px. Side by
   side on one page that is not a difference in emphasis, it is two products:

                       .dir-cat-card (band 1)     the five bands below it
     surface           tone wash + corner bloom   flat #fff
     edge              rgba(hue, .20)             flat #e7eaf0
     plate             tone gradient, white glyph blue tint, blue glyph — ×5
     lift              tone-tinted, 4 layers      one grey shadow
     hover             ring sweep + foot bar      border colour
     truncation        —                          provider names ellipsised

   §ACXPRM closes all six rows. It is NOT a copy of §CATPRM — that block is
   scoped to `.dir-cat-card` and lives in a sheet these five classes do not
   share a selector with — but every value below is §CATPRM's, so the six
   bands on this page are visibly one system.

   ── WHAT IS DIFFERENT FROM §CATPRM, AND WHY ───────────────────────────────
   1 · `background-color` is a LONGHAND here, and the `background` shorthand
       appears nowhere in this block. §CATPRM has to fight a base sheet that
       sets `background:#fff` at (0,2,0) and `background:rgba(28,31,42,.9)` at
       (0,3,1) — the shorthand resets `background-image`, which is how a wash
       ships correct by day and flat by night. These five classes have no base
       rule anywhere else, so the trap is designed out rather than worked
       around. See [[dark-background-shorthand-trap]].
   2 · Every value that BOTH the dark twin and a hover state want to change
       goes through a `--acp-…-now` alias, read as
       `var(--acp-x-now, var(--acp-x))`. A hover rule is (0,4,0) and the dark
       twin is (0,4,1), so a hover that writes the PROPERTY works by day and
       does nothing by night. Writing the custom property instead is a fight
       there is nothing to lose. Same technique, same reason, as §CATPRM's
       `--dcp-edge-now`.
   3 · The tone comes with TWO values, not one — see §ACXPRM-RGB.

   Data: every count, name and ratio on these bands is read live in
   App\Http\Livewire\Public\V2\AiCourseCategoryIndex::render().
   ═══════════════════════════════════════════════════════════════════════════ */


/* ── §ACXPRM-RGB) One palette, two values per tone ────────────────────────
   `--acx-rgb` is the HUE as a triplet, identical in both themes, and it is
   what every alpha layer below interpolates. `--acx-ink` is the READABLE twin
   of that hue: the same colour darkened 40% for a light surface, lightened
   30% for a dark one.

   Two values because one cannot do both jobs. Amber is the proof: #F59E0B
   measures 2.15:1 on white — unreadable as 14px text and short even of the
   3:1 non-text floor — while the lightened #F8BB54 measures 9.7:1 on the dark
   card and is invisible on a white one. A single "ink" token that is not tone
   stable is exactly the bug [[dtc-ink-dark-not-tone-stable]] records.

   The eight triplets are §CATPRM-RGB's verbatim, so an amber goal tile, an
   amber category card and an amber promise card on THIS page are one amber.
   The light inks are the hue at 40% black and measure 5.1:1 – 12:1 on their
   own tint; the dark inks are the hue at 30% white and measure 6.7:1 – 14:1
   on the dark card. Both floors are for 13–16px text, which is what these
   tokens actually colour.

   ⚠️ THE FALLBACK ON THE BARE SELECTOR IS LOAD-BEARING. An undefined triplet
   makes every `rgba(var(--acx-rgb), …)` below an INVALID declaration, and an
   invalid declaration is dropped SILENTLY — no wash, no bloom, no edge, no
   ring, and nothing in the output to say why. `data-tone` is cycled by
   position here, but it is an ATTRIBUTE: an unlisted value reaching it is a
   when, not an if. Same trap §CATPRM-RGB and §HPXP-RGB both record.

   ⚠️ SPECIFICITY, and it is not decoration: the light tone rules are (0,4,0)
   and the bare dark rule is (0,4,1), so a bare `body.theme-dark` twin would
   out-rank EVERY light tone rule and paint eight violet tiles blue after
   dark. Each dark rule is therefore tone-scoped too, at (0,5,1). */
.v2x.acx :is(.acx-goal,.acx-prov,.acx-panel,.acx-pill){--acx-rgb:54,128,237;--acx-ink:#204D8E}
.v2x.acx :is(.acx-goal,.acx-prov,.acx-panel,.acx-pill)[data-tone="blue"]   {--acx-rgb:54,128,237;--acx-ink:#204D8E}
.v2x.acx :is(.acx-goal,.acx-prov,.acx-panel,.acx-pill)[data-tone="violet"] {--acx-rgb:139,92,246;--acx-ink:#533794}
.v2x.acx :is(.acx-goal,.acx-prov,.acx-panel,.acx-pill)[data-tone="indigo"] {--acx-rgb:99,102,241;--acx-ink:#3B3D91}
.v2x.acx :is(.acx-goal,.acx-prov,.acx-panel,.acx-pill)[data-tone="rose"]   {--acx-rgb:244,63,94; --acx-ink:#922638}
.v2x.acx :is(.acx-goal,.acx-prov,.acx-panel,.acx-pill)[data-tone="amber"]  {--acx-rgb:245,158,11;--acx-ink:#935F07}
.v2x.acx :is(.acx-goal,.acx-prov,.acx-panel,.acx-pill)[data-tone="emerald"]{--acx-rgb:16,185,129;--acx-ink:#0A6F4D}
.v2x.acx :is(.acx-goal,.acx-prov,.acx-panel,.acx-pill)[data-tone="cyan"]   {--acx-rgb:34,184,217;--acx-ink:#146E82}
.v2x.acx :is(.acx-goal,.acx-prov,.acx-panel,.acx-pill)[data-tone="orange"] {--acx-rgb:249,115,22;--acx-ink:#95450D}

body.theme-dark .v2x.acx :is(.acx-goal,.acx-prov,.acx-panel,.acx-pill){--acx-ink:#72A6F2}
body.theme-dark .v2x.acx :is(.acx-goal,.acx-prov,.acx-panel,.acx-pill)[data-tone="blue"]   {--acx-ink:#72A6F2}
body.theme-dark .v2x.acx :is(.acx-goal,.acx-prov,.acx-panel,.acx-pill)[data-tone="violet"] {--acx-ink:#AE8DF9}
body.theme-dark .v2x.acx :is(.acx-goal,.acx-prov,.acx-panel,.acx-pill)[data-tone="indigo"] {--acx-ink:#9294F5}
body.theme-dark .v2x.acx :is(.acx-goal,.acx-prov,.acx-panel,.acx-pill)[data-tone="rose"]   {--acx-ink:#F7798E}
body.theme-dark .v2x.acx :is(.acx-goal,.acx-prov,.acx-panel,.acx-pill)[data-tone="amber"]  {--acx-ink:#F8BB54}
body.theme-dark .v2x.acx :is(.acx-goal,.acx-prov,.acx-panel,.acx-pill)[data-tone="emerald"]{--acx-ink:#58CEA7}
body.theme-dark .v2x.acx :is(.acx-goal,.acx-prov,.acx-panel,.acx-pill)[data-tone="cyan"]   {--acx-ink:#64CDE4}
body.theme-dark .v2x.acx :is(.acx-goal,.acx-prov,.acx-panel,.acx-pill)[data-tone="orange"] {--acx-ink:#FB9D5C}


/* ── §ACXPRM-SCRIM) One number for every solid tone plate ─────────────────
   A white glyph or a white label on a raw brand hue is not safe: amber
   measures 2.15:1 against white and cyan 2.6:1, so half the palette would
   fail even the 3:1 icon floor and all of it would fail 4.5:1 for text.

   The fix is one flat 32% BLACK SCRIM composited over the hue —
   `background-color: rgb(hue)` plus `background-image: linear-gradient(
   rgba(0,0,0,.32), rgba(0,0,0,.32))` — which is deterministic, needs no
   `color-mix()` (Chrome 111+ / Safari 16.2+, and a dropped declaration here
   would be an unreadable chip rather than a wrong-but-legible one) and lands
   every tone in the same band. Measured, white on the scrimmed hue:

     amber  4.42:1   cyan  4.13:1   emerald 4.41:1   orange 4.9:1
     blue   7.36:1   rose  5.5:1    violet  9.7:1    indigo 8.6:1

   Every one clears 4.5:1 except cyan and amber, which clear it on the two
   places they are used — 22px icons and a 17px/820 monogram, both well past
   the large-text threshold — and clear the 3:1 non-text floor with room.

   It is the same technique §PLATE at the head of this file uses for the
   listing card plate, inverted: there a WHITE scrim lifts a hue off a dark
   card, here a BLACK one drops it under white type. One number, eight tones,
   both themes — the contrast of white-on-hue does not depend on what is
   behind the chip, so this needs no dark twin at all. */


/* ── §ACXPRM-SURF) The shared premium surface ─────────────────────────────
   `.acx-pc` is worn by the goal tile, the provider row and both panels. It is
   §CATPRM's five layers with §CATPRM's alphas:

     wash   linear-gradient(152deg, rgba(hue,.075) → 0 @48% → rgba(hue,.055))
     bloom  radial-gradient(220px 200px at calc(100%+30px) -54px, rgba(hue,.20))
     edge   border-color: rgba(hue, .20)
     lift   4 layers, one of them rgba(hue, .40)
     bar    a background LAYER, 34% wide at 3px, growing to 100% at 4px

   The 152deg angle, the 48% dead stop and the fade to `rgba(same-hue, 0)`
   rather than the `transparent` KEYWORD are all load-bearing: a gradient
   fading to `transparent` interpolates through transparent BLACK in sRGB and
   leaves a grey fringe down the middle of the card. The bloom's centre sits
   OUTSIDE the box on purpose, so what lands on the card is the falloff rather
   than a circle drawn on it — draw the whole circle inside and it reads as a
   sticker instead of as light.

   The foot bar is a background layer and not a pseudo-element for the same
   reason §CATPRM-BAR gives: `background-size` is animatable, and both pseudo
   slots are spent — `::before` is the sheen, `::after` is the ring. */
.v2x.acx .acx-pc{
  /* the ramp — four numbers, and dark is these four numbers and nothing else */
  --acp-a1:.075;      /* wash, the lit corner */
  --acp-a2:.055;      /* wash, the far corner */
  --acp-edge:.20;     /* the tinted hairline */
  --acp-bloom:.20;    /* the corner bloom's hot end */
  --acp-plate-a:.12;  /* the rest-state icon plate tint */
  --acp-sheen:rgba(255,255,255,.5);
  --acp-sh-inset:rgba(255,255,255,.7);
  --acp-sh-seat:rgba(16,24,40,.04);
  --acp-sh-neut:rgba(16,24,40,.26);
  --acp-sh-tone:.40;
  --acp-surface:#fff;

  position:relative;
  isolation:isolate;
  overflow:hidden;
  border:1px solid rgba(var(--acx-rgb), var(--acp-edge-now, var(--acp-edge)));
  border-radius:20px;
  text-decoration:none;
  color:var(--v2-ink);

  background-color:var(--acp-surface);
  background-image:
    /* 1 · the foot bar */
    linear-gradient(90deg,
      rgba(var(--acx-rgb), .18) 0%,
      rgba(var(--acx-rgb), 1)  50%,
      rgba(var(--acx-rgb), .18) 100%),
    /* 2 · the corner bloom */
    radial-gradient(220px 200px at calc(100% + 30px) -54px,
      rgba(var(--acx-rgb), var(--acp-bloom-now, var(--acp-bloom))) 0%,
      rgba(var(--acx-rgb), 0) 72%),
    /* 3 · the diagonal wash */
    linear-gradient(152deg,
      rgba(var(--acx-rgb), var(--acp-a1)) 0%,
      rgba(var(--acx-rgb), 0)             48%,
      rgba(var(--acx-rgb), var(--acp-a2)) 100%);
  background-repeat:no-repeat;
  background-position:50% 100%, 0 0, 0 0;
  background-size:var(--acp-bar-w, 34%) var(--acp-bar-h, 3px), 100% 100%, 100% 100%;

  box-shadow:
    inset 0 1px 0 var(--acp-sh-inset),
    0 1px 2px var(--acp-sh-seat),
    0 var(--acp-sh-y, 14px) var(--acp-sh-blur, 30px) var(--acp-sh-spread, -22px)
      rgba(var(--acx-rgb), var(--acp-sh-tone-now, var(--acp-sh-tone))),
    0 var(--acp-sh-y2, 10px) var(--acp-sh-blur2, 24px) -20px var(--acp-sh-neut);

  transform:translateY(var(--acp-lift, 0));
  transition:
    transform .34s var(--ease-out),
    border-color .26s ease,
    box-shadow .34s ease,
    background-size .34s var(--ease-out);
}

/* Dark. The card sits LIGHTER than the page it is on and separates by itself,
   so the wash is free to carry hue rather than separation — and every alpha
   rises anyway, because a 5% tint that reads over white is invisible over
   near-black. Nothing but tokens is set here, which is what keeps the hover
   states below working in both themes. */
body.theme-dark .v2x.acx .acx-pc{
  --acp-a1:.13;
  --acp-a2:.09;
  --acp-edge:.30;
  --acp-bloom:.17;
  --acp-plate-a:.18;
  --acp-sheen:rgba(255,255,255,.10);
  --acp-sh-inset:rgba(255,255,255,.05);
  --acp-sh-seat:rgba(0,0,0,.42);
  --acp-sh-neut:rgba(0,0,0,.78);
  --acp-sh-tone:.34;
  --acp-surface:rgba(29,29,34,.92);
}

/* The content sits ABOVE the sheen. `.acx-pc` isolates, `::before` is at
   z-index 0 and in-flow children paint BEFORE positioned descendants in the
   CSS painting order — so without this lift a 50%-white sheen would sweep
   over every word on the card. The user-visible symptom of getting this
   wrong is text that flashes out on hover, which is why it is spelled out. */
.v2x.acx .acx-pc > *{position:relative;z-index:1}

/* ── §ACXPRM-SHEEN) The light that crosses on hover ───────────────────────
   A single diagonal highlight, one pass, .9s. It runs ONCE per pointer entry
   rather than looping: a loop on eleven cards is eleven permanent animations
   and reads as a screensaver. */
.v2x.acx .acx-pc::before{
  content:'';
  position:absolute;
  inset:-40% -12%;
  z-index:0;
  pointer-events:none;
  opacity:0;
  background-image:linear-gradient(104deg,
    rgba(255,255,255,0) 40%,
    var(--acp-sheen) 50%,
    rgba(255,255,255,0) 60%);
  transform:translateX(-140%) rotate(2deg);
}
@keyframes acx-sheen{
  0%  {opacity:0;transform:translateX(-140%) rotate(2deg)}
  18% {opacity:1}
  100%{opacity:0;transform:translateX(140%)  rotate(2deg)}
}
@media (hover:hover){
  .v2x.acx .acx-pc:hover::before{animation:acx-sheen .9s var(--ease-out) 1}
}

/* ── §ACXPRM-ORBIT) The rotating light ────────────────────────────────────
   §CATPRM-ORBIT on this page's own hosts. THE HUE IS NOT FIXED: it reads
   `--acx-rgb`, so a violet tile orbits violet and an amber one amber — the
   difference between an effect pasted onto a band and a system.

   Speed is a statement about SIZE, which is why the three hosts differ: the
   small goal tile sweeps in 3.4s, the smaller provider row in 3.0s, and the
   tall panel in 5.4s, because slow reads as large.

   A NEW registered property and keyframe rather than reusing §CATPRM's
   `--dcp-spin`: public-dir-bands.css and this file are both loaded here
   today, but this sheet is also the one an /ai-courses page loads on its own,
   and borrowing a name is borrowing a definition that may not be there. */
@property --acx-spin{syntax:"<angle>";inherits:false;initial-value:0deg}
@keyframes acx-orbit{to{--acx-spin:360deg}}

@supports ((-webkit-mask-composite: xor) or (mask-composite: exclude)){
  /* Two full-box mask layers — one clipped to the content box, one to the
     border box — composited with xor, leaving exactly the padding band.
     `mask-clip` follows `border-radius`, so the inner cut is a rounded rect
     on a rounded rect and the corners stay true.

     ⚠️ THE @supports GATE IS LOAD-BEARING, NOT DEFENSIVE. Without
     mask-composite the two layers UNION and the conic paints as a SOLID
     BLOCK over the card, covering every word on it. Where it is missing
     there is simply no ring, which is the previous design and not a broken
     one. */
  .v2x.acx .acx-pc::after{
    content:'';
    position:absolute;
    inset:0;
    z-index:2;
    pointer-events:none;
    border-radius:inherit;
    padding:1.5px;
    opacity:0;
    --acx-spin:0deg;
    background-image:conic-gradient(from var(--acx-spin),
      rgba(var(--acx-rgb), 0)                   0deg,
      rgba(var(--acx-rgb), var(--acp-o1, .5))  30deg,
      rgba(255,255,255,1)                      52deg,
      rgba(var(--acx-rgb), var(--acp-o2, .88)) 74deg,
      rgba(var(--acx-rgb), 0)                 118deg,
      rgba(var(--acx-rgb), 0)                 180deg,
      rgba(var(--acx-rgb), var(--acp-o1, .5)) 210deg,
      rgba(255,255,255,1)                     232deg,
      rgba(var(--acx-rgb), var(--acp-o2, .88))254deg,
      rgba(var(--acx-rgb), 0)                 298deg,
      rgba(var(--acx-rgb), 0)                 360deg);
    -webkit-mask:linear-gradient(#000 0 0) content-box,linear-gradient(#000 0 0);
            mask:linear-gradient(#000 0 0) content-box,linear-gradient(#000 0 0);
    -webkit-mask-composite:xor;
            mask-composite:exclude;
    transition:opacity .32s ease;
    animation:acx-orbit var(--acp-spin-t, 3.4s) linear infinite;
    /* A paused animation does not tick, so eleven idle cards cost nothing —
       and re-entering RESUMES the sweep rather than snapping the comet back
       to 0deg under the pointer. */
    animation-play-state:paused;
  }
  body.theme-dark .v2x.acx .acx-pc::after{--acp-o1:.66;--acp-o2:1}

  .v2x.acx .acx-prov::after {--acp-spin-t:3s}
  .v2x.acx .acx-panel::after{--acp-spin-t:5.4s;padding:1.7px}

  /* Keyboard is deliberately OUTSIDE the hover query. A keyboard on a touch
     screen is a real combination, and focus deserves the same answer as the
     pointer. */
  .v2x.acx .acx-pc:focus-visible::after{opacity:1;animation-play-state:running}
  @media (hover:hover){
    .v2x.acx .acx-pc:hover::after{opacity:1;animation-play-state:running}
  }
}

/* ── §ACXPRM-STATE) Hover and focus, through the tokens ───────────────────
   Every value here is a CUSTOM PROPERTY, never the property itself. A hover
   rule is (0,4,0) and the dark twin above is (0,4,1), so writing
   `border-color` or `box-shadow` directly would work by day and do nothing by
   night. The `var()`s inside §ACXPRM-SURF pick these up in both themes
   because nothing else sets them. */
@media (hover:hover){
  .v2x.acx .acx-pc:hover{
    --acp-lift:-6px;
    --acp-edge-now:.46;
    --acp-bloom-now:.30;
    --acp-bar-w:100%;
    --acp-bar-h:4px;
    --acp-sh-y:26px;
    --acp-sh-blur:48px;
    --acp-sh-spread:-26px;
    --acp-sh-tone-now:.55;
    --acp-sh-y2:18px;
    --acp-sh-blur2:38px;
  }
}
.v2x.acx .acx-pc:focus-visible{
  --acp-edge-now:.5;
  --acp-bar-w:100%;
  outline:2px solid rgba(var(--acx-rgb), .85);
  outline-offset:3px;
}


/* ═══ §ACXPRM-BAND — the shared band geometry ══════════════════════════════
   These five bands are EDITORIAL and they are capped, where the catalogue
   grid above them is not. The reason is measured, not aesthetic: this shell
   is `--seo-shell-max` (1920px) and /ai-directory renders `.v2x` at 1872px on
   a 2546px monitor. Six goal tiles on a 1872px track auto-fill to FIVE
   columns and leave one orphan stretched across the second row; eight
   provider rows fill to seven and leave one. A 1180px cap fixes the count at
   3 and 4 — which is what makes the rows read as designed rather than as
   whatever fitted. The catalogue grid keeps the full width because it is a
   catalogue: more columns there is more of the thing you came for. */
.v2x.acx{--acx-band:1180px}
.v2x.acx .acx-goals,
.v2x.acx .acx-provgrid,
.v2x.acx .acx-pills,
.v2x.acx .acx-two{max-width:var(--acx-band);margin-inline:auto}

/* The skill head sits under the level pills inside ONE section, so it carries
   its own separation. This used to be an inline `style="margin-top:34px"`. */
.v2x.acx .acx-head-gap{margin-top:40px}


/* ═══ §ACXPRM-GOAL — "Browse by where you are" ═════════════════════════════
   Six tiles, each applying a REAL filter against the listing, so a tile can
   never land on an empty page it promised would be full.

   The composition changed with the skin. It was a two-column row — 40px plate
   beside a title and a 12.5px description — which put the description in a
   ~180px column and made a two-line sentence look like an overflow. It is a
   CARD now: plate and arrow on the head line, title, then the description
   across the full width at 13px/1.6, unclamped. Nothing is truncated on this
   band at any width. */
.v2x.acx .acx-goals{
  display:grid;
  /* 286, not 300: measured in the iframe harness, the goals grid is 598px
     inside a 640px viewport, and 2×300+16 = 616 misses it by 18px — so a
     landscape phone got ONE 598px tile carrying a five-word description.
     2×286+16 = 588 fits, and 3×286+32 = 890 still needs 1024 to appear, so
     nothing above it moves. */
  grid-template-columns:repeat(auto-fill, minmax(min(100%, 286px), 1fr));
  gap:16px;
}
.v2x.acx .acx-goal{
  display:flex;
  flex-direction:column;
  gap:9px;
  padding:20px 20px 22px;
}
.v2x.acx .acx-goal-hd{display:flex;align-items:center;justify-content:space-between;gap:12px}

/* The plate is a TINT at rest and a solid tone chip on hover — the single
   clearest before/after on the band, and the reason the tone reads as
   information rather than as decoration. */
.v2x.acx .acx-goal-ic{
  display:grid;
  place-items:center;
  width:46px;
  height:46px;
  flex:0 0 auto;
  border-radius:15px;
  background-color:rgba(var(--acx-rgb), var(--acp-plate-a));
  background-image:none;
  color:var(--acx-ink);
  box-shadow:inset 0 0 0 1px rgba(var(--acx-rgb), .18);
  transition:background-color .28s ease,color .24s ease,transform .34s var(--ease-spring),box-shadow .28s ease;
}
.v2x.acx .acx-goal-ic svg{width:22px;height:22px}

.v2x.acx .acx-goal-arr{
  display:grid;
  place-items:center;
  width:30px;
  height:30px;
  flex:0 0 auto;
  border-radius:50%;
  background-color:rgba(var(--acx-rgb), .10);
  color:var(--acx-ink);
  opacity:0;
  transform:translateX(-10px) scale(.82);
  transition:opacity .26s ease,transform .34s var(--ease-spring),background-color .26s ease,color .22s ease;
}
.v2x.acx .acx-goal-arr svg{width:15px;height:15px}

.v2x.acx .acx-goal-t{
  display:block;
  font-size:15.5px;
  font-weight:760;
  line-height:1.32;
  letter-spacing:-.014em;
  color:var(--v2-ink);
  transition:color .22s ease;
}
.v2x.acx .acx-goal-d{
  display:block;
  font-size:13px;
  font-weight:500;
  line-height:1.6;
  color:var(--v2-muted);
}

@media (hover:hover){
  .v2x.acx .acx-goal:hover .acx-goal-ic{
    background-color:rgb(var(--acx-rgb));
    background-image:linear-gradient(rgba(0,0,0,.32),rgba(0,0,0,.32));  /* §ACXPRM-SCRIM */
    color:#fff;
    transform:translateY(-2px) scale(1.05);
    box-shadow:inset 0 1px 0 rgba(255,255,255,.3),0 10px 18px -10px rgba(var(--acx-rgb),.9);
  }
  .v2x.acx .acx-goal:hover .acx-goal-arr{
    opacity:1;
    transform:none;
    background-color:rgb(var(--acx-rgb));
    background-image:linear-gradient(rgba(0,0,0,.32),rgba(0,0,0,.32));
    color:#fff;
  }
  .v2x.acx .acx-goal:hover .acx-goal-t{color:var(--acx-ink)}
}


/* ═══ §ACXPRM-PILL — the level ladder and the skill vocabulary ═════════════
   Two rows of chips that must not read as one thing. `is-level` is a LADDER —
   four rungs, tone-coded, filling with their own hue. `is-skill` is a flat
   VOCABULARY — one accent for all of it, with the three the catalogue covers
   most tinted at rest.

   The hover is a fill that slides in from the left rather than a colour
   swap: on a 999px shape a `scaleX` fill reads as a growing bar, a
   `translateX` fill reads as the chip filling up. */
.v2x.acx .acx-pills{
  display:flex;
  flex-wrap:wrap;
  gap:10px;
  justify-content:center;
}
.v2x.acx .acx-pill{
  --acp-pill-bg:#fff;
  --acp-pill-tint:0;
  --acp-pill-edge:.22;

  position:relative;
  isolation:isolate;
  overflow:hidden;
  display:inline-flex;
  align-items:center;
  gap:9px;
  min-height:42px;
  padding:0 7px 0 15px;
  border:1px solid rgba(var(--acx-rgb), var(--acp-pill-edge));
  border-radius:999px;
  background-color:var(--acp-pill-bg);
  background-image:linear-gradient(
    rgba(var(--acx-rgb), var(--acp-pill-tint)),
    rgba(var(--acx-rgb), var(--acp-pill-tint)));
  box-shadow:0 1px 2px rgba(16,24,40,.05);
  font-size:13.5px;
  font-weight:660;
  letter-spacing:-.006em;
  color:var(--v2-ink);
  text-decoration:none;
  transform:translateY(var(--acp-pill-lift, 0));
  transition:transform .28s var(--ease-out),border-color .22s ease,box-shadow .28s ease,color .2s ease;
}
body.theme-dark .v2x.acx .acx-pill{--acp-pill-bg:rgba(29,29,34,.92);box-shadow:0 1px 2px rgba(0,0,0,.4)}

/* The fill. `z-index:-1` under the chip's own `isolation:isolate` puts it
   above the chip background and below every child, so the label is never
   painted over — the same lift §ACXPRM-SURF spells out. */
.v2x.acx .acx-pill::before{
  content:'';
  position:absolute;
  inset:0;
  z-index:-1;
  border-radius:inherit;
  background-color:rgb(var(--acx-rgb));
  background-image:linear-gradient(rgba(0,0,0,.32),rgba(0,0,0,.32));   /* §ACXPRM-SCRIM */
  transform:translateX(-101%);
  transition:transform .42s var(--ease-out);
}

.v2x.acx .acx-pill-t{white-space:nowrap}
.v2x.acx .acx-pill-dot{
  width:9px;
  height:9px;
  flex:0 0 auto;
  border-radius:50%;
  background-color:rgb(var(--acx-rgb));
  background-image:none;
  box-shadow:0 0 0 3px rgba(var(--acx-rgb), .16);
  transition:background-color .24s ease,box-shadow .24s ease;
}
/* ⚠ The dot needs a dark twin, and this is measured rather than assumed:
   against the dark chip the worst of the four level hues is 3.00:1 at full
   saturation — the non-text floor with zero margin. A 22% white scrim lifts
   it to 4.5:1 and every hue stays recognisable. §PLATE's technique, and not
   `color-mix()`, for §PLATE's Safari-16.2 reason. */
body.theme-dark .v2x.acx .acx-pill-dot{
  background-image:linear-gradient(rgba(255,255,255,.22),rgba(255,255,255,.22));
}
.v2x.acx .acx-pill-spark{
  display:grid;
  place-items:center;
  width:13px;
  height:13px;
  flex:0 0 auto;
  color:rgba(var(--acx-rgb), .5);
  transition:color .24s ease,transform .34s var(--ease-spring);
}
.v2x.acx .acx-pill-spark svg{width:13px;height:13px}
.v2x.acx .acx-pill.is-top .acx-pill-spark{color:var(--acx-ink)}

.v2x.acx .acx-pill-n{
  display:inline-grid;
  place-items:center;
  min-width:24px;
  height:26px;
  padding:0 8px;
  border-radius:999px;
  background-color:rgba(var(--acx-rgb), .10);
  color:var(--acx-ink);
  font-size:11.5px;
  font-weight:780;
  font-variant-numeric:tabular-nums;
  transition:background-color .26s ease,color .22s ease,box-shadow .26s ease;
}

/* The three skills the catalogue covers most, tinted at rest. This is the
   ORDER the component already returns (arsort by count) read as a rank — no
   figure is printed that the count chip does not already carry. */
.v2x.acx .acx-pill.is-top{--acp-pill-tint:.07;--acp-pill-edge:.34}
body.theme-dark .v2x.acx .acx-pill.is-top{--acp-pill-tint:.14;--acp-pill-edge:.4}

@media (hover:hover){
  .v2x.acx .acx-pill:hover{
    --acp-pill-lift:-3px;
    border-color:rgba(var(--acx-rgb), .9);
    box-shadow:0 14px 26px -14px rgba(var(--acx-rgb), .7);
    color:#fff;
  }
  .v2x.acx .acx-pill:hover::before{transform:translateX(0)}
  .v2x.acx .acx-pill:hover .acx-pill-dot{background-color:#fff;background-image:none;box-shadow:0 0 0 3px rgba(255,255,255,.26)}
  .v2x.acx .acx-pill:hover .acx-pill-spark{color:#fff;transform:rotate(90deg) scale(1.1)}
  /* Black, NOT white: a 20% white chip over the scrimmed hue lifts the local
     background far enough that the numeral drops to 3.1:1. Darkening instead
     takes it to 6.6:1 on the worst tone, and reads as a recess rather than
     as a second badge. */
  .v2x.acx .acx-pill:hover .acx-pill-n{
    background-color:rgba(0,0,0,.22);
    color:#fff;
    box-shadow:inset 0 0 0 1px rgba(255,255,255,.18);
  }
}
.v2x.acx .acx-pill:focus-visible{
  outline:2px solid rgba(var(--acx-rgb), .85);
  outline-offset:3px;
}


/* ═══ §ACXPRM-PROV — the provider rows ═════════════════════════════════════
   ⚠ THE NAME WRAPS, IT DOES NOT TRUNCATE, and this is the fix the band was
   opened for. `.acx-prov-nm` was `white-space:nowrap` + `text-overflow:
   ellipsis` in a 212px track, which rendered the eighth provider as
   "MIT OpenCourseW…". An ellipsis on a PROPER NOUN is the one place
   truncation costs a reader the whole word — and the row had 40px of free
   height under it. The track sizes on `1fr` and grid items stretch, so a
   two-line name simply makes its own card taller and the row keeps a flat top
   edge. Measured across the eight live providers: one wraps, seven do not.

   The monogram is the SOLID tone chip, not a blue tint on all eight. `logo`
   is NULL on every row today, so what ships is eight letters in eight
   colours; `.is-img` is the branch that survives the day one of them gets a
   logo, and it drops the tone rather than tinting a brand mark — see
   [[platform-chips-brand-marks]] for why a tinted chip destroys one. */
.v2x.acx .acx-provgrid{
  display:grid;
  grid-template-columns:repeat(auto-fill, minmax(min(100%, 232px), 1fr));
  gap:14px;
}
.v2x.acx .acx-prov{
  display:grid;
  grid-template-columns:auto minmax(0,1fr) auto;
  align-items:center;
  gap:12px;
  padding:14px 13px 16px 14px;
  border-radius:18px;
}
.v2x.acx .acx-prov-mono{
  display:grid;
  place-items:center;
  width:42px;
  height:42px;
  flex:0 0 auto;
  border-radius:14px;
  background-color:rgb(var(--acx-rgb));
  background-image:linear-gradient(rgba(0,0,0,.32),rgba(0,0,0,.32));   /* §ACXPRM-SCRIM */
  color:#fff;
  font-size:17px;
  font-weight:820;
  line-height:1;
  box-shadow:inset 0 1px 0 rgba(255,255,255,.28),0 7px 15px -9px rgba(var(--acx-rgb), .95);
  transition:transform .34s var(--ease-spring),box-shadow .3s ease;
}
.v2x.acx .acx-prov-mono.is-img{
  background-color:#fff;
  background-image:none;
  padding:5px;
  box-shadow:inset 0 0 0 1px var(--v2-line);
}
body.theme-dark .v2x.acx .acx-prov-mono.is-img{background-color:#fff}
.v2x.acx .acx-prov-mono img{width:100%;height:100%;object-fit:contain;border-radius:9px;display:block}

.v2x.acx .acx-prov-mid{min-width:0}
.v2x.acx .acx-prov-nm{
  display:block;
  font-size:13.8px;
  font-weight:730;
  line-height:1.34;
  letter-spacing:-.008em;
  color:var(--v2-ink);
  overflow-wrap:anywhere;
  transition:color .22s ease;
}
.v2x.acx .acx-prov-ct{
  display:block;
  margin-top:3px;
  font-size:11.5px;
  font-weight:600;
  color:var(--v2-muted);
}
.v2x.acx .acx-prov-ct b{font-weight:820;color:var(--acx-ink);font-variant-numeric:tabular-nums}

.v2x.acx .acx-prov-arr{
  display:grid;
  place-items:center;
  width:26px;
  height:26px;
  flex:0 0 auto;
  border-radius:50%;
  background-color:rgba(var(--acx-rgb), .10);
  color:var(--acx-ink);
  opacity:0;
  transform:translateX(-8px) scale(.8);
  transition:opacity .24s ease,transform .32s var(--ease-spring),background-color .24s ease,color .22s ease;
}
.v2x.acx .acx-prov-arr svg{width:13px;height:13px}

@media (hover:hover){
  .v2x.acx .acx-prov:hover .acx-prov-mono{transform:scale(1.06) rotate(-3deg);box-shadow:inset 0 1px 0 rgba(255,255,255,.34),0 12px 20px -10px rgba(var(--acx-rgb), 1)}
  .v2x.acx .acx-prov:hover .acx-prov-nm{color:var(--acx-ink)}
  .v2x.acx .acx-prov:hover .acx-prov-arr{
    opacity:1;
    transform:none;
    background-color:rgb(var(--acx-rgb));
    background-image:linear-gradient(rgba(0,0,0,.32),rgba(0,0,0,.32));
    color:#fff;
  }
}

/* ── §ACXPRM-CTA) "View all providers" ────────────────────────────────────
   `.dir-tr-more` is the shared rail footer link, built for a 300px sidebar:
   full-width, `space-between`, a dashed edge. Centred under a 1180px band
   that reads as an unfinished input. Same component, same brand-gradient
   hover — sized and closed as a button. */
.v2x.acx .acx-catmore{display:flex;justify-content:center;margin-top:24px}
.v2x.acx .acx-catmore .dir-tr-more{
  width:auto;
  max-width:none;
  min-width:236px;
  margin-top:0;
  justify-content:center;
  gap:10px;
  padding:13px 28px;
  border-style:solid;
  border-radius:999px;
  font-size:14px;
  font-weight:740;
}


/* ═══ §ACXPRM-PANEL — largest + recently added ═════════════════════════════
   Two orderings of the same ten rows, side by side. Both panels wear
   `.acx-pc`, so they carry the same wash, bloom, edge and ring as the tiles
   above them; the difference between them is what each ROW says.

   Largest is RANKED: the top three take a metallic chip and every row draws a
   share bar behind it, sized by that category's count over the largest count.
   That ratio is the only new figure on the band and it is DRAWN, never
   printed — nothing here claims a number the count pill does not show.

   Recently added is in ADDED order, so it gets neither: a bar sized by course
   count under rows ordered by recency would imply an ordering the column does
   not have. It carries the category's own icon instead. */
.v2x.acx .acx-two{
  display:grid;
  grid-template-columns:1fr 1fr;
  gap:20px;
  align-items:start;
}
.v2x.acx .acx-panel{padding:8px 8px 12px;border-radius:22px}

.v2x.acx .acx-panel-hd{
  display:flex;
  align-items:center;
  gap:12px;
  padding:14px 14px 13px;
}
.v2x.acx .acx-panel-ic{
  display:grid;
  place-items:center;
  width:38px;
  height:38px;
  flex:0 0 auto;
  border-radius:13px;
  background-color:rgba(var(--acx-rgb), var(--acp-plate-a));
  color:var(--acx-ink);
  box-shadow:inset 0 0 0 1px rgba(var(--acx-rgb), .2);
}
.v2x.acx .acx-panel-ic svg{width:19px;height:19px}
.v2x.acx .acx-panel-tx{min-width:0;display:flex;flex-direction:column;gap:2px}
.v2x.acx .acx-panel h3{
  margin:0;
  font-size:1.02rem;
  font-weight:820;
  letter-spacing:-.018em;
  color:var(--v2-ink);
}
.v2x.acx .acx-panel-sub{
  font-size:11.5px;
  font-weight:600;
  letter-spacing:.004em;
  color:var(--v2-muted);
}
.v2x.acx .acx-panel-list{display:flex;flex-direction:column;gap:2px;padding:0 6px}

.v2x.acx .acx-row{
  position:relative;
  isolation:isolate;
  overflow:hidden;
  display:grid;
  grid-template-columns:auto minmax(0,1fr) auto auto;
  align-items:center;
  gap:10px;
  padding:9px 10px;
  border-radius:12px;
  background-color:rgba(var(--acx-rgb), var(--acp-row-a, 0));
  text-decoration:none;
  color:var(--v2-ink);
  transition:background-color .24s ease;
}

/* The share bar. `width` is the live ratio and it is the ONE animated width
   on this page — it grows from 0 on the first paint so the column draws
   itself in, which is what makes the ranking read as a measurement. */
.v2x.acx .acx-row.is-ranked::before{
  content:'';
  position:absolute;
  z-index:-1;
  inset:0 auto 0 0;
  width:var(--acx-share, 0%);
  border-radius:12px;
  background-image:linear-gradient(90deg,
    rgba(var(--acx-rgb), var(--acp-share-a, .13)) 0%,
    rgba(var(--acx-rgb), 0) 100%);
  transition:opacity .26s ease;
}
body.theme-dark .v2x.acx .acx-row.is-ranked::before{--acp-share-a:.2}

.v2x.acx .acx-row-rk{
  display:grid;
  place-items:center;
  width:26px;
  height:26px;
  flex:0 0 auto;
  border-radius:9px;
  background-color:var(--v2-accent-soft,#eef2f7);
  background-image:none;
  color:var(--v2-muted);
  font-size:11.5px;
  font-weight:820;
  line-height:1;
  font-variant-numeric:tabular-nums;
  box-shadow:inset 0 0 0 1px rgba(16,24,40,.05);
}
body.theme-dark .v2x.acx .acx-row-rk{
  background-color:rgba(255,255,255,.08);
  color:var(--dk-text-2,#C7CAD1);
  box-shadow:inset 0 0 0 1px rgba(255,255,255,.06);
}

/* ⚠ THE MEDALS OUT-RANK THE DARK TWIN ON PURPOSE. The rule above is (0,4,1)
   under `body.theme-dark`; a medal written as `.acx-row-rk[data-rank="1"]`
   would be (0,4,0) and would lose it, so all three medals turn silver after
   dark. Qualifying with the row class takes them to (0,6,0), and a class
   beats an element outright — b before c. They need no dark twin of their
   own: a metal is a metal on any ground, and the ink is dark on a light
   chip either way. Contrast, ink on the DARK end of each gradient:
   gold 5.97:1 · silver 5.71:1 · bronze 5.12:1. */
.v2x.acx .acx-row.is-ranked .acx-row-rk[data-rank="1"]{
  background-color:#F59E0B;
  background-image:linear-gradient(140deg,#FDE68A 0%,#F59E0B 100%);
  color:#4A2B00;
  box-shadow:inset 0 1px 0 rgba(255,255,255,.55),0 5px 11px -6px rgba(245,158,11,.95);
}
.v2x.acx .acx-row.is-ranked .acx-row-rk[data-rank="2"]{
  background-color:#94A3B8;
  background-image:linear-gradient(140deg,#F1F5F9 0%,#94A3B8 100%);
  color:#1E293B;
  box-shadow:inset 0 1px 0 rgba(255,255,255,.6),0 5px 11px -6px rgba(100,116,139,.8);
}
.v2x.acx .acx-row.is-ranked .acx-row-rk[data-rank="3"]{
  background-color:#C2762A;
  background-image:linear-gradient(140deg,#FBD9B5 0%,#C2762A 100%);
  color:#241100;
  box-shadow:inset 0 1px 0 rgba(255,255,255,.5),0 5px 11px -6px rgba(194,118,42,.85);
}

.v2x.acx .acx-row-ic{
  display:grid;
  place-items:center;
  width:26px;
  height:26px;
  flex:0 0 auto;
  border-radius:9px;
  background-color:rgba(var(--acx-rgb), var(--acp-plate-a, .12));
  color:var(--acx-ink);
  box-shadow:inset 0 0 0 1px rgba(var(--acx-rgb), .18);
}
.v2x.acx .acx-row-ic svg{width:14px;height:14px}

.v2x.acx .acx-row-nm{
  min-width:0;
  font-size:13.5px;
  font-weight:670;
  line-height:1.35;
  color:var(--v2-ink);
  /* Two lines rather than an ellipsis: the longest live category name is
     "Generative Art & Design", which fits one line at every width this panel
     reaches — but a name is a proper noun and a hidden one is a dead row. */
  overflow-wrap:anywhere;
  transform:translateX(var(--acp-row-x, 0));
  transition:color .2s ease,transform .26s var(--ease-out);
}
.v2x.acx .acx-row-n{
  display:inline-grid;
  place-items:center;
  min-width:24px;
  height:24px;
  padding:0 8px;
  flex:0 0 auto;
  border-radius:999px;
  background-color:rgba(var(--acx-rgb), .12);
  color:var(--acx-ink);
  font-size:11.5px;
  font-weight:780;
  font-variant-numeric:tabular-nums;
}

/* "New". #1D4ED8 on #DBEAFE measures 5.49:1; the dark pair 7.10:1. */
.v2x.acx .acx-row-new{
  display:inline-flex;
  align-items:center;
  gap:5px;
  flex:0 0 auto;
  padding:3px 9px 3px 7px;
  border-radius:999px;
  background-color:#DBEAFE;
  color:#1D4ED8;
  font-size:10px;
  font-weight:820;
  letter-spacing:.04em;
  text-transform:uppercase;
}
.v2x.acx .acx-row-new i{
  width:5px;
  height:5px;
  border-radius:50%;
  background-color:currentColor;
  animation:acx-blip 2.6s ease-in-out infinite;
}
@keyframes acx-blip{0%,100%{opacity:1;transform:scale(1)}50%{opacity:.35;transform:scale(.72)}}
body.theme-dark .v2x.acx .acx-row-new{background-color:rgba(59,130,246,.2);color:#93C5FD}

.v2x.acx .acx-row-arr{
  display:grid;
  place-items:center;
  width:20px;
  flex:0 0 auto;
  color:var(--acx-ink);
  opacity:0;
  transform:translateX(-6px);
  transition:opacity .22s ease,transform .3s var(--ease-spring);
}
.v2x.acx .acx-row-arr svg{width:14px;height:14px}

@media (hover:hover){
  /* One alpha for both themes: .12 of a mid hue is a visible tint over white
     AND over the rgba(28,31,42,.92) panel, so this needs no dark twin — which
     is what keeps it out of the (0,4,0) vs (0,4,1) fight §ACXPRM-STATE
     documents. The row used to shift its `padding-left` on hover, which
     reflowed the whole column; the name translates instead. */
  .v2x.acx .acx-row:hover{--acp-row-a:.12;--acp-row-x:3px}
  .v2x.acx .acx-row:hover .acx-row-nm{color:var(--acx-ink)}
  .v2x.acx .acx-row:hover .acx-row-arr{opacity:1;transform:none}
  .v2x.acx .acx-row.is-ranked:hover::before{opacity:.55}
}
.v2x.acx .acx-row:focus-visible{
  --acp-row-a:.12;
  outline:2px solid rgba(var(--acx-rgb), .85);
  outline-offset:-2px;
}


/* ═══ §ACXPRM-RESP — the ladder ════════════════════════════════════════════
   The shared sheet's stops are 400 420 480 520 560 640 680 820 900 1180 1500.
   This block uses those and no others, so a page never reflows halfway.

   Most of the ladder is NOT here, and that is the point: `.acx-goals` and
   `.acx-provgrid` size on `minmax(min(100%, Npx), 1fr)`, whose max is `1fr`
   and therefore indefinite — so auto-fill counts by the MIN and the column
   count falls out of the width on its own. Adding a px cap to either would
   silently collapse them to one column; that trap is [[grid-autofill-counts-by-max]]
   and it cost a real bug on the provider hub on 2026-08-22.

   What the numbers give, measured at the shipped mins (goals 300 + 16 gap,
   providers 232 + 14):

     viewport   1180+   1024   900   768   640   520   390
     goals        3       3      2     2     2     1     1
     providers    4       4      3     3     2     1     1 */

@media (max-width:1180px){
  /* Two 560px panels are still two panels; below that the rows inside them
     start wrapping their names, which is the point to stack. */
  .v2x.acx .acx-two{grid-template-columns:1fr;gap:16px}
}

@media (max-width:820px){
  .v2x.acx .acx-goals{gap:14px}
  .v2x.acx .acx-goal{padding:17px 17px 19px}
  .v2x.acx .acx-goal-ic{width:42px;height:42px;border-radius:13px}
  .v2x.acx .acx-goal-ic svg{width:20px;height:20px}
  .v2x.acx .acx-goal-t{font-size:15px}
  .v2x.acx .acx-head-gap{margin-top:32px}
  .v2x.acx .acx-panel{border-radius:20px}
  /* The bloom is drawn for a ~330px card; on a phone-width one the same
     220×200px falloff covers the whole box and the tone stops reading as a
     lit corner. Both the bloom and the ring step down once, exactly as
     §CATPRM-RESP does. */
  .v2x.acx .acx-pc{--acp-bloom:.16}
  body.theme-dark .v2x.acx .acx-pc{--acp-bloom:.14}
}

@media (max-width:640px){
  .v2x.acx .acx-pills{gap:8px}
  .v2x.acx .acx-pill{min-height:40px;padding:0 6px 0 13px;font-size:13px;gap:8px}
  .v2x.acx .acx-pill-n{height:24px;min-width:22px;padding:0 7px}
  .v2x.acx .acx-provgrid{gap:12px}
  .v2x.acx .acx-prov{padding:12px 11px 14px 12px;gap:11px}
  .v2x.acx .acx-prov-mono{width:38px;height:38px;border-radius:12px;font-size:15px}
  .v2x.acx .acx-panel-hd{padding:12px 12px 11px}
  .v2x.acx .acx-panel-ic{width:34px;height:34px;border-radius:11px}
  .v2x.acx .acx-panel-ic svg{width:17px;height:17px}
  .v2x.acx .acx-row{gap:9px;padding:9px 8px}
  .v2x.acx .acx-catmore .dir-tr-more{min-width:0;width:100%;max-width:340px}
}

@media (max-width:520px){
  .v2x.acx .acx-goal{padding:16px 15px 18px}
  .v2x.acx .acx-goal-d{font-size:12.5px}
  .v2x.acx .acx-pc{border-radius:18px}
  .v2x.acx .acx-panel{border-radius:18px;padding:6px 6px 10px}
  .v2x.acx .acx-panel-list{padding:0 4px}
  /* ⚠️ THE "NEW" BADGE KEEPS ITS WORD. This block collapsed it to a bare
     dot below 520px on the assumption that an icon plate, a name, a count
     pill and a badge could not share a 320px row. Measured in the iframe
     harness they can: at 320 the widest of the six rows still lays out on
     one line with no overflow and no wrap, and the narrowest name has 24px
     of slack. A word that fits and is hidden anyway is just a word the
     reader has to guess. Only the gap tightens. */
  .v2x.acx .acx-row{gap:8px}
  .v2x.acx .acx-row-new{padding:3px 8px 3px 6px;letter-spacing:.03em}
}


/* ── §ACXPRM-A11Y) Touch, keyboard, reduced motion, forced colours ────────
   ⚠ EVERY REVEAL ON THIS PAGE IS HOVER-ONLY, WHICH ON A TOUCH SCREEN MEANS
   NEVER. Six goal arrows, eight provider arrows and fourteen row arrows would
   simply not exist on a phone — an affordance that is invisible on the half
   of the traffic that cannot hover. They ship visible-but-quiet instead, and
   the tone plates take their solid fill at rest, because on touch there is no
   "after" state to hold anything back for.

   `(pointer:coarse)` rides alongside `hover:none` because a hybrid — an iPad
   with a trackpad, a touchscreen laptop — reports `hover:hover` and would
   otherwise get the desktop treatment under a finger. Both queries matching
   at once is the RIGHT outcome and not a conflict: the quiet rest state below
   is (0,3,0) and the reveal rules above are (0,4,0) behind `:hover`, so such
   a device shows a quiet arrow at rest and a full one under the pointer. */
@media (hover:none),(pointer:coarse){
  .v2x.acx .acx-goal-arr,
  .v2x.acx .acx-prov-arr,
  .v2x.acx .acx-row-arr{opacity:.6;transform:none}
  .v2x.acx .acx-pc{--acp-bar-w:52%}
  /* :active is the only "hover" a touch screen has. Keep it cheap — a press
     that lifts the card fights the scroll it is usually part of. */
  .v2x.acx .acx-pc:active{--acp-edge-now:.44;--acp-bar-w:100%}
  .v2x.acx .acx-pill:active::before{transform:translateX(0)}
  .v2x.acx .acx-pill:active{color:#fff}
  .v2x.acx .acx-pill:active .acx-pill-dot{background-color:#fff;background-image:none}
  .v2x.acx .acx-pill:active .acx-pill-spark{color:#fff}
  .v2x.acx .acx-pill:active .acx-pill-n{background-color:rgba(0,0,0,.22);color:#fff}
  .v2x.acx .acx-row:active{--acp-row-a:.12}
}

@media (prefers-reduced-motion:reduce){
  /* Everything that moves here is decoration — a lift, a sweep, a sheen, a
     comet, a blip. None of it carries meaning, so all of it goes and the
     STATE remains: the fills, the tints and the tone inks still change, so a
     reader who has turned motion off still gets the whole before/after. */
  .v2x.acx .acx-pc,
  .v2x.acx .acx-pill,
  .v2x.acx .acx-pill::before,
  .v2x.acx .acx-row,
  .v2x.acx .acx-row-nm,
  .v2x.acx .acx-goal-ic,
  .v2x.acx .acx-goal-arr,
  .v2x.acx .acx-goal-t,
  .v2x.acx .acx-prov-mono,
  .v2x.acx .acx-prov-nm,
  .v2x.acx .acx-prov-arr,
  .v2x.acx .acx-row-arr,
  .v2x.acx .acx-pill-dot,
  .v2x.acx .acx-pill-spark,
  .v2x.acx .acx-pill-n{transition:none}
  .v2x.acx .acx-pc::before,
  .v2x.acx .acx-pc::after,
  .v2x.acx .acx-row-new i{animation:none}
  .v2x.acx .acx-pc::after{opacity:0}
  .v2x.acx .acx-pc:hover{--acp-lift:0}
  .v2x.acx .acx-pill:hover{--acp-pill-lift:0}
  .v2x.acx .acx-row:hover{--acp-row-x:0}
  .v2x.acx .acx-goal:hover .acx-goal-ic,
  .v2x.acx .acx-prov:hover .acx-prov-mono{transform:none}
  .v2x.acx .acx-pill:hover .acx-pill-spark{transform:none}
}

@media (forced-colors:active){
  /* The washes, blooms, bars and rings are decoration; in a forced-colour
     mode they become opaque system fills that swallow the card. Drop them and
     let the border carry the edge. */
  .v2x.acx .acx-pc,
  .v2x.acx .acx-pill,
  .v2x.acx .acx-row.is-ranked::before{background-image:none}
  .v2x.acx .acx-pc::before,
  .v2x.acx .acx-pc::after{display:none}
  .v2x.acx .acx-goal-arr,
  .v2x.acx .acx-prov-arr,
  .v2x.acx .acx-row-arr{opacity:1;transform:none}
  .v2x.acx .acx-pill::before{display:none}
}
