/* ── Serpent product-page components — THE shared copy ───────────────────────
   Loaded by the 29 product landing pages, AFTER styles.css and mobile.css and BEFORE each page's
   own <style> block. Owner review, 2026-09-08.

   WHY THIS FILE EXISTS. Every one of those pages carried its own private copy of the rules below.
   Measured before this file was written: 10 different versions of the same pricing-card block
   across 12 pages. That is why one page's cards look broken and the others' do not — it is not one
   bug, it is ten copies drifting. Fixing it in one place is the owner's own instruction
   (session-34 review §1c: "or better: promote them into the shared stylesheet in ONE place").

   SCOPE IS DELIBERATELY NARROW. Only rules that were BYTE-IDENTICAL on every page that declared
   them are here, so lifting them out cannot change how any page renders. Verified by parsing all
   29 pages' <style> blocks and grouping each selector's body.
     • IN  — .ep-tiers and its rows, .endpoint-card's label/price/unit/bullets, .skip-link,
             the JSON code-sample syntax colours.
     • OUT — `.endpoint-card` itself (4 variants), `.ep-link` (3), `h3` (3), `ul` (2), `:hover` (2),
             and `.data-grid`/`.data-card`, whose variants genuinely conflict (2-column vs auto-fit,
             plus per-engine hover branding on the AI pages). A "union" of those would be
             last-declaration-wins, i.e. a silent redesign of half the pages.

   ⚠ SELECTOR DEPTH IS LOAD-BEARING. Every rule is written at exactly the depth the pages already
   used (`.ep-tiers .ep-tier`, not `.ep-tier`). A page's own <style> comes AFTER this file, so at
   equal specificity the page wins. Writing these shallower would half-apply on any page whose
   inline copy was not removed — the new declarations would land while the old ones still won,
   which looks nearly fixed and is the worst outcome to debug. At equal depth a leftover inline
   copy is a clean no-op instead.

   ⚠ Do NOT add page-specific rules here, and do NOT add anything that is not identical everywhere.
   The next person's fix has to be one edit, which is the whole point.
   ────────────────────────────────────────────────────────────────────────── */

/* ── Endpoint / pricing cards ─────────────────────────────────────────────── */
/* `.endpoint-card` itself stays per-page: 4 conflicting variants (border-radius, padding, and
   whether the card is a flex column at all). ✅ 2026-09-08: linkedin-api and instagram-api were the
   two that were NOT flex columns; both are now `display:flex; flex-direction:column` with
   `margin-top:auto` on `.ep-link`, which took their CTA-gap spread from 70px and 73px to 1px and
   4px. Nothing left to fix here — do not re-fix it. (Was: fixed when those pages are
   rebuilt, not by overriding them from here. */
.endpoint-card .ep-label { font-size: 0.75rem; font-weight: 700; text-transform: uppercase; color: var(--accent); letter-spacing: 0.05em; margin-bottom: 0.5rem; }
.endpoint-card .ep-price { color: var(--accent); font-weight: 700; font-size: 1.5rem; margin-bottom: 0.25rem; }
.endpoint-card .ep-unit { color: var(--text-muted); font-size: 0.85rem; margin-bottom: 1rem; }
.endpoint-card ul li { color: var(--text-secondary); padding: 0.35rem 0; padding-left: 1.25rem; position: relative; font-size: 0.9rem; }
.endpoint-card ul li::before { content: ''; position: absolute; left: 0; top: 0.7rem; width: 6px; height: 6px; background: var(--accent); border-radius: 50%; }

/* ── The tier ladder — the owner's 2026-09-08 fix, in one place ───────────────
   MEASURED on bing-serp-api at 1280px before the change (prose-line QA sweep):
     card heights   817 / 817 / 817 / 817   — already equal; the grid stretches them. Not the bug.
     price → CTA    [0, 84, 63, 63] px      — the first card really has none.
     tier row height  48px on card 1, 27px on cards 2–4
     name → price gap 0px on card 1, 30–44px on cards 2–4
   CAUSE, confirmed: all three of card 1's prices WRAP to two lines, because
   "$0.60/1K SERP API calls" is longer than "$0.20/1K Queries". Three rows at 48px instead of 27px
   eats 63px — which is exactly the gap the other cards have above their button.
   The label and price do NOT overlap; their gap is 0, i.e. they are flush. That is what reads as
   "Default$0.60/1K SERP API calls" when the price fills the row.

   Three declarations fix it, and the third only holds if the copy cooperates: `white-space: nowrap`
   stops a price wrapping, but a price too long for the row would then overflow instead. So the
   unit string is normalised to ONE wording across every card and every page. */
.ep-tiers {
  margin-top: 0.75rem;
  padding-top: 0.75rem;
  border-top: 1px solid var(--border);
  /* NEW — a FLOOR under the gap above the button. Removing the wrap fixed the 60–110px the
     two-line prices were eating and collapsed the spread between cards (bing 84px → 21px), but the
     card with the most content still ends up with literally 0px, because equal-height cards plus a
     bottom-pinned CTA leave the tallest card no slack at all. That is what the owner saw described
     as "almost touching the button below". This guarantees breathing room on every card whether or
     not it has slack to spare. */
  margin-bottom: 1.25rem;
}
.ep-tiers .ep-tier {
  display: flex;
  justify-content: space-between;
  align-items: baseline;   /* NEW — a 2-line price used to drag the label to its top */
  gap: 0.75rem;            /* NEW — the label and price were flush at 0px */
  font-size: 0.82rem;
  color: var(--text-secondary);
  padding: 0.2rem 0;
}
.ep-tiers .ep-tier .tier-name { font-weight: 500; }
.ep-tiers .ep-tier .tier-price {
  font-weight: 600;
  color: var(--text-primary);
  white-space: nowrap;     /* NEW — the wrap is what ate the space above the button */
}

/* ── Long endpoint paths inside a card ────────────────────────────────────────
   An endpoint card is a narrow grid track, and `GET /api/social/youtube/playlist` is a single
   32-character unbreakable token to a line-breaker — there is no break opportunity in it. A `1fr`
   track cannot shrink below its min-content width, so ONE long path widened all four tracks and
   pushed the youtube-api page 155px sideways at 1280. Found by the first browser QA run of the
   vertical views; fixed here rather than per page, because every rebuilt vertical now names its
   endpoint in a card and the next long path would do it again. */
.endpoint-card code,
.engine-card code { overflow-wrap: anywhere; word-break: break-word; }

/* ── JSON code samples ────────────────────────────────────────────────────────
   `.c-num` was used by google-serp-api and declared nowhere it loads, so every number in its JSON
   sample rendered as body text. The five shopping pages hit the same bug under a different name,
   `.c-number`, which is declared nowhere at all. Both are covered here so the palette is complete
   on all 29 pages and the two names cannot drift apart again. */
.code-body .c-key { color: var(--accent); }
.code-body .c-str { color: #f59e0b; }
.code-body .c-num,
.code-body .c-number { color: #ec4899; }
.code-body .c-comment { color: var(--text-muted); }

/* ── Skip link ────────────────────────────────────────────────────────────────
   Identical on 28 of the 29 pages and absent from google-maps-api, where it therefore rendered as
   a visible link sitting above the navigation. */
.skip-link { position: absolute; top: -40px; left: 0; background: var(--accent); color: #fff; padding: 8px 16px; z-index: 10000; font-size: 14px; text-decoration: none; border-radius: 0 0 4px 0; transition: top 0.2s; }
.skip-link:focus { top: 0; }

/* ── Competitor comparison table ──────────────────────────────────────────────
   Promoted here 2026-09-08. It existed ONLY inline on serp-api.html, so each of the twelve pages
   being rebuilt would have invented its own — the same per-page duplication this file exists to
   end, and twelve chances for a price table to look different from the one beside it.

   ⚠ `public/index.html` keeps its OWN copy on purpose: it does not load this stylesheet, and its
   variant carries `min-width:640px` for the homepage's narrower container. Do not "consolidate" it.

   CONTENT-PLAYBOOK §12c governs what goes IN the table: name ourselves once, the column header is
   "Cost per 1,000", and if our cell shows our lowest rate then every competitor cell must show
   THEIR lowest published rate too — including the ones that beat us. */
.comparison-table { width: 100%; border-collapse: collapse; margin: 2rem 0; }
.comparison-table th, .comparison-table td { padding: 1rem 1.25rem; text-align: left; border-bottom: 1px solid var(--border); }
.comparison-table th { color: var(--text-secondary); font-weight: 600; font-size: 0.8rem; text-transform: uppercase; letter-spacing: 0.05em; background: var(--bg-secondary); }
.comparison-table td { font-size: 0.95rem; }
.comparison-table tr:hover td { background: var(--bg-card-hover); }
.comparison-table .highlight-row { background: var(--accent-dim); }
.comparison-table .highlight-row td { font-weight: 600; }
.comparison-table .price-good { color: var(--accent); font-weight: 700; }
.comparison-table .price-bad { color: var(--text-muted); }

/* A wide table must scroll inside its own container, never make the page scroll sideways. */
.lp-table-wrap { overflow-x: auto; -webkit-overflow-scrolling: touch; }

@media (max-width: 768px) {
  .comparison-table { font-size: 0.85rem; }
  .comparison-table th, .comparison-table td { padding: 0.75rem 0.5rem; }
}
