/* ══════════════════════════════════════════════════════════════════════════
   AI DEALS — DELTA over the AI Directory design system
   --------------------------------------------------------------------------
   /deals and /deals/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 FIVE PAGES — /ai-directory,
     /browser-extensions, /gpts, /workflows and /deals. Check all five.

   Both deal routes render ONE blade, so this file dresses both. The DETAIL
   page (/deals/{slug}) is NOT in this stack — it wears `.dd-` classes from
   v2-public-deal-show.css and shares nothing here.

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

     §PLATE  the accent plate — a deal has no logo, but does have a colour
     §PRICE  the price / was-price / discount block
     §SAVE   the savings line
     §CPN    the coupon chip and its copy button
     §FEAT   the featured-deal wash
     §FIG    the list row's company / code / validity figures
     §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
     §HERE   the "you are here" marker on the category rail
     §CTA    the submit band (admin-gated, module-specific)
     §RESP   the handful of responsive fixes the above need

   Loaded LAST of the three sheets, so it wins where it must. Everything it
   does not define is inherited — deliberately. If a rule here duplicates the
   directory's, delete it here: the point of a delta is that it stays small
   enough to read in one sitting.

   ⚠ 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.
   Verified ranges, read off the DEPLOYED directory sheet:
     .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. The shared sheet has zero uses of it (grep it),
   and Safari below 15.4 drops the entire selector rather than the one rule.

   Dark mode: the directory sheet keys dark off `body.theme-dark`. Every rule
   here that sets a colour declares its dark twin the same way, in the same
   block, so a light-only addition cannot slip through review. The two
   deliberate exceptions are marked where they occur (§CTA).

   The breakpoints below are the SHARED SHEET's ladder — 1180 · 900 · 820 ·
   680 · 640 · 520 · 480 · 420 — not Bootstrap's. /workflows shipped on
   991.98/767.98/479.98 first and every one of its responsive steps fired
   between the page's real ones.
   ══════════════════════════════════════════════════════════════════════════ */


/* ═══ §PLATE — the accent plate ════════════════════════════════════════════
   The directory's card plate carries a product logo. Every row in `deals`
   has `logo`, `featured_image` AND `company_logo` NULL — there is no logo to
   carry — but every one carries `accent`. So the plate is tinted with the
   deal's own colour and holds the company's monogram.

   ⚠ THE ACCENT IS THE PLATE, NEVER THE INK, AND THIS MUST NOT BE
   "SIMPLIFIED" BACK. `--dlx-accent` is whatever hex an admin typed. The
   seeded set alone runs #10A37F, #0F0F12, #D97757, #1B1F3B, #15A472 and
   #ffffff — a range from near-black to pure white. As INK on a light plate
   the greens measure under the 3:1 non-text floor; as INK on a dark plate
   the near-blacks vanish entirely. Saturation is not luminance, which is
   exactly why an arbitrary admin hex can never be trusted as ink.

   The fix needs no per-hue table: a white scrim is painted OVER the accent
   in light and a dark scrim in dark, so whatever the hue the plate lands on
   the right side of the ground, and the monogram is drawn in the sheet's own
   guaranteed ink.

   ⚠ THE HAIRLINE RING IS LOAD-BEARING, NOT DECORATION. The directory's plate
   ring is `rgba(255,255,255,.5)` — white on white. One seeded accent IS
   `#ffffff`, which under a white scrim gives a pure-white plate: without a
   neutral ring that card would render a monogram floating on the card with
   no plate behind it at all. The ring is drawn in `--v2-line` so the plate
   survives any accent, including the two extremes.

   ⚠ THE THIRD LAYER — a constant `rgba(15,23,42,.10)` tint ON TOP of the
   scrim — is what makes a NEAR-WHITE accent still read as a plate. One
   seeded accent is literally `#ffffff`: white scrim over white is white,
   so before this layer that card measured 1.00:1 against its own white
   background and the monogram floated with no plate behind it at all.
   The tint is constant rather than conditional because CSS cannot branch
   on the lightness of a custom property without color-mix()/relative
   colours, and it costs the saturated accents nothing visible.

   Measured across all six accents actually in the table:
     monogram ink   12.14:1 worst light · 7.39:1 worst dark
     plate vs card  1.23–1.58:1 light · 1.07–1.93:1 dark
   against a house hairline (--v2-line on a card) of 1.21 light / 1.22
   dark — so the plate reads at least as strongly as every other divider
   on the page. The two EXTREME accents (#ffffff in light, #0F0F12 in
   dark) are the cases where the fill alone cannot separate; there the
   inset ring carries it — 1.21:1 light and 1.60:1 dark against the card,
   both at or above the house hairline. That is why the ring is not
   optional and why it is NOT the directory's rgba(255,255,255,.5),
   which would be white-on-white on exactly the card that needs it.

   ⚠ THE SECOND WASH IS NOT DECORATION AND THESE ALPHAS ARE MEASURED, NOT
   PICKED. A scrim ALONE fails at both extremes of the accent range. One
   seeded accent is `#ffffff`, and a white scrim over white is white: the
   plate measured 1.000:1 against the card — it did not exist, leaving a
   monogram floating on the card face. The dark side has the mirror problem
   with the near-black accents (#0F0F12, #1B1F3B, and #000000 is one keystroke
   away): 1.019:1. So a wash in the OPPOSITE direction rides ON TOP of the
   scrim, giving the plate a ceiling it cannot rise above in light and a floor
   it cannot fall below in dark, whatever hex an admin types.

   The acceptance test is not an abstract number — it is /ai-directory's OWN
   plate-vs-card separation, because matching that is what "wears the same
   design" means. Measured over all 22 hues in the catalogue plus pure #fff
   and #000, worst case:
       light  separation 1.282:1  (directory 1.098:1)   monogram 10.20:1
       dark   separation 1.229:1  (directory 1.218:1)   monogram  5.93:1
   Dropping either wash "to simplify" puts the dark side back under the
   directory's own figure and the white accent back to invisible. Do not.

   `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. */
.v2x.dlx .dlx-plate{
  background:
    linear-gradient(rgba(15,23,42,.12),rgba(15,23,42,.12)),
    linear-gradient(rgba(255,255,255,.86),rgba(255,255,255,.86)),
    var(--dlx-accent,#3680ED);
  box-shadow:inset 0 0 0 1px var(--v2-line);
  overflow:hidden}
/* Ink only — the SIZE of all three monograms comes from the shared sheet
   (.dir-tc-mono 26px, .dir-lc-mono 20px with its own 640px step,
   .dir-tr-mono 13px), so the delta never has to track a ramp it did not
   write. Only the colour has to move, because the sheet paints them in the
   card's cycled tone and this plate is not that ground. */
.v2x.dlx .dlx-plate .dir-tc-mono,
.v2x.dlx .dlx-plate .dir-lc-mono,
.v2x.dlx .dlx-plate .dir-tr-mono{color:var(--v2-ink)}
body.theme-dark .v2x.dlx .dlx-plate{
  background:
    linear-gradient(rgba(234,240,250,.14),rgba(234,240,250,.14)),
    linear-gradient(rgba(16,20,28,.80),rgba(16,20,28,.80)),
    var(--dlx-accent,#3680ED);
  box-shadow:inset 0 0 0 1px rgba(255,255,255,.10)}
body.theme-dark .v2x.dlx .dlx-plate .dir-tc-mono,
body.theme-dark .v2x.dlx .dlx-plate .dir-lc-mono,
body.theme-dark .v2x.dlx .dlx-plate .dir-tr-mono{color:#EAF0FA}

/* The directory's hover rule repaints the plate ring in the card's cycled
   tone. Keeping that is the point — the plate is the one element that reacts
   to the card's own colour — so only the ring is restated, not the fill. */
@media (hover:hover){
  .v2x.dlx .dir-tc:hover .dir-tc-logo.dlx-plate,
  .v2x.dlx .dir-lc:hover .dir-lc-logo.dlx-plate{box-shadow:inset 0 0 0 1px var(--dtc-ink)}
}

/* The trending rail's plate paints a flat brand tint rather than --dtc-bg, so
   the scrim has to be restated for it specifically. The plate BOXES (66px
   card, 52px list row, 34px rail, 78px hero tile) are all the sheet's. */
.v2x.dlx .dir-tr-lg.dlx-plate{background:
    linear-gradient(rgba(15,23,42,.12),rgba(15,23,42,.12)),
    linear-gradient(rgba(255,255,255,.86),rgba(255,255,255,.86)),
    var(--dlx-accent,#3680ED)}
body.theme-dark .v2x.dlx .dir-tr-lg.dlx-plate{
  background:
    linear-gradient(rgba(234,240,250,.14),rgba(234,240,250,.14)),
    linear-gradient(rgba(16,20,28,.80),rgba(16,20,28,.80)),
    var(--dlx-accent,#3680ED)}

/* Hero orbit tiles. Same scrim recipe at 78px, one shade lighter so the tile
   reads as glass rather than as a solid chip against the hero wash. */
.v2x.dlx .dir-hh-tile.dlx-tile{
  background:
    linear-gradient(rgba(15,23,42,.12),rgba(15,23,42,.12)),
    linear-gradient(rgba(255,255,255,.86),rgba(255,255,255,.86)),
    var(--dlx-accent,#3680ED);
  color:var(--v2-ink)}
.v2x.dlx .dlx-tile-mono{font-size:30px;font-weight:840;line-height:1;letter-spacing:-.03em}
body.theme-dark .v2x.dlx .dir-hh-tile.dlx-tile{
  background:
    linear-gradient(rgba(234,240,250,.14),rgba(234,240,250,.14)),
    linear-gradient(rgba(16,20,28,.80),rgba(16,20,28,.80)),
    var(--dlx-accent,#3680ED);
  color:#EAF0FA}

/* The category rail card's icon. `.dir-cat-card-ico` is already tone-cycled
   by the directory sheet, so this only sizes the Lucide SVG it renders. No
   colour is set here on purpose — inheriting keeps the rail identical to
   /ai-directory's. */
.v2x.dlx .dir-cat-card-ico svg{width:26px;height:26px}


/* ═══ §MAIN — the results column ══════════════════════════════════════════
   `.dir-main` (the directory's own hook) carries no rule in the shared
   sheet — verified: /ai-directory emits it unstyled too. It is the middle
   track of `minmax(0,1fr)`, and a grid item's default `min-width:auto` is
   what lets one long unbreakable string (a coupon code, a company name)
   push the track past its share and squeeze the rails. `.dlx-main` is also
   the scroll target the rail's Apply button jumps back to. */
.v2x.dlx .dlx-main{min-width:0}


/* ═══ §PRICE — the headline of any deal card ═══════════════════════════════
   Three parts, each dropped independently by the blade when the column is
   empty: the price now, the price before (struck), and the percentage off.
   A deal with no `original_price` renders a price alone rather than "$0 was"
   followed by nothing.

   The discount badge is EMERALD rather than the card's cycled tone: it is
   the one figure on the card that means the same thing on every card, and
   letting it cycle would make an identical 20% read as five different
   signals across one grid. Inks measured on their own fills:
     light  #065F46 on #DCFCE7 = 9.05:1
     dark   #6EE7B7 on #052E23 = 9.71:1                                    */
.v2x.dlx .dlx-price{
  display:flex;align-items:baseline;justify-content:center;flex-wrap:wrap;gap:7px;
  margin-top:12px;min-height:26px}
.v2x.dlx .dlx-now{
  font-size:19px;font-weight:820;letter-spacing:-.028em;line-height:1.1;color:var(--v2-ink);
  font-variant-numeric:tabular-nums}
.v2x.dlx .dlx-now i{
  font-style:normal;font-size:12px;font-weight:640;letter-spacing:0;color:var(--v2-muted)}
.v2x.dlx .dlx-was{
  font-size:13px;font-weight:600;color:var(--v2-muted);text-decoration-thickness:1.5px;
  text-decoration-color:rgba(148,163,184,.9);font-variant-numeric:tabular-nums}
.v2x.dlx .dlx-off{
  display:inline-flex;align-items:center;padding:2px 8px;border-radius:999px;
  background:#DCFCE7;color:#065F46;
  font-size:11.5px;font-weight:820;letter-spacing:.01em;line-height:1.5;
  font-variant-numeric:tabular-nums}
body.theme-dark .v2x.dlx .dlx-now{color:#EDF2FA}
body.theme-dark .v2x.dlx .dlx-was{text-decoration-color:rgba(148,163,184,.7)}
body.theme-dark .v2x.dlx .dlx-off{background:#052E23;color:#6EE7B7}

/* List mode stacks the same three parts into the row's right-hand slot. */
.v2x.dlx .dlx-price.is-row{
  justify-content:flex-end;margin-top:0;margin-bottom:8px;gap:6px;min-height:0}
.v2x.dlx .dlx-price.is-row .dlx-now{font-size:17px}


/* ═══ §SAVE — the savings line ═════════════════════════════════════════════
   Text, not a pill: the card already carries a pill row and a badge, and a
   third filled shape at this size turns the card into confetti.
   Inks: light #047857 on #fff = 4.76:1 · dark #34D399 on the card's
   rgba(28,31,42,.9) ground = 8.88:1.                                       */
.v2x.dlx .dlx-save{
  display:inline-flex;align-items:center;gap:5px;margin-top:6px;
  font-size:11.8px;font-weight:700;line-height:1.4;color:#047857}
.v2x.dlx .dlx-save svg{width:13px;height:13px;flex:0 0 auto}
body.theme-dark .v2x.dlx .dlx-save{color:#34D399}


/* ═══ §CPN — the coupon chip ═══════════════════════════════════════════════
   The code is printed, not hidden behind a reveal-wall, so the chip is a
   ticket rather than a button: the dashed edge says "tear here" and the only
   interactive part is the copy control.

   The copy button sits AFTER `.dir-tc-lnk` in DOM order and both are at
   z-index 1, so it takes the click without swallowing the card's own
   navigation. That ordering is the directory's own contract for `.dir-tc-btn`
   — see the `> *:not(:where(...))` rule in the shared sheet. */
.v2x.dlx .dlx-cpn{
  display:inline-flex;align-items:center;gap:8px;margin-top:10px;
  padding:4px 4px 4px 10px;border-radius:10px;
  border:1px dashed rgba(54,128,237,.42);
  background:var(--v2-accent-soft);
  max-width:100%}
.v2x.dlx .dlx-cpn-lbl{
  font-size:9.5px;font-weight:820;letter-spacing:.09em;text-transform:uppercase;
  color:var(--v2-muted);flex:0 0 auto}
.v2x.dlx .dlx-cpn-code{
  font-family:ui-monospace,SFMono-Regular,"SF Mono",Menlo,Consolas,monospace;
  font-size:12.4px;font-weight:800;letter-spacing:.045em;color:var(--v2-ink);
  min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.v2x.dlx .dlx-cpn-btn{
  flex:0 0 auto;display:inline-grid;place-items:center;width:24px;height:24px;
  padding:0;border:0;border-radius:7px;cursor:pointer;
  background:rgba(54,128,237,.16);color:var(--brand-blue-dark);
  transition:background .18s ease,color .18s ease,transform .18s ease}
.v2x.dlx .dlx-cpn-btn svg{width:13px;height:13px}
.v2x.dlx .dlx-cpn-btn:hover{background:rgba(54,128,237,.3);transform:scale(1.08)}
/* The tick is a CSS state, not swapped markup, so a Livewire re-render
   resets it instead of leaving a permanently ticked button. */
.v2x.dlx .dlx-cpn-ok{display:none}
.v2x.dlx .dlx-cpn-btn.is-copied{background:#DCFCE7;color:#065F46}
.v2x.dlx .dlx-cpn-btn.is-copied .dlx-cpn-ic{display:none}
.v2x.dlx .dlx-cpn-btn.is-copied .dlx-cpn-ok{display:block}
body.theme-dark .v2x.dlx .dlx-cpn{
  border-color:rgba(96,164,245,.4);background:rgba(54,128,237,.14)}
body.theme-dark .v2x.dlx .dlx-cpn-code{color:#EDF2FA}
body.theme-dark .v2x.dlx .dlx-cpn-btn{background:rgba(96,164,245,.2);color:#9CC8F9}
body.theme-dark .v2x.dlx .dlx-cpn-btn:hover{background:rgba(96,164,245,.34)}
body.theme-dark .v2x.dlx .dlx-cpn-btn.is-copied{background:#052E23;color:#6EE7B7}


/* ═══ §VALID — the validity line ═══════════════════════════════════════════
   `deals.expires_at` is NULL on every row, so there is no countdown to draw
   and none is faked. What the data DOES hold is `validity_label` — free text
   an editor wrote ("Until Jun 30, 2026") — so it is printed as text with a
   clock, at muted weight, because a claim we cannot verify should not look
   like a live timer. */
.v2x.dlx .dlx-valid{
  display:inline-flex;align-items:center;gap:5px;margin-top:9px;
  font-size:11.4px;font-weight:640;line-height:1.4;color:var(--v2-muted)}
.v2x.dlx .dlx-valid svg{width:12px;height:12px;flex:0 0 auto;opacity:.8}


/* ═══ §FEAT — the featured wash ════════════════════════════════════════════
   `is_featured_deal` is true on 3 of 6 rows, so it has to read as a
   distinction rather than as the default. A tinted top wash plus an amber
   border does that without taking a corner: the card's top-left is the rank
   badge and its top-right is the bookmark, and a third floating element
   there collides below ~300px.

   `background-image` rather than `background`: the shared sheet's
   `.dir-tc{background:#fff}` shorthand sets the COLOUR, and painting only
   the image layer here leaves that colour — and its dark twin — intact.

   The hover state is restated because the directory's
   `.dir-tc:hover{border-color:var(--v2-line)}` would otherwise drop the
   amber edge exactly when the visitor is looking at the card. */
.v2x.dlx .dir-tc.is-featured,
.v2x.dlx .dir-lc.is-featured{
  border-color:rgba(217,119,6,.44);
  background-image:linear-gradient(180deg,rgba(245,158,11,.10),rgba(245,158,11,0) 130px)}
body.theme-dark .v2x.dlx .dir-tc.is-featured,
body.theme-dark .v2x.dlx .dir-lc.is-featured{
  border-color:rgba(251,191,36,.34);
  background-image:linear-gradient(180deg,rgba(251,191,36,.10),rgba(251,191,36,0) 130px)}
@media (hover:hover){
  .v2x.dlx .dir-tc.is-featured:hover,
  .v2x.dlx .dir-lc.is-featured:hover{border-color:rgba(217,119,6,.6)}
  body.theme-dark .v2x.dlx .dir-tc.is-featured:hover,
  body.theme-dark .v2x.dlx .dir-lc.is-featured:hover{border-color:rgba(251,191,36,.5)}
}


/* ═══ §FIG — list-row figures ══════════════════════════════════════════════
   The row has horizontal space the card does not, so company, coupon and
   validity ride in the meta line as label/value pairs. Same visual weight as
   `.dir-tc-pill` without the fill, so the pill stays the row's one accent. */
.v2x.dlx .dlx-fig{
  display:inline-flex;align-items:center;gap:5px;
  font-size:11.8px;font-weight:640;line-height:1.4;color:var(--v2-muted)}
.v2x.dlx .dlx-fig svg{width:13px;height:13px;flex:0 0 auto;opacity:.85}
.v2x.dlx .dlx-fig b{font-weight:760;color:var(--v2-ink)}
.v2x.dlx .dlx-fig-cpn b{
  font-family:ui-monospace,SFMono-Regular,"SF Mono",Menlo,Consolas,monospace;
  font-size:11.4px;letter-spacing:.04em}
body.theme-dark .v2x.dlx .dlx-fig b{color:#EDF2FA}

/* The row's right column stacks price over actions; the directory's version
   holds a single button, so the column needs an explicit end-alignment. */
.v2x.dlx .dir-lc-side{flex-direction:column;align-items:flex-end;gap:0}
.v2x.dlx .dlx-lc-act{display:flex;align-items:center;gap:8px}


/* ═══ §CHIP — active-filter chips ══════════════════════════════════════════
   One-tap removal without opening the rail. Deliberately identical in shape
   to /workflows' chip row so the two catalogues read as one product. */
.v2x.dlx .dlx-chips{
  display:flex;flex-wrap:wrap;align-items:center;gap:8px;margin:0 0 16px}
.v2x.dlx .dlx-chip{
  display:inline-flex;align-items:center;gap:6px;
  padding:5px 6px 5px 12px;border-radius:999px;
  background:var(--v2-accent-soft);color:var(--brand-blue-dark);
  border:1px solid rgba(54,128,237,.22);
  font-size:12.4px;font-weight:650;line-height:1.35;
  max-width:100%}
.v2x.dlx .dlx-chip button{
  display:inline-grid;place-items:center;width:18px;height:18px;flex:0 0 auto;
  border:0;border-radius:50%;background:rgba(54,128,237,.16);color:inherit;
  cursor:pointer;padding:0;opacity:.82;transition:opacity .16s ease,background .16s ease}
.v2x.dlx .dlx-chip button svg{width:10px;height:10px}
.v2x.dlx .dlx-chip button:hover{opacity:1;background:rgba(54,128,237,.3)}
.v2x.dlx .dlx-chip-clear{
  border:0;background:none;padding:5px 4px;cursor:pointer;
  font-size:12.4px;font-weight:700;color:var(--v2-muted);text-decoration:underline;
  text-underline-offset:3px;transition:color .16s ease}
.v2x.dlx .dlx-chip-clear:hover{color:var(--brand-blue)}
body.theme-dark .v2x.dlx .dlx-chip{
  background:rgba(54,128,237,.16);border-color:rgba(96,164,245,.3);color:#9CC8F9}
body.theme-dark .v2x.dlx .dlx-chip button{background:rgba(96,164,245,.2)}
body.theme-dark .v2x.dlx .dlx-chip button:hover{background:rgba(96,164,245,.36)}

/* The hero's popular row is a set of BUTTONS here, not links — they set the
   company facet rather than navigating away. `.dir-hh-chip` is styled for an
   <a>, so the button reset and the on-state are ours. */
.v2x.dlx button.dir-hh-chip{border:1px solid var(--v2-line);cursor:pointer;font-family:inherit}
.v2x.dlx button.dir-hh-chip.is-on{
  background:var(--v2-accent-soft);border-color:rgba(54,128,237,.4);color:var(--brand-blue-dark)}
body.theme-dark .v2x.dlx button.dir-hh-chip{border-color:rgba(255,255,255,.1)}
body.theme-dark .v2x.dlx button.dir-hh-chip.is-on{
  background:rgba(54,128,237,.2);border-color:rgba(96,164,245,.36);color:#9CC8F9}


/* ═══ §BUSY — dim while filtering ══════════════════════════════════════════
   `wire:loading.class="is-busy"` lands a class that NO sheet in the stack
   defines — the same dead-class trap /browser-extensions, /gpts and
   /workflows all hit in turn. 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.dlx .dlx-results{transition:opacity .18s ease,filter .18s ease}
.v2x.dlx .dlx-results.is-busy{opacity:.45;filter:saturate(.6);pointer-events:none}


/* ═══ §HERE — "you are here" on the category rail ══════════════════════════
   The rail renders on the hub pages too, so on /deals/category/ai-coding the
   AI Coding card is in that rail. Without a marker it reads as a link to
   somewhere else. Uses the card's own tone through currentColor, so it is one
   rule rather than eight. */
.v2x.dlx .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.dlx .dir-cat-card.is-here{
  box-shadow:inset 0 0 0 2px currentColor,0 10px 30px -14px rgba(0,0,0,.7)}
.v2x.dlx .dir-cat-card.is-here .dir-cat-card-cnt{font-weight:800}


/* ═══ §CTA — submit band ═══════════════════════════════════════════════════
   Module-specific and admin-gated (`cta.show`). Built on the same
   dot-field-over-brand-gradient language as the directory's
   `.dir-why-card.is-lead`, so it reads as part of the same page.

   ⚠ THE GRADIENT IS THE ONE MEASURED ON /workflows AND MUST NOT BE
   BRIGHTENED BACK TOWARD THE BRAND RAMP. The obvious ramp
   (--brand-blue-dark → --brand-blue → #5B9BF5) FAILS: white measures 3.84:1
   on the --brand-blue mid stop and 2.82:1 on #5B9BF5 against a 4.5 floor, so
   the band is legible at one end and not at the other — exactly the miss an
   average hides. This ramp was solved by darkening each stop along its own
   hue until rgba(255,255,255,.92) — the BODY copy, a hair worse than the
   pure-white heading — cleared 4.6:1, then sampling at 0/10/25/40/58/70/85/
   100% because the interpolated middle is what a visitor actually reads:
       worst across the whole band → white 5.49:1 · body 4.92:1
   It ends violet rather than light blue because darkening the light stop in
   place turned it slate (#416FAF) and cost the band its life. */
.v2x.dlx .dlx-cta{
  position:relative;overflow:hidden;isolation:isolate;
  margin:44px 0 8px;padding:30px 32px;border-radius:22px;
  display:flex;align-items:center;justify-content:space-between;gap:20px;flex-wrap:wrap;
  background:linear-gradient(135deg,#1B4FB3 0%,#2F63D1 58%,#6127C4 100%);
  color:#fff;
  box-shadow:0 22px 48px -24px rgba(49,32,150,.6)}
.v2x.dlx .dlx-cta-dots{
  position:absolute;inset-block:0;inset-inline-end:0;width:min(340px,46%);z-index:-1;
  background-image:radial-gradient(rgba(255,255,255,.32) 1.5px,transparent 1.5px);
  background-size:17px 17px;
  -webkit-mask-image:linear-gradient(260deg,#000,transparent 82%);
          mask-image:linear-gradient(260deg,#000,transparent 82%)}
.v2x.dlx .dlx-cta-tx{min-width:0;flex:1 1 420px}
.v2x.dlx .dlx-cta h2{margin:0 0 6px;font-size:1.35rem;font-weight:800;letter-spacing:-.02em;color:#fff}
.v2x.dlx .dlx-cta p{margin:0;font-size:14.4px;line-height:1.6;color:rgba(255,255,255,.92)}
.v2x.dlx .dlx-cta-btn{
  flex:0 0 auto;display:inline-flex;align-items:center;gap:9px;
  padding:12px 22px;border-radius:12px;
  background:#fff;color:#1B4FB3;                 /* 8.59:1 */
  font-size:14.2px;font-weight:750;text-decoration:none;
  box-shadow:0 8px 20px -10px rgba(0,0,0,.4);
  transition:transform .2s var(--ease-out,cubic-bezier(.16,1,.3,1)),box-shadow .2s ease,background .2s ease}
.v2x.dlx .dlx-cta-btn svg{width:16px;height:16px;transition:transform .2s ease}
.v2x.dlx .dlx-cta-btn:hover{background:#EEF4FF;color:#173F92;transform:translateY(-2px);
  box-shadow:0 14px 28px -12px rgba(0,0,0,.45);text-decoration:none}
.v2x.dlx .dlx-cta-btn:hover svg{transform:translateX(3px)}
/* ⚠ DELIBERATELY NO DARK TWIN for the four ink rules above
   (.dlx-cta h2 / p / -btn / -btn:hover), and none should be added. They are
   painted on the brand GRADIENT, which this band keeps in BOTH themes — it is
   the page's one saturated surface and inverting it would make the CTA vanish
   into a dark page. The gradient does not change, so the ink measured against
   it does not change either: white 5.49:1 at the worst stop, either theme. A
   dark twin here would be a twin for a background that never arrives.
   (The mask in §RESP is likewise theme-free: a mask reads alpha, not hue.) */


/* ═══ §MISC — iOS focus-zoom on the shared search field ════════════════════
   `.dir-hh-search input` is 15.5px in the SHARED sheet (14px small-screen),
   and iOS Safari zooms the viewport on focus for anything under 16px. That
   miss is real on /ai-directory, /browser-extensions, /gpts and /workflows
   too and needs its own pass on the shared sheet; fixing it there would move
   four other pages, so it is corrected `.v2x.dlx`-scoped only. */
.v2x.dlx .dir-hh-search input{font-size:16px}


/* ═══ §RESP — responsive ═══════════════════════════════════════════════════
   Every breakpoint below is one the SHARED SHEET already uses, so this delta
   steps at the same moments the page does rather than between them. */

@media (max-width:1180px){
  /* Cards narrow before the grid drops a column; the price row is the first
     thing to run out of room, so it centres rather than wrapping mid-figure. */
  .v2x.dlx .dlx-price{gap:6px}
  .v2x.dlx .dlx-now{font-size:18px}
}

@media (max-width:900px){
  .v2x.dlx .dlx-cta{padding:26px 24px}
  .v2x.dlx .dlx-cta h2{font-size:1.25rem}
}

@media (max-width:820px){
  /* The grid is single-column from here and the facet rail becomes an
     in-flow accordion, so the CTA goes column-wise at the same moment
     instead of 140px later. */
  .v2x.dlx .dlx-cta{flex-direction:column;align-items:flex-start;text-align:start;margin-top:34px}
  .v2x.dlx .dlx-cta-dots{width:100%;
    -webkit-mask-image:linear-gradient(200deg,#000,transparent 76%);
            mask-image:linear-gradient(200deg,#000,transparent 76%)}
  .v2x.dlx .dlx-cta-btn{width:100%;justify-content:center}
  /* The list row's right column sits beside a much narrower middle here. */
  .v2x.dlx .dlx-price.is-row{margin-bottom:6px}
}

@media (max-width:680px){
  .v2x.dlx .dlx-chips{gap:6px}
  .v2x.dlx .dlx-chip{font-size:11.8px;padding:4px 5px 4px 10px}
  /* In list mode the row stacks, so the price stops right-aligning — it
     would otherwise sit alone against an edge with its label on the far side
     of the card. */
  .v2x.dlx .dlx-price.is-row{justify-content:flex-start}
  .v2x.dlx .dir-lc-side{align-items:stretch;width:100%}
  .v2x.dlx .dlx-lc-act{width:100%}
  .v2x.dlx .dlx-lc-act .dir-tc-btn{flex:1 1 auto;justify-content:center}
}

@media (max-width:520px){
  .v2x.dlx .dlx-cta{padding:22px 18px;border-radius:18px}
  .v2x.dlx .dlx-cta h2{font-size:1.15rem}
  .v2x.dlx .dlx-cta p{font-size:13.6px}
  .v2x.dlx .dlx-now{font-size:17px}
  /* The coupon chip is the widest fixed-content element on the card. Letting
     it fill the width keeps the code on one line instead of ellipsing the
     part the visitor came for. */
  .v2x.dlx .dlx-cpn{width:100%;justify-content:space-between}
}

@media (max-width:420px){
  .v2x.dlx .dlx-cpn-lbl{display:none}
  .v2x.dlx .dlx-fig{font-size:11.2px}
}

/* Reduced motion: the two transforms this file adds are the only motion it
   introduces, so both are dropped rather than shortened. */
@media (prefers-reduced-motion:reduce){
  .v2x.dlx .dlx-cpn-btn,
  .v2x.dlx .dlx-cta-btn,
  .v2x.dlx .dlx-cta-btn svg,
  .v2x.dlx .dlx-results{transition:none !important}
  .v2x.dlx .dlx-cpn-btn:hover,
  .v2x.dlx .dlx-cta-btn:hover{transform:none !important}
}

/* ═══ §CATGRID — /deals/categories: the rail card, re-laid as a grid ═══════
   The CARD is the shared sheet's `.dir-cat-card` and is not restyled here.
   Only its CONTAINER changes: on /deals those cards live in `.dir-cat-rail`,
   a horizontal snap rail, which is right for a teaser and 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. Breakpoints below are this sheet's own
   ladder (1180 · 900 · 820 · 680 · 520 · 420), not Bootstrap's. */
.v2x.dlx .dlx-catsect{margin-top:clamp(24px,4vw,44px)}
.v2x.dlx .dlx-catgrid{
  display:grid;grid-template-columns:repeat(auto-fit,minmax(240px,1fr));
  gap:18px;max-width:1240px;margin:0 auto;justify-content:center}
/* In the rail the card is `flex:0 0 <width>`; inside a grid track that fixed
   basis fights the track, so it is released here and ONLY here. */
.v2x.dlx .dlx-catgrid .dir-cat-card{flex:1 1 auto;width:auto;min-width:0;scroll-snap-align:none}

/* ═══ §CATBACK — an index of categories must not be a dead end ════════════ */
.v2x.dlx .dlx-catback{display:flex;justify-content:center;margin:clamp(28px,5vw,52px) 0 8px}
.v2x.dlx .dlx-catback-btn{width:auto;min-width:220px;max-width:100%}

@media (max-width:1180px){
  .v2x.dlx .dlx-catgrid{grid-template-columns:repeat(auto-fit,minmax(224px,1fr));gap:16px}
}
@media (max-width:820px){
  .v2x.dlx .dlx-catgrid{grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:14px}
}
@media (max-width:520px){
  /* Two up rather than one: these cards are short, and a single column turns
     five categories into a long scroll for no gain. */
  .v2x.dlx .dlx-catgrid{grid-template-columns:1fr 1fr;gap:12px}
}
@media (max-width:420px){
  .v2x.dlx .dlx-catgrid{grid-template-columns:1fr}
  .v2x.dlx .dlx-catback-btn{min-width:0;width:100%}
}
