/*
  components.css — one rule block per class in docs/build-contract.md §5. Flat surfaces only
  (box-shadow: none everywhere, per brand/visual-identity.md §3.3 — direction A never lifts a
  card). Status colour comes from data-status; the maturity label text is never conveyed by
  colour alone (brand/visual-identity.md §3.2).
*/

/* skip link — first element in <body>, visible only on focus */
.skip-link {
  position: absolute;
  top: -3rem;
  left: var(--space-4);
  z-index: 100;
  background: var(--surface);
  color: var(--text-primary);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: var(--space-2) var(--space-4);
  box-shadow: none;
}

.skip-link:focus {
  top: var(--space-4);
}

/* site header */
.site-header {
  background: var(--surface);
  border-bottom: 1px solid var(--border);
  box-shadow: none;
}

.site-header .container {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
  padding-top: var(--space-4);
  padding-bottom: var(--space-4);
  flex-wrap: wrap;
}

/* Narrow viewports (G5.5, 390px pass): the header's three children wrap one per line, so the
   wordmark, the six nav links and the theme toggle each took a row and the toggle ended up alone
   on the left under the navigation. Giving the nav its own full-width row keeps the wordmark and
   the toggle on the first line, the arrangement a reader expects, and drops the header from three
   rows to two. Desktop (>= 768px) keeps the single-row space-between layout untouched. */
@media (max-width: 767px) {
  .site-header .container {
    row-gap: var(--space-3);
  }

  .site-header__wordmark {
    order: 1;
  }

  .site-header .theme-toggle {
    order: 2;
  }

  .site-header .site-nav {
    order: 3;
    flex-basis: 100%;
  }
}

.site-header__wordmark {
  display: inline-flex;
  align-items: center;
}

.site-header__wordmark-img {
  height: 1.75rem;
  width: auto;
}

/* icon set — Lucide, inlined by partials.mjs#renderIcon (brand/visual-identity.md §3.5) */
.icon {
  display: inline-block;
  flex-shrink: 0;
  vertical-align: -0.2em;
}

.icon--20 {
  width: 1.25rem;
  height: 1.25rem;
}

.icon--24 {
  width: 1.5rem;
  height: 1.5rem;
}

/* primary navigation */
.site-nav {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-4);
}

.site-nav ul {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-4);
  margin: 0;
  padding: 0;
  list-style: none;
}

.site-nav a {
  color: var(--text-secondary);
  text-decoration: none;
  font-weight: var(--weight-medium);
  font-size: var(--text-sm);
  padding: var(--space-1) 0;
  border-bottom: 2px solid transparent;
}

.site-nav a:hover {
  color: var(--text-primary);
}

.site-nav a[aria-current="page"] {
  color: var(--text-primary);
  border-bottom-color: var(--accent);
}

/* A page inside a navigated section (e.g. /verticals/<id>/ under "Verticals"): the same colour
   promotion, a lighter rule, so the section reads as active without claiming to be the page. */
.site-nav a[aria-current="true"] {
  color: var(--text-primary);
  border-bottom-color: var(--border-strong, var(--border));
}

/* theme toggle control (wired by site/src/js/app.js) */
.theme-toggle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: 1px solid var(--border);
  background: var(--surface-alt);
  color: var(--text-primary);
  border-radius: var(--radius-pill);
  padding: var(--space-2);
  box-shadow: none;
}

.theme-toggle:hover {
  border-color: var(--accent);
}

/*
  Theme-aware image swaps (wordmark, theme-toggle icon) — same rule shape as tokens.css's own
  palette swap (plan §0.3 "Theme-aware"): light wins on bare :root and under an explicit
  data-theme="light"; dark wins under the OS preference (unless data-theme="light" overrides it)
  and under an explicit data-theme="dark". Kept together here because every pair below is toggled
  by the same three selectors.
*/
.site-header__wordmark-img--dark,
.site-footer__wordmark-img--dark,
.theme-toggle__icon--moon {
  display: none;
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .site-header__wordmark-img--light,
  :root:not([data-theme="light"]) .site-footer__wordmark-img--light,
  :root:not([data-theme="light"]) .theme-toggle__icon--sun {
    display: none;
  }

  :root:not([data-theme="light"]) .site-header__wordmark-img--dark,
  :root:not([data-theme="light"]) .site-footer__wordmark-img--dark,
  :root:not([data-theme="light"]) .theme-toggle__icon--moon {
    display: inline-block;
  }
}

:root[data-theme="dark"] .site-header__wordmark-img--light,
:root[data-theme="dark"] .site-footer__wordmark-img--light,
:root[data-theme="dark"] .theme-toggle__icon--sun {
  display: none;
}

:root[data-theme="dark"] .site-header__wordmark-img--dark,
:root[data-theme="dark"] .site-footer__wordmark-img--dark,
:root[data-theme="dark"] .theme-toggle__icon--moon {
  display: inline-block;
}

/* site footer */
.site-footer {
  background: var(--surface-alt);
  border-top: 1px solid var(--border);
  margin-top: var(--space-8);
}

.site-footer .container {
  padding-top: var(--space-6);
  padding-bottom: var(--space-6);
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
}

.site-footer__wordmark {
  display: inline-flex;
  align-items: center;
}

.site-footer__wordmark-img {
  height: 1.5rem;
  width: auto;
}

.site-nav--footer ul {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-4);
  margin: 0;
  padding: 0;
  list-style: none;
}

.site-nav--footer a {
  color: var(--text-secondary);
  text-decoration: none;
  font-size: var(--text-sm);
}

.site-nav--footer a:hover {
  color: var(--text-primary);
}

.site-footer__social {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-4);
  margin: 0;
  padding: 0;
  list-style: none;
}

.site-footer__social a,
.contact-block__channels a {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  color: var(--text-secondary);
  text-decoration: none;
  font-size: var(--text-sm);
}

.site-footer__social a:hover,
.contact-block__channels a:hover {
  color: var(--text-primary);
}

.site-footer__copyright {
  color: var(--text-secondary);
  font-size: var(--text-xs);
  margin-bottom: 0;
}

/* Every page except the home page opens with a bare <h1> directly under the header, and headings
   carry no top margin, so a 48-64px headline started about 15px below the header rule — tight
   enough to read as a rendering fault at 390 (G5.5). The home page's <h1> lives inside .hero,
   which has its own padding, so it is deliberately not matched here. */
main > .container > h1 {
  margin-top: var(--space-6);
}

/* Reading measure for page prose (G5.5, visual pass at 1440).
   The hero already caps its own lines (40rem headline, 36rem subhead), but nothing capped the
   page's body copy, so at 1440 every long paragraph ran the container's full 72rem — about 150
   characters per line on the About long story, the seven vertical prose sections and the home
   intro, roughly twice a comfortable measure. 44rem at 1rem/1.6 is ~70-75 characters, the same
   band the hero sits in. Scoped to direct page prose: components that manage their own width
   (project and vertical cards, CTA band, filter bar, profile block) are untouched. */
main > .container > p,
main > .container > section > p,
main > .container > section > ul,
main > .container > section > ol,
.services-offer > p {
  max-width: 44rem;
}

/* hero */
.hero {
  padding: var(--space-8) 0;
}

@media (min-width: 768px) {
  .hero {
    padding: var(--space-9) 0;
  }
}

.hero__headline {
  max-width: 40rem;
}

.hero__subhead {
  max-width: 36rem;
  color: var(--text-secondary);
  font-size: var(--text-md);
}

.hero__cta {
  margin-top: var(--space-5);
}

/* buttons (primary CTA) shared by hero, cta-band, contact-block */
.btn {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  border-radius: var(--radius-md);
  padding: var(--space-3) var(--space-5);
  font-weight: var(--weight-medium);
  text-decoration: none;
  border: 1px solid transparent;
  box-shadow: none;
}

.btn--primary {
  background: var(--accent);
  color: var(--text-on-accent);
}

.btn--primary:hover {
  background: var(--accent-hover);
  color: var(--text-on-accent);
}

.btn--secondary {
  background: transparent;
  color: var(--text-primary);
  border-color: var(--border);
}

.btn--secondary:hover {
  border-color: var(--accent);
  color: var(--accent);
}

/* card grids */
.vertical-card-grid,
.project-card-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-6);
}

@media (min-width: 768px) {
  .vertical-card-grid,
  .project-card-grid {
    grid-template-columns: repeat(2, 1fr);
  }
}

@media (min-width: 1440px) {
  .vertical-card-grid,
  .project-card-grid {
    grid-template-columns: repeat(3, 1fr);
  }
}

/* vertical card */
.vertical-card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  padding: var(--space-5);
  box-shadow: none;
  text-decoration: none;
  color: inherit;
  display: block;
}

.vertical-card:hover {
  border-color: var(--accent);
}

.vertical-card__name {
  font-weight: var(--weight-bold);
  font-size: var(--text-lg);
  color: var(--text-primary);
  margin-bottom: var(--space-2);
}

.vertical-card__proposition {
  color: var(--text-secondary);
}

.vertical-card__count {
  margin-top: var(--space-3);
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  color: var(--text-secondary);
}

/* project card */
.project-card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  padding: var(--space-5);
  box-shadow: none;
}

.project-card__figure {
  margin: var(--space-4) 0 0 0;
}

/* Natural aspect, not a forced 16:10 crop (G5.5, visual pass). The harvested product screenshots
   are wide UI strips — consultancy-ask-answer is 1600x345, a 4.6:1 ratio — and `aspect-ratio:16/10`
   with `object-fit: cover` scaled them up and cropped away two thirds of the width, so a card
   showed an unreadable middle slice with words cut through the middle of a character. `height:auto`
   against the img's own width/height attributes keeps each artefact whole and still reserves the
   right box before the image loads, so nothing shifts. */
.project-card__figure img {
  width: 100%;
  height: auto;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  box-shadow: none;
}

.project-card__no-artefact {
  border: 1px dashed var(--border);
  border-radius: var(--radius-md);
  margin: var(--space-4) 0 0 0;
  padding: var(--space-4);
  text-align: center;
  color: var(--text-secondary);
  font-size: var(--text-sm);
  font-style: italic;
  background: var(--surface-alt);
}

.project-card__name {
  font-weight: var(--weight-bold);
  font-size: var(--text-lg);
  margin-bottom: var(--space-2);
}

.project-card__disclosure {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  color: var(--text-secondary);
}

.project-card__summary,
.project-card__problem,
.project-card__does {
  color: var(--text-secondary);
}

.project-card__highlights {
  margin: var(--space-3) 0;
}

.project-card__stack {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  margin: var(--space-3) 0 0 0;
  padding: 0;
  list-style: none;
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  color: var(--text-secondary);
}

.project-card__stack li {
  background: var(--surface-alt);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: var(--space-1) var(--space-2);
}

/* wrapper list around the nested component lines below (G1.4F, KI-14/KI-15) */
.project-card__components {
  margin: 0;
  padding: 0;
  list-style: none;
}

/* nested component line inside a lead's project-card (G1.4F, KI-14/KI-15) */
.project-card__component {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  margin-top: var(--space-4);
  padding-top: var(--space-3);
  padding-left: var(--space-4);
  border-top: 1px solid var(--border);
  border-left: 2px solid var(--border);
  font-size: var(--text-sm);
}

.project-card__component-name {
  font-weight: var(--weight-medium);
}

/* maturity badge — colour by data-status; disclosure sentence always accompanies it in text */
.maturity-badge {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  font-weight: var(--weight-medium);
  border: 1px solid currentColor;
  border-radius: var(--radius-sm);
  padding: var(--space-1) var(--space-2);
  color: var(--text-secondary);
  background: transparent;
}

.maturity-badge[data-status="active"] {
  color: var(--status-active);
}

.maturity-badge[data-status="prototype"] {
  color: var(--status-prototype);
}

.maturity-badge[data-status="docs-only"] {
  color: var(--status-docs-only);
}

/* "Parked". `--status-dormant` is the only status token that does not clear the 4.5:1 body-text
   floor (3.66:1 in both themes, measured on the real build at 12px). brand/visual-identity.md §3.2
   chose that grey on the understanding that it would tint "a small dot or badge fill, never body
   text" — but the badge renders the label itself in the status colour, so the word "Parked" was
   failing. The border keeps the muted grey (the visual distinction the palette intended); the text
   falls back to --text-secondary, which clears 4.5:1 on every surface in both themes (G5.5). */
.maturity-badge[data-status="dormant"] {
  color: var(--text-secondary);
  border-color: var(--status-dormant);
}

/* cta band */
.cta-band {
  background: var(--surface-alt);
  border-radius: var(--radius-lg);
  padding: var(--space-7) var(--space-5);
  text-align: center;
  box-shadow: none;
}

@media (min-width: 768px) {
  .cta-band {
    padding: var(--space-8);
  }
}

.cta-band__link {
  margin: 0 auto;
}

/* profile block */
.profile-block {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  padding: var(--space-5);
  box-shadow: none;
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}

.profile-block__header-bio {
  font-weight: var(--weight-bold);
  font-size: var(--text-lg);
  margin-bottom: 0;
}

.profile-block__personal-note {
  color: var(--text-secondary);
  font-size: var(--text-sm);
  font-style: italic;
  margin-bottom: 0;
}

/* filter bar */
.filter-bar {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  margin-bottom: var(--space-6);
}

.filter-bar__group {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
}

.filter-bar button {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-pill);
  padding: var(--space-1) var(--space-3);
  font-size: var(--text-sm);
  color: var(--text-secondary);
}

.filter-bar button[aria-pressed="true"] {
  border-color: var(--accent);
  color: var(--text-primary);
  background: var(--surface-alt);
}

.filter-bar__count {
  color: var(--text-secondary);
  font-size: var(--text-sm);
}

/* contact block */
.contact-block {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
}

.contact-block__channels {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-4);
}

.contact-block form {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  max-width: 32rem;
}

.contact-block label {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  font-size: var(--text-sm);
  color: var(--text-secondary);
}

.contact-block input,
.contact-block textarea {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: var(--space-3);
  color: var(--text-primary);
}

/* honeypot field — hidden from sighted users and real visitors, left in the tab order for
   nobody (tabindex -1), per research/contact-options.md's form contract */
.contact-block__honeypot {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

/* generic section rhythm — every <section> pages.mjs emits inside <main> (home-*, vertical-*,
   about-*, services-offer, privacy-*, contact-privacy-note) shares one vertical gap so no route
   needs its own one-off spacing class (docs/build-contract.md §5 fixes only the components
   table above; page-section classes are layout-only and never carry component behaviour). */
main section {
  margin-bottom: var(--space-8);
}

main section:last-child {
  margin-bottom: 0;
}

.services-offer {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  padding: var(--space-5);
  box-shadow: none;
  margin-bottom: var(--space-6);
}

.services-offer:last-child {
  margin-bottom: 0;
}

.services-offer-list {
  display: flex;
  flex-direction: column;
}
