/* ══════════════════════════════════════════════════════════════════════════
   /ai-courses/provider/{slug} — module-only components
   Scoped `.v2x.atd.atdx.pvd`, one class deeper than public-atd-detail.css.

   Everything this page can borrow it borrows: the hero, the section rail, the
   sidebar cards, `.atdx-rel*` for every course / provider card, `.atd-caps`
   for the icon plates, `.atd-tags` for the chip clouds and `.atd-ctax` for the
   closing band all come from the shared kit. What is left here is the handful
   of things ONLY this page has — the filterable course directory, the
   learning-path columns and the read-only review block.

   Colours are ATD tokens and the §TONE6 ramp; each is declared in the light
   block first and re-stated in the dark twin. See [[dark-background-shorthand-trap]]:
   nothing below uses the `background` shorthand on a card.
   ══════════════════════════════════════════════════════════════════════════ */

/* ── §PVDX) The course directory ────────────────────────────────────────
   REBUILT 2026-08-22. WHAT WAS WRONG: a 248px checkbox rail owned a third of
   the card and the catalog it filtered was five rows long — six filter groups
   beside five courses. The rail is gone. What replaced it is one search-and-
   sort bar over a full-width card grid, so the courses are the widest thing in
   the section instead of the third widest.

   ONE CARD, THREE GRIDS. `.pvdx-c` is what Featured, this directory and
   Certifications all render, because they are the same object and used to be
   the same card (`.atdx-rel`). Anything that changes here changes all three.

   THE HOVER IS THE POINT. Every card ships a REST state that already reads as
   finished — a soft tone CTA pill, a tone-filled thumb, live meta pills — and
   hover promotes it: the top accent bar wipes in (`::after`), a tone wash
   fades up behind the content (`::before`), the card lifts on a tone-coloured
   shadow, the thumb grows, the title takes the tone ink and the CTA fills
   solid with `--t-btn` while its arrow slides. Nothing is HIDDEN until hover;
   coarse pointers get the filled CTA up front (see §PVDX-RESP) because they
   never get the promotion.

   NOTHING HERE CLAMPS TEXT. The old row card capped the subtitle at two lines
   and the grid it sat in was 272px wide, so real course titles lost their
   second half. Titles, instructors and categories all wrap in full; the cards
   equalise on `margin-top:auto` at the footer instead — see
   [[card-footer-margin-auto-trap]], which is why nothing between the header and
   the footer carries a margin-top.

   Colours are ATD tokens and the §TONE6 ramp, light block first and a dark twin
   for every one of them. Per [[dark-background-shorthand-trap]] nothing below
   uses the `background` shorthand on a surface, and per
   [[background-shorthand-tiles-later-image]] the select chevron is set with
   background-image / -position / -size / -repeat longhands. The card is an
   `<a>`, so every colour on it is restated at (0,5,1) or deeper to clear
   `.v2x.atd a` — see [[atd-link-rule-outranks-borrowed-kits]]. */

/* ── The bar ──────────────────────────────────────────────────────────── */
.v2x.atd.atdx.pvd .pvdx-bar{
  display:flex; flex-wrap:wrap; align-items:center; gap:10px;
  padding:10px; margin-bottom:14px;
  border-radius:17px; border:1px solid var(--line);
  background-color:var(--accent-soft2);
  background-image:linear-gradient(115deg, rgba(54,128,237,.07) 0%, rgba(1,150,253,.05) 48%, rgba(54,128,237,0) 100%);
}
body.theme-dark .v2x.atd.atdx.pvd .pvdx-bar{
  border-color:var(--dk-line-solid,#2C2C31); background-color:rgba(255,255,255,.035);
  background-image:linear-gradient(115deg, rgba(96,164,245,.10) 0%, rgba(160,120,250,.07) 48%, rgba(96,164,245,0) 100%);
}

/* Search. `flex:1 1 220px` is the whole responsive story for this row: it
   fills whatever the sort control leaves, and drops to its own line the moment
   220px is not there. */
.v2x.atd.atdx.pvd .pvdx-sch{ position:relative; display:flex; align-items:center; flex:1 1 220px; min-width:0; }
.v2x.atd.atdx.pvd .pvdx-sch-ic{
  position:absolute; inset-inline-start:14px; z-index:2;
  display:inline-flex; align-items:center; justify-content:center;
  color:var(--muted2); pointer-events:none;
  transition:color .2s ease;
}
.v2x.atd.atdx.pvd .pvdx-sch input{
  width:100%; height:46px; padding-block:0; padding-inline:42px 42px;
  border:1px solid var(--line); border-radius:13px;
  font-family:var(--font); font-size:.9rem; font-weight:550; color:var(--ink);
  background-color:#fff;
  transition:border-color .2s ease, box-shadow .2s ease, background-color .2s ease;
}
.v2x.atd.atdx.pvd .pvdx-sch input::placeholder{ color:var(--muted2); font-weight:500; }
/* The UA clear button is drawn by the OS and does not follow the body theme —
   see [[prefers-color-scheme-is-not-the-theme]] — so it is a black glyph on a
   dark field. Ours is `.pvdx-sch-x`, which does. */
.v2x.atd.atdx.pvd .pvdx-sch input::-webkit-search-cancel-button,
.v2x.atd.atdx.pvd .pvdx-sch input::-webkit-search-decoration{ -webkit-appearance:none; appearance:none; }
.v2x.atd.atdx.pvd .pvdx-sch input:hover{ border-color:var(--line-strong); }
.v2x.atd.atdx.pvd .pvdx-sch input:focus{
  outline:none; border-color:var(--accent);
  box-shadow:0 0 0 4px rgba(54,128,237,.16);
}
.v2x.atd.atdx.pvd .pvdx-sch:focus-within .pvdx-sch-ic{ color:var(--accent); }
body.theme-dark .v2x.atd.atdx.pvd .pvdx-sch input{
  background-color:var(--dk-surface-4,#24242A); border-color:var(--dk-line-solid-2,#3A3A42); color:var(--dk-text,#F4F5F7);
}
body.theme-dark .v2x.atd.atdx.pvd .pvdx-sch input:hover{ border-color:#3C4356; }
body.theme-dark .v2x.atd.atdx.pvd .pvdx-sch input:focus{ border-color:#60A4F5; box-shadow:0 0 0 4px rgba(96,164,245,.20); }
body.theme-dark .v2x.atd.atdx.pvd .pvdx-sch:focus-within .pvdx-sch-ic{ color:#8CBEFA; }

.v2x.atd.atdx.pvd .pvdx-sch-x{
  position:absolute; inset-inline-end:9px; z-index:2;
  display:inline-flex; align-items:center; justify-content:center;
  width:26px; height:26px; padding:0; border:0; border-radius:8px; cursor:pointer;
  color:var(--muted); background-color:rgba(15,23,42,.06);
  transition:color .18s ease, background-color .18s ease;
}
.v2x.atd.atdx.pvd .pvdx-sch-x:hover{ color:#fff; background-color:var(--accent); }
.v2x.atd.atdx.pvd .pvdx-sch-x:focus-visible{ outline:none; box-shadow:0 0 0 3px rgba(54,128,237,.32); }
body.theme-dark .v2x.atd.atdx.pvd .pvdx-sch-x{ color:var(--dk-text-3,#9AA0AB); background-color:rgba(255,255,255,.09); }
body.theme-dark .v2x.atd.atdx.pvd .pvdx-sch-x:hover{ color:#fff; background-color:#3373D6; }

/* Livewire swaps this in for the magnifier while the debounced search is in
   flight, so the field says "working" instead of looking inert for 350ms. */
.v2x.atd.atdx.pvd .pvdx-spin{
  display:none; width:15px; height:15px; border-radius:50%;
  border:2px solid rgba(54,128,237,.22); border-top-color:var(--accent);
  animation:pvdxspin .62s linear infinite;
}
body.theme-dark .v2x.atd.atdx.pvd .pvdx-spin{ border-color:rgba(96,164,245,.24); border-top-color:#60A4F5; }
/* The swap itself. `.pvdx-spin` is display:none at rest and NOTHING else turns
   it back on: `wire:loading.class="is-busy"` lands on `.pvdx-sch-ic`, and the
   only `.is-busy` rule in this sheet is `.pvdx-grid.is-busy`. Without this pair
   the magnifier never yields, the spinner is dead markup and the 350ms debounce
   reads as an inert field — which is the exact thing the note above says this
   block exists to prevent. */
.v2x.atd.atdx.pvd .pvdx-sch-ic.is-busy > svg{ display:none; }
.v2x.atd.atdx.pvd .pvdx-sch-ic.is-busy .pvdx-spin{ display:block; }
@keyframes pvdxspin{ to{ transform:rotate(360deg); } }

/* Sort. The chevron is a background-image longhand, never the `background`
   shorthand, and gets a lighter twin after dark because the glyph colour is
   baked into the data URI. */
.v2x.atd.atdx.pvd .pvdx-sort{ position:relative; display:flex; align-items:center; flex:0 1 auto; min-width:0; }
.v2x.atd.atdx.pvd .pvdx-sort-ic{
  position:absolute; inset-inline-start:13px; z-index:2;
  display:inline-flex; align-items:center; color:var(--accent); pointer-events:none;
}
.v2x.atd.atdx.pvd .pvdx-sort select{
  width:100%; height:46px; padding-block:0; padding-inline:38px 36px;
  border:1px solid var(--line); border-radius:13px;
  font-family:var(--font); font-size:.86rem; font-weight:700; color:var(--ink);
  cursor:pointer; appearance:none; -webkit-appearance:none;
  background-color:#fff;
  background-image:var(--selx-chev);
  background-repeat:no-repeat; background-position:var(--selx-chev-pos, right 12px center); background-size:var(--selx-chev-size, 15px 15px);
  transition:border-color .2s ease, box-shadow .2s ease;
}
.v2x.atd.atdx.pvd .pvdx-sort select:hover{ border-color:var(--accent); }
.v2x.atd.atdx.pvd .pvdx-sort select:focus{ outline:none; border-color:var(--accent); box-shadow:0 0 0 4px rgba(54,128,237,.16); }
/* Native <option> menus are painted by the OS: without an explicit pair the
   dark list renders black-on-black on Chromium/Linux. */
.v2x.atd.atdx.pvd .pvdx-sort select option{ color:#0F0F12; background-color:#fff; }
body.theme-dark .v2x.atd.atdx.pvd .pvdx-sort select{
  background-color:var(--dk-surface-4,#24242A); border-color:var(--dk-line-solid-2,#3A3A42); color:var(--dk-text,#F4F5F7);
  /* No background-image here: --selx-chev in §SELX already carries the dark
     glyph, and a lone background-image line is what tiles when a host
     shorthand wins the geometry. */
}
body.theme-dark .v2x.atd.atdx.pvd .pvdx-sort select:hover,
body.theme-dark .v2x.atd.atdx.pvd .pvdx-sort select:focus{ border-color:#60A4F5; }
body.theme-dark .v2x.atd.atdx.pvd .pvdx-sort select option{ color:var(--dk-text,#F4F5F7); background-color:var(--dk-surface-4,#24242A); }
body.theme-dark .v2x.atd.atdx.pvd .pvdx-sort-ic{ color:#8CBEFA; }
[dir="rtl"] .v2x.atd.atdx.pvd .pvdx-sort select{ background-position:var(--selx-chev-pos, left 12px center); }

/* A bar holding ONLY the sort control shrink-wraps instead of stretching an
   empty surface across the card — which is exactly what a two-course provider
   gets, since the search field does not earn its row under five. `:only-child`
   scores (0,5,0) and so outranks the §PVDX-RESP phone rule that makes the sort
   full-width beside a search field; without that the lone control would be
   stretched to 100% of a container that is sizing itself from it. */
.v2x.atd.atdx.pvd .pvdx-bar:has(> .pvdx-sort:only-child){ display:inline-flex; }
.v2x.atd.atdx.pvd .pvdx-sort:only-child{ flex:0 0 auto; }
.v2x.atd.atdx.pvd .pvdx-sort:only-child select{ width:auto; min-width:206px; }

/* ── The result line ──────────────────────────────────────────────────── */
.v2x.atd.atdx.pvd .pvdx-res{
  display:flex; flex-wrap:wrap; align-items:baseline; gap:4px 10px;
  margin-bottom:14px; font-size:.84rem; color:var(--muted);
}
.v2x.atd.atdx.pvd .pvdx-res b{ color:var(--ink); font-weight:800; font-variant-numeric:tabular-nums; }
.v2x.atd.atdx.pvd .pvdx-res .p{
  padding-inline-start:10px; border-inline-start:1px solid var(--line);
  font-size:.79rem; color:var(--muted2); font-variant-numeric:tabular-nums;
}
body.theme-dark .v2x.atd.atdx.pvd .pvdx-res .p{ border-inline-start-color:var(--dk-line-solid-2,#3A3A42); }
.v2x.atd.atdx.pvd .pvdx-res .q{ font-weight:700; color:var(--accent-dark); }
body.theme-dark .v2x.atd.atdx.pvd .pvdx-res .q{ color:#8CBEFA; }

/* ── §PVDX-GRID) The card grid ────────────────────────────────────────
   auto-FILL, not auto-fit. auto-fit collapses the empty tracks, so a two-card
   result stretched one card across the whole card and floated its meta pills a
   screen from the title. auto-fill holds the track width and the row simply
   ends early. Only fewer-cards-than-tracks behaviour differs; a full row is
   identical either way. */
.v2x.atd.atdx.pvd .pvdx-grid{
  display:grid; gap:14px;
  grid-template-columns:repeat(auto-fill, minmax(min(100%, 292px), 1fr));
}
/* Livewire is mid-flight: the old results stay on screen and go quiet rather
   than blanking, so the grid never jumps to zero height and back. */
.v2x.atd.atdx.pvd .pvdx-grid.is-busy{
  opacity:.42; pointer-events:none; transition:opacity .2s ease;
}

/* ── §PVDX-CARD) One course ───────────────────────────────────────────── */
.v2x.atd.atdx.pvd a.pvdx-c{
  position:relative; isolation:isolate; overflow:hidden;
  display:flex; flex-direction:column; gap:10px;
  padding:16px 17px 15px; border-radius:18px; text-decoration:none;
  color:var(--ink);
  background-color:#fff;
  border:1px solid var(--t-line);
  box-shadow:0 1px 2px rgba(15,23,42,.05);
  transition:transform .4s cubic-bezier(.16,1,.3,1), box-shadow .32s ease, border-color .26s ease;
}
body.theme-dark .v2x.atd.atdx.pvd a.pvdx-c{
  background-color:var(--atd-surface,var(--dk-surface-2,#17171B));
  box-shadow:0 1px 2px rgba(0,0,0,.45);
}
/* The wash. z-index:-1 paints it ABOVE the card's own background and BELOW
   every in-flow child, which is exactly the layer a tint wants; `isolation`
   on the card keeps it from escaping behind an ancestor. */
.v2x.atd.atdx.pvd a.pvdx-c::before{
  content:''; position:absolute; z-index:-1; inset:0; border-radius:inherit;
  opacity:0; transition:opacity .34s ease;
  background-image:
    radial-gradient(115% 88% at 100% 0%, rgba(var(--t-rgb),.17) 0%, rgba(var(--t-rgb),0) 60%),
    linear-gradient(180deg, rgba(var(--t-rgb),.10) 0%, rgba(var(--t-rgb),0) 44%);
}
/* The accent bar. It wipes rather than fades so the card has a direction. */
.v2x.atd.atdx.pvd a.pvdx-c::after{
  content:''; position:absolute; z-index:2; top:0; inset-inline:0; height:3px;
  transform:scaleX(0); transform-origin:0 50%;
  background-image:linear-gradient(90deg, var(--t-1) 0%, var(--t-2) 100%);
  transition:transform .44s cubic-bezier(.16,1,.3,1);
}
body.theme-dark .v2x.atd.atdx.pvd a.pvdx-c::after{
  background-image:linear-gradient(90deg, var(--t-1) 0%, rgba(var(--t-rgb),.5) 100%);
}
[dir="rtl"] .v2x.atd.atdx.pvd a.pvdx-c::after{ transform-origin:100% 50%; }

.v2x.atd.atdx.pvd .pvdx-c-hd{ display:flex; align-items:flex-start; gap:12px; }
.v2x.atd.atdx.pvd .pvdx-c-lg{
  flex:0 0 auto; width:54px; height:54px; border-radius:16px; overflow:hidden;
  display:inline-flex; align-items:center; justify-content:center;
  color:#fff; font-weight:800; font-size:1.3rem; line-height:1;
  background-color:var(--t-1p);
  background-image:linear-gradient(145deg, rgba(255,255,255,.28) 0%, rgba(255,255,255,0) 60%);
  box-shadow:0 6px 15px -7px rgba(var(--t-rgb),.7);
  transition:transform .4s cubic-bezier(.16,1,.3,1), box-shadow .32s ease;
}
.v2x.atd.atdx.pvd .pvdx-c-lg img{ width:100%; height:100%; object-fit:cover; display:block; }

/* Price is the loudest thing on the card on purpose — it is the one field a
   catalog is scanned by. Solid `--t-btn`, which is the step of each tone that
   clears 4.6:1 against a white LABEL (`--t-1` is measured for a white glyph at
   3:1 and is not enough here). Free gets the emerald of the same ramp so it
   reads as a different KIND of price, not a different card. */
.v2x.atd.atdx.pvd .pvdx-c-pr{
  margin-inline-start:auto; flex:0 0 auto;
  display:inline-flex; align-items:center; gap:5px;
  padding:5px 11px; border-radius:999px; white-space:nowrap;
  font-size:.79rem; font-weight:800; line-height:1.45; letter-spacing:-.01em;
  color:#fff; background-color:var(--t-btn);
  box-shadow:0 4px 11px -6px rgba(var(--t-rgb),.75);
}
.v2x.atd.atdx.pvd .pvdx-c-pr.is-free{ background-color:#0A8561; box-shadow:0 4px 11px -6px rgba(16,185,129,.8); }

.v2x.atd.atdx.pvd .pvdx-c-tx{ display:flex; flex-direction:column; gap:5px; min-width:0; }
/* No line clamp. See the block header — the title is the only thing that tells
   two courses apart and it wraps in full at every width. */
.v2x.atd.atdx.pvd .pvdx-c-nm{
  font-size:1rem; font-weight:770; line-height:1.34; letter-spacing:-.014em;
  color:var(--ink); overflow-wrap:anywhere;
  transition:color .22s ease;
}
.v2x.atd.atdx.pvd .pvdx-c-sub{
  display:flex; flex-wrap:wrap; align-items:center; gap:4px 9px;
  font-size:.815rem; line-height:1.5;
}
.v2x.atd.atdx.pvd .pvdx-c-cat{ font-weight:750; color:var(--t-ink); }
.v2x.atd.atdx.pvd .pvdx-c-by{
  display:inline-flex; align-items:center; gap:5px; min-width:0;
  color:var(--muted); overflow-wrap:anywhere;
}
.v2x.atd.atdx.pvd .pvdx-c-by svg{ flex:0 0 auto; opacity:.7; }

.v2x.atd.atdx.pvd .pvdx-c-meta{ display:flex; flex-wrap:wrap; align-items:center; gap:6px; }
.v2x.atd.atdx.pvd .pvdx-p{
  display:inline-flex; align-items:center; gap:5px;
  padding:4px 10px; border-radius:999px;
  font-size:.735rem; font-weight:700; line-height:1.45; white-space:nowrap;
  color:var(--t-ink); background-color:rgba(var(--t-rgb),.11);
  border:1px solid rgba(var(--t-rgb),.22);
}
body.theme-dark .v2x.atd.atdx.pvd .pvdx-p{ background-color:rgba(var(--t-rgb),.2); border-color:rgba(var(--t-rgb),.3); }
/* The certificate pill is the one meta value people filter FOR, so it keeps a
   fixed emerald across the tone cycle instead of restating the card's hue. */
.v2x.atd.atdx.pvd .pvdx-p.is-cert{ color:#08795A; background-color:rgba(16,185,129,.12); border-color:rgba(16,185,129,.26); }
body.theme-dark .v2x.atd.atdx.pvd .pvdx-p.is-cert{ color:#6EE7BE; background-color:rgba(16,185,129,.2); border-color:rgba(52,211,153,.3); }

/* `margin-top:auto` is what equalises cards of different title lengths. Per
   [[card-footer-margin-auto-trap]] NOTHING above it carries a margin-top — the
   column is spaced with `gap`, which adds to the auto margin instead of
   competing with it. */
.v2x.atd.atdx.pvd .pvdx-c-ft{
  display:flex; flex-wrap:wrap; align-items:center; gap:10px;
  margin-top:auto; padding-top:12px;
  border-top:1px solid var(--t-line);
}
.v2x.atd.atdx.pvd .pvdx-c-rt{
  display:inline-flex; align-items:center; gap:5px;
  font-size:.83rem; font-weight:750; color:var(--ink); font-variant-numeric:tabular-nums;
}
.v2x.atd.atdx.pvd .pvdx-c-rt svg{ color:#D08700; }
body.theme-dark .v2x.atd.atdx.pvd .pvdx-c-rt{ color:var(--dk-text,#F4F5F7); }
body.theme-dark .v2x.atd.atdx.pvd .pvdx-c-rt svg{ color:#F5B301; }

/* The REST state of the CTA is a finished button, not a ghost that appears on
   hover — the whole card is one link and a reader on a phone must be able to
   see where it goes. Hover only promotes it to the solid fill. */
.v2x.atd.atdx.pvd .pvdx-c-go{
  margin-inline-start:auto; flex:0 0 auto;
  display:inline-flex; align-items:center; gap:6px;
  padding:7px 13px; border-radius:999px; white-space:nowrap;
  font-size:.78rem; font-weight:750; line-height:1.45;
  color:var(--t-ink); background-color:rgba(var(--t-rgb),.12);
  border:1px solid rgba(var(--t-rgb),.26);
  transition:color .24s ease, background-color .24s ease, border-color .24s ease, box-shadow .24s ease;
}
body.theme-dark .v2x.atd.atdx.pvd .pvdx-c-go{ background-color:rgba(var(--t-rgb),.2); border-color:rgba(var(--t-rgb),.34); }
.v2x.atd.atdx.pvd .pvdx-c-go svg{ flex:0 0 auto; transition:transform .32s cubic-bezier(.16,1,.3,1); }

/* Keyboard reaches the card as a whole; the ring is drawn on the card, not on
   the CTA inside it. */
.v2x.atd.atdx.pvd a.pvdx-c:focus-visible{
  outline:none; border-color:var(--t-1);
  box-shadow:0 0 0 4px rgba(var(--t-rgb),.3);
}

@media (hover:hover) and (pointer:fine){
  .v2x.atd.atdx.pvd a.pvdx-c:hover{
    transform:translateY(-4px);
    border-color:rgba(var(--t-rgb),.48);
    box-shadow:0 22px 40px -24px rgba(var(--t-rgb),.75), 0 4px 12px -8px rgba(15,23,42,.16);
  }
  body.theme-dark .v2x.atd.atdx.pvd a.pvdx-c:hover{
    box-shadow:0 22px 44px -24px rgba(var(--t-rgb),.6), 0 4px 14px -8px rgba(0,0,0,.6);
  }
  .v2x.atd.atdx.pvd a.pvdx-c:hover::before{ opacity:1; }
  .v2x.atd.atdx.pvd a.pvdx-c:hover::after{ transform:scaleX(1); }
  .v2x.atd.atdx.pvd a.pvdx-c:hover .pvdx-c-lg{
    transform:translateY(-2px) scale(1.06);
    box-shadow:0 12px 24px -9px rgba(var(--t-rgb),.85);
  }
  .v2x.atd.atdx.pvd a.pvdx-c:hover .pvdx-c-nm{ color:var(--t-ink); }
  .v2x.atd.atdx.pvd a.pvdx-c:hover .pvdx-c-go{
    color:#fff; background-color:var(--t-btn); border-color:var(--t-btn);
    box-shadow:0 8px 18px -8px rgba(var(--t-rgb),.8);
  }
  .v2x.atd.atdx.pvd a.pvdx-c:hover .pvdx-c-go svg{ transform:translateX(3px); }
  [dir="rtl"] .v2x.atd.atdx.pvd a.pvdx-c:hover .pvdx-c-go svg{ transform:translateX(-3px); }
}
.v2x.atd.atdx.pvd a.pvdx-c:active{ transform:translateY(-1px); }

/* ── §PVDX-EMPTY) Nothing matched ─────────────────────────────────────── */
.v2x.atd.atdx.pvd .pvdx-empty{
  display:flex; flex-direction:column; align-items:center; text-align:center;
  padding:44px 24px; border-radius:18px;
  border:1px dashed var(--line-strong); background-color:var(--accent-soft2);
  color:var(--muted);
}
body.theme-dark .v2x.atd.atdx.pvd .pvdx-empty{ border-color:#343A4C; background-color:rgba(255,255,255,.03); }
.v2x.atd.atdx.pvd .pvdx-empty .ic{
  display:inline-flex; align-items:center; justify-content:center;
  width:52px; height:52px; margin-bottom:13px; border-radius:16px;
  color:#fff; background-image:var(--grad-brand);
  box-shadow:0 8px 20px -10px rgba(54,128,237,.7);
}
.v2x.atd.atdx.pvd .pvdx-empty b{ display:block; font-size:1.02rem; font-weight:770; color:var(--ink); }
.v2x.atd.atdx.pvd .pvdx-empty p{ margin:6px 0 0; font-size:.87rem; line-height:1.55; max-width:42ch; }
.v2x.atd.atdx.pvd .pvdx-empty .pvdx-reset{
  margin-top:16px; display:inline-flex; align-items:center; gap:7px;
  padding:10px 18px; border:0; border-radius:999px; cursor:pointer;
  font-family:var(--font); font-size:.84rem; font-weight:750; line-height:1.45;
  color:#fff; background-image:var(--grad-brand);
  box-shadow:0 8px 20px -10px rgba(54,128,237,.65);
  transition:transform .24s cubic-bezier(.16,1,.3,1), box-shadow .24s ease, filter .2s ease;
}
.v2x.atd.atdx.pvd .pvdx-empty .pvdx-reset:hover{
  transform:translateY(-2px); filter:saturate(1.12);
  box-shadow:0 14px 26px -12px rgba(54,128,237,.8);
}
.v2x.atd.atdx.pvd .pvdx-empty .pvdx-reset:focus-visible{ outline:none; box-shadow:0 0 0 4px rgba(54,128,237,.34); }


/* Pagination — the same plate the directory listings use, restated here
   because that sheet is not linked on a detail route. */
.v2x.atd.atdx.pvd .pvd-pg{ display:flex; justify-content:center; margin-top:22px; }
.v2x.atd.atdx.pvd .pvd-pg .pagination{
  display:inline-flex; align-items:center; gap:4px; padding:6px; margin:0; list-style:none;
  background-color:#fff; border:1px solid var(--line); border-radius:14px;
  box-shadow:0 1px 2px rgba(16,24,40,.04);
}
body.theme-dark .v2x.atd.atdx.pvd .pvd-pg .pagination{ background-color:rgba(29,29,34,.85); border-color:var(--dk-line,rgba(255,255,255,.10)); }
.v2x.atd.atdx.pvd .pvd-pg .page-item{ margin:0; }
.v2x.atd.atdx.pvd .pvd-pg .page-link,
.v2x.atd.atdx.pvd .pvd-pg span.page-link{
  display:inline-flex; align-items:center; justify-content:center;
  min-width:34px; height:34px; padding:0 10px; border:0; border-radius:10px;
  font-size:.83rem; font-weight:700; line-height:1; text-decoration:none;
  color:var(--muted); background-color:transparent;
  transition:background-color .18s ease, color .18s ease;
}
.v2x.atd.atdx.pvd .pvd-pg .page-link:hover{ background-color:var(--accent-soft); color:var(--accent-dark); }
.v2x.atd.atdx.pvd .pvd-pg .page-item.active .page-link{
  color:#fff; background-image:var(--grad-brand);
  box-shadow:0 6px 16px -6px rgba(54,128,237,.45);
}
.v2x.atd.atdx.pvd .pvd-pg .page-item.disabled .page-link,
.v2x.atd.atdx.pvd .pvd-pg .page-item.disabled span.page-link{ color:#C9CED9; pointer-events:none; }
body.theme-dark .v2x.atd.atdx.pvd .pvd-pg .page-item.disabled span.page-link{ color:#4A5162; }
body.theme-dark .v2x.atd.atdx.pvd .pvd-pg .page-link:hover{ background-color:rgba(54,128,237,.16); color:#8CBEFA; }
/* Bootstrap's paginator ships the words "Previous"/"Next"; the plate is a row
   of 34px squares and the words break it. Keep the arrow, drop the label. */
.v2x.atd.atdx.pvd .pvd-pg .page-item:first-child .page-link,
.v2x.atd.atdx.pvd .pvd-pg .page-item:last-child .page-link{ font-size:0; padding:0 12px; }
.v2x.atd.atdx.pvd .pvd-pg .page-item:first-child .page-link::before,
.v2x.atd.atdx.pvd .pvd-pg .page-item:last-child .page-link::after{
  content:''; display:inline-block; width:7px; height:7px;
  border-top:1.8px solid currentColor; border-right:1.8px solid currentColor;
}
.v2x.atd.atdx.pvd .pvd-pg .page-item:first-child .page-link::before{ transform:rotate(-135deg); }
.v2x.atd.atdx.pvd .pvd-pg .page-item:last-child .page-link::after{ transform:rotate(45deg); }


/* ── §PVDX-DECK) The one-line deck under a section heading ──────────────
   Was `<p class="atdx-note" style="margin-top:-10px">` on both bands. That
   note is an .8rem CAVEAT style built to sit under a hero CTA, and the inline
   negative margin was there to undo spacing the wrong component brought with
   it — so the admin-authored subtitle read as a footnote apologising for the
   section instead of introducing it. This is a deck: same family, one step up
   in size, and its own spacing so no caller needs a style attribute. */
.v2x.atd.atdx.pvd .pvdx-deck{
  display:flex; align-items:flex-start; gap:9px;
  margin:-4px 0 18px; max-width:72ch;
  font-size:.9rem; line-height:1.6; color:var(--muted);
}
.v2x.atd.atdx.pvd .pvdx-deck svg{ flex:0 0 auto; margin-top:3px; color:var(--accent); }
body.theme-dark .v2x.atd.atdx.pvd .pvdx-deck svg{ color:#8CBEFA; }

/* ── §PVDX-CERT) The certifications band ────────────────────────────────
   The CARD is the same `.pvdx-c` the directory renders — that is the point of
   §PVDX-CARD and it does not change here. What changes is the ground under it.

   WHAT WAS WRONG: the band was a bare `.pvdx-grid`, so at a wide body column
   auto-fill made four 292px tracks and the two certificate courses most
   providers publish sat in the left 63% with a quarter of the card empty
   beside them. It read as a broken row, not as a short set.

   TWO FIXES, both needed. The track gains a 360px CAP so a card can never
   stretch into a banner, and the grid is CENTRED, so two cards under a wide
   heading are visibly a pair rather than the start of a row that failed to
   fill. `justify-content` is the whole mechanism; the tracks themselves are
   unchanged from §PVDX-GRID.

   The emerald ground is the same hue as the `is-cert` pill on the cards inside
   it, which is what makes this band read as credentials at a glance instead of
   as a second directory. It is a WASH, not a card: no shadow, no radius on the
   cards' own surface — see [[dark-background-shorthand-trap]], the dark twin
   is a `background-color` longhand because the base sheet's dark card rule
   resets `background-image`. */
.v2x.atd.atdx.pvd .pvdx-cert{
  padding:18px; border-radius:18px;
  border:1px solid rgba(16,185,129,.20);
  background-color:rgba(16,185,129,.055);
  background-image:radial-gradient(90% 130% at 0% 0%, rgba(16,185,129,.10) 0%, rgba(16,185,129,0) 62%);
}
body.theme-dark .v2x.atd.atdx.pvd .pvdx-cert{
  border-color:rgba(52,211,153,.20);
  background-color:rgba(16,185,129,.07);
  background-image:radial-gradient(90% 130% at 0% 0%, rgba(52,211,153,.12) 0%, rgba(52,211,153,0) 62%);
}
/* FLEX, NOT GRID — and that is not a style preference.
   `repeat(auto-fill, minmax(min(100%,290px), 360px))` counts its repetitions
   off the MAXIMUM track sizing function whenever that max is definite (CSS
   Grid §7.2.3.1). 360px IS definite, so in the 709px grid of a 1280px viewport
   the browser fitted 2×360+14 = 734 > 709 and made ONE track — the two
   certificate cards stacked in a centred column and the band was worse than
   the bug it was meant to fix. Counting by the 290px MIN is the behaviour this
   band actually wants, and a wrapping flex row is the only form that gives it
   while still capping the item: `flex-basis` sets the wrap point, `max-width`
   caps the card, and `justify-content:center` centres whatever is left over.
      709px  → two cards of 348, side by side
     1214px  → two cards capped at 400, centred as a pair
      390px  → one card per row
   MEASURED in the §HARNESS iframe at each of those widths. */
.v2x.atd.atdx.pvd .pvdx-cert .pvdx-grid{
  display:flex; flex-wrap:wrap; justify-content:center; gap:14px;
}
.v2x.atd.atdx.pvd .pvdx-cert .pvdx-c{ flex:1 1 290px; min-width:0; max-width:400px; }

/* ── §PVDX-PATH) Learning paths ─────────────────────────────────────────
   REBUILT 2026-08-22 in the §PVDX language, so the page stops carrying two
   generations of card at once: the same tone plate, the same `::before` wash
   and `::after` accent wipe, the same lift, the same `--t-btn` promotion on
   the thing you click.

   WHAT WAS WRONG. The step title was `-webkit-line-clamp:2` — on a 250px
   column that cut real course titles in half, and the title is the only thing
   that tells one step from the next. NOTHING IS CLAMPED HERE; a title wraps to
   as many lines as it needs and the rows simply grow.

   THE ORDER IS THE CONTENT. These are "start here, then this" routes, so the
   numbers ride a drawn rail rather than sitting as loose counters — the
   connector is what says the steps are a sequence and not a set of links. It
   is drawn per-item on `:not(:last-child)`, which is the only form that stays
   correct when a tier has one course.

   THE TRACK IS CAPPED AND CENTRED. A provider that publishes at a single level
   has ONE tier, and an uncapped `1fr` stretched it across the whole card with
   the duration pinned a screen from the course it belonged to. 420px is the
   widest a single tier reads as a column; auto-FIT collapses the tracks a
   short set does not use and `justify-content:center` keeps one, two or three
   tiers balanced under the heading. */
/* Flex for the same reason as §PVDX-CERT — see the note there. A definite
   420px max made auto-fit count ONE track in a 747px section and all three
   tiers stacked. `flex:1 1 250px` wraps on the MIN instead:
      747px  → two tiers across, the third centred on row two
     1250px  → three tiers across at ~406 each
      390px  → one tier per row, capped at 440
   250px is the floor because the header row is a 34px plate, the tier name and
   the count chip on one line, and that needs ~242px before the name wraps
   mid-word. Flex items stretch by default, so tiers in a row stay equal height
   however many courses each holds. */
.v2x.atd.atdx.pvd .pvdx-paths{
  display:flex; flex-wrap:wrap; justify-content:center; gap:16px;
}
.v2x.atd.atdx.pvd .pvdx-path{ flex:1 1 250px; min-width:0; max-width:440px; }
.v2x.atd.atdx.pvd .pvdx-path{
  position:relative; isolation:isolate; overflow:hidden;
  display:flex; flex-direction:column;
  padding:17px 18px 14px; border-radius:18px;
  background-color:var(--t-bg); border:1px solid var(--t-line);
  transition:transform .4s cubic-bezier(.16,1,.3,1), box-shadow .32s ease, border-color .26s ease;
}
.v2x.atd.atdx.pvd .pvdx-path::before{
  content:''; position:absolute; z-index:-1; inset:0; border-radius:inherit;
  opacity:0; transition:opacity .34s ease;
  background-image:radial-gradient(115% 85% at 100% 0%, rgba(var(--t-rgb),.20) 0%, rgba(var(--t-rgb),0) 62%);
}
.v2x.atd.atdx.pvd .pvdx-path::after{
  content:''; position:absolute; z-index:2; top:0; inset-inline:0; height:3px;
  transform:scaleX(0); transform-origin:0 50%;
  background-image:linear-gradient(90deg, var(--t-1) 0%, var(--t-2) 100%);
  transition:transform .44s cubic-bezier(.16,1,.3,1);
}
body.theme-dark .v2x.atd.atdx.pvd .pvdx-path::after{
  background-image:linear-gradient(90deg, var(--t-1) 0%, rgba(var(--t-rgb),.5) 100%);
}
[dir="rtl"] .v2x.atd.atdx.pvd .pvdx-path::after{ transform-origin:100% 50%; }

/* `flex-wrap` here is a guard, not a layout. A flex item's `min-width:auto`
   resolves to its MIN-CONTENT width, so the tier name normally refuses to
   squeeze and the count chip is what has to give — but only if the name has a
   real min-content width. MEASURED at a 238px plate: with
   `overflow-wrap:anywhere` on the name (which is what §PVDX-CARD wants for
   course titles, and what this rule used to copy) min-content collapses to one
   CHARACTER, and "Intermediate" broke across two lines beside a chip that had
   room to spare. The name keeps normal wrapping; the chip wraps instead. */
.v2x.atd.atdx.pvd .pvdx-path-h{
  display:flex; flex-wrap:wrap; align-items:center; gap:6px 10px; margin-bottom:12px;
}
.v2x.atd.atdx.pvd .pvdx-path-ic{
  flex:0 0 auto; width:34px; height:34px; border-radius:11px;
  display:inline-flex; align-items:center; justify-content:center;
  color:#fff; background-color:var(--t-1p);
  background-image:linear-gradient(145deg, rgba(255,255,255,.30) 0%, rgba(255,255,255,0) 62%);
  box-shadow:0 5px 12px -6px rgba(var(--t-rgb),.75);
  transition:transform .4s cubic-bezier(.16,1,.3,1), box-shadow .32s ease;
}
.v2x.atd.atdx.pvd .pvdx-path-t{
  font-size:1rem; font-weight:770; letter-spacing:-.012em; color:var(--ink);
}
/* A labelled chip, not a bare digit. "2" alone beside a tier name reads as a
   position in a list rather than as how many courses the tier holds. */
.v2x.atd.atdx.pvd .pvdx-path-c{
  margin-inline-start:auto; flex:0 0 auto;
  display:inline-flex; align-items:center;
  padding:3px 10px; border-radius:999px; white-space:nowrap;
  font-size:.71rem; font-weight:750; line-height:1.45;
  color:var(--t-ink); background-color:rgba(var(--t-rgb),.16);
  border:1px solid rgba(var(--t-rgb),.24);
}
body.theme-dark .v2x.atd.atdx.pvd .pvdx-path-c{ background-color:rgba(var(--t-rgb),.24); border-color:rgba(var(--t-rgb),.32); }

.v2x.atd.atdx.pvd .pvdx-steps{ margin:0; padding:0; list-style:none; }
.v2x.atd.atdx.pvd .pvdx-stepli{ position:relative; }
/* The rail. `top`/`bottom` are measured off the 26px node: it starts 9px into
   the row and the line picks up 4px below it. `:not(:last-child)` is what
   keeps a one-course tier from growing a connector to nothing. */
.v2x.atd.atdx.pvd .pvdx-stepli:not(:last-child)::before{
  content:''; position:absolute; z-index:0; inset-inline-start:21px;
  top:39px; bottom:1px; width:2px; border-radius:2px;
  background-color:rgba(var(--t-rgb),.24);
}
body.theme-dark .v2x.atd.atdx.pvd .pvdx-stepli:not(:last-child)::before{ background-color:rgba(var(--t-rgb),.32); }

.v2x.atd.atdx.pvd .pvdx-step{
  position:relative; z-index:1;
  display:flex; align-items:flex-start; gap:11px;
  padding:8px 9px; border-radius:12px; text-decoration:none;
  transition:background-color .22s ease;
}
.v2x.atd.atdx.pvd .pvdx-step .n{
  flex:0 0 auto; width:26px; height:26px; border-radius:9px;
  display:inline-flex; align-items:center; justify-content:center;
  font-size:.73rem; font-weight:800; line-height:1; font-variant-numeric:tabular-nums;
  color:var(--t-ink); background-color:rgba(var(--t-rgb),.18);
  border:1px solid rgba(var(--t-rgb),.10);
  transition:color .22s ease, background-color .22s ease, box-shadow .22s ease, transform .3s cubic-bezier(.16,1,.3,1);
}
body.theme-dark .v2x.atd.atdx.pvd .pvdx-step .n{ background-color:rgba(var(--t-rgb),.26); border-color:rgba(var(--t-rgb),.18); }
.v2x.atd.atdx.pvd .pvdx-step .tx{ min-width:0; flex:1 1 auto; display:flex; flex-direction:column; gap:3px; }
/* No clamp. See the block header. */
.v2x.atd.atdx.pvd .pvdx-step .t{
  font-size:.865rem; font-weight:650; line-height:1.42; color:var(--ink);
  overflow-wrap:anywhere; transition:color .22s ease;
}
.v2x.atd.atdx.pvd .pvdx-step .d{
  display:inline-flex; align-items:center; gap:5px; align-self:flex-start;
  font-size:.735rem; font-weight:600; line-height:1.4; color:var(--muted);
  font-variant-numeric:tabular-nums;
}
.v2x.atd.atdx.pvd .pvdx-step .d svg{ flex:0 0 auto; opacity:.7; }
/* Visible at rest, promoted on hover — a chevron that only exists on hover is
   not there at all on a phone, and this row is the whole link. */
.v2x.atd.atdx.pvd .pvdx-step .go{
  flex:0 0 auto; align-self:center; margin-inline-start:auto;
  display:inline-flex; align-items:center; justify-content:center;
  width:24px; height:24px; border-radius:8px;
  color:var(--t-ink); background-color:transparent; opacity:.45;
  transition:opacity .22s ease, color .22s ease, background-color .22s ease, transform .3s cubic-bezier(.16,1,.3,1);
}

@media (hover:hover) and (pointer:fine){
  .v2x.atd.atdx.pvd .pvdx-path:hover{
    transform:translateY(-4px);
    border-color:rgba(var(--t-rgb),.48);
    box-shadow:0 22px 40px -24px rgba(var(--t-rgb),.75), 0 4px 12px -8px rgba(15,23,42,.16);
  }
  body.theme-dark .v2x.atd.atdx.pvd .pvdx-path:hover{
    box-shadow:0 22px 44px -24px rgba(var(--t-rgb),.6), 0 4px 14px -8px rgba(0,0,0,.6);
  }
  .v2x.atd.atdx.pvd .pvdx-path:hover::before{ opacity:1; }
  .v2x.atd.atdx.pvd .pvdx-path:hover::after{ transform:scaleX(1); }
  .v2x.atd.atdx.pvd .pvdx-path:hover .pvdx-path-ic{
    transform:translateY(-2px) scale(1.06);
    box-shadow:0 11px 22px -8px rgba(var(--t-rgb),.85);
  }
  .v2x.atd.atdx.pvd a.pvdx-step:hover{ background-color:rgba(var(--t-rgb),.14); }
  body.theme-dark .v2x.atd.atdx.pvd a.pvdx-step:hover{ background-color:rgba(var(--t-rgb),.20); }
  .v2x.atd.atdx.pvd a.pvdx-step:hover .n{
    color:#fff; background-color:var(--t-btn); border-color:var(--t-btn);
    transform:scale(1.06);
    box-shadow:0 6px 14px -6px rgba(var(--t-rgb),.85);
  }
  .v2x.atd.atdx.pvd a.pvdx-step:hover .t{ color:var(--t-ink); }
  .v2x.atd.atdx.pvd a.pvdx-step:hover .go{ opacity:1; transform:translateX(2px); }
  [dir="rtl"] .v2x.atd.atdx.pvd a.pvdx-step:hover .go{ transform:translateX(-2px); }
}
/* Keyboard gets the same read as the pointer. The ring is on the row, which is
   the link; the plate around it is not focusable. */
.v2x.atd.atdx.pvd a.pvdx-step:focus-visible{
  outline:none; background-color:rgba(var(--t-rgb),.14);
  box-shadow:0 0 0 3px rgba(var(--t-rgb),.42);
}
.v2x.atd.atdx.pvd a.pvdx-step:focus-visible .n{ color:#fff; background-color:var(--t-btn); border-color:var(--t-btn); }
.v2x.atd.atdx.pvd a.pvdx-step:focus-visible .go{ opacity:1; }

/* Coarse pointers never receive the promotion, so the accent bar and the
   chevron ship in their promoted state — same rule the cards follow. */
@media (hover:none){
  .v2x.atd.atdx.pvd .pvdx-path::after{ transform:scaleX(1); }
  .v2x.atd.atdx.pvd .pvdx-step .go{ opacity:.8; }
}

@media (prefers-reduced-motion:reduce){
  .v2x.atd.atdx.pvd .pvdx-path,
  .v2x.atd.atdx.pvd .pvdx-path::before,
  .v2x.atd.atdx.pvd .pvdx-path::after,
  .v2x.atd.atdx.pvd .pvdx-path-ic,
  .v2x.atd.atdx.pvd .pvdx-step,
  .v2x.atd.atdx.pvd .pvdx-step .n,
  .v2x.atd.atdx.pvd .pvdx-step .t,
  .v2x.atd.atdx.pvd .pvdx-step .go{ transition:none; }
  .v2x.atd.atdx.pvd .pvdx-path:hover,
  .v2x.atd.atdx.pvd .pvdx-path:hover .pvdx-path-ic,
  .v2x.atd.atdx.pvd a.pvdx-step:hover .n,
  .v2x.atd.atdx.pvd a.pvdx-step:hover .go{ transform:none; }
  .v2x.atd.atdx.pvd .pvdx-path::after{ transform:scaleX(1); }
}


/* ── §PVD-REV) Reviews ──────────────────────────────────────────────────
   Read-only, like the course page's: `v2.public.partials.reviews-section`
   needs a review-writing contract ($reviewSort, $reviewDone, $alreadyReviewed,
   $userVotes, $reportingId) this component does not expose, and including it
   500s on any provider that actually has reviews. */
.v2x.atd.atdx.pvd .pvd-dist{
  display:grid; grid-template-columns:auto minmax(0,1fr); gap:26px; align-items:center;
  padding:16px 18px; margin-bottom:18px; border-radius:14px;
  background-color:var(--accent-soft2); border:1px solid var(--line);
}
body.theme-dark .v2x.atd.atdx.pvd .pvd-dist{ background-color:rgba(255,255,255,.04); border-color:var(--dk-line-solid,#2C2C31); }
.v2x.atd.atdx.pvd .pvd-dist-score{ display:flex; flex-direction:column; align-items:center; gap:3px; min-width:96px; }
.v2x.atd.atdx.pvd .pvd-dist-score .n{ font-size:2.2rem; font-weight:800; line-height:1; color:var(--ink); }
.v2x.atd.atdx.pvd .pvd-dist-score .c{ font-size:.76rem; color:var(--muted); }
.v2x.atd.atdx.pvd .pvd-dist-bars{ display:flex; flex-direction:column; gap:5px; }
.v2x.atd.atdx.pvd .pvd-dist-row{ display:flex; align-items:center; gap:10px; font-size:.76rem; color:var(--muted); }
.v2x.atd.atdx.pvd .pvd-dist-row .s{ display:inline-flex; align-items:center; gap:3px; min-width:26px; color:#D08700; }
.v2x.atd.atdx.pvd .pvd-dist-row .bar{ flex:1 1 auto; height:7px; border-radius:99px; background-color:rgba(15,23,42,.09); overflow:hidden; }
body.theme-dark .v2x.atd.atdx.pvd .pvd-dist-row .bar{ background-color:rgba(255,255,255,.10); }
.v2x.atd.atdx.pvd .pvd-dist-row .bar span{ display:block; height:100%; border-radius:99px; background-image:linear-gradient(90deg,#F5B301,#D08700); }
.v2x.atd.atdx.pvd .pvd-dist-row .p{ min-width:34px; text-align:end; font-variant-numeric:tabular-nums; }

.v2x.atd.atdx.pvd .pvd-revs{ display:flex; flex-direction:column; gap:12px; margin:0; padding:0; list-style:none; }
.v2x.atd.atdx.pvd .pvd-rev{
  display:flex; align-items:flex-start; gap:13px; padding:15px 16px; border-radius:14px;
  background-color:var(--t-bg); border:1px solid var(--t-line);
}
.v2x.atd.atdx.pvd .pvd-rev-av{
  flex:0 0 auto; width:36px; height:36px; border-radius:11px;
  display:inline-flex; align-items:center; justify-content:center;
  color:#fff; background-color:var(--t-1p); font-weight:800;
  box-shadow:0 2px 6px rgba(var(--t-rgb),.32);
}
.v2x.atd.atdx.pvd .pvd-rev-tx{ min-width:0; flex:1 1 auto; display:flex; flex-direction:column; gap:4px; }
.v2x.atd.atdx.pvd .pvd-rev-h{ display:flex; flex-wrap:wrap; align-items:center; gap:9px; font-size:.9rem; color:var(--ink); }
.v2x.atd.atdx.pvd .pvd-rev-h .v{ display:inline-flex; align-items:center; gap:4px; font-size:.7rem; font-weight:700; color:var(--t-ink); }
.v2x.atd.atdx.pvd .pvd-rev-h .d{ font-size:.76rem; color:var(--muted); }
.v2x.atd.atdx.pvd .pvd-rev-t{ font-size:.95rem; font-weight:700; color:var(--ink); }
.v2x.atd.atdx.pvd .pvd-rev-b{ font-size:.88rem; line-height:1.6; color:var(--muted); }
.v2x.atd.atdx.pvd .pvd-rev-f{ display:flex; flex-wrap:wrap; align-items:center; gap:10px; font-size:.76rem; color:var(--muted); }
.v2x.atd.atdx.pvd .pvd-rev-f a{ color:var(--t-ink); font-weight:650; }

/* ── §PVDX-RESP) Every viewport ─────────────────────────────────────────
   Three real breakpoints, and each one exists because something MEASURED
   breaks at it — not because 768 and 1024 are round numbers.

   ⚠ THE HOST WILL NOT RESIZE BELOW ~1600px. Everything below was checked in a
   same-origin iframe, which carries its own viewport for media queries — see
   [[iframe-responsive-harness]]. A browser window on this box cannot reach
   these widths and will report the desktop layout at every one of them. */

/* ≤1199px — the body column is still `col-lg-8`, but the shell has narrowed it
   past the point where a 292px track fits twice with a 14px gutter. Dropping
   the track to 260px keeps two cards across instead of one very wide one. */
@media (max-width:1199.98px){
  .v2x.atd.atdx.pvd .pvdx-grid{ grid-template-columns:repeat(auto-fill, minmax(min(100%, 260px), 1fr)); }
}

/* ≤991px (tablet) — Bootstrap has just dropped `col-lg-8` to full width, so
   the grid GAINS room here rather than losing it and the track goes back up. */
@media (max-width:991.98px){
  .v2x.atd.atdx.pvd .pvdx-grid{ grid-template-columns:repeat(auto-fill, minmax(min(100%, 286px), 1fr)); }
}

/* ≤767px — the sort control stops competing with the search field for one row
   and takes its own, full width. Below this the two of them share ~330px of
   content box, which puts "Most Popular" on two lines inside a 46px select. */
@media (max-width:767.98px){
  .v2x.atd.atdx.pvd .pvdx-bar{ padding:9px; gap:9px; }
  .v2x.atd.atdx.pvd .pvdx-sch{ flex:1 1 100%; }
  .v2x.atd.atdx.pvd .pvdx-sort{ flex:1 1 100%; }
}

/* ≤575px (phone) — one column, and the card tightens rather than shrinking its
   type: the title, the instructor and the meta pills are the content, and all
   three still wrap in full. */
@media (max-width:575.98px){
  .v2x.atd.atdx.pvd .pvdx-grid{ grid-template-columns:minmax(0,1fr); gap:12px; }
  .v2x.atd.atdx.pvd a.pvdx-c{ padding:14px 15px 13px; border-radius:16px; gap:9px; }
  .v2x.atd.atdx.pvd .pvdx-c-lg{ width:46px; height:46px; border-radius:14px; font-size:1.12rem; }
  .v2x.atd.atdx.pvd .pvdx-c-nm{ font-size:.95rem; }
  .v2x.atd.atdx.pvd .pvdx-c-ft{ padding-top:11px; }
  .v2x.atd.atdx.pvd .pvdx-empty{ padding:34px 18px; }
  .v2x.atd.atdx.pvd .pvd-dist{ grid-template-columns:minmax(0,1fr); gap:14px; }

  /* The certifications wash and the tier plates give up PADDING, never type.
     The deck keeps its size deliberately: it is the sentence that says what
     the band is, and on a phone it is the first thing under the heading. */
  .v2x.atd.atdx.pvd .pvdx-cert{ padding:12px; border-radius:15px; }
  .v2x.atd.atdx.pvd .pvdx-cert .pvdx-grid{ gap:12px; }
  .v2x.atd.atdx.pvd .pvdx-paths{ gap:12px; }
  .v2x.atd.atdx.pvd .pvdx-path{ padding:15px 15px 12px; border-radius:16px; }
  .v2x.atd.atdx.pvd .pvdx-step{ padding:8px 7px; }
}

/* Coarse pointers never receive the hover promotion, so the CTA ships in its
   promoted state instead of its resting one — otherwise the one control that
   says where the card goes is permanently the quietest thing on it. */
@media (hover:none){
  .v2x.atd.atdx.pvd .pvdx-c-go{
    color:#fff; background-color:var(--t-btn); border-color:var(--t-btn);
    box-shadow:0 5px 14px -7px rgba(var(--t-rgb),.7);
  }
  .v2x.atd.atdx.pvd a.pvdx-c::after{ transform:scaleX(1); }
}

@media (prefers-reduced-motion:reduce){
  .v2x.atd.atdx.pvd a.pvdx-c,
  .v2x.atd.atdx.pvd a.pvdx-c::before,
  .v2x.atd.atdx.pvd a.pvdx-c::after,
  .v2x.atd.atdx.pvd .pvdx-c-lg,
  .v2x.atd.atdx.pvd .pvdx-c-go,
  .v2x.atd.atdx.pvd .pvdx-c-go svg,
  .v2x.atd.atdx.pvd .pvdx-empty .pvdx-reset{ transition:none; }
  .v2x.atd.atdx.pvd a.pvdx-c:hover,
  .v2x.atd.atdx.pvd a.pvdx-c:active,
  .v2x.atd.atdx.pvd a.pvdx-c:hover .pvdx-c-lg,
  .v2x.atd.atdx.pvd a.pvdx-c:hover .pvdx-c-go svg,
  .v2x.atd.atdx.pvd .pvdx-empty .pvdx-reset:hover{ transform:none; }
  .v2x.atd.atdx.pvd a.pvdx-c::after{ transform:scaleX(1); }
  .v2x.atd.atdx.pvd .pvdx-spin{ animation:none; }
}
