/* cybernotes.it — Redesign v2, non-critical styles.
 *
 * Every colour, font and measure here comes from a var() defined in the inline
 * critical block (pages/templates/pages/_critical_css.html). Nothing is
 * redefined, so there is one place to change a token and no drift between the
 * inline block and this file.
 *
 * Plain hand-written CSS, no framework and no build step — the convention on
 * every site in this stack.
 *
 * NO MEDIA QUERIES except the reduced-motion rule in the critical block. The
 * layout is single and fluid and has to hold at 320px. Five rules do that work
 * and every one of them is load-bearing:
 *
 *   1. Every minmax() floor is collapsible — minmax(min(100%, 320px), 1fr),
 *      never minmax(320px, 1fr). A bare floor plus 28px of container padding
 *      overflows a 320px viewport.
 *   2. Two-pane rows wrap. The article + contents row is a wrapping flex, not
 *      a two-track grid: a fixed 250px sidebar track starves the article
 *      column to zero on a phone.
 *   3. Part rows are wrapping flex with `flex: 1 1 220px; min-width: 0` on the
 *      title. A `46px minmax(0,1fr) auto` grid keeps the nowrap meta column at
 *      full width and collapses the title instead.
 *   4. The header row wraps (min-height, not height).
 *   5. Long values — the client secret — scroll INSIDE their chip:
 *      `overflow-x: auto; min-width: 0`.
 *
 * The one fixed two-track grid on the site is the series page's four part
 * cards, because four items in two tracks never orphans one.
 */

/* --- Typography primitives ------------------------------------------------ */

h1, h2, h3, h4 { font-weight: 600; }

.h1 {
  margin: 0;
  font-size: clamp(28px, 3.6vw, 40px);
  line-height: 1.12;
  letter-spacing: -1.1px;
  font-weight: 600;
  max-width: 26ch;
  text-wrap: pretty;
}
/* Home only. Bigger, tighter, and balanced rather than pretty — it is three
 * short lines and balance is what stops the last one being a single word. */
.h1--home {
  font-size: clamp(30px, 4vw, 44px);
  line-height: 1.1;
  letter-spacing: -1.2px;
  max-width: 22ch;
  text-wrap: balance;
}
/* `specify` in the home headline. An <em> that is not italic — the emphasis is
 * carried by colour, and the tag is there because the word is genuinely
 * emphasised rather than decorated. */
.h1 em { font-style: normal; color: var(--accent); }

.lede {
  margin: 18px 0 0;
  font-size: 17px;
  line-height: 1.55;
  color: var(--fg-muted);
  max-width: 68ch;
  text-wrap: pretty;
}

/* Every body section opens with one of these. It is the section's <h2>: the
 * kicker IS the heading, so the outline and the visible structure are the same
 * thing rather than two things that can disagree. */
.kicker {
  margin: 0;
  font-family: var(--font-mono);
  font-size: 12.5px;
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.14em;
  color: var(--fg-dim);
}

/* The section's first paragraph. */
.statement {
  margin: 20px 0 0;
  font-size: 19px;
  line-height: 1.5;
  letter-spacing: -0.3px;
  color: var(--fg);
  max-width: 62ch;
  text-wrap: pretty;
}
.statement--wide { max-width: 74ch; }
/* A button on its own line after a statement or a paragraph. */
.statement + p, .prose + p { margin: 26px 0 0; }
.statement--narrow { max-width: 50ch; }
.statement--tight { max-width: 56ch; }

/* --- Prose ---------------------------------------------------------------- */

/* Markdown-rendered body copy. The content files are the source of truth and
 * are never edited to suit a template, so this styles what they already
 * produce: paragraphs, bold lead-ins, lists and links. */
.prose { margin: 0; }

/* THE GAP UNDER A SECTION KICKER, and it is 20px because the design says 20px
 * — measured off the prototype, where every section's first element carries
 * `margin: 20px 0 0` outside a panel and `18px` inside one.
 *
 * This rule used to be `margin-top: 0`, borrowed from the "prose inside a card"
 * case, and it silently closed that gap to ZERO on every section rendered
 * through pages/_prose_rows.html — measured at 0px on four sections of a part
 * page. That is the "body text is too close to the section title" this fixes. */
.prose > :first-child { margin-top: 20px; }
.panel .prose > :first-child { margin-top: 18px; }
.prose > :last-child { margin-bottom: 0; }
.prose p {
  margin: 18px 0 0;
  font-size: 16px;
  color: var(--fg-muted);
  max-width: 68ch;
  text-wrap: pretty;
}
.prose strong { color: var(--fg); font-weight: 600; }
.prose ul, .prose ol { margin: 16px 0 0; padding-left: 22px; max-width: 72ch; }
.prose li { margin-bottom: 10px; color: var(--fg-muted); }
.prose li::marker { color: var(--fg-dim); }

/* Prose whose first paragraph is the section STATEMENT rather than body copy:
 * 19px, --fg, tightened tracking. Not every section has one — the design opens
 * "What this is", "Free, and reusable", "Who is writing this" and "What you
 * should be able to do afterwards" this way, and opens "Working through it",
 * "Where this session stops" and "Next" with ordinary 16px body copy instead.
 * So this is applied per section id from the views, not globally. */
.prose--statement > p:first-child {
  font-size: 19px;
  line-height: 1.5;
  letter-spacing: -0.3px;
  color: var(--fg);
  max-width: 62ch;
}

/* The abstract under the outcomes list. 16px in --fg, not the 19px statement:
 * it is a summary of the session, and the design distinguishes it from a
 * section's opening thesis by weight of colour alone. 26px of air above it
 * separates it from the bullet list. */
.summary > p:first-child { margin-top: 26px; color: var(--fg); max-width: 70ch; }
.summary p { max-width: 70ch; }

/* The series page's opening paragraphs: their own section, no kicker, so the
 * section's 48px padding is the space above them and the first paragraph needs
 * none of its own. */
.prose--lead > p:first-child { margin-top: 0; }

/* A single-column list of bold-lead-in paragraphs. Single column deliberately
 * where the count is odd — three items in a two-track grid orphans one. */
.leads {
  display: flex;
  flex-direction: column;
  gap: 22px;
  margin: 26px 0 0;
  max-width: 76ch;
}
.leads p { margin: 0; font-size: 16px; color: var(--fg-muted); text-wrap: pretty; }
.leads strong { color: var(--fg); font-weight: 600; }

/* "What I am not" opens with a plain intro sentence and only THEN starts the
 * lead-in run. The design gives that paragraph its own measure (72ch against
 * the run's 76ch) and 26px of air beneath it, rather than folding it into the
 * 22px gap as if it were another item.
 *
 * Selected by shape, not by position: a lead-in item always begins with a
 * <strong>, an intro never does. "What it covers" and "The ground it covers"
 * have no intro at all, so a bare :first-child rule would wrongly re-style
 * their first item. */
.leads > p:first-child:not(:has(> strong:first-child)) {
  max-width: 72ch;
  margin-bottom: 4px;
}

/* Two or three tracks of the same. Six items divide evenly into 1, 2 and 3, so
 * auto-fit is safe here in a way it is not for four. */
.leads--grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 320px), 1fr));
  gap: 28px 48px;
  max-width: none;
}

/* Inline code inside prose. A chip, not a block. */
.prose code, .code-chip {
  padding: 2px 7px;
  border-radius: 4px;
  background: var(--surface-2);
  font-family: var(--font-mono);
  font-size: 13.5px;
  color: var(--fg);
  white-space: nowrap;
}

/* --- Breadcrumb ----------------------------------------------------------- */

.crumb {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  margin: 0 0 18px;
  font-family: var(--font-mono);
  font-size: 13px;
}
.crumb a { color: var(--fg-dim); }
.crumb a:hover { color: var(--fg); }
/* The separator is decorative and aria-hidden in the template; the current
 * page is plain text and never a link. */
.crumb__sep { color: var(--fg-dim); }
.crumb__here { color: var(--fg-muted); }

/* --- Buttons -------------------------------------------------------------- */

.btn {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  padding: 11px 19px;
  border-radius: 8px;
  font-size: 14.5px;
  font-weight: 600;
  text-decoration: none;
  border: 0;
  cursor: pointer;
  font-family: inherit;
}
.btn:hover { text-decoration: none; }

.btn--primary { background: var(--accent); color: var(--accent-ink); }
.btn--primary:hover { filter: brightness(1.06); color: var(--accent-ink); }

/* The form/action variant of primary: slightly larger and heavier, because it
 * submits rather than navigates. */
.btn--action { padding: 13px 22px; font-size: 15px; font-weight: 700; }

.btn--secondary {
  background: var(--surface);
  border: 1px solid var(--border-strong);
  color: var(--fg);
  font-weight: 500;
}
.btn--secondary:hover { border-color: var(--accent); color: var(--fg); }

.btn--outline {
  padding: 12px 20px;
  border: 1px solid var(--border-strong);
  background: transparent;
  color: var(--accent-text);
  font-size: 15px;
  font-weight: 700;
}
.btn--outline:hover { border-color: var(--accent); color: var(--accent-text); }

.btn--small {
  padding: 8px 14px;
  border-radius: 6px;
  border: 1px solid var(--border-strong);
  background: transparent;
  color: var(--fg);
  font-size: 13.5px;
  font-weight: 600;
}
.btn--small:hover { border-color: var(--accent); color: var(--fg); }

.btn[disabled] { opacity: .45; cursor: not-allowed; }
.btn[disabled]:hover { filter: none; }

.btn-row { display: flex; flex-wrap: wrap; align-items: center; gap: 18px; margin: 26px 0 0; }

/* A text link that reads as a next step. */
.text-link { display: inline-block; margin: 22px 0 0; font-size: 15px; font-weight: 600; }

/* --- Panel card ----------------------------------------------------------- */

/* The single card treatment across the site. */
.panel {
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 24px;
  background: var(--surface);
  box-shadow: var(--shadow);
}
.panel > :first-child { margin-top: 0; }
.panel > :last-child { margin-bottom: 0; }

/* --- Callout -------------------------------------------------------------- */

.callout {
  padding: 18px 22px;
  border-left: 3px solid var(--accent);
  border-radius: 0 8px 8px 0;
  background: var(--surface);
  font-size: 16px;
  color: var(--fg-muted);
}
.callout { margin: 26px 0 0; }
.callout p { margin: 0; text-wrap: pretty; }
.callout p + p { margin-top: 12px; }
.callout strong { color: var(--fg); font-weight: 600; }
/* Mint, and used in exactly one place: the "everything here is synthetic"
 * notice. A second colour that means one thing stays meaning that one thing. */
.callout--mint { border-left-color: var(--accent-2); }

/* --- Code block ----------------------------------------------------------- */

/* white-space: pre AND overflow-x: auto. A long token command has to scroll,
 * not clip and not widen the page. */
pre, .code {
  margin: 0;
  padding: 18px 20px;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--surface);
  font-family: var(--font-mono);
  font-size: 13px;
  line-height: 1.75;
  color: var(--fg);
  white-space: pre;
  overflow-x: auto;
}
pre code {
  padding: 0;
  background: none;
  font-size: inherit;
  white-space: inherit;
  color: inherit;
}

/* --- Part row list -------------------------------------------------------- */

/* Home ("Available now") and the trainings index series panel. Eight rows
 * total across the two pages, from one include. */
.parts {
  margin: 22px 0 0;
  padding: 0;
  list-style: none;
  border: 1px solid var(--border);
  border-radius: 10px;
  background: var(--surface);
  box-shadow: var(--shadow);
  overflow: hidden;
}
/* When the list sits inside the trainings series panel it is the panel's lower
 * half, so it drops its own frame. */
.parts--in-panel {
  margin: 0;
  border: 0;
  border-radius: 0;
  background: none;
  box-shadow: none;
}
.parts > li + li { border-top: 1px solid var(--border); }

.part-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px 18px;
  padding: 20px 22px;
  color: inherit;
  text-decoration: none;
}
a.part-row:hover { background: var(--surface-2); color: inherit; text-decoration: none; }

.part-row__n {
  flex: 0 0 46px;
  font-family: var(--font-mono);
  font-size: 19px;
  color: var(--accent-text);
}
/* Parts 3 and 4: dim, and not a link anywhere on the site. */
.part-row--pending .part-row__n { color: var(--fg-dim); }

/* `flex: 1 1 220px; min-width: 0` — rule 3. Without min-width: 0 a long title
 * refuses to shrink below its longest word and pushes the row wider than the
 * viewport. */
.part-row__body { flex: 1 1 220px; min-width: 0; display: flex; flex-direction: column; gap: 3px; }
.part-row__title { font-size: 17.5px; font-weight: 600; letter-spacing: -0.3px; color: var(--fg); }
a.part-row:hover .part-row__title { color: var(--accent-text); }
.part-row--pending .part-row__title { color: var(--fg-muted); }
.part-row__sub { font-size: 14.5px; color: var(--fg-muted); }

.part-row__meta {
  flex: 0 0 auto;
  margin-left: auto;
  display: flex;
  align-items: center;
  gap: 14px;
}
.part-row__dur { font-family: var(--font-mono); font-size: 12.5px; color: var(--fg-muted); }

/* --- Status pills --------------------------------------------------------- */

/* The status is TEXT, always, and read in DOM order. Colour and shape are the
 * second and third channels, never the first. */
.pill {
  padding: 4px 10px;
  border-radius: 999px;
  font-size: 11px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  white-space: nowrap;
}
.pill--published {
  background: var(--accent-soft);
  border: 1px solid var(--accent);
  color: var(--accent-text);
}
.pill--pending {
  background: var(--surface-2);
  border: 1px solid var(--border-strong);
  color: var(--fg-dim);
}
/* Staging only. Amber fill with fixed dark ink, the same treatment as the
 * staging banner, because it means the same thing: this is not the live site.
 * series_parts() sets `draft` nowhere but staging, so this cannot render in
 * production — there is no truthy value to render it from. */
.pill--draft {
  background: var(--accent);
  border: 1px solid var(--accent);
  color: var(--accent-ink);
}

/* --- Home: the numbered feature grid -------------------------------------- */

/* "How it is put together". Five items; auto-fit with a collapsible floor.
 *
 * The 01–05 indices are a CSS counter, not content. The content file writes
 * five bold-lead-in paragraphs and nothing else, and generating the numbers
 * here is what lets the design have them without a template inventing prose or
 * a helper rewriting it. Add a sixth paragraph upstream and it numbers itself.
 */
.features {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 290px), 1fr));
  gap: 32px 52px;
  margin: 30px 0 0;
  counter-reset: feature;
}
.features p {
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: 8px;
  max-width: none;
  font-size: 15.5px;
  color: var(--fg-muted);
  text-wrap: pretty;
  counter-increment: feature;
}
.features p::before {
  content: counter(feature, decimal-leading-zero);
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--accent-text);
}
/* The lead-in becomes the item heading. It is the content's own <strong>, not
 * a synthesised <h3>: the copy rules forbid editing prose to suit a template,
 * and promoting a sentence to a heading is an edit to the document even when
 * it is not an edit to the words. Visually identical to the handoff. */
.features strong {
  display: block;
  font-size: 17.5px;
  font-weight: 600;
  line-height: 1.3;
  letter-spacing: -0.3px;
  color: var(--fg);
}

/* --- Trainings index: the series panel ------------------------------------ */

.series-panel {
  margin: 0;
  border: 1px solid var(--border);
  border-radius: 10px;
  background: var(--surface);
  box-shadow: var(--shadow);
  overflow: hidden;
}
.series-panel__head { padding: 24px 22px; border-bottom: 1px solid var(--border); }
.series-title {
  margin: 0;
  font-size: 23px;
  line-height: 1.25;
  letter-spacing: -0.7px;
  font-weight: 600;
}
/* On the home page the series title follows the section kicker directly and
 * needs the same 20px the statement gets. Inside the trainings panel head it
 * is the first child and keeps margin 0. */
.kicker + .series { margin-top: 20px; }
.series-title a { color: var(--fg); }
.series-title a:hover { color: var(--accent-text); text-decoration: none; }
.series-desc { margin: 12px 0 0; font-size: 16px; color: var(--fg-muted); max-width: 72ch; text-wrap: pretty; }

/* --- Series page: the four part cards ------------------------------------- */

/* THE ONE FIXED TWO-TRACK GRID ON THE SITE. Four items in two tracks never
 * orphans one; auto-fit would give three columns at ~1100px and leave the
 * fourth alone on a row. Do not "fix" this to auto-fit. */
.part-cards {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 16px;
  margin: 26px 0 0;
  padding: 0;
  list-style: none;
}
.part-card {
  display: flex;
  flex-direction: column;
  gap: 8px;
  height: 100%;
  padding: 24px;
  border: 1px solid var(--border);
  border-top: 3px solid var(--accent);
  border-radius: 10px;
  background: var(--surface);
  box-shadow: var(--shadow);
  color: inherit;
  text-decoration: none;
}
a.part-card:hover { border-color: var(--accent); color: inherit; text-decoration: none; }
/* The solid 3px top border is kept on the pending cards so all four boxes are
 * the same height; only its colour and the side borders change. */
.part-card--pending {
  border: 1px dashed var(--border-strong);
  border-top: 3px solid var(--border-strong);
  background: transparent;
  box-shadow: none;
  color: var(--fg-muted);
}
.part-card__top { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 12px; }
.part-card__n { font-family: var(--font-mono); font-size: 12px; color: var(--fg-muted); }
.part-card__title { margin: 0; font-size: 17px; line-height: 1.3; letter-spacing: -0.3px; font-weight: 600; color: var(--fg); }
a.part-card:hover .part-card__title { color: var(--accent-text); }
.part-card--pending .part-card__title { color: var(--fg-muted); }
.part-card__sub { margin: 0; font-size: 14.5px; color: var(--fg-muted); text-wrap: pretty; }
.part-card__meta { margin: auto 0 0; padding-top: 6px; font-family: var(--font-mono); font-size: 12px; color: var(--fg-muted); }
/* The status on a series card is TEXT, not a pill — the pill is the part row's
 * treatment. The card's own amber top border is the second channel, and the
 * words are the first. */
.part-card__status {
  margin-left: auto;
  font-size: 11px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  white-space: nowrap;
  color: var(--accent-text);
}
.part-card__status--pending { color: var(--fg-dim); }
/* The staging draft badge stays a pill: it is a warning, and it is meant to be
 * louder than the resting design. */
.part-card__top .pill { margin-left: auto; }

/* --- Two-pane rows -------------------------------------------------------- */

/* Text left, panel card right. auto-fit with a collapsible floor: at 320px
 * both panes are one full-width column, with no breakpoint deciding it. */
.two-pane {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 320px), 1fr));
  gap: 48px;
  align-items: start;
}

/* --- Training detail ------------------------------------------------------ */

.eyebrow {
  margin: 0 0 10px;
  font-family: var(--font-mono);
  font-size: 13px;
  color: var(--accent-text);
}

/* Duration / Level / Cost, then Prerequisites across the full width. */
.meta-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 190px), 1fr));
  gap: 20px 32px;
  margin: 32px 0 0;
  padding-top: 22px;
  border-top: 1px solid var(--border);
}
.meta-grid dt {
  font-family: var(--font-mono);
  font-size: 11.5px;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--fg-dim);
}
.meta-grid dd { margin: 4px 0 0; font-size: 16px; color: var(--fg); }
/* Prerequisites is two or three sentences of prose, not a phrase — it spans
 * the whole grid rather than being truncated into a column. */
.meta-grid__wide { grid-column: 1 / -1; }
.meta-grid__wide dd { color: var(--fg-muted); }
.meta-grid__wide p { margin: 4px 0 0; max-width: 72ch; }

.deck-note { margin: 14px 0 0; font-size: 14.5px; color: var(--fg-dim); max-width: 68ch; }

/* Article + contents. WRAPPING FLEX, not a two-track grid — rule 2. A fixed
 * 250px sidebar track starves the article column to zero on a narrow screen;
 * `flex: 1 1 420px` lets the sidebar drop below instead. */
.detail__main {
  display: flex;
  flex-wrap: wrap;
  gap: 56px;
  align-items: flex-start;
}
.detail__content { flex: 1 1 420px; min-width: 0; }
.detail__toc { flex: 0 1 250px; }

.toc {
  position: sticky;
  /* Clears the sticky header. */
  top: 76px;
}
.toc__label {
  margin: 0 0 12px;
  font-family: var(--font-mono);
  font-size: 11.5px;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--fg-dim);
}
.toc__list { margin: 0; padding-left: 20px; }
.toc__list li { margin-bottom: 8px; }
.toc__list li::marker { color: var(--fg-dim); font-size: 12px; }
.toc__list a { font-size: 14px; }

.outcomes { margin: 20px 0 0; padding-left: 22px; }
.outcomes li { margin-bottom: 10px; font-size: 16px; color: var(--fg-muted); }
.outcomes li::marker { color: var(--fg-dim); }

/* Anchor targets land under the sticky header without this. */
.detail__content :is(h2, h3), .section { scroll-margin-top: 76px; }

/* Further reading, inside a panel. */
/* Materials list. No training carries materials today, so this renders on no
 * page yet — styled anyway, because the alternative is the first one that does
 * arriving unstyled. */
.material-list__desc { display: block; font-size: 15px; color: var(--fg-muted); }

.further { margin: 0; padding-left: 22px; }
.further li { margin-bottom: 14px; font-size: 16px; color: var(--fg-muted); }
.further li:last-child { margin-bottom: 0; }
.further strong { color: var(--fg); font-weight: 600; }

/* Next / previous. */
.pager-card {
  display: flex;
  flex-direction: column;
  gap: 6px;
  max-width: 460px;
  margin: 24px 0 0;
  padding: 24px;
  border: 1px solid var(--border);
  border-radius: 10px;
  background: var(--surface);
  box-shadow: var(--shadow);
  text-decoration: none;
}
.pager-card:hover { border-color: var(--accent); text-decoration: none; }
.pager-card__dir { font-family: var(--font-mono); font-size: 12px; color: var(--fg-dim); }
.pager-card__title { font-size: 17px; font-weight: 600; color: var(--accent-text); }

/* --- Demo API: tabs ------------------------------------------------------- */

/* THE NO-JS CONTRACT, and it is the default state of this stylesheet:
 *
 *   - every panel is visible, stacked, each under its own visible heading;
 *   - the tab bar is NOT shown, because a row of buttons that does nothing is
 *     worse than no row at all.
 *
 * `[data-tabs="on"]` is set by config/inline_scripts/tabs.js, synchronously in
 * <head>, before first paint. Everything below that selector is the enhanced
 * state. The script that sets the marker is the same file that wires the
 * behaviour up, so there is no arrangement in which the marker is set and the
 * tabs do not work.
 *
 * The handoff's prototype keeps only the active panel in the DOM. This does
 * not: all four are server-rendered, so the page stays one indexable document
 * and a crawler sees all four routes. Deviation noted in the summary. */
.tabs { margin: 30px 0 0; }
.tabs__list { display: none; }
.tabs__panel { margin-top: 32px; }
.tabs__panel-title { margin: 0 0 16px; font-size: 17px; }

:root[data-tabs="on"] .tabs__list {
  display: flex;
  flex-wrap: wrap;
  gap: 2px;
  border-bottom: 1px solid var(--border);
}
:root[data-tabs="on"] .tabs__panel { display: none; margin-top: 0; padding: 26px 0 0; }
:root[data-tabs="on"] .tabs__panel.is-active { display: block; }
/* With the tab bar showing, the tab already names the panel through
 * aria-labelledby; repeating it as a heading reads as a stutter. */
:root[data-tabs="on"] .tabs__panel-title { display: none; }

.tabs__tab {
  padding: 12px 18px;
  margin-bottom: -1px;
  border: 0;
  border-bottom: 3px solid transparent;
  border-radius: 8px 8px 0 0;
  background: transparent;
  color: var(--accent-text);
  font-family: inherit;
  font-size: 15px;
  font-weight: 600;
  cursor: pointer;
  transition: color .15s ease, background .15s ease;
}
/* Three selection indicators and none of them colour alone: a 3px underline, a
 * filled background, and a heavier weight. Colour is the fourth. */
.tabs__tab[aria-selected="true"] {
  background: var(--surface);
  color: var(--fg);
  font-weight: 700;
  border-bottom-color: var(--accent);
}

/* The panel is a tab stop so its content is reachable from the keyboard
 * whatever it contains, which means it needs a focus ring of its own. */
.tabs__panel:focus-visible { outline: 2px solid var(--accent-text); outline-offset: 4px; }

/* Top margin, not only bottom. Before the credentials are issued #cred-output
 * is hidden, so "Copy the secret now." follows the button row directly — with
 * bottom-only margins it sat against the button. */
.tabs__panel > p { margin: 18px 0 0; font-size: 16px; color: var(--fg-muted); max-width: 74ch; text-wrap: pretty; }
.tabs__panel > p:first-child { margin-top: 0; }
.tabs__panel strong { color: var(--fg); font-weight: 600; }
.tabs__panel pre { margin: 0 0 20px; }
.tabs__panel ol { margin: 0 0 20px; padding-left: 22px; max-width: 74ch; }
.tabs__panel ol li { margin-bottom: 12px; font-size: 16px; color: var(--fg-muted); }
.tabs__panel ol li::marker { color: var(--fg-dim); }
.tabs__panel em { font-style: normal; color: var(--fg); font-weight: 600; }
.tabs__panel .callout { margin: 0 0 20px; }

/* Two hero callouts side by side, collapsing to one column with no
 * breakpoint. */
.hero-callouts {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 300px), 1fr));
  gap: 16px;
  margin: 30px 0 0;
}
/* Inside the hero the surface token is a translucent white, so these read as
 * panels on the gradient rather than as a second flat colour. */
.hero-callouts .callout { margin: 0; border-radius: 0 8px 8px 0; }

/* --- Demo API: credentials ------------------------------------------------ */

/* The two halves of the no-JS contract for the issue button. BOTH are in the
 * served HTML; `data-credentials` decides which one is visible, and
 * demo-credentials.js sets it synchronously in <head> so neither state is
 * painted and then replaced.
 *
 * Default = JS off: no button, and a real link to the Swagger operation that
 * issues credentials. A button that cannot do anything is worse than a link
 * that can. */
.cred-issue { display: none; }
:root[data-credentials="on"] .cred-issue { display: inline-flex; }
:root[data-credentials="on"] .cred-nojs { display: none; }

.cred-status { margin: 0; font-size: 15.5px; font-weight: 600; color: var(--fg-muted); }
.cred-status--ok { color: var(--fg); }
.cred-status--pending { color: var(--fg-muted); }
/* The message itself says what went wrong, so colour is never the only
 * channel carrying the failure. */
.cred-status--error { color: var(--accent-text); }

.cred-fields { display: flex; flex-direction: column; gap: 12px; margin: 26px 0 0; }
.cred-row { display: flex; flex-wrap: wrap; align-items: center; gap: 12px; }
.cred-row__label { flex: 0 0 120px; font-size: 15.5px; font-weight: 600; color: var(--fg); }
/* Rule 5: a 43-character secret scrolls INSIDE this chip. `min-width: 0` is
 * what allows the flex item to shrink below its content width; without it the
 * chip widens the row and the row widens the page. */
.cred-row__value {
  /* NO flex-grow. The design sizes this to its content — `min-width: 0` with
   * an `auto` basis — so the chip is as wide as the value and no wider. With
   * `flex: 1 1 auto` it stretched to the full row, which put a 12-character
   * client id in a chip several hundred pixels wide.
   *
   * min-width: 0 is still what lets it shrink BELOW its content when the
   * viewport is narrow, which is what makes the secret scroll inside the chip
   * at 320px instead of widening the page. */
  min-width: 0;
  padding: 8px 12px;
  border-radius: 6px;
  background: var(--surface-2);
  font-family: var(--font-mono);
  font-size: 13.5px;
  color: var(--fg);
  white-space: nowrap;
  overflow-x: auto;
}

/* --- Specs page ----------------------------------------------------------- */

.spec-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 280px), 1fr));
  gap: 16px;
  margin: 30px 0 0;
  padding: 0;
  list-style: none;
}
.spec-card {
  display: flex;
  flex-direction: column;
  gap: 8px;
  height: 100%;
  padding: 24px;
  border: 1px solid var(--border);
  border-radius: 10px;
  background: var(--surface);
  box-shadow: var(--shadow);
  text-decoration: none;
}
.spec-card:hover { border-color: var(--accent); text-decoration: none; }
.spec-card__title { margin: 0; font-size: 17px; line-height: 1.3; letter-spacing: -0.3px; font-weight: 600; }
.spec-card__title a { color: var(--fg); }
.spec-card:hover .spec-card__title a, .spec-card__title a:hover { color: var(--accent-text); text-decoration: none; }

/* ONE INLINE RUN, not a flex row.
 *
 * The separators are bound to the segment before them with a non-breaking
 * space in the template, so a wrap can only fall AFTER a separator. A flex row
 * with gaps drops lines that begin with a stray "·", which is what this
 * replaced. */
.spec-card__meta {
  margin: 0;
  font-family: var(--font-mono);
  font-size: 12.5px;
  line-height: 1.9;
  color: var(--fg-dim);
}
.spec-card__meta code {
  padding: 2px 7px;
  border-radius: 4px;
  background: var(--surface-2);
  font-size: 12.5px;
  color: var(--fg);
}
.spec-card__desc { margin: 0; font-size: 15px; color: var(--fg-muted); text-wrap: pretty; }

/* --- About: the contact form ---------------------------------------------- */

.form { display: flex; flex-direction: column; gap: 18px; }
.field { display: flex; flex-direction: column; gap: 8px; }
.field__label {
  font-family: var(--font-mono);
  font-size: 11.5px;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--fg-dim);
}
/* `background: var(--bg)` — darker than the card the field sits in, so the
 * input reads as a well rather than a raised block. box-sizing is inherited
 * from the global reset and is required, or `width: 100%` plus padding
 * overflows the card. */
.field input, .field textarea {
  padding: 12px 14px;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--bg);
  color: var(--fg);
  font-family: inherit;
  font-size: 16px;
  width: 100%;
}
.field textarea { line-height: 1.55; resize: vertical; }
.field input:focus, .field textarea:focus { border-color: var(--accent); outline: none; }
/* :focus-visible still draws the global ring for keyboard users; the border
 * colour above is the mouse-and-keyboard-alike affordance the design asks for. */
.field input:focus-visible, .field textarea:focus-visible {
  outline: 2px solid var(--accent-text);
  outline-offset: 3px;
}
.field input::placeholder, .field textarea::placeholder { color: var(--fg-dim); }

/* Field-level errors. The message is words, and it is bound to the control
 * with aria-describedby — the red-ish tint is the second channel, never the
 * first. */
.field--invalid input, .field--invalid textarea { border-color: var(--accent); }
.field__error { font-size: 14.5px; color: var(--accent-text); }
.form__error {
  margin: 0;
  padding: 14px 16px;
  border-left: 3px solid var(--accent);
  border-radius: 0 8px 8px 0;
  background: var(--surface-2);
  font-size: 15px;
  color: var(--fg);
}

.form .btn { align-self: flex-start; padding: 13px 24px; }

.thanks { display: flex; flex-direction: column; gap: 12px; }
/* `.thanks p.thanks__title`, and every part of that selector is load-bearing.
 *
 * `.thanks p` below sets font-size and color at specificity 0,1,1. A bare
 * `.thanks__title` is 0,1,0 and loses outright. `p.thanks__title` TIES at
 * 0,1,1 — and a tie is decided by source order, so `.thanks p` still won and
 * the confirmation rendered as 16px muted body copy while quietly keeping the
 * weight and tracking from this rule. Measured, after that first attempt
 * failed to change anything.
 *
 * 0,2,1 wins outright, wherever the rules sit. */
.thanks p.thanks__title {
  margin: 0;
  font-size: 26px;
  line-height: 1.2;
  letter-spacing: -0.6px;
  font-weight: 600;
  color: var(--accent-text);
}
.thanks p { margin: 0; font-size: 16px; color: var(--fg-muted); }

/* The honeypot. Off-screen rather than display:none — a bot that reads
 * computed styles skips a hidden field, and this one is meant to be filled in.
 * aria-hidden and tabindex="-1" in the template keep it away from anyone real. */
.hp {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

/* --- Staging marker ------------------------------------------------------- */

/* Loud on purpose. Someone looking at staging must never spend a minute
 * wondering whether they are looking at production. */
.staging-banner {
  margin: 0;
  padding: 8px var(--gut);
  background: var(--accent);
  color: var(--accent-ink);
  font-size: 15px;
  font-weight: 600;
  text-align: center;
}

/* --- Footer --------------------------------------------------------------- */

.site-footer { background: var(--band); border-top: 1px solid var(--border); }
.site-footer__inner {
  max-width: var(--maxw);
  margin: 0 auto;
  padding: 48px var(--gut);
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 20px;
}
.site-footer__nav ul {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 22px;
  margin: 0;
  padding: 0;
  list-style: none;
}
.site-footer__nav a { font-size: 14px; color: var(--fg-muted); }
.site-footer__nav a:hover { color: var(--fg); }
.site-footer__meta { margin: 0; font-size: 13px; color: var(--fg-dim); }
/* The licence link keeps the site's link colour. It was overridden to --fg-dim,
 * which made it indistinguishable from the sentence around it — the one thing
 * an inline link must not be. */
.site-footer__meta a { color: var(--accent-text); }
