/* ══════════════════════════════════════════════════════════════════════════
   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 · enrolment · length · certificate signal strip
     §BY      the instructor byline
     §PRICE   the price + CTA row (the one number a course grid is scanned for)
     §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(16,20,28,.82),rgba(16,20,28,.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(20,25,34,.86),rgba(20,25,34,.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 · enrolment · length · certificate. These four answer "is this worth
   an afternoon" faster than any blurb, and each 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}
/* 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 instructor byline ═══════════════════════════════════════════
   Below the strip, above the pills. Truncated with ellipsis rather than
   wrapped: two lines of a name pushes the price 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}


/* ═══ §PRICE — the price + CTA row ══════════════════════════════════════════
   ⚠ `.dir-tc-btn` in the shared sheet is `width:100%` + `margin-top:auto`,
   which is what pins it to the bottom of a flex card. Wrapping it in a row
   breaks BOTH: the auto margin now belongs to the wrapper, and 100% width
   would leave the price no room. So the wrapper takes the auto margin and the
   button drops to auto width. Removing either line collapses the card's
   bottom alignment across the grid — the cards stop lining up. */
.v2x.acx .acx-cta{
  display:flex;align-items:center;justify-content:space-between;gap:10px;
  width:100%;margin-top:auto;padding-top:14px}
.v2x.acx .acx-cta .dir-tc-btn{width:auto;margin-top:0;flex:0 0 auto;padding:10px 14px}

.v2x.acx .acx-price{
  display:inline-flex;align-items:baseline;gap:5px;
  font-size:17px;font-weight:820;letter-spacing:-.02em;color:var(--v2-ink);line-height:1}
.v2x.acx .acx-price s{
  font-size:12px;font-weight:600;color:var(--v2-muted);text-decoration-thickness:1px}
/* Free is a different KIND of answer, not a cheaper number, so it is a chip
   rather than a bigger figure. #047857 on #ECFDF5 = 5.21:1. */
.v2x.acx .acx-price.is-free{
  padding:4px 10px;border-radius:999px;background:#ECFDF5;color:#047857;font-size:13px}
body.theme-dark .v2x.acx .acx-price.is-free{background:rgba(16,185,129,.16);color:#6EE7B7}

/* List mode stacks price over button in the fixed right-hand column. */
.v2x.acx .dir-lc-side{display:flex;flex-direction:column;align-items:flex-end;gap:8px}
.v2x.acx .dir-lc-side .acx-price{font-size:15px}


/* ═══ §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 categories" footer link under the rail. */
.v2x.acx .acx-catmore{display:flex;justify-content:center;margin-top:18px}
.v2x.acx .acx-catmore .dir-tr-more{max-width:280px}


/* ═══ §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(28,31,42,.92);border-color:rgba(255,255,255,.08);
  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}

/* Skill / level pills — the browse-by rows on the hub. The accent is the DOT,
   never the text: same reasoning as §PLATE, and these sit on a plain card. */
.v2x.acx .acx-pills{display:flex;flex-wrap:wrap;gap:9px}
.v2x.acx .acx-pill{
  display:inline-flex;align-items:center;gap:8px;
  padding:9px 15px;border:1px solid var(--v2-line);border-radius:999px;background:#fff;
  font-size:13px;font-weight:640;color:var(--v2-ink);text-decoration:none;
  transition:border-color .18s ease,box-shadow .2s ease,transform .18s var(--ease-out)}
.v2x.acx .acx-pill:hover{
  border-color:var(--brand-blue,#3680ED);transform:translateY(-2px);
  box-shadow:0 10px 22px -14px rgba(16,24,40,.45);text-decoration:none;color:var(--v2-ink)}
.v2x.acx .acx-pill-dot{width:8px;height:8px;border-radius:50%;background:var(--acx-accent,#3680ED);flex:0 0 auto}
/* ⚠ The dot needs a dark twin. Measured over all NINE accents in
   `ai_course_categories` against the dark card: at full saturation the
   worst (#7048E8) is exactly 3.00:1 — the non-text floor with zero
   margin, and an admin can add a tenth hue at any time. A 22% white
   scrim lifts the worst to 4.54:1 and every hue stays recognisable.
   Same technique as §PLATE, inverted; not color-mix(), for the same
   Safari-16.2 reason. */
body.theme-dark .v2x.acx .acx-pill-dot{
  background:linear-gradient(rgba(255,255,255,.22),rgba(255,255,255,.22)),var(--acx-accent,#3680ED)}
.v2x.acx .acx-pill-n{
  font-size:11.5px;font-weight:720;color:var(--v2-muted);
  padding:1px 7px;border-radius:999px;background:var(--v2-accent-soft,#eef2f7)}
body.theme-dark .v2x.acx .acx-pill{background:rgba(28,31,42,.92);border-color:rgba(255,255,255,.08);color:#EAF0FA}
body.theme-dark .v2x.acx .acx-pill:hover{box-shadow:0 10px 22px -14px rgba(0,0,0,.8)}
body.theme-dark .v2x.acx .acx-pill:hover{color:#EAF0FA}
body.theme-dark .v2x.acx .acx-pill-n{background:rgba(255,255,255,.08);color:#B9C2D0}

/* Provider rows — a provider has a name and a course count and nothing else
   worth a card, so they are rows, not tiles. */
.v2x.acx .acx-provgrid{
  display:grid;grid-template-columns:repeat(auto-fill,minmax(212px,1fr));gap:12px}
.v2x.acx .acx-prov{
  display:flex;align-items:center;gap:11px;
  padding:13px 15px;border:1px solid var(--v2-line);border-radius:16px;background:#fff;
  text-decoration:none;transition:border-color .18s ease,box-shadow .2s ease,transform .18s var(--ease-out)}
.v2x.acx .acx-prov:hover{
  border-color:var(--brand-blue,#3680ED);transform:translateY(-2px);
  box-shadow:0 10px 22px -14px rgba(16,24,40,.45);text-decoration:none}
.v2x.acx .acx-prov-mono{
  display:grid;place-items:center;width:38px;height:38px;flex:0 0 auto;border-radius:12px;
  background:var(--v2-accent-soft,#eaf1fe);color:var(--brand-blue,#2060C0);
  font-size:15px;font-weight:820;line-height:1}
.v2x.acx .acx-prov-mid{min-width:0;display:flex;flex-direction:column;gap:2px}
.v2x.acx .acx-prov-nm{
  font-size:13.5px;font-weight:700;color:var(--v2-ink);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.v2x.acx .acx-prov-ct{font-size:11.5px;font-weight:600;color:var(--v2-muted)}
body.theme-dark .v2x.acx .acx-prov{background:rgba(28,31,42,.92);border-color:rgba(255,255,255,.08)}
body.theme-dark .v2x.acx .acx-prov:hover{box-shadow:0 10px 22px -14px rgba(0,0,0,.8)}
body.theme-dark .v2x.acx .acx-prov-mono{background:rgba(54,128,237,.18);color:#9DC4FA}

/* Leaderboard + newest, two-up. Reuses the trending rail's box so the hub and
   the listing share one panel language. */
.v2x.acx .acx-two{display:grid;grid-template-columns:1fr 1fr;gap:18px;align-items:start}
.v2x.acx .acx-panel{
  padding:20px 20px 14px;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-panel h3{
  margin:0 0 12px;font-size:1.02rem;font-weight:800;letter-spacing:-.015em;color:var(--v2-ink)}
.v2x.acx .acx-row{
  display:flex;align-items:center;gap:10px;padding:9px 4px;
  border-bottom:1px solid var(--v2-line);text-decoration:none;
  transition:padding-left .18s var(--ease-out)}
.v2x.acx .acx-row:last-child{border-bottom:0}
.v2x.acx .acx-row:hover{padding-left:8px;text-decoration:none}
.v2x.acx .acx-row-rk{
  display:grid;place-items:center;width:22px;height:22px;flex:0 0 auto;border-radius:7px;
  background:var(--v2-accent-soft,#eef2f7);color:var(--v2-muted);
  font-size:11px;font-weight:780;line-height:1}
.v2x.acx .acx-row-nm{
  flex:1;min-width:0;font-size:13.5px;font-weight:650;color:var(--v2-ink);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.v2x.acx .acx-row-n{
  font-size:11.5px;font-weight:720;color:var(--v2-muted);
  padding:2px 8px;border-radius:999px;background:var(--v2-accent-soft,#eef2f7);flex:0 0 auto}
/* "New" badge. #1D4ED8 on #DBEAFE measures 5.49:1; dark 7.10:1. */
.v2x.acx .acx-row-new{
  font-size:10.5px;font-weight:760;letter-spacing:.02em;
  padding:2px 8px;border-radius:999px;background:#DBEAFE;color:#1D4ED8;flex:0 0 auto}
body.theme-dark .v2x.acx .acx-panel{
  background:rgba(28,31,42,.92);border-color:rgba(255,255,255,.08);
  box-shadow:inset 0 1px 0 rgba(255,255,255,.06),0 1px 2px rgba(0,0,0,.4)}
body.theme-dark .v2x.acx .acx-row{border-bottom-color:rgba(255,255,255,.07)}
body.theme-dark .v2x.acx .acx-row-rk,
body.theme-dark .v2x.acx .acx-row-n{background:rgba(255,255,255,.08);color:#B9C2D0}
body.theme-dark .v2x.acx .acx-row-new{background:rgba(59,130,246,.2);color:#93C5FD}

/* Goal tiles — "browse by where you are". Each one applies a REAL filter, so
   it is a link, not a decorative card. */
.v2x.acx .acx-goals{
  display:grid;grid-template-columns:repeat(auto-fill,minmax(252px,1fr));gap:14px}
.v2x.acx .acx-goal{
  display:flex;align-items:flex-start;gap:13px;
  padding:17px 18px;border:1px solid var(--v2-line);border-radius:18px;background:#fff;
  text-decoration:none;
  transition:border-color .18s ease,box-shadow .2s ease,transform .18s var(--ease-out)}
.v2x.acx .acx-goal:hover{
  border-color:var(--brand-blue,#3680ED);transform:translateY(-3px);
  box-shadow:0 14px 28px -18px rgba(16,24,40,.5);text-decoration:none}
.v2x.acx .acx-goal-ic{
  display:grid;place-items:center;width:40px;height:40px;flex:0 0 auto;border-radius:13px;
  background:var(--v2-accent-soft,#eaf1fe);color:var(--brand-blue,#2060C0)}
.v2x.acx .acx-goal-ic svg{width:20px;height:20px}
.v2x.acx .acx-goal-t{
  display:block;font-size:14px;font-weight:740;color:var(--v2-ink);letter-spacing:-.01em}
.v2x.acx .acx-goal-d{
  display:block;margin-top:3px;font-size:12.5px;font-weight:500;color:var(--v2-muted);line-height:1.5}
body.theme-dark .v2x.acx .acx-goal{background:rgba(28,31,42,.92);border-color:rgba(255,255,255,.08)}
body.theme-dark .v2x.acx .acx-goal:hover{box-shadow:0 14px 28px -18px rgba(0,0,0,.85)}
body.theme-dark .v2x.acx .acx-goal-ic{background:rgba(54,128,237,.18);color:#9DC4FA}


/* ═══ §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. */
@media (max-width:1180px){
  .v2x.acx .acx-two{grid-template-columns:1fr}
}

@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}
  .v2x.acx .acx-goals{grid-template-columns:1fr}
}

@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. */
  .v2x.acx .dir-lc-side{flex-direction:row;align-items:center;justify-content:space-between;width:100%}
  .v2x.acx .acx-cta{flex-wrap:wrap;gap:8px}
  .v2x.acx .acx-cta .dir-tc-btn{flex:1 1 auto}
}

@media (max-width:520px){
  .v2x.acx .acx-catgrid,
  .v2x.acx .acx-provgrid{grid-template-columns:1fr}
  .v2x.acx .acx-strip{gap:5px 8px}
  .v2x.acx .acx-fig{font-size:11px}
  .v2x.acx .acx-price{font-size:15.5px}
  .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){
  .v2x.acx .acx-pill,
  .v2x.acx .acx-prov,
  .v2x.acx .acx-goal,
  .v2x.acx .acx-row,
  .v2x.acx .acx-chip button,
  .v2x.acx .acx-results{transition:none}
  .v2x.acx .acx-pill:hover,
  .v2x.acx .acx-prov:hover,
  .v2x.acx .acx-goal:hover{transform:none}
  .v2x.acx .acx-row:hover{padding-left:4px}
  .v2x.acx .acx-chip button:hover{transform:none}
}
