/* patentcontinuation.com
 *
 * Rebuilt 2026-08-15. The first version was a mobile-first document stylesheet
 * that never got a desktop design: a 42rem column on a 1280px viewport left most
 * of the screen empty, every block had the same rhythm, and the brand palette
 * this repo had just written a conventions document about went unused.
 *
 * Brand values are verbatim from docs/conventions/ui-ux.md, which records where the
 * canonical palette lives. That citation stays in docs/ and not in this file:
 * THIS STYLESHEET IS SERVED TO EVERY VISITOR, so a comment naming a private
 * sibling repo is a live leak. Component code uses the SEMANTIC names below, never
 * the raw --brand-* values.
 *
 * The one recorded divergence still holds: brand cyan measures about 2.05:1 on
 * white, under the 4.5:1 AA floor, so cyan is for SURFACES, focus rings and the
 * glow. Accent TEXT uses the darker derived cyan.
 *
 * Self-hosted only. No CDN font, no icon set, no third-party request of any kind:
 * the CSP in main.go enforces that rather than trusting it.
 */

/* Brand type, self-hosted. Inter for body and UI, Satoshi for display and headings,
 * both upright variable only: the italic variants are another 432 KB for a surface
 * that sets no italic display type. font-src 'self' in main.go's CSP already
 * anticipated these, so no policy change is needed. The internal provenance of the
 * files is recorded in docs/conventions/ui-ux.md, not here: THIS FILE IS SERVED TO
 * THE PUBLIC, so a comment naming a private sibling repo is a live leak, which is
 * exactly what this one was until 2026-08-15. */
@font-face {
  font-family: "Inter";
  src: url("/static/fonts/InterVariable.woff2") format("woff2-variations");
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Satoshi";
  src: url("/static/fonts/Satoshi-Variable.woff2") format("woff2-variations");
  font-weight: 300 900;
  font-style: normal;
  font-display: swap;
}

:root {
  --font-sans: "Inter", ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  --font-display: "Satoshi", "Inter", ui-sans-serif, system-ui, sans-serif;

  /* Brand, verbatim. Do not adjust or re-sample. */
  --brand-black: #111111;
  --brand-white: #ffffff;
  --brand-cyan: #2dc5e8;
  --brand-purple: #4a3f78;
  --brand-purple-light: #bfa8ff;
  --brand-rose: #d4637a;
  --brand-gray-light: #e5e5e5;
  --brand-gray-bg: #f7f8fa;

  /* Semantic. Use these in component code. */
  --bg-canvas: var(--brand-white);
  --bg-subtle: var(--brand-gray-bg);
  --bg-inverse: var(--brand-black);
  --fg-default: var(--brand-black);
  --fg-muted: #55606c;
  --fg-inverse: #f2f5f7;
  --fg-on-accent: #06222b;
  --border-subtle: var(--brand-gray-light);
  --border-strong: #cdd4db; /* DECORATIVE only: dividers, dots, rules. Not a control boundary. */
  /* --border-control is the visual boundary of an interactive control, which WCAG
     2.2 SC 1.4.11 holds to 3:1 against its background. --border-strong is 1.50:1 on
     white and was being used for .btn-secondary's outline, which made the secondary
     button's boundary effectively invisible as a control. Caught by
     contrast_test.go, not by eye. */
  --border-control: #7d8792; /* 3.65:1 on canvas, 3.44:1 on the subtle surface */
  --accent-default: #0e7a96; /* accent TEXT: 4.95:1 on white. See divergence. */
  --accent-surface: var(--brand-cyan);
  --accent-deep: var(--brand-purple);
  /* Footer links. The brand assigns brand-rose (#d4637a) this role, and adopting it
     verbatim on a light ground gives 3.37:1, under the 4.5 floor: the SAME mistake
     the cyan divergence already documents, in a second role. Darkened here, and
     brand-rose is kept for the surfaces and tags where it is not body-weight text.
     On the dark ground brand-rose itself clears the floor, exactly as cyan does, so
     the divergence is once again light-theme-only. */
  --footer-link: #a8455c; /* 5.38:1 on the subtle surface */

  --radius-sm: 4px;
  --radius-md: 6px;
  --radius-lg: 8px;
  --radius-xl: 12px;

  --shell: 74rem; /* full-width section inner bound */
  --prose: 38rem; /* reading measure, narrower on purpose */

  --step-0: 1.0625rem;
  --step-1: 1.25rem;
  --step-2: 1.5rem;
  --step-3: clamp(1.6rem, 1.2rem + 1.6vw, 2.1rem);
  --step-4: clamp(2.2rem, 1.5rem + 3.2vw, 3.6rem);
}

@media (prefers-color-scheme: dark) {
  :root {
    --bg-canvas: #0d1319;
    --bg-subtle: #141d26;
    --bg-inverse: #060a0e;
    --fg-default: #e9eff4;
    --fg-muted: #9fb1c0;
    --border-subtle: #26323e;
    --border-strong: #35434f;
    --border-control: #5d6d78; /* 3.49:1 on the dark canvas, 3.18:1 on the subtle surface */
    /* Brand rose clears 4.5:1 on the dark ground unchanged, so the light-theme
       darkening above is not carried here. */
    --footer-link: var(--brand-rose);
    /* On a dark ground the brand cyan clears AA comfortably, so it is the accent
       here. The divergence is a light-theme problem only. */
    --accent-default: #5ad4f0;
  }
}

* { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  background: var(--bg-canvas);
  color: var(--fg-default);
  font: var(--step-0)/1.6 var(--font-sans);
  text-rendering: optimizeLegibility;
}

.skip { position: absolute; left: -9999px; }
.skip:focus {
  left: 1rem; top: 1rem; padding: .6rem 1rem; z-index: 20;
  background: var(--accent-surface); color: var(--fg-on-accent); border-radius: var(--radius-md);
}

/* ---------- shell ---------- */

.wrap { width: 100%; max-width: var(--shell); margin: 0 auto; padding: 0 1.5rem; }
.prose { max-width: var(--prose); }

/* ---------- header ---------- */

header.site {
  position: sticky; top: 0; z-index: 10;
  background: color-mix(in srgb, var(--bg-canvas) 88%, transparent);
  backdrop-filter: blur(10px);
  border-bottom: 1px solid var(--border-subtle);
}
header.site .wrap {
  display: flex; align-items: center; gap: 1rem 2rem; flex-wrap: wrap;
  min-height: 4rem;
}
.brand {
  display: inline-flex; align-items: center; gap: .55rem;
  font-weight: 700; letter-spacing: -.01em; color: var(--fg-default); text-decoration: none;
  margin-right: auto;
}
.brand img { width: 1.5rem; height: 1.5rem; display: block; }
header.site nav { display: flex; flex-wrap: wrap; gap: 1.5rem; }
header.site nav a {
  color: var(--fg-muted); text-decoration: none; font-size: .97rem;
  padding: .25rem 0; border-bottom: 2px solid transparent;
}
header.site nav a:hover, header.site nav a:focus-visible {
  color: var(--fg-default); border-bottom-color: var(--accent-surface);
}

/* ---------- type ---------- */

/* Satoshi carries the display voice; the tight tracking below is part of it and
   should not be loosened. Body and UI stay on Inter via the body rule. */
h1, h2, h3 { font-family: var(--font-display); }
h1 { font-size: var(--step-4); line-height: 1.05; letter-spacing: -.025em; margin: 0 0 1rem; font-weight: 800; }
h2 { font-size: var(--step-3); line-height: 1.15; letter-spacing: -.018em; margin: 0 0 .75rem; font-weight: 700; }
h3 { font-size: var(--step-1); line-height: 1.25; margin: 0 0 .4rem; font-weight: 650; }
p { margin: 0 0 1rem; }
.lede { font-size: var(--step-1); line-height: 1.5; color: var(--fg-muted); }
.small { font-size: .92rem; color: var(--fg-muted); }
.eyebrow {
  display: inline-block; font-size: .8rem; font-weight: 700; letter-spacing: .09em;
  text-transform: uppercase; color: var(--accent-default); margin-bottom: .9rem;
}
a { color: var(--accent-default); text-underline-offset: 2px; }

/* ---------- sections ---------- */

section.band { padding: 4.5rem 0; }
section.band + section.band { border-top: 1px solid var(--border-subtle); }
section.band.tint { background: var(--bg-subtle); }
.band-head { margin-bottom: 2rem; max-width: var(--prose); }

/* ---------- hero ---------- */

.hero {
  padding: 4.5rem 0 4rem;
  background:
    radial-gradient(60rem 28rem at 78% -12%, color-mix(in srgb, var(--accent-surface) 17%, transparent), transparent 70%),
    radial-gradient(44rem 24rem at 4% 8%, color-mix(in srgb, var(--accent-deep) 11%, transparent), transparent 70%);
}
.hero-grid { display: grid; gap: 3rem; align-items: start; }
@media (min-width: 62rem) {
  .hero-grid { grid-template-columns: minmax(0, 1fr) minmax(0, 1.05fr); gap: 4rem; align-items: center; }
}

/* ---------- buttons ---------- */

.cta-row { display: flex; flex-wrap: wrap; gap: .75rem; margin: 1.75rem 0 1rem; }
/* The top-of-funnel entry, above .cta-row rather than in it. A third .btn would have
   changed which control is first, and that ordering is another plan's shipped decision;
   this adds a stage in front of the row without touching it. */
.cta-lead {
  margin: 1.6rem 0 0; padding: .8rem 1rem; font-size: .98rem;
  background: var(--bg-subtle); border: 1px solid var(--border-subtle);
  border-left: 3px solid var(--accent-surface); border-radius: var(--radius-lg);
}
.btn {
  display: inline-flex; align-items: center; gap: .5rem;
  padding: .8rem 1.4rem; border-radius: var(--radius-lg);
  font-weight: 650; font-size: 1.02rem; text-decoration: none; border: 1px solid transparent;
  transition: transform .12s ease, box-shadow .12s ease, background .12s ease;
}
.btn-primary {
  background: var(--bg-inverse); color: var(--fg-inverse);
  box-shadow: 0 1px 2px rgba(17, 17, 17, .18);
}
.btn-primary:hover { transform: translateY(-1px); box-shadow: 0 6px 20px -8px var(--accent-surface); }
.btn-secondary { background: transparent; color: var(--fg-default); border-color: var(--border-control); }
.btn-secondary:hover { border-color: var(--accent-surface); background: color-mix(in srgb, var(--accent-surface) 8%, transparent); }

/* ---------- the output sample: the product, shown ---------- */

.sample {
  border: 1px solid var(--border-subtle); border-radius: var(--radius-xl);
  background: var(--bg-canvas); overflow: hidden;
  box-shadow: 0 24px 60px -32px rgba(17, 17, 17, .38);
}
.sample-bar {
  display: flex; align-items: center; gap: .5rem;
  padding: .7rem 1rem; border-bottom: 1px solid var(--border-subtle);
  background: var(--bg-subtle); font-size: .82rem; color: var(--fg-muted);
}
.dot { width: .6rem; height: .6rem; border-radius: 50%; background: var(--border-strong); }
.sample-body { padding: 1.1rem 1.2rem; display: grid; gap: .9rem; }
.sample-step { display: grid; gap: .3rem; }
.sample-label {
  font-size: .74rem; font-weight: 700; letter-spacing: .08em; text-transform: uppercase;
  color: var(--fg-muted);
}
.claim {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: .86rem; line-height: 1.55;
  background: var(--bg-subtle); border-left: 3px solid var(--border-strong);
  padding: .7rem .85rem; border-radius: 0 var(--radius-md) var(--radius-md) 0;
}
.claim.out { border-left-color: var(--accent-surface); }
.flag {
  display: grid; gap: .25rem;
  border-left: 3px solid var(--brand-rose);
  background: color-mix(in srgb, var(--brand-rose) 8%, transparent);
  padding: .7rem .85rem; border-radius: 0 var(--radius-md) var(--radius-md) 0;
  font-size: .88rem;
}
.flag-tag { font-weight: 700; color: var(--brand-rose); font-size: .78rem; letter-spacing: .04em; }

/* ---------- card grids ---------- */

.grid { display: grid; gap: 1.25rem; }
.grid-3 { grid-template-columns: 1fr; }
@media (min-width: 44rem) { .grid-3 { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 66rem) { .grid-3 { grid-template-columns: repeat(3, 1fr); } }
/* Two-up, for the five tier cards on the practice hub. Deliberately not grid-3: a
   tier card carries a sentence rather than a label, and three columns of prose at this
   measure is unreadable. Five cards over two columns also leaves the last one wide,
   which is where Tier E sits and reads as a footnote, which it roughly is. */
.grid-2 { grid-template-columns: 1fr; }
@media (min-width: 50rem) { .grid-2 { grid-template-columns: repeat(2, 1fr); } }

.card {
  border: 1px solid var(--border-subtle); border-radius: var(--radius-xl);
  padding: 1.4rem 1.5rem; background: var(--bg-canvas);
  transition: border-color .12s ease, transform .12s ease;
}
.card:hover { border-color: var(--brand-purple-light); transform: translateY(-2px); }
/* A CARD IS A LINK WRAPPING A BLOCK OF PROSE, and until 2026-08-17 every word of that
   prose rendered underlined and in the accent colour. `a` sets a colour and never resets
   text-decoration, and `.card` never overrode it, so the browser default underlined the
   title, the meta line and the summary alike. It was live on production and had been
   since the corpus shipped.

   Found while rebuilding the hub rather than by review, and the reason is worth the
   line: the defect was survivable when a card carried a one-line summary and became
   obvious when phase 1 gave each card a full sentence. A readability problem scales with
   the content, so the change that made the page better is the change that surfaced it.

   The title keeps the accent colour and gains an underline on hover, so the affordance
   is still there; the body text stops shouting. */
.card { color: var(--fg-default); text-decoration: none; }
.card h3 { display: flex; align-items: baseline; gap: .5rem; color: var(--accent-default); }
.card:hover h3 { text-decoration: underline; }
.card p:last-child { margin-bottom: 0; }
/* .card-meta WAS USED BY THE MARKUP AND DEFINED BY NOTHING, on every record card since
   the corpus shipped. Found 2026-08-17 while rebuilding the hub, by checking a class
   name I was about to reuse. Undefined, it inherited the enclosing anchor's colour and
   the body size, so a card's subtitle rendered as full-size cyan link text competing
   with the title above it. A dangling class is invisible in review because the markup
   reads exactly as intended; only the rendered page disagrees. */
.card-meta { font-size: .88rem; color: var(--fg-muted); margin-bottom: .6rem; }
.card-rule { width: 2.2rem; height: 3px; border-radius: 2px; background: var(--accent-surface); margin-bottom: .9rem; }

/* ---------- tier cards ---------- */

.tiers { display: grid; gap: 1.25rem; grid-template-columns: 1fr; }
@media (min-width: 50rem) { .tiers { grid-template-columns: repeat(2, 1fr); } }
.tier { display: flex; flex-direction: column; }
.tier .machine { font-size: .85rem; color: var(--fg-muted); font-weight: 600; letter-spacing: .02em; }
.tier .model {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 1.22rem; font-weight: 700; margin: .2rem 0 .9rem; color: var(--fg-default);
}
.figs { display: flex; flex-wrap: wrap; gap: .5rem; margin-bottom: .9rem; }
.fig {
  border: 1px solid var(--border-subtle); border-radius: 999px;
  padding: .22rem .7rem; font-size: .82rem; color: var(--fg-muted);
}
.fig strong { color: var(--fg-default); }
.fig.warn { border-color: var(--brand-rose); color: var(--brand-rose); }
.fig.warn strong { color: var(--brand-rose); }
.tier .why { flex: 1; }
.tier .go { margin-top: 1rem; }

/* ---------- steps ---------- */

.steps { counter-reset: step; display: grid; gap: 1.5rem; max-width: 46rem; }
.step { counter-increment: step; display: grid; grid-template-columns: 2.25rem 1fr; gap: 1rem; align-items: start; }
.step::before {
  content: counter(step);
  width: 2.25rem; height: 2.25rem; border-radius: 50%;
  display: grid; place-items: center; font-weight: 700; font-size: .95rem;
  background: var(--accent-surface); color: var(--fg-on-accent);
}
.step > div > :last-child { margin-bottom: 0; }

/* ---------- code ---------- */

code, pre { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; }
code { background: var(--bg-subtle); padding: .1em .35em; border-radius: var(--radius-sm); font-size: .9em; }
pre {
  background: var(--bg-inverse); color: var(--fg-inverse);
  border-radius: var(--radius-lg); padding: .95rem 1.1rem; overflow-x: auto;
  font-size: .87rem; line-height: 1.6; margin: .6rem 0 0;
}
pre code { background: none; padding: 0; color: inherit; }

/* ---------- notes, tables, lists ---------- */

.note {
  border: 1px solid var(--border-subtle); border-left: 3px solid var(--accent-surface);
  background: var(--bg-subtle); border-radius: 0 var(--radius-lg) var(--radius-lg) 0;
  padding: 1.2rem 1.4rem;
}
.note h2, .note h3 { margin-top: 0; }
.note :last-child { margin-bottom: 0; }
.warnbox { border-left-color: var(--brand-rose); background: color-mix(in srgb, var(--brand-rose) 7%, transparent); }

table { border-collapse: collapse; width: 100%; font-size: .94rem; }
th, td { text-align: left; padding: .65rem .7rem; border-bottom: 1px solid var(--border-subtle); }
th { font-weight: 650; color: var(--fg-muted); font-size: .84rem; letter-spacing: .04em; text-transform: uppercase; }
.table-scroll { overflow-x: auto; }

ul.plain { list-style: none; padding: 0; margin: 0; display: grid; gap: .5rem; }
ul.downloads { list-style: none; padding: 0; display: grid; gap: .5rem; }
ul.downloads li {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: .5rem 1rem;
  padding: .85rem 1rem; border: 1px solid var(--border-subtle); border-radius: var(--radius-lg);
}
ul.downloads li:hover { border-color: var(--accent-surface); }
ul.downloads a { font-weight: 650; }
ul.downloads code { margin-left: auto; color: var(--fg-muted); font-size: .8rem; }

/* ---------- small layout utilities ----------
 *
 * These exist because the CSP forbids inline styles, deliberately. An earlier
 * revision used style="margin-top:1rem" attributes and the browser blocked every
 * one of them: the policy this site ships was blocking the site's own markup.
 * Utilities in the stylesheet are the fix; relaxing style-src to 'unsafe-inline'
 * would have been the other one, and it would have re-opened the hole the policy
 * exists to close.
 */

.note-after { margin-top: 1rem; }
.section-gap { margin-top: 2rem; }
.sample-title { margin-left: .5rem; }

/* ---------- footer ---------- */

footer.site { border-top: 1px solid var(--border-subtle); background: var(--bg-subtle); padding: 3rem 0; }
footer.site .maturity { max-width: 46rem; font-size: .95rem; color: var(--fg-muted); }
footer.site .maturity strong { color: var(--fg-default); }
footer.site a { color: var(--footer-link); }
/* The footer had the disclaimer and nothing else, so the bottom of a long page was
   a dead end. Targets are padded to clear the 44px minimum with room to spare. */
.footer-nav {
  display: flex; flex-wrap: wrap; gap: .25rem 1.5rem;
  margin-top: 1.75rem; padding-top: 1.5rem;
  border-top: 1px solid var(--border-subtle);
}
.footer-nav a { font-size: .92rem; display: inline-flex; align-items: center; min-height: 44px; }

/* Small screens: the nav wrapped to a second line and pushed the hero ~275px
   down on a 390px viewport, which is a lot of the fold spent on chrome. */
@media (max-width: 34rem) {
  header.site .wrap { min-height: 0; padding-top: .6rem; padding-bottom: .6rem; gap: .5rem 1rem; }
  .brand { font-size: .98rem; margin-right: 0; width: 100%; }
  header.site nav { gap: .5rem 1.1rem; width: 100%; }
  header.site nav a { font-size: .9rem; }
  .hero { padding: 2.5rem 0 3rem; }
  section.band { padding: 3rem 0; }
}

:focus-visible {
  /* --accent-default, NOT --accent-surface. WCAG 2.2 SC 1.4.11 wants 3:1 for a
     focus indicator against what it sits on, and brand cyan is 2.05:1 on the light
     canvas: the same ratio that disqualified it for text. The conventions file used
     to list focus rings alongside surfaces as a cyan role; it was corrected on
     2026-08-15 and this is the fix. Dark theme is unaffected either way (cyan runs
     about 9:1 on #0d1319), but one token that is correct in both themes beats two. */
  outline: 3px solid var(--accent-default);
  outline-offset: 2px;
  border-radius: var(--radius-sm);
}

@media (prefers-reduced-motion: reduce) {
  * { transition: none !important; }
  .btn:hover, .card:hover { transform: none; }
}

/* Label for a figure group. Two studies sit on the home page and running their
   figures together implied one study with the wrong n; the labels are what keep
   them apart. */
.figs-label {
  font-size: .78rem; font-weight: 700; letter-spacing: .08em; text-transform: uppercase;
  color: var(--fg-muted); margin: 1.5rem 0 .6rem;
}
.figs-label:first-of-type { margin-top: 0; }

/* Current-page indication. Colour alone is not an indicator: the underline carries it
   for anyone who cannot distinguish the two colours, and aria-current carries it for
   anyone not looking at all. */
header.site nav a.here {
  color: var(--fg-default);
  border-bottom: 2px solid var(--accent-default);
  padding-bottom: 2px;
}

/* /sample's provenance list. A definition list is the right element for
   label/value pairs and the default rendering is an indented block, which reads
   as an afterthought next to the claims above it. */
dl.meta {
  display: grid; grid-template-columns: max-content 1fr; gap: .35rem 1.25rem;
  margin: 1rem 0 1.5rem; font-size: .93rem;
}
dl.meta dt { font-weight: 650; color: var(--fg-muted); }
dl.meta dd { margin: 0; }
@media (max-width: 34rem) { dl.meta { grid-template-columns: 1fr; gap: .1rem .5rem; } }
.sample-note { font-size: .88rem; color: var(--fg-muted); margin: .35rem 0 0; }
