/* ===========================================================================
   seo-pages.css — the content layer for the public SEO pages.

   Loaded by website_security_scanner.html, methodology.html, security.html,
   the guides hub and the four guide articles, plus the guides-style pages.
   Nothing here styles a control the shell already owns; it is the shared
   vocabulary for one thing: a long page of English with tables and code in it.

   Why a separate file rather than more of style.css: `test_frontend_integrity`
   resolves every class a template names against every stylesheet, so the two
   ways to keep that honest are "add to the shared sheet forever" and "keep the
   content layer separable". This is the second one — the rule is that a class
   in here is for prose, and a class in style.css is for the product. A reader
   comparing the two stylesheets can tell them apart.

   Everything is built from tokens.css, so it inherits the dark palette and the
   responsive behaviour without restating either.
   =========================================================================== */

/* --------------------------------------------------------------- page frame */

/* The measure. Wider than `.legal`'s 800px because these pages carry tables,
   and narrower than the landing page's 1160px because they are read rather
   than scanned. The hero is allowed to break out wider than the prose below
   it — see `.sp-wide` — which is what stops a long page from reading as a
   single grey column. */
.sp-page { max-width: var(--maxw); margin: 0 auto; padding: 0 var(--space-6); }
.sp-narrow { max-width: 860px; }
.sp-wide { max-width: var(--maxw); }

/* Section rhythm. Tighter than `.section`'s 80px top padding, because these
   pages have more sections than a landing page has and 80px between each of
   fourteen of them is a page that scrolls for a minute before anything
   happens. */
.sp-section { padding: var(--space-16) 0; }
.sp-section + .sp-section { border-top: 1px solid var(--border); }
.sp-section-head { max-width: 720px; margin-bottom: var(--space-8); }
.sp-section-head > h2 { font-size: 1.5rem; margin: 0 0 var(--space-3); }
.sp-section-head > p { color: var(--text-secondary); margin: 0; line-height: 1.65; }

/* Hero. An eyebrow, an h1, a standfirst and at most one row of actions — the
   shape every content page on the site shares, so a reader arriving from
   search and a reader arriving from the footer land somewhere familiar. */
.sp-hero { padding: var(--space-16) 0 var(--space-12); }
.sp-hero h1 {
  font-size: clamp(1.9rem, 4.4vw, 2.6rem);
  line-height: 1.15;
  margin: var(--space-3) 0 var(--space-4);
  max-width: 20ch;
}
.sp-hero-lede { font-size: 1.0625rem; color: var(--text-secondary); line-height: 1.65; max-width: 62ch; }
.sp-actions { display: flex; flex-wrap: wrap; gap: var(--space-3); margin-top: var(--space-6); }

/* ------------------------------------------------------------ breadcrumbs */

.sp-crumbs {
  font-size: 0.8125rem;
  color: var(--text-tertiary);
  padding: var(--space-5) 0 0;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px;
}
.sp-crumbs ol { list-style: none; margin: 0; padding: 0; display: contents; }
.sp-crumbs li { display: flex; align-items: center; gap: 6px; }
.sp-crumbs li + li::before { content: "/"; color: var(--text-tertiary); opacity: 0.5; }
.sp-crumbs a { color: var(--text-secondary); text-decoration: none; }
.sp-crumbs a:hover { color: var(--text); text-decoration: underline; }
.sp-crumbs [aria-current="page"] { color: var(--text-tertiary); }

/* Wrapper for the pages that keep their own shell (pricing, the example report)
   and therefore cannot put the trail at the top of a `sp-page`. `margin: 0`
   rather than zeroed `padding` because an inline `style` attribute would be
   blocked by this site's own Content-Security-Policy — `style-src 'self'` with
   no `unsafe-inline` — and `tests/test_hardening_findings.py` asserts that
   none creeps back in. */
.sp-crumbs-frame { margin: var(--space-4) 0; }
.sp-crumbs-wrap { padding-top: var(--space-4); margin-bottom: var(--space-4); }

/* ------------------------------------------------------------------ prose */

/* The reading column. `> * + *` spacing rather than per-element margins, so a
   paragraph, a list, a table and a note all get the same gap and none of them
   has to remember to declare one. */
.sp-prose { font-size: 0.9375rem; line-height: 1.75; color: var(--text-secondary); }
.sp-prose > * + * { margin-top: var(--space-4); }
.sp-prose h2 {
  font-size: 1.375rem;
  color: var(--text);
  margin-top: var(--space-12);
  scroll-margin-top: var(--space-8);
}
.sp-prose h3 { font-size: 1.0625rem; color: var(--text); margin-top: var(--space-8); scroll-margin-top: var(--space-8); }
.sp-prose strong { color: var(--text); font-weight: 600; }
.sp-prose ul, .sp-prose ol { padding-left: 22px; display: grid; gap: 10px; }
.sp-prose li::marker { color: var(--text-tertiary); }
.sp-prose a { color: var(--accent); }
.sp-prose a:hover { color: var(--accent-hover); }
.sp-prose code {
  font-family: var(--mono);
  font-size: 0.8125rem;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: 1px 5px;
  color: var(--text);
  /* A long TXT record or a CSP source list is one unbroken token; without this
     it drags the whole page sideways at 375px, which is the exact bug the
     example report page was patched for. */
  overflow-wrap: anywhere;
}
.sp-prose pre {
  margin: 0;
  padding: var(--space-4);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  overflow-x: auto;
}
.sp-prose pre code {
  background: none;
  border: 0;
  padding: 0;
  font-size: 0.8125rem;
  line-height: 1.6;
  white-space: pre;
}

.sp-prose blockquote { color: var(--text-tertiary); border-left: 2px solid var(--border-strong); padding-left: var(--space-4); }
.sp-prose-nested { font-size: 0.875rem; color: var(--text-secondary); line-height: 1.7; }
.sp-prose-nested > * + * { margin-top: var(--space-3); }

/* A definition row: the term in the product's own terms on the left, the
   plain-language reading on the right. Collapses to one column on a phone,
   because two columns of prose at 375px is two columns of three words. */
.sp-def { display: grid; gap: var(--space-2); padding: var(--space-4) 0; border-top: 1px solid var(--border); }
.sp-def:first-of-type { border-top: 0; }
.sp-def dt { font-weight: 600; color: var(--text); }
.sp-def dd { margin: 0; color: var(--text-secondary); line-height: 1.65; }
@media (min-width: 720px) {
  .sp-def { grid-template-columns: minmax(180px, 26%) minmax(0, 1fr); gap: var(--space-6); align-items: baseline; }
}

/* ------------------------------------------------------------- call-outs */

/* The one box these pages use to say something the reader must not skim past:
   a scope boundary, a false-positive warning, a "this is not a pentest". One
   visual treatment, so a boundary statement looks the same on every page and a
   reader learns to read it. */
.sp-callout {
  border: 1px solid var(--border);
  border-left: 3px solid var(--accent);
  border-radius: var(--radius-md);
  background: var(--surface);
  padding: var(--space-5);
}
.sp-callout-title {
  font-size: 0.6875rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.07em;
  color: var(--text-tertiary);
  margin: 0 0 var(--space-2);
}
.sp-callout > *:last-child { margin-bottom: 0; }
.sp-callout p { margin: 0; color: var(--text-secondary); line-height: 1.65; }
.sp-callout ul { margin: var(--space-3) 0 0; padding-left: 20px; display: grid; gap: 8px; color: var(--text-secondary); }
.sp-callout li::marker { color: var(--text-tertiary); }
/* Scope boundaries get the warning colour, because that is what they are. The
   rule is on the element rather than the page so a page cannot accidentally
   style a boundary as reassuring. */
.sp-callout.is-boundary { border-left-color: var(--warning); }
.sp-callout.is-boundary .sp-callout-title { color: var(--warning-text); }

/* --------------------------------------------------------------- card rows */

.sp-grid { display: grid; gap: var(--space-4); }
/* `minmax(0, 1fr)` rather than `1fr`. A `1fr` track is really `minmax(auto, 1fr)`
   and its automatic minimum is the item's content size, so a single unbreakable
   token in a card — a long check id, a URL, a product name — widens the track
   past its share and pushes the grid wider than its container. The content pages
   have no such token today; the footer hit exactly this bug class when it grew a
   fifth column, so the guard is applied uniformly rather than waiting. */
@media (min-width: 640px) { .sp-grid-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); } }

.sp-card {
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  background: var(--surface);
  padding: var(--space-5);
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}
.sp-card h3 { font-size: 1rem; margin: 0; color: var(--text); }
.sp-card h3 a { color: inherit; text-decoration: none; }
.sp-card h3 a:hover { color: var(--accent); }
.sp-card p { margin: 0; font-size: 0.875rem; color: var(--text-secondary); line-height: 1.6; }
.sp-card-meta { font-size: 0.75rem; color: var(--text-tertiary); }

/* A check-ID chip. The scanner's own identifier for a finding, which is what a
   reader greps a report for, so it is printed in the monospace face rather than
   styled as a decorative badge. */
.sp-check {
  font-family: var(--mono);
  font-size: 0.6875rem;
  color: var(--text-tertiary);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: 1px 6px;
  white-space: nowrap;
}

/* ------------------------------------------------------------------ tables */

/* `.table-wrap` is the shared horizontal-scroll box; `.table` is the shared
   table skin. What is added here is the narrower, denser variant these pages
   need for comparison tables that would otherwise force a scroll on a laptop.
   Nothing about the table is redefined — only its density. */
.sp-table { font-size: 0.8125rem; }
.sp-table th, .sp-table td { padding: var(--space-3); vertical-align: top; }
.sp-table th:first-child, .sp-table td:first-child { white-space: nowrap; }
.sp-table tbody tr + tr td { border-top: 1px solid var(--border); }
.sp-table td code { white-space: normal; }

/* --------------------------------------------------------------- in-page TOC */

/* The article contents list. Reuses `.legal-toc` and `.legal-toc-list` from
   style.css — same two-column fill layout — and adds only the article-specific
   label. Reusing the rule rather than restating it is what keeps a legal page
   and an article's contents list looking like the same site. */
.sp-toc { margin: var(--space-8) 0; }

/* ---------------------------------------------------------------- articles */

.sp-article { padding-bottom: var(--space-16); }
.sp-article-head { padding: var(--space-12) 0 var(--space-8); border-bottom: 1px solid var(--border); }
.sp-article-head h1 {
  font-size: clamp(1.75rem, 4vw, 2.35rem);
  line-height: 1.18;
  margin: var(--space-3) 0 var(--space-4);
  max-width: 24ch;
}
.sp-article-dek { font-size: 1.0625rem; color: var(--text-secondary); line-height: 1.65; max-width: 60ch; }

/* The byline. Author and both dates, because a guide that says when it was last
   reviewed is a guide somebody can decide to trust; one that does not is a page
   with an unknown age on it. The dates are real stored values, not a build
   timestamp — see `GUIDES` in web/seo.py. */
.sp-byline {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2) var(--space-4);
  font-size: 0.8125rem;
  color: var(--text-tertiary);
  margin-top: var(--space-6);
  padding-top: var(--space-4);
  border-top: 1px solid var(--border);
}
.sp-byline time { white-space: nowrap; }
.sp-byline-label { color: var(--text-tertiary); }

/* "Keep reading" — the contextual next actions at the foot of a guide. Two or
   three links to the pages the article actually argued for, not a generic
   "related content" block. */
.sp-related {
  margin-top: var(--space-12);
  padding-top: var(--space-8);
  border-top: 1px solid var(--border);
}
.sp-related h2 { font-size: 0.6875rem; text-transform: uppercase; letter-spacing: 0.07em; color: var(--text-tertiary); margin: 0 0 var(--space-4); }
.sp-related ul { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--space-2); }
.sp-related a { display: inline-flex; gap: 8px; align-items: baseline; color: var(--text-secondary); text-decoration: none; font-size: 0.875rem; }
.sp-related a:hover { color: var(--text); text-decoration: underline; }

/* The last thing on a content page. One primary action and the honest
   qualifier next to it — what happens, and that it is not a pentest — so the
   CTA is not asked to carry a claim it cannot make. */
.sp-cta {
  margin-top: var(--space-16);
  padding: var(--space-10);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg, 16px);
  background: var(--surface);
  text-align: center;
}
.sp-cta h2 { font-size: 1.25rem; margin: 0 0 var(--space-3); }
.sp-cta p { color: var(--text-secondary); max-width: 52ch; margin: 0 auto; line-height: 1.65; }
.sp-cta .sp-actions { justify-content: center; }
.sp-cta-note { font-size: 0.8125rem; color: var(--text-tertiary); margin-top: var(--space-4); }

/* ------------------------------------------------------------- guides hub */

.sp-guide-list { display: grid; gap: var(--space-4); }
@media (min-width: 760px) { .sp-guide-list { grid-template-columns: repeat(2, minmax(0, 1fr)); } }

.sp-guide {
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  background: var(--surface);
  padding: var(--space-6);
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}
.sp-guide h2 { font-size: 1.0625rem; margin: 0; line-height: 1.4; }
.sp-guide h2 a { color: var(--text); text-decoration: none; }
.sp-guide h2 a:hover { color: var(--accent); }
.sp-guide-summary { font-size: 0.875rem; color: var(--text-secondary); line-height: 1.6; margin: 0; }
.sp-guide-meta {
  margin-top: auto;
  padding-top: var(--space-3);
  border-top: 1px solid var(--border);
  font-size: 0.75rem;
  color: var(--text-tertiary);
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2) var(--space-4);
}

/* ----------------------------------------------------------- free-check form */

/* The quick-check page reuses the product's own domain input rather than
   inventing a second one. `.sp-domainbar` is only the wrapper; the field, the
   button and the error state inside it are `.domain-bar`, `.input-domain` and
   the landing page's own classes, so this control behaves identically
   everywhere it appears. The form posts nowhere: it is the same progressive
   enhancement the landing page uses, and app.js/landing.js own the submit. */
.sp-domainbar { margin: var(--space-8) 0; }
.sp-domainbar-row {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3);
  align-items: center;
}
.sp-domainbar-label { font-size: 0.75rem; color: var(--text-tertiary); margin-bottom: var(--space-2); display: block; }
.sp-domainbar-note { margin-top: var(--space-3); margin-bottom: 0; }
.sp-domainbar .input-domain { min-width: 240px; }

/* ------------------------------------------------------------- narrow print */

/* A content page is the one thing on this site somebody is likely to print or
   save as a PDF and read offline, so the chrome goes and the ink budget drops.
   The light theme is forced because the site is dark by default and a printed
   dark page is a black rectangle. */
@media print {
  .sp-page { max-width: none; }
  .sp-toc, .sp-cta, .sp-actions, .site-nav, .mobile-nav { display: none !important; }
  .sp-prose { color: #000; }
  .sp-prose a { color: #000; text-decoration: underline; }
  .sp-section + .sp-section { border-top: 0; }
}