/* ══════════════════════════════════════════════════════════════════════════
   AI GLOSSARY — DELTA over the AI Directory design system
   --------------------------------------------------------------------------
   /glossary, /glossary/categories and /glossary/category/{slug} wear
   /ai-directory's sheet — v2-public-directory-listing.css — by using that
   page's own `.v2x .dir-*` class names. Sharing the sheet rather than copying
   it is what keeps the pages from drifting: /browser-extensions tried a
   snapshot first and it rotted in two days.

   ⚠ AN EDIT TO THE DIRECTORY SHEET NOW REACHES SEVEN PAGES — /ai-directory,
     /browser-extensions, /gpts, /workflows, /ai-projects, /ai-courses and
     /glossary. Check all seven.

   LOAD ORDER (load-bearing):
     custom.*.css → public-partials-styles.css (the `.v2x` TOKEN layer) →
     v2-public-directory-listing.css → THIS FILE.
   The token layer is not optional: `linear-gradient(var(--brand-blue),…)`
   with the var unset is INVALID CSS, not a fallback colour.

   ⚠ `--v2-surface`, `--v2-soft`, `--v2-ink-2` and `--v2-ink-3` are NOT
   declared anywhere in the stack — grep the token layer, it has --v2-ink,
   --v2-line, --v2-muted, --v2-bg and no others in that family. So every
   `var(--v2-ink-2,#475569)` below paints its FALLBACK in BOTH themes, which is
   why each is paired with an explicit `body.theme-dark` twin. Removing a twin
   does not fall back to a dark value; it leaves slate-on-slate. This is the
   same arrangement /ai-projects and /ai-courses use — do not "tidy" it.

   This file holds ONLY what a GLOSSARY needs and a catalogue of tools has no
   concept of:

     §PLATE   the icon plate — an entry has no logo; it inherits its area's
              icon + colour, and the accent is the PLATE, never the glyph
     §AZ      the A–Z letter index — the control that makes this a glossary
     §ABBR    the acronym chip on the card
     §DEF     the definition body: this card leads with prose, not with metrics
     §CHIP    the active-filter chip row above the results
     §BUSY    the dim-while-filtering state the directory keys on a class it
              does not define anywhere in the stack
     §HERE    the "you are here" marker on the areas rail
     §ACRO    the alias decoder — gl_synonyms rendered as a lookup table
     §ABOUT   the hub pages' about panel
     §CATGRID /glossary/categories — the same cards, a browse layout
     §IOS     the 16px floor that stops iOS zooming on search focus
     §RESP    the handful of responsive fixes the above need

   ⚠ THE TONE VOCABULARY IS THE DIRECTORY'S, NOT A NEW ONE. An unmatched
   `data-tone` falls back to blue SILENTLY with nothing reporting an error.
   Read off the DEPLOYED directory sheet on 2026-08-14:
     .dir-hh-stat     12  amber blue cyan emerald green indigo orange pink
                          rose slate teal violet
     .dir-tc-pill     10  amber blue cyan emerald indigo orange rose slate
                          teal violet
     .dir-cat-card     8  amber blue cyan emerald indigo orange rose violet
     .dir-fx-dot       6  amber blue cyan emerald rose violet  ← NO indigo
     .dir-why-card     6  amber blue cyan emerald rose violet
     .dir-ts-ic /
     .dir-ts-opt-ic    5  amber blue cyan indigo violet        ← the tight one

   ⚠ NO `:has()` ANYWHERE — zero precedent in the directory sheet, and Safari
   <15.4 drops the entire selector rather than the unsupported part.
   ══════════════════════════════════════════════════════════════════════════ */


/* ═══ §HIDE — per-band responsive visibility ════════════════════════════════
   `GlSection::hiddenClasses()` emits `glp-hide-desktop|tablet|mobile` from the
   Page Editor's "visible on" checkboxes. Those class NAMES belong to the old
   `.glp-` kit, and that kit is not loaded here — so without this block the
   switch would land a dead class and a band an editor hid on mobile would
   render anyway, with nothing reporting the mistake.

   The names are kept rather than renamed because the DETAIL page still emits
   them from the same PHP method; forking the method to emit `.glx-hide-*` here
   would leave two vocabularies for one setting.

   Breakpoints are the OLD kit's (1200 / 768), not the directory sheet's ladder
   — they have to be, or a band hidden "on tablet" would cover a different
   range on this page than on /glossary/{slug}. */
@media (min-width:1200px){ .v2x.glx .glp-hide-desktop{display:none !important} }
@media (min-width:768px) and (max-width:1199.98px){ .v2x.glx .glp-hide-tablet{display:none !important} }
@media (max-width:767.98px){ .v2x.glx .glp-hide-mobile{display:none !important} }


/* ═══ §PLATE — the icon plate ═══════════════════════════════════════════════
   A glossary entry carries no logo and, on this install, no per-entry
   `icon_name` either (0 of 32 rows have one). It inherits its AREA's icon and
   colour — a truer mark than the first letter of the term, and it makes the
   grid readable by subject at a glance.

   ⚠ THE ACCENT IS THE PLATE, NEVER THE GLYPH, AND THIS MUST NOT BE
   "SIMPLIFIED" BACK. Measured over all EIGHT accents stored on gl_categories,
   as glyph ink on white: worst #0891B2 at 3.68:1, i.e. under AA for the
   14px-equivalent glyph that is the plate's only content. Saturation is not
   luminance, which is why an admin-supplied hue can never be trusted as ink.

   A white scrim painted OVER the accent needs no per-hue table: whatever the
   hue, the plate lands light and the glyph is drawn in the sheet's own ink.
   Measured across the same eight: 15.62–16.60:1 light. Dark mode swaps to the
   row's stored `color_dark` twin under a dark scrim: 10.47–11.96:1.

   `linear-gradient(rgba(...),rgba(...))` over a colour 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. */
.v2x.glx .glx-plate{
  background:linear-gradient(rgba(255,255,255,.88),rgba(255,255,255,.88)),var(--glx-accent,#3680ED);
  color:var(--v2-ink);
  display:grid;place-items:center;overflow:hidden}
body.theme-dark .v2x.glx .glx-plate{
  background:linear-gradient(rgba(19,19,23,.82),rgba(19,19,23,.82)),var(--glx-accent-dark,var(--glx-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, not <i> glyphs, so the lever is width/height — a
   font-size rule here would do nothing and the icon would sit at its
   intrinsic 24px everywhere. */
.v2x.glx .dir-tc-logo.glx-plate svg{width:26px;height:26px}
.v2x.glx .dir-lc-logo.glx-plate svg{width:21px;height:21px}
.v2x.glx .dir-tr-lg.glx-plate   svg{width:15px;height:15px}

/* Hero 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.
   Measured: 16.18:1 light worst, 13.03:1 dark worst. */
.v2x.glx .dir-hh-tile.glx-tile{
  background:linear-gradient(rgba(255,255,255,.9),rgba(255,255,255,.9)),var(--glx-accent,#3680ED);
  color:var(--v2-ink)}
.v2x.glx .dir-hh-tile.glx-tile svg{width:29px;height:29px}
body.theme-dark .v2x.glx .dir-hh-tile.glx-tile{
  background:linear-gradient(rgba(23,23,27,.86),rgba(23,23,27,.86)),var(--glx-accent-dark,var(--glx-accent,#3680ED));
  color:#EAF0FA}

/* The areas-rail card 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.glx .dir-cat-card-ico svg{width:22px;height:22px}


/* ═══ §AZ — the A–Z letter index ════════════════════════════════════════════
   The one control that makes this page a glossary rather than a directory.
   It is a FILTER, not an anchor list: pressing R re-queries the catalogue, so
   the letter state round-trips through the URL and survives a share.

   Counts are honest and pre-computed with the letter itself lifted out of the
   filter set (GlCatalog::azCounts), so a letter's count is what pressing it
   will actually return. A letter with none is kept visible but inert: hiding
   it makes the row reflow every time a filter changes, and the gap is itself
   information — "nothing here starts with J".

   ⚠ The ACTIVE fill is --brand-blue-dark (#2060C0), NOT --brand-blue
   (#3680ED). White on #3680ED measures 3.84:1 — under AA for a 13px bold
   glyph. On #2060C0 it is 6.01:1. */
/* ⚠ NO max-width. `--dir-shell` is NOT declared anywhere in the stack, so
   `var(--dir-shell,1280px)` paints the 1280px FALLBACK — and the bands around
   this one (.dir-lab, .dir-cat-sect, .dir-why-sect) have no cap at all. On a
   2560px screen that rendered the A–Z block 1280px wide inside a 1872px
   column: measured in-browser, visibly inset from everything above and below
   it. The horizontal padding matches .dir-lab (0 4px) so the two line up. */
.v2x.glx .glx-az{
  margin:0 auto;padding:clamp(18px,3vw,30px) 4px 0}
/* The same surface the acronym cards and the term cards wear: a diagonal
   brand wash, a tinted edge and the 1px inset highlight along the top. The
   panel used to be plain white with a grey hairline, which read as a form
   toolbar rather than as part of this page. */
.v2x.glx .glx-az-box{
  background-color:#fff;
  background-image:linear-gradient(152deg,
    rgba(54,128,237,.055) 0%, rgba(54,128,237,0) 46%, rgba(54,128,237,.04) 100%);
  border:1px solid rgba(54,128,237,.18);
  border-radius:18px;
  padding:clamp(13px,2vw,18px);
  box-shadow:0 1px 0 rgba(255,255,255,.7) inset, 0 1px 2px rgba(16,24,40,.04);
  display:flex;flex-wrap:wrap;align-items:center;gap:clamp(10px,2vw,18px)}
.v2x.glx .glx-az-lbl{
  display:inline-flex;align-items:center;gap:8px;
  font-size:.72rem;font-weight:800;letter-spacing:.07em;text-transform:uppercase;
  color:var(--v2-ink-3,#64748B);flex:0 0 auto;line-height:1}
.v2x.glx .glx-az-lbl svg{width:15px;height:15px;color:var(--brand-blue,#3680ED)}
/* A GRID, not a wrapping flex row. 26 letters cannot fit one line below
   ~1100px, so the row wraps regardless; `auto-fit` + `1fr` makes every wrapped
   line full-width and evenly divided instead of leaving a ragged last row that
   reads as a rendering fault. The track FLOOR is what controls how many rows
   the block takes:
     320px viewport → 232px of track → 6 columns → 5 rows
     390px          → 302px          → 8 columns → 4 rows
     820px+         → the row fits in 1–2 lines
   34px is above the 24px minimum target size with room to spare; the 30px
   floor at ≤520px (§RESP) still clears it. */
.v2x.glx .glx-az-row{
  display:grid;grid-template-columns:repeat(auto-fit,minmax(34px,1fr));
  gap:5px;flex:1 1 320px;min-width:0}
/* "All" needs two tracks — its label is a word, not a glyph. */
.v2x.glx .glx-az-row .is-all{grid-column:span 2}

.v2x.glx .glx-az-k{
  --glx-k:34px;
  display:inline-flex;align-items:center;justify-content:center;
  min-width:var(--glx-k);height:var(--glx-k);padding:0 7px;
  border:1px solid rgba(15,23,42,.09);border-radius:12px;
  background:#fff;
  font-size:.82rem;font-weight:750;line-height:1;
  color:var(--v2-ink-2,#475569);            /* 7.58:1 on white */
  cursor:pointer;text-decoration:none;
  box-shadow:0 1px 0 rgba(255,255,255,.8) inset, 0 1px 1px rgba(16,24,40,.03);
  transition:border-color .18s ease,background-color .18s ease,color .18s ease,transform .18s cubic-bezier(.34,1.4,.64,1),box-shadow .18s ease}
/* Hover now tints the FILL as well as the edge. Edge-only left the key looking
   inert next to the rest of the page, where every interactive surface moves. */
.v2x.glx .glx-az-k:hover:not(:disabled){
  border-color:rgba(54,128,237,.45);
  background:rgba(54,128,237,.09);
  color:var(--brand-blue-dark,#2060C0);
  transform:translateY(-2px);
  box-shadow:0 6px 14px -8px rgba(32,96,192,.5)}
/* ⚠ THE FILL STAYS FLAT --brand-blue-dark. A brand gradient here would put
   white glyphs over #3680ED at the light end, which measures 3.84:1 — under
   AA, and the exact figure recorded below as the reason this rule uses the
   dark twin in the first place. The depth comes from the ring and the shadow,
   which cost no contrast. */
.v2x.glx .glx-az-k.is-on{
  background:var(--brand-blue-dark,#2060C0);border-color:var(--brand-blue-dark,#2060C0);
  color:#fff;                               /* 6.01:1 */
  transform:translateY(-1px);
  box-shadow:0 1px 0 rgba(255,255,255,.28) inset,
             0 0 0 3px rgba(54,128,237,.18),
             0 8px 18px -8px rgba(32,96,192,.8)}
.v2x.glx .glx-az-k.is-on:hover{background:var(--brand-blue-dark,#2060C0);color:#fff}
/* A letter with no entries. Disabled controls are exempt from the WCAG text
   minimum, but there are up to five of them in a row here and a row of ghosts
   reads as a rendering fault — so it is held at 4.51:1 rather than greyed to
   the usual ~2.5:1. */
.v2x.glx .glx-az-k:disabled{
  color:#6E7787;background:var(--v2-soft,#F8FAFC);
  border-color:var(--v2-line,#E2E8F0);cursor:default;box-shadow:none}
.v2x.glx .glx-az-k.is-all{min-width:auto;padding:0 6px;font-size:.76rem;letter-spacing:.02em}

body.theme-dark .v2x.glx .glx-az-box{
  background-color:var(--dk-surface-2,#17171B);
  background-image:linear-gradient(152deg,
    rgba(96,164,245,.09) 0%, rgba(96,164,245,0) 46%, rgba(96,164,245,.06) 100%);
  border-color:rgba(96,164,245,.2);
  box-shadow:0 1px 0 rgba(255,255,255,.04) inset, 0 1px 2px rgba(0,0,0,.4)}
body.theme-dark .v2x.glx .glx-az-lbl{color:var(--dk-text-3,#9AA0AB)}
body.theme-dark .v2x.glx .glx-az-lbl svg{color:#60A4F5}
body.theme-dark .v2x.glx .glx-az-k{
  background:rgba(148,163,184,.08);border-color:rgba(148,163,184,.18);color:var(--dk-text-2,#C7CAD1);
  box-shadow:0 1px 0 rgba(255,255,255,.03) inset}
body.theme-dark .v2x.glx .glx-az-k:hover:not(:disabled){
  border-color:rgba(96,164,245,.5);
  background:rgba(96,164,245,.14);
  color:#BFDBFE;
  box-shadow:0 6px 14px -8px rgba(0,0,0,.7)}
/* ⚠ DARK FLIPS THE POLARITY. Measured in-browser: white on --brand-blue
   (#3680ED) is 3.84:1 — under AA for a 12px bold glyph, and the same figure
   that made the LIGHT rule use --brand-blue-dark. Going darker is not an
   option on a dark ground, so the fill goes LIGHTER and the ink goes dark:
   #0B1220 on #60A4F5 measures 7.25:1. #60A4F5 is the brand blue's dark twin
   already used across this stack, so the key still reads as "selected, brand". */
body.theme-dark .v2x.glx .glx-az-k.is-on{
  background:#60A4F5;border-color:#60A4F5;color:var(--dk-bg,#0E0E11);
  box-shadow:0 6px 16px -8px rgba(96,164,245,.55)}
body.theme-dark .v2x.glx .glx-az-k:disabled{
  color:#7C8798;background:rgba(148,163,184,.05);border-color:rgba(148,163,184,.12)}


/* ═══ §ABBR — the acronym chip ══════════════════════════════════════════════
   Seven of the 32 entries carry an abbreviation and 22 aliases point at them,
   so "RAG" and "CNN" are how a visitor arrives. The chip is monospaced
   because it is a token, not a word — and it is dropped by the blade when the
   abbreviation equals the term rather than printed twice. */
.v2x.glx .glx-abbr{
  display:inline-flex;align-items:center;
  padding:2px 7px;border-radius:6px;
  font-family:'JetBrains Mono',ui-monospace,SFMono-Regular,Menlo,monospace;
  font-size:.68rem;font-weight:700;letter-spacing:.01em;line-height:1.6;
  background:#EFF6FF;color:#1D4ED8;         /* 6.16:1 */
  white-space:nowrap;flex:0 0 auto}
body.theme-dark .v2x.glx .glx-abbr{
  background:rgba(96,164,245,.16);color:#93C5FD}   /* 7.45:1 */

/* On the card the term and its acronym share one baseline row. `min-width:0`
   is what lets the term truncate instead of shoving the chip off the card. */
.v2x.glx .glx-nmrow{
  display:flex;align-items:center;gap:8px;min-width:0;margin:0 0 2px}
.v2x.glx .glx-nmrow .dir-tc-nm{margin:0;min-width:0}


/* ═══ §DEF — the definition body ════════════════════════════════════════════
   The directory's card gives its description one clamped line because the
   product NAME is the payload. Here the DEFINITION is the payload: a visitor
   who can read it on the card never needs to open the entry. So it gets three
   lines and a taller line-height, and the card's fixed metric strip is gone. */
.v2x.glx .dir-tc-desc.glx-def{
  display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:3;
  overflow:hidden;font-size:.855rem;line-height:1.62;min-height:calc(.855rem * 1.62 * 3)}
.v2x.glx .dir-lc-desc.glx-def{
  display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2;
  overflow:hidden;line-height:1.6}


/* ═══ §CHIP — active-filter chips ══════════════════════════════════════════
   One-tap removal without opening the rail. Taxonomy ids are resolved to
   names in the blade: a chip reading "7" would be worse than no chip. */
.v2x.glx .glx-chips{
  display:flex;flex-wrap:wrap;align-items:center;gap:8px;
  margin:0 0 16px}
.v2x.glx .glx-chip{
  display:inline-flex;align-items:center;gap:6px;
  padding:5px 6px 5px 12px;border-radius:999px;
  background:rgba(54,128,237,.09);border:1px solid rgba(54,128,237,.22);
  font-size:.78rem;font-weight:650;color:#1D4ED8;line-height:1.6}  /* 6.03:1 */
.v2x.glx .glx-chip button{
  display:inline-flex;align-items:center;justify-content:center;
  width:17px;height:17px;border:0;border-radius:50%;cursor:pointer;
  background:rgba(54,128,237,.18);color:inherit;opacity:.75;
  transition:opacity .15s ease,background .15s ease}
.v2x.glx .glx-chip button svg{width:10px;height:10px}
.v2x.glx .glx-chip button:hover{opacity:1;background:rgba(54,128,237,.3)}
.v2x.glx .glx-chip-clear{
  border:0;background:none;cursor:pointer;padding:5px 4px;
  font-size:.78rem;font-weight:650;color:var(--v2-ink-3,#64748B);
  text-decoration:underline;text-underline-offset:3px;
  transition:color .15s ease}
.v2x.glx .glx-chip-clear:hover{color:var(--brand-blue-dark,#2060C0)}
body.theme-dark .v2x.glx .glx-chip{
  background:rgba(96,164,245,.14);border-color:rgba(96,164,245,.3);color:#BFDBFE}  /* 11.01:1 */
body.theme-dark .v2x.glx .glx-chip button{background:rgba(96,164,245,.2)}
body.theme-dark .v2x.glx .glx-chip button:hover{background:rgba(96,164,245,.36)}
body.theme-dark .v2x.glx .glx-chip-clear{color:var(--dk-text-3,#9AA0AB)}
/* --brand-blue-dark is NOT remapped by the token layer's dark block (which
   touches --v2-ink/-muted/-line/-bg, the greys and the accent-softs, and
   nothing in the brand family). Left alone this hover measured 3.19:1 on the
   dark ground; #60A4F5 is 7.41:1 and is the twin the rest of the stack uses. */
body.theme-dark .v2x.glx .glx-chip-clear:hover{color:#60A4F5}


/* ═══ §BUSY — dim while filtering ══════════════════════════════════════════
   `wire:loading.class="is-busy"` lands a class that NO sheet in the stack
   defines — verified by grep against the directory sheet and the token layer,
   and the sixth module in a row to hit it. Mid-filter the rows on screen are
   the OLD set, so they are dimmed AND made inert rather than left looking
   interactive and current. */
.v2x.glx .glx-results{transition:opacity .18s ease,filter .18s ease}
.v2x.glx .glx-results.is-busy{opacity:.45;filter:saturate(.6);pointer-events:none}


/* ═══ §HERE — "you are here" on the areas rail ══════════════════════════════
   The rail renders on the hub pages too, so on /glossary/category/deep-learning
   one of its cards IS the current page. Marked with a ring rather than a
   colour change, so the tone cycle stays readable. */
.v2x.glx .dir-cat-card.is-here{
  box-shadow:inset 0 0 0 2px currentColor,0 10px 30px -14px rgba(16,24,40,.3)}
/* The ring is currentColor and therefore already theme-correct; only the drop
   shadow needs a twin — a near-black shadow on a dark ground is invisible,
   which loses the lift that separates the current card. */
body.theme-dark .v2x.glx .dir-cat-card.is-here{
  box-shadow:inset 0 0 0 2px currentColor,0 10px 30px -14px rgba(0,0,0,.7)}
.v2x.glx .dir-cat-card.is-here .dir-cat-card-cnt{font-weight:800}


/* ═══ §ACRO — the alias decoder ═════════════════════════════════════════════
   The one band on this page that could not be borrowed from a sibling module.
   `gl_synonyms` is why searching "LLM" finds "Large Language Model", and the
   rows are real: 22 of them, every one routable to its canonical entry. Only
   aliases whose target is still LIVE are listed — a decoder pointing at a
   withdrawn entry is worse than no decoder.

   Two columns of one row: the alias as a mono token, the canonical term as
   prose, an arrow between them. Reads as a lookup table because it is one. */
/* Full shell width, no cap. Every other band on this page — the A–Z panel, the
   filter rail, the term grid, the why band — runs the shell's 1864px; this one
   was pinned to 1240 and sat visibly narrower than its neighbours. */
.v2x.glx .glx-acro-grid{
  display:grid;grid-template-columns:repeat(auto-fill,minmax(268px,1fr));
  gap:14px}

/* ── The tone map. Same eleven values §CATPRM gives `.dir-cat-card`, restated
   for `.glx-acro` rather than added to that selector list: public-dir-bands is
   shared by twenty verticals and this band belongs to one. --dtc-rgb is the
   only thing a tone sets; every layer below reads it. */
.v2x.glx .glx-acro[data-tone="blue"]   { --dtc-rgb: 54, 128, 237; }
.v2x.glx .glx-acro[data-tone="violet"] { --dtc-rgb: 139, 92, 246; }
.v2x.glx .glx-acro[data-tone="indigo"] { --dtc-rgb: 99, 102, 241; }
.v2x.glx .glx-acro[data-tone="rose"]   { --dtc-rgb: 244, 63, 94; }
.v2x.glx .glx-acro[data-tone="amber"]  { --dtc-rgb: 245, 158, 11; }
.v2x.glx .glx-acro[data-tone="emerald"]{ --dtc-rgb: 16, 185, 129; }
.v2x.glx .glx-acro[data-tone="cyan"]   { --dtc-rgb: 34, 184, 217; }
.v2x.glx .glx-acro[data-tone="orange"] { --dtc-rgb: 249, 115, 22; }
.v2x.glx .glx-acro[data-tone="teal"]   { --dtc-rgb: 20, 184, 166; }
.v2x.glx .glx-acro[data-tone="pink"]   { --dtc-rgb: 236, 72, 153; }
.v2x.glx .glx-acro[data-tone="slate"]  { --dtc-rgb: 100, 116, 139; }

/* The ramp, both halves, exactly the numbers §CATPRM uses. A 5% tint that
   reads over white is invisible over near-black, which is why dark is not a
   filter but its own four values. */
.v2x.glx .glx-acro{
  --dcp-a1:.075; --dcp-a2:.055; --dcp-edge:.20; --dcp-bloom:.20;
  --acro-surface:#fff}
body.theme-dark .v2x.glx .glx-acro{
  --dcp-a1:.13; --dcp-a2:.09; --dcp-edge:.30; --dcp-bloom:.17;
  --acro-surface:var(--dk-surface-3,#1D1D22)}

/* Two rows, not two columns. Side by side the alias and the term shared one
   track and the TERM carried the ellipsis, so the card clipped exactly the
   half a decoder exists to deliver. Stacked, neither is ever cut. */
.v2x.glx .glx-acro{
  position:relative;display:flex;flex-direction:column;gap:11px;
  padding:16px 17px 17px;border-radius:20px;text-decoration:none;
  background-color:var(--acro-surface);
  background-image:
    radial-gradient(200px 180px at calc(100% + 26px) -48px,
      rgba(var(--dtc-rgb), var(--dcp-bloom)) 0%, rgba(var(--dtc-rgb), 0) 72%),
    linear-gradient(152deg,
      rgba(var(--dtc-rgb), var(--dcp-a1)) 0%,
      rgba(var(--dtc-rgb), 0) 48%,
      rgba(var(--dtc-rgb), var(--dcp-a2)) 100%);
  background-repeat:no-repeat;background-position:0 0,0 0;
  background-size:100% 100%,100% 100%;
  border:1px solid rgba(var(--dtc-rgb), var(--dcp-edge));
  box-shadow:0 1px 0 rgba(255,255,255,.7) inset, 0 1px 2px rgba(16,24,40,.04);
  transition:box-shadow .24s ease,transform .24s cubic-bezier(.34,1.3,.64,1),border-color .24s ease}

.v2x.glx .glx-acro:hover,
.v2x.glx .glx-acro:focus-visible{
  transform:translateY(-4px);
  border-color:rgba(var(--dtc-rgb), .55);
  box-shadow:0 18px 38px -22px rgba(var(--dtc-rgb), .6), 0 3px 8px rgba(16,24,40,.06)}
.v2x.glx .glx-acro:focus-visible{outline:3px solid rgba(var(--dtc-rgb), .45);outline-offset:3px}

/* `.v2x a:hover{text-decoration:underline}` is (0,2,1) and would underline the
   whole card, since text-decoration propagates from the anchor. This is
   (0,4,0), and the reset must sit on the ANCHOR — a descendant cannot take
   back a line its ancestor set. */
.v2x.glx .glx-acro:hover,
.v2x.glx .glx-acro:focus,
.v2x.glx .glx-acro:active{text-decoration:none}

.v2x.glx .glx-acro-top{display:flex;align-items:center;gap:9px;width:100%}

/* ⚠ `flex:0 1 auto`, NOT `1 1 auto`. Grown, the badge stretched the full card
   width and a three-letter token like ANN became an empty bar that read as a
   disabled input rather than a key.

   ⚠ THE TOKEN WRAPS AND IS NEVER TRUNCATED — the corpus holds "Reinforcement
   Learning from Human Feedback", 41 characters, which fits no single line.

   ⚠ `break-word`, NOT `anywhere`: `anywhere` drops min-content to ONE
   CHARACTER, so the badge collapsed to the narrowest thing the row allowed and
   broke three-letter tokens mid-word — "GA/N", "RA/G", "ConvNe/t" were live. */
.v2x.glx .glx-acro-k{
  flex:0 1 auto;min-width:0;
  font-family:'JetBrains Mono',ui-monospace,SFMono-Regular,Menlo,monospace;
  font-size:.735rem;font-weight:700;line-height:1.45;letter-spacing:.01em;
  padding:5px 10px;border-radius:9px;
  background:rgba(var(--dtc-rgb), .1);
  color:var(--v2-ink,#0F0F12);
  border:1px solid rgba(var(--dtc-rgb), .22);
  overflow-wrap:break-word;
  transition:background-color .22s ease,border-color .22s ease}
.v2x.glx .glx-acro:hover .glx-acro-k{
  background:rgba(var(--dtc-rgb), .17);border-color:rgba(var(--dtc-rgb), .38)}

/* The connector — the decoder idea made visible. It also takes the slack, so
   the button stays pinned right however short the token is. */
.v2x.glx .glx-acro-line{
  flex:1 1 auto;min-width:10px;height:2px;border-radius:2px;position:relative;
  background:repeating-linear-gradient(90deg,rgba(var(--dtc-rgb),.35) 0 4px,transparent 4px 8px)}
.v2x.glx .glx-acro-line::after{
  content:'';position:absolute;inset:0;border-radius:inherit;
  background:rgba(var(--dtc-rgb), .95);
  transform:scaleX(0);transform-origin:left center;
  transition:transform .34s cubic-bezier(.4,0,.2,1)}
.v2x.glx .glx-acro:hover .glx-acro-line::after,
.v2x.glx .glx-acro:focus-visible .glx-acro-line::after{transform:scaleX(1)}

/* Filled at rest, like `.dir-tc-btn` on the term cards above — that constant
   block of tone is most of what makes this page look like this page. 13px to
   echo that button's radius. */
.v2x.glx .glx-acro-arr{
  flex:0 0 auto;width:30px;height:30px;border-radius:13px;
  display:inline-flex;align-items:center;justify-content:center;
  color:#fff;border:0;
  background-color:rgb(var(--dtc-rgb));
  background-image:linear-gradient(160deg,rgba(255,255,255,.22) 0%,rgba(255,255,255,0) 58%);
  box-shadow:0 4px 10px -4px rgba(var(--dtc-rgb), .7);
  transition:transform .28s cubic-bezier(.34,1.4,.64,1),box-shadow .22s ease}
.v2x.glx .glx-acro-arr svg{width:15px;height:15px;display:block}
.v2x.glx .glx-acro:hover .glx-acro-arr,
.v2x.glx .glx-acro:focus-visible .glx-acro-arr{
  transform:translateX(3px) scale(1.06);
  box-shadow:0 8px 18px -6px rgba(var(--dtc-rgb), .85)}

/* No nowrap, no ellipsis — this is the answer and it is never abbreviated. */
.v2x.glx .glx-acro-nm{
  font-size:.95rem;font-weight:700;line-height:1.38;letter-spacing:-.01em;
  color:var(--v2-ink,#0F0F12);min-width:0;
  overflow-wrap:break-word}

/* Dark surface only. Everything else themes itself, because a tone is one RGB
   triplet and the ramp above already has its dark half. */
body.theme-dark .v2x.glx .glx-acro{
  box-shadow:0 1px 0 rgba(255,255,255,.04) inset, 0 1px 2px rgba(0,0,0,.4)}
body.theme-dark .v2x.glx .glx-acro:hover,
body.theme-dark .v2x.glx .glx-acro:focus-visible{
  box-shadow:0 20px 38px -24px rgba(0,0,0,.9), 0 3px 8px rgba(0,0,0,.45)}
body.theme-dark .v2x.glx .glx-acro-k{color:var(--dk-text,#F4F5F7)}


/* ═══ §ABOUT — hub about panel ═════════════════════════════════════════════
   Built from the area row's own description / about_intro / about_points, on
   the same card language as the rest of the page. */
/* Same reasoning as .glx-az — see the note there. */
.v2x.glx .glx-about{
  margin:0 auto;padding:0 4px 8px}
.v2x.glx .glx-about-box{
  background:var(--v2-surface,#fff);
  border:1px solid var(--v2-line,#E2E8F0);
  border-radius:18px;padding:clamp(20px,3vw,32px)}
.v2x.glx .glx-about-box h2{
  font-size:clamp(1.15rem,2.4vw,1.5rem);font-weight:800;
  letter-spacing:-.02em;color:var(--v2-ink);margin:0 0 12px}
.v2x.glx .glx-about-box p{
  font-size:.95rem;line-height:1.75;color:var(--v2-ink-2,#475569);margin:0 0 14px}
.v2x.glx .glx-about-box ul{list-style:none;margin:0;padding:0;display:grid;gap:9px}
.v2x.glx .glx-about-box li{
  display:flex;align-items:flex-start;gap:9px;
  font-size:.9rem;line-height:1.6;color:var(--v2-ink-2,#475569)}
.v2x.glx .glx-about-box li svg{
  width:17px;height:17px;flex:0 0 auto;margin-top:2px;color:var(--brand-blue,#3680ED)}
body.theme-dark .v2x.glx .glx-about-box{
  background:var(--v2-surface,#141922);border-color:rgba(148,163,184,.16)}
body.theme-dark .v2x.glx .glx-about-box p,
body.theme-dark .v2x.glx .glx-about-box li{color:var(--dk-text-2,#C7CAD1)}   /* 9.78:1 */
/* The tick icon is decoration at 17px, so the 3:1 non-text floor applies and
   #3680ED already clears it at 4.59:1 on the dark card — the twin is here for
   parity with the p/li ink beside it, not to fix a failure. */
body.theme-dark .v2x.glx .glx-about-box li svg{color:#60A4F5}


/* ═══ §CATGRID — /glossary/categories ══════════════════════════════════════
   THE CARD IS THE SHARED SHEET'S `.dir-cat-card`; only the CONTAINER is
   local. On the listing page those cards live in `.dir-cat-rail`, a
   horizontal snap rail — right for an eight-card teaser, wrong for a
   browse-everything index where the visitor wants all of them at once.

   `auto-fit` + a track RANGE + a capped, centred track keeps the card WIDTH
   matching the rail's rather than the column COUNT — the /gpts pass shipped
   the column-count version and the same component rendered 50% wider a few
   hundred pixels above its twin. */
.v2x.glx .glx-sect{margin-top:clamp(28px,5vw,56px)}
.v2x.glx .glx-catgrid{
  display:grid;grid-template-columns:repeat(auto-fit,minmax(240px,1fr));
  gap:18px;max-width:1240px;margin:0 auto;justify-content:center}
/* The rail card is `flex:0 0 <width>` inside the rail; in a grid track that
   fixed basis would fight the track, so it is released here and only here. */
.v2x.glx .glx-catgrid .dir-cat-card{flex:1 1 auto;width:auto;min-width:0;scroll-snap-align:none}

/* "View all areas" / "Browse every term" footer link. */
.v2x.glx .glx-more{
  display:flex;justify-content:center;
  margin-top:clamp(20px,3vw,32px)}
.v2x.glx .glx-more .dir-tr-more{max-width:340px}


/* ═══ §IOS — the 16px focus-zoom floor ═════════════════════════════════════
   `.dir-hh-search input` is 15.5px in the SHARED sheet (14px under 820px) and
   iOS Safari zooms the viewport on focus for anything under 16px. Pinned here
   rather than in the shared sheet, because raising it there would reflow six
   pages that have not been re-verified. The shared miss is real and still
   wants its own pass. */
.v2x.glx .dir-hh-search input{font-size:16px}
@media (max-width:820px){
  .v2x.glx .dir-hh-search input{font-size:16px}
}


/* ═══ §RESP — responsive fixes the above need ══════════════════════════════
   Every breakpoint here is one the SHARED sheet already uses, measured by
   frequency: 820 · 520 · 1180 · 640. Introducing a new stop (1100 was the
   temptation) makes the layout change twice within 80px. */
@media (max-width:1180px){
  .v2x.glx .glx-az-box{gap:12px}
}
@media (max-width:820px){
  .v2x.glx .glx-az{padding-top:16px}
  .v2x.glx .glx-az-lbl{flex:1 1 100%}
  .v2x.glx .glx-az-row{flex:1 1 100%}
  .v2x.glx .glx-az-k{--glx-k:32px;font-size:.78rem}
  .v2x.glx .glx-acro-grid{grid-template-columns:repeat(auto-fill,minmax(228px,1fr))}
}
@media (max-width:640px){
  .v2x.glx .glx-catgrid{grid-template-columns:1fr}
}
@media (max-width:520px){
  /* The grid track floor drops with the key, so the block keeps the same
     number of ROWS rather than growing one. 30px is still above the 24px
     minimum target size, and the same filter is reachable from the search box
     for anyone who cannot hit it. */
  .v2x.glx .glx-az-k{--glx-k:30px;padding:0 4px;border-radius:9px;font-size:.75rem}
  .v2x.glx .glx-az-row{gap:4px;grid-template-columns:repeat(auto-fit,minmax(30px,1fr))}
  .v2x.glx .glx-az-box{padding:12px}
  /* ONE column, and the floor is arithmetic rather than taste. The badge
     must fit its longest unbroken WORD or `break-word` splits it mid-word —
     "Confabulat/ion", "Distillati/on" were both live at a 150px track. The
     longest words in the corpus are 13 characters ("Reinforcement",
     "Confabulation"); at .735rem JetBrains Mono that is ~92px, plus 20px of
     badge padding, 28px of arrow, 18px of gaps, 10px of connector and 32px of
     card padding — a ~200px track before anything breaks. Two columns cannot
     reach that on a phone, so the row goes single and the connector stretches
     to fill the width instead, which is what makes a wide card read as
     deliberate rather than empty. */
  .v2x.glx .glx-acro-grid{grid-template-columns:1fr}
}


/* ═══ Motion ═══════════════════════════════════════════════════════════════ */
@media (prefers-reduced-motion:reduce){
  .v2x.glx .glx-az-k,
  .v2x.glx .glx-acro,
  .v2x.glx .glx-results{transition:none}
  .v2x.glx .glx-az-k:hover:not(:disabled),
  .v2x.glx .glx-acro:hover{transform:none}
  .v2x.glx .glx-acro::before,
  .v2x.glx .glx-acro::after,
  .v2x.glx .glx-acro-k,
  .v2x.glx .glx-acro-arr,
  .v2x.glx .glx-acro-nm{transition:none}
  .v2x.glx .glx-acro:hover .glx-acro-arr{transform:none}
  .v2x.glx .glx-acro-line::after{transition:none}
  .v2x.glx .glx-acro:hover .glx-acro-arr{transform:none}
}


/* ══════════════════════════════════════════════════════════════════════════
   §GXA / §GXT / §GXP — the three hub bands under the areas grid
   Rebuilt 2026-08-22. They previously borrowed `.glx-acro`, which is the A–Z
   DECODER on gl/listing.blade.php: a two-row alias→term lookup whose children
   belong inside `.glx-acro-top`. Dropped into a bare column flex they stacked,
   so its 30px arrow button became a blank row through the middle of every
   card. Worse, `.glx-acro` reads its entire palette from `--dtc-rgb`, which is
   set by `data-tone` — and neither band passed one. Every
   `rgba(var(--dtc-rgb), …)` was therefore an INVALID value and dropped whole:
   no wash, no border tint, and an arrow button with no background at all. The
   dead space in those cards was an invisible button.

   `.glx-acro` is deliberately left alone here — the listing still uses it
   correctly. These are their own namespaces.

   ── Colour ──────────────────────────────────────────────────────────────
   `--gx-l` / `--gx-d` are "r,g,b" triplets written inline from the ROW's own
   `accent` / `accent_dark`, so an area is the same colour everywhere and the
   editor's choice is what ships. `--gx` resolves one of them off the THEME
   CLASS, never `prefers-color-scheme` — the two can disagree.

   Per §PLATE on GlCategory these values are SURFACES, not small-text ink: the
   worst light value is 3.03:1 on white. Names and counts are always
   `--v2-ink` / `--v2-muted`. The only place a raw accent carries a glyph is
   the dark-mode plate, where the stored light twin (#8DBEFF …) sits ~9:1 on
   the dark card.
   ══════════════════════════════════════════════════════════════════════════ */

.v2x.glx .glxa-card,
.v2x.glx .glxt-chip,
.v2x.glx .glxp-chip{--gx:var(--gx-l,54,128,237)}
body.theme-dark .v2x.glx .glxa-card,
body.theme-dark .v2x.glx .glxt-chip,
body.theme-dark .v2x.glx .glxp-chip{--gx:var(--gx-d,var(--gx-l,96,164,245))}

/* ── Band shell. Same surface language as `.glx-about-box` so these sit in the
      page rather than on it; built from --white / --v2-line, which the dark
      theme already retokenises at `body.theme-dark .v2x`. ─────────────────── */
.v2x.glx .glxa,
.v2x.glx .glxt,
.v2x.glx .glxp{margin:0 auto;padding:0 4px 8px}
.v2x.glx .glxa-box,
.v2x.glx .glxt-box,
.v2x.glx .glxp-box{
  background-color:var(--white,#fff);
  border:1px solid var(--v2-line,#e7eaf0);
  border-radius:22px;padding:clamp(18px,2.6vw,30px)}

/* ── Band head — brand plate, title, one line of copy ───────────────────── */
.v2x.glx .glxa-head{display:flex;align-items:flex-start;gap:13px;margin:0 0 clamp(16px,2vw,22px)}
.v2x.glx .glxa-head-ic{
  flex:0 0 auto;width:40px;height:40px;border-radius:13px;
  display:inline-flex;align-items:center;justify-content:center;color:#fff;
  background-image:linear-gradient(135deg,#2060C0 0%,#3680ED 52%,#60A4F5 100%);
  box-shadow:0 6px 16px -8px rgba(54,128,237,.85)}
.v2x.glx .glxa-head-ic.is-t{
  background-image:linear-gradient(135deg,#0B5ED7 0%,#0196FD 52%,#5CCBFF 100%);
  box-shadow:0 6px 16px -8px rgba(112,72,232,.85)}
.v2x.glx .glxa-head-ic svg{width:20px;height:20px;display:block}
.v2x.glx .glxa-head-tx{min-width:0}
.v2x.glx .glxa-head h2{
  font-size:clamp(1.15rem,2.4vw,1.5rem);font-weight:800;letter-spacing:-.02em;
  color:var(--v2-ink,#0F0F12);margin:0 0 5px;line-height:1.25}
.v2x.glx .glxa-head p{
  font-size:.925rem;line-height:1.65;color:var(--v2-muted,#4A4A5A);margin:0;
  overflow-wrap:break-word}

/* ══ §GXA — one card per area ═══════════════════════════════════════════════
   `min(100%, 300px)` in the track, not a bare 300px: auto-fill sizes columns
   by the track MAXIMUM, so a bare px floor wider than the container collapses
   the grid to one overflowing column on a phone. */
.v2x.glx .glxa-grid{
  display:grid;grid-template-columns:repeat(auto-fill,minmax(min(100%,300px),1fr));
  gap:clamp(12px,1.4vw,16px)}

.v2x.glx .glxa-card{
  position:relative;display:flex;flex-direction:column;
  border-radius:18px;overflow:hidden;
  background-color:var(--white,#fff);
  background-image:
    radial-gradient(230px 170px at 100% 0,rgba(var(--gx),.16) 0%,rgba(var(--gx),0) 70%),
    linear-gradient(155deg,rgba(var(--gx),.07) 0%,rgba(var(--gx),0) 46%);
  background-repeat:no-repeat;background-size:100% 100%,100% 100%;
  border:1px solid rgba(var(--gx),.22);
  box-shadow:0 1px 2px rgba(16,24,40,.05);
  transition:transform .26s cubic-bezier(.34,1.28,.64,1),box-shadow .26s ease,border-color .26s ease}
/* The top hairline — the "after" state made literal. Scales from the left on
   hover, which is the one motion that reads as "this card is now active". */
.v2x.glx .glxa-card::after{
  content:'';position:absolute;inset:0 0 auto;height:3px;
  background-image:linear-gradient(90deg,rgba(var(--gx),1),rgba(var(--gx),.35));
  transform:scaleX(0);transform-origin:left center;
  transition:transform .4s cubic-bezier(.4,0,.2,1)}
.v2x.glx .glxa-card:hover,
.v2x.glx .glxa-card:focus-within{
  transform:translateY(-5px);
  border-color:rgba(var(--gx),.5);
  box-shadow:0 22px 42px -26px rgba(var(--gx),.75),0 4px 10px rgba(16,24,40,.07)}
.v2x.glx .glxa-card:hover::after,
.v2x.glx .glxa-card:focus-within::after{transform:scaleX(1)}

/* Header link. `.v2x a{color:…}` is (0,2,0) and `.v2x a:hover{text-decoration:
   underline}` is (0,2,1); these are (0,3,0)/(0,3,1) and win. The reset has to
   sit on the ANCHOR — a descendant cannot take back a line its ancestor set. */
.v2x.glx .glxa-card-hd{
  display:flex;align-items:center;gap:11px;padding:15px 16px 13px;
  color:var(--v2-ink,#0F0F12);text-decoration:none}
.v2x.glx .glxa-card-hd:hover,
.v2x.glx .glxa-card-hd:focus,
.v2x.glx .glxa-card-hd:active{text-decoration:none;color:var(--v2-ink,#0F0F12)}
.v2x.glx .glxa-plate{
  flex:0 0 auto;width:38px;height:38px;border-radius:12px;
  display:inline-flex;align-items:center;justify-content:center;
  color:#fff;background-color:rgb(var(--gx));
  background-image:linear-gradient(155deg,rgba(255,255,255,.26) 0%,rgba(255,255,255,0) 60%);
  box-shadow:0 5px 13px -6px rgba(var(--gx),.9);
  transition:transform .3s cubic-bezier(.34,1.5,.64,1)}
.v2x.glx .glxa-plate svg{width:19px;height:19px;display:block}
.v2x.glx .glxa-card:hover .glxa-plate{transform:scale(1.07) rotate(-4deg)}
.v2x.glx .glxa-hd-tx{display:flex;flex-direction:column;gap:2px;min-width:0}
.v2x.glx .glxa-hd-nm{
  font-size:1rem;font-weight:800;letter-spacing:-.015em;line-height:1.3;
  color:var(--v2-ink,#0F0F12);overflow-wrap:break-word}
.v2x.glx .glxa-hd-ct{
  font-size:.78rem;font-weight:600;color:var(--v2-muted,#4A4A5A);letter-spacing:.01em}

/* Term rows. A tinted plane slides in from the left under the label — the
   "before/after" the flat list never had. */
.v2x.glx .glxa-terms{list-style:none;margin:0;padding:0 10px 4px;display:grid;gap:3px}
.v2x.glx .glxa-term{
  position:relative;display:flex;align-items:center;gap:9px;
  padding:9px 10px;border-radius:11px;
  color:var(--v2-ink,#0F0F12);text-decoration:none;
  font-size:.9rem;font-weight:600;line-height:1.4;
  transition:color .2s ease}
.v2x.glx .glxa-term::before{
  content:'';position:absolute;inset:0;border-radius:inherit;
  background-color:rgba(var(--gx),.11);
  transform:scaleX(0);transform-origin:left center;
  transition:transform .3s cubic-bezier(.4,0,.2,1)}
.v2x.glx .glxa-term:hover::before,
.v2x.glx .glxa-term:focus-visible::before{transform:scaleX(1)}
.v2x.glx .glxa-term:hover,
.v2x.glx .glxa-term:focus,
.v2x.glx .glxa-term:active{text-decoration:none;color:var(--v2-ink,#0F0F12)}
.v2x.glx .glxa-term:focus-visible{outline:3px solid rgba(var(--gx),.5);outline-offset:1px}
.v2x.glx .glxa-term-dot{
  position:relative;flex:0 0 auto;width:7px;height:7px;border-radius:50%;
  background-color:rgb(var(--gx));
  box-shadow:0 0 0 0 rgba(var(--gx),.35);
  transition:box-shadow .28s ease}
.v2x.glx .glxa-term:hover .glxa-term-dot{box-shadow:0 0 0 4px rgba(var(--gx),.22)}
/* NOT truncated. The term is the whole point of the row, and the copy above
   promises three names — a clipped one answers nothing. */
.v2x.glx .glxa-term-nm{position:relative;flex:1 1 auto;min-width:0;overflow-wrap:break-word}
.v2x.glx .glxa-term-arr{
  position:relative;flex:0 0 auto;width:17px;height:17px;
  display:inline-flex;align-items:center;justify-content:center;
  color:rgb(var(--gx));opacity:0;transform:translateX(-5px);
  transition:opacity .24s ease,transform .28s cubic-bezier(.34,1.4,.64,1)}
.v2x.glx .glxa-term-arr svg{width:15px;height:15px;display:block}
.v2x.glx .glxa-term:hover .glxa-term-arr,
.v2x.glx .glxa-term:focus-visible .glxa-term-arr{opacity:1;transform:translateX(0)}

/* Footer. `margin-top:auto` pins it to the bottom so cards holding a
   different number of rows still line their footers up — and NO sibling above
   may carry a margin-top, or it wins the slack and the footers stagger. */
.v2x.glx .glxa-all{
  margin-top:auto;display:flex;align-items:center;justify-content:space-between;
  gap:8px;padding:11px 16px 13px;
  border-top:1px solid rgba(var(--gx),.16);
  font-size:.8rem;font-weight:700;letter-spacing:.01em;
  color:var(--v2-muted,#4A4A5A);text-decoration:none;
  transition:color .2s ease,background-color .24s ease}
.v2x.glx .glxa-all svg{width:15px;height:15px;flex:0 0 auto;
  transition:transform .28s cubic-bezier(.34,1.4,.64,1)}
.v2x.glx .glxa-all:hover,
.v2x.glx .glxa-all:focus,
.v2x.glx .glxa-all:active{text-decoration:none}
.v2x.glx .glxa-all:hover,
.v2x.glx .glxa-all:focus-visible{
  color:var(--v2-ink,#0F0F12);background-color:rgba(var(--gx),.09)}
.v2x.glx .glxa-all:hover svg{transform:translateX(4px)}
.v2x.glx .glxa-all:focus-visible{outline:3px solid rgba(var(--gx),.5);outline-offset:-3px}
.v2x.glx .glxa-card-hd:focus-visible{outline:3px solid rgba(var(--gx),.5);outline-offset:-3px;border-radius:12px}

/* ══ §GXT — topic chips ═════════════════════════════════════════════════════
   A wrapping flex row, not a grid: tag labels run from "Acronym" to
   "Beginner Friendly", and fixed tracks gave the short ones a half-empty box
   with the count marooned at the bottom. A chip that hugs its label reads as
   the filter it actually is. */
.v2x.glx .glxt-wrap{display:flex;flex-wrap:wrap;gap:10px}
.v2x.glx .glxt-chip{
  position:relative;display:inline-flex;align-items:center;gap:9px;
  padding:10px 13px;border-radius:14px;isolation:isolate;
  background-color:var(--white,#fff);
  border:1px solid rgba(var(--gx),.28);
  color:var(--v2-ink,#0F0F12);text-decoration:none;
  box-shadow:0 1px 2px rgba(16,24,40,.05);
  transition:transform .24s cubic-bezier(.34,1.3,.64,1),box-shadow .24s ease,border-color .24s ease}
/* The wash — the "before" that becomes the "after". Behind the label, never
   over it, so nothing the chip says is ever dimmed by its own hover state. */
.v2x.glx .glxt-chip::before{
  content:'';position:absolute;inset:0;border-radius:inherit;z-index:-1;
  background-image:linear-gradient(120deg,rgba(var(--gx),.20) 0%,rgba(var(--gx),.08) 100%);
  opacity:0;transition:opacity .26s ease}
.v2x.glx .glxt-chip:hover,
.v2x.glx .glxt-chip:focus-visible{
  transform:translateY(-3px);
  border-color:rgba(var(--gx),.6);
  box-shadow:0 16px 30px -20px rgba(var(--gx),.8),0 3px 7px rgba(16,24,40,.06)}
.v2x.glx .glxt-chip:hover::before,
.v2x.glx .glxt-chip:focus-visible::before{opacity:1}
.v2x.glx .glxt-chip:hover,
.v2x.glx .glxt-chip:focus,
.v2x.glx .glxt-chip:active{text-decoration:none;color:var(--v2-ink,#0F0F12)}
.v2x.glx .glxt-chip:focus-visible{outline:3px solid rgba(var(--gx),.45);outline-offset:3px}
.v2x.glx .glxt-hash{
  flex:0 0 auto;width:24px;height:24px;border-radius:8px;
  display:inline-flex;align-items:center;justify-content:center;
  font-size:.85rem;font-weight:800;line-height:1;color:#fff;
  background-color:rgb(var(--gx));
  background-image:linear-gradient(150deg,rgba(255,255,255,.3) 0%,rgba(255,255,255,0) 62%);
  transition:transform .28s cubic-bezier(.34,1.5,.64,1)}
.v2x.glx .glxt-chip:hover .glxt-hash{transform:rotate(-8deg) scale(1.08)}
.v2x.glx .glxt-nm{
  font-size:.9rem;font-weight:700;letter-spacing:-.005em;line-height:1.35;
  overflow-wrap:break-word}
/* Tabular figures so a column of counts lines up, and the badge inverts to a
   solid plate on hover rather than merely darkening. */
.v2x.glx .glxt-ct{
  flex:0 0 auto;min-width:26px;text-align:center;
  padding:3px 8px;border-radius:8px;
  font-size:.76rem;font-weight:800;line-height:1.35;
  font-variant-numeric:tabular-nums;
  color:var(--v2-ink,#0F0F12);
  background-color:rgba(var(--gx),.15);
  transition:background-color .24s ease,color .24s ease}
.v2x.glx .glxt-chip:hover .glxt-ct,
.v2x.glx .glxt-chip:focus-visible .glxt-ct{
  background-color:rgb(var(--gx));color:#fff}

/* ══ §GXP — areas in progress ══════════════════════════════════════════════
   The quietest band on the page on purpose: dashed, unlifted, no hover
   affordance and no counts, because there is nothing behind these yet and a
   "0 terms" card reads as a broken catalogue rather than an unfinished one. */
.v2x.glx .glxp-box{display:flex;flex-wrap:wrap;align-items:flex-start;gap:13px}
.v2x.glx .glxp-ic{
  flex:0 0 auto;width:34px;height:34px;border-radius:11px;
  display:inline-flex;align-items:center;justify-content:center;
  color:var(--v2-muted,#4A4A5A);
  background-color:rgba(120,132,158,.12);
  border:1px dashed rgba(120,132,158,.4)}
.v2x.glx .glxp-ic svg{width:18px;height:18px;display:block}
.v2x.glx .glxp-tx{flex:1 1 240px;min-width:0}
.v2x.glx .glxp-tx h2{
  font-size:1.02rem;font-weight:800;letter-spacing:-.015em;
  color:var(--v2-ink,#0F0F12);margin:0 0 3px;line-height:1.3}
.v2x.glx .glxp-tx p{
  font-size:.875rem;line-height:1.6;color:var(--v2-muted,#4A4A5A);margin:0}
.v2x.glx .glxp-list{
  list-style:none;margin:0;padding:0;flex:1 1 100%;
  display:flex;flex-wrap:wrap;gap:8px}
.v2x.glx .glxp-chip{
  display:inline-flex;align-items:center;gap:7px;
  padding:7px 12px;border-radius:11px;
  font-size:.84rem;font-weight:600;line-height:1.4;
  color:var(--v2-muted,#4A4A5A);
  background-color:rgba(var(--gx),.06);
  border:1px dashed rgba(var(--gx),.34);
  overflow-wrap:break-word}
.v2x.glx .glxp-dot{
  flex:0 0 auto;width:6px;height:6px;border-radius:50%;
  background-color:rgb(var(--gx));opacity:.75}

/* ══ Dark ══════════════════════════════════════════════════════════════════
   Surfaces and ink ride --white / --v2-ink / --v2-muted, which
   `body.theme-dark .v2x` already retokenises, so only three things need
   saying: a heavier tint (a 7% wash that reads over white is invisible over
   #171922), black-based shadows, and the PLATE — its stored light twin would
   carry a white glyph at roughly 1.6:1, so dark flips it to a tinted plate
   with the accent as the glyph instead. Same swap for the hovered count
   badge, where white on #8DBEFF would be unreadable. */
body.theme-dark .v2x.glx .glxa-card{
  background-image:
    radial-gradient(230px 170px at 100% 0,rgba(var(--gx),.20) 0%,rgba(var(--gx),0) 70%),
    linear-gradient(155deg,rgba(var(--gx),.10) 0%,rgba(var(--gx),0) 46%);
  border-color:rgba(var(--gx),.26);
  box-shadow:0 1px 2px rgba(0,0,0,.45)}
body.theme-dark .v2x.glx .glxa-card:hover,
body.theme-dark .v2x.glx .glxa-card:focus-within{
  box-shadow:0 24px 44px -28px rgba(0,0,0,.9),0 4px 10px rgba(0,0,0,.5)}
body.theme-dark .v2x.glx .glxa-plate,
body.theme-dark .v2x.glx .glxt-hash{
  color:rgb(var(--gx));
  background-color:rgba(var(--gx),.16);
  background-image:none;
  box-shadow:inset 0 0 0 1px rgba(var(--gx),.3)}
body.theme-dark .v2x.glx .glxa-term:hover::before,
body.theme-dark .v2x.glx .glxa-term:focus-visible::before{background-color:rgba(var(--gx),.16)}
body.theme-dark .v2x.glx .glxt-chip{box-shadow:0 1px 2px rgba(0,0,0,.45)}
body.theme-dark .v2x.glx .glxt-chip:hover,
body.theme-dark .v2x.glx .glxt-chip:focus-visible{
  box-shadow:0 18px 32px -22px rgba(0,0,0,.9),0 3px 7px rgba(0,0,0,.45)}
body.theme-dark .v2x.glx .glxt-chip:hover .glxt-ct,
body.theme-dark .v2x.glx .glxt-chip:focus-visible .glxt-ct{
  background-color:rgb(var(--gx));color:var(--dk-bg,#0E0E11)}
body.theme-dark .v2x.glx .glxp-ic{
  color:var(--dk-text-3,#9AA0AB);background-color:rgba(255,255,255,.05);
  border-color:var(--dk-line-strong,rgba(255,255,255,.16))}
body.theme-dark .v2x.glx .glxp-chip{
  color:var(--dk-text-2,#C7CAD1);background-color:rgba(var(--gx),.09);
  border-color:rgba(var(--gx),.32)}

/* ══ Tablet / phone ════════════════════════════════════════════════════════ */
@media (max-width:1024px){
  .v2x.glx .glxa-grid{grid-template-columns:repeat(auto-fill,minmax(min(100%,262px),1fr))}
}
@media (max-width:640px){
  .v2x.glx .glxa-box,
  .v2x.glx .glxt-box,
  .v2x.glx .glxp-box{border-radius:18px;padding:16px 14px}
  .v2x.glx .glxa-grid{grid-template-columns:1fr;gap:11px}
  .v2x.glx .glxa-head{gap:11px;margin-bottom:15px}
  .v2x.glx .glxa-head-ic{width:34px;height:34px;border-radius:11px}
  .v2x.glx .glxa-head-ic svg{width:17px;height:17px}
  .v2x.glx .glxa-head p{font-size:.875rem}
  .v2x.glx .glxa-card-hd{padding:13px 13px 11px}
  .v2x.glx .glxa-terms{padding:0 8px 3px}
  .v2x.glx .glxa-all{padding:10px 13px 12px}
  /* The arrow is a hover reward, and a phone has no hover. Parked visible at
     low opacity so the row still reads as a link. */
  .v2x.glx .glxa-term-arr{opacity:.5;transform:none}
  .v2x.glx .glxt-wrap{gap:8px}
  .v2x.glx .glxt-chip{padding:9px 11px;gap:8px}
  .v2x.glx .glxt-nm{font-size:.865rem}
}

/* Coarse pointers get no lift — a transform that only fires on tap reads as a
   glitch, and :hover sticks on touch until the next tap elsewhere. */
@media (hover:none){
  .v2x.glx .glxa-card:hover,
  .v2x.glx .glxt-chip:hover{transform:none}
  .v2x.glx .glxa-term-arr{opacity:.5;transform:none}
}

@media (prefers-reduced-motion:reduce){
  .v2x.glx .glxa-card,
  .v2x.glx .glxa-card::after,
  .v2x.glx .glxa-plate,
  .v2x.glx .glxa-term,
  .v2x.glx .glxa-term::before,
  .v2x.glx .glxa-term-dot,
  .v2x.glx .glxa-term-arr,
  .v2x.glx .glxa-all,
  .v2x.glx .glxa-all svg,
  .v2x.glx .glxt-chip,
  .v2x.glx .glxt-chip::before,
  .v2x.glx .glxt-hash,
  .v2x.glx .glxt-ct{transition:none}
  .v2x.glx .glxa-card:hover,
  .v2x.glx .glxt-chip:hover{transform:none}
  .v2x.glx .glxa-card::after{transition:none}
}
