/*
 * site.css — John Laverick.
 *
 * Every value here comes from `_tokens.css`, generated from
 * `apps/laverick/tokens.json` (ADR 0041). No hex, no magic number that
 * means a colour or a size — `tests/test_design_tokens.py` enforces it.
 *
 * The brief: intelligent, editorial, understated. Typography and
 * whitespace do the work. So there is no card, no shadow, no gradient, no
 * hero and almost no radius — and the one accent colour appears on links
 * and nowhere else. If something needs a box drawn round it to be
 * understood, the writing is doing the wrong job.
 *
 * Read the measure first: `--measure-prose` is 66 characters, and it is
 * the most consequential number on the site. It is the rule the
 * holding-page stylesheet (#1245) named as the one thing stage 3 should
 * keep, expressed in `ch` rather than `rem` so it tracks the face rather
 * than approximating it.
 *
 * That stylesheet was deliberately colourless, on the grounds that with no
 * token file there was nowhere legitimate for a colour to live. The token
 * file is here now, so the colours moved into it — which is exactly the
 * handover it was written to expect.
 */

/* --- Reset ------------------------------------------------------------ */

*,
*::before,
*::after {
  box-sizing: border-box;
}

html {
  -webkit-text-size-adjust: 100%;
  /* Anchored headings must not land under the masthead. */
  scroll-padding-top: var(--space-7);
}

body {
  margin: 0;
  background: var(--surface-bg);
  color: var(--text-primary);
  font-family: var(--font-serif);
  font-size: var(--text-base);
  line-height: var(--lh-prose);
  /* Old-style figures where the face has them: numerals in running text
     should sit on the baseline like letters, not shout like data. */
  font-variant-numeric: oldstyle-nums proportional-nums;
  text-rendering: optimizeLegibility;
  -webkit-font-smoothing: antialiased;
  /* Kept from the holding-page stylesheet this replaces (#1245): stops a
     paragraph ending on a single orphaned word, which is the cheapest
     typographic improvement available anywhere. */
  text-wrap: pretty;
}

img,
svg,
video {
  max-width: 100%;
  height: auto;
  display: block;
}

/* --- Layout ----------------------------------------------------------- */
/*
 * One rule for horizontal space, applied everywhere: a centred column at
 * the reading measure with a 16px gutter that never lets the page scroll
 * sideways on a phone.
 */

.wrap {
  width: 100%;
  max-width: var(--measure-prose);
  margin-inline: auto;
  padding-inline: var(--space-4);
}

.wrap--wide {
  max-width: var(--measure-wide);
}

/* --- Skip link -------------------------------------------------------- */

.skip-link {
  position: absolute;
  left: -9999px;
  top: var(--space-2);
  z-index: 10;
  background: var(--surface-card);
  color: var(--text-primary);
  padding: var(--space-2) var(--space-3);
  border: 1px solid var(--text-primary);
  border-radius: var(--radius-sm);
  font-family: var(--font-sans);
  font-size: var(--text-sm);
  text-decoration: none;
}

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

/* --- Focus ------------------------------------------------------------ */
/*
 * One visible focus style for everything. `:focus-visible` rather than
 * `:focus` so a mouse click on a link does not draw a ring, but every
 * keyboard route through the page does.
 */

:focus-visible {
  outline: 2px solid var(--focus-ring);
  outline-offset: 2px;
  border-radius: var(--radius-sm);
}

/* --- Masthead --------------------------------------------------------- */
/*
 * The name, and up to five places to go. No logo, no tagline in the
 * header, no sticky bar eating the top of a phone screen while someone
 * reads two thousand words.
 */

.masthead {
  padding-block: var(--space-6) var(--space-5);
}

.masthead__inner {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-3) var(--space-5);
}

.masthead__name {
  font-size: var(--text-lg);
  font-weight: var(--weight-semibold);
  letter-spacing: -0.01em;
  color: var(--text-primary);
  text-decoration: none;
}

.masthead__name:hover {
  color: var(--accent-base);
}

.nav {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-4);
  font-family: var(--font-sans);
  font-size: var(--text-sm);
}

.nav a {
  color: var(--text-muted);
  text-decoration: none;
}

.nav a:hover,
.nav a[aria-current="page"] {
  color: var(--text-primary);
}

.nav a[aria-current="page"] {
  /* The current page is marked, not highlighted. */
  text-decoration: underline;
  text-underline-offset: 0.25em;
}

/* --- Banner ----------------------------------------------------------- */
/*
 * The homepage photograph, with the name and descriptor set over it as real
 * text. Two layouts, and the breakpoint is a legibility decision rather
 * than a taste one.
 *
 * WIDE: text overlaid on the picture, in the pale sky on the left — which
 * is where the composition leaves room, and where the contrast is about
 * 10:1.
 *
 * NARROW: the picture becomes a band and the text sits BELOW it, on the
 * page. A 2.7:1 photograph cropped to a phone is mostly sky or mostly
 * rock depending on where the crop lands, and text over a crop you cannot
 * predict is text you cannot promise is readable. The brief puts reading
 * ahead of visual cleverness, so at the size where they conflict, reading
 * wins and the picture is simply a picture.
 */

.banner {
  margin-block-end: var(--space-7);
}

.banner__media {
  /* Full-bleed out of any centred column, without a wrapper. */
  width: 100vw;
  margin-inline: calc(50% - 50vw);
  overflow: hidden;
}

.banner__img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* Hold the right of the frame — the sun and the figure — when the crop
     bites. That is the part of this photograph worth keeping. */
  object-position: 72% center;
}

.banner__body {
  padding-block-start: var(--space-5);
}

.banner__name {
  font-size: var(--text-3xl);
  line-height: var(--lh-tight);
  letter-spacing: -0.02em;
  font-weight: var(--weight-bold);
  margin: 0 0 var(--space-3);
}

.banner__descriptor {
  font-size: var(--text-lg);
  line-height: var(--lh-snug);
  margin: 0;
  max-width: 34ch;
  text-wrap: balance;
}

@media (max-width: 47.99rem) {
  /* Band proportions, so a phone gets a picture rather than a letterbox. */
  .banner__media {
    aspect-ratio: 16 / 9;
  }
}

@media (min-width: 48rem) {
  .banner {
    display: grid;
    align-items: center;
  }

  .banner__media,
  .banner__body {
    grid-area: 1 / 1;
  }

  .banner__media {
    aspect-ratio: 2055 / 765;
    /* Never taller than two-thirds of the viewport: a picture that fills
       the screen makes a reader scroll before they can read anything. */
    max-height: 66vh;
  }

  .banner__body {
    position: relative;
    padding-block-start: 0;
    /* A wash, not a panel. It lifts the text off the sky where the crop
       slides it onto the hills, and is invisible where it does not. */
    background: linear-gradient(
      to right,
      var(--banner-scrim) 0%,
      var(--banner-scrim) 38%,
      var(--banner-scrim-edge) 62%
    );
  }

  .banner__body .wrap {
    padding-block: var(--space-6);
  }

  .banner__name,
  .banner__descriptor {
    color: var(--banner-ink);
  }

  .banner__descriptor {
    color: var(--banner-ink-muted);
  }

  .banner__name {
    font-size: var(--text-4xl);
  }
}

/* The masthead name is suppressed on the homepage, where the banner is the
   <h1>. The element stays so the nav keeps its place in the flex row. */
.masthead__name--hidden {
  display: block;
}

/* --- Prose ------------------------------------------------------------ */
/*
 * The reading experience. Everything in here is subordinate to one
 * question: does a long paragraph stay easy to read?
 */

main {
  padding-block-end: var(--space-9);
}

.prose > * + * {
  margin-block-start: var(--space-5);
}

.prose p,
.prose li {
  hanging-punctuation: first last;
}

.prose h2,
.prose h3,
.prose h4 {
  font-weight: var(--weight-semibold);
  line-height: var(--lh-snug);
  letter-spacing: -0.01em;
  /* Space above a heading, not below it: a heading belongs to what
     follows. */
  margin-block-start: var(--space-7);
  margin-block-end: var(--space-3);
}

.prose h2 {
  font-size: var(--text-xl);
}

.prose h3 {
  font-size: var(--text-lg);
}

.prose h4 {
  font-size: var(--text-base);
  font-style: italic;
  font-weight: var(--weight-normal);
}

.prose a {
  color: var(--accent-base);
  text-decoration-line: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 0.18em;
  /* Descenders should interrupt the rule, not be crossed out by it. */
  text-decoration-skip-ink: auto;
}

.prose a:hover {
  color: var(--accent-hover);
  text-decoration-thickness: 2px;
}

.prose blockquote {
  margin-inline: 0;
  padding-inline-start: var(--space-5);
  border-inline-start: 2px solid var(--accent-base);
  color: var(--text-primary);
  font-style: italic;
}

.prose blockquote p {
  margin-block: var(--space-3);
}

.prose ul,
.prose ol {
  padding-inline-start: var(--space-5);
}

.prose li + li {
  margin-block-start: var(--space-2);
}

.prose hr {
  margin-block: var(--space-7);
  border: 0;
  border-top: 1px solid var(--surface-border);
}

.prose code {
  font-family: var(--font-mono);
  font-size: 0.875em;
  background: var(--surface-muted);
  padding: 0.1em 0.3em;
  border-radius: var(--radius-sm);
}

.prose pre {
  font-family: var(--font-mono);
  font-size: var(--text-sm);
  line-height: var(--lh-normal);
  background: var(--surface-muted);
  border: 1px solid var(--surface-border);
  border-radius: var(--radius-md);
  padding: var(--space-4);
  overflow-x: auto;
}

.prose pre code {
  background: none;
  padding: 0;
  font-size: inherit;
}

.prose figure {
  margin-inline: 0;
}

.prose figcaption {
  margin-block-start: var(--space-2);
  font-family: var(--font-sans);
  font-size: var(--text-sm);
  color: var(--text-muted);
}

/* --- Page furniture --------------------------------------------------- */

.page-title {
  font-size: var(--text-3xl);
  line-height: var(--lh-tight);
  letter-spacing: -0.02em;
  font-weight: var(--weight-bold);
  margin-block: 0 var(--space-4);
}

.lede {
  font-size: var(--text-lg);
  line-height: var(--lh-normal);
  color: var(--text-muted);
  margin-block: 0 var(--space-6);
  /* A short block read as a unit: balance beats pretty here. */
  text-wrap: balance;
}

/* Kind · date · themes. Sans, small, quiet — it is apparatus, not text. */
.meta {
  font-family: var(--font-sans);
  font-size: var(--text-sm);
  line-height: var(--lh-normal);
  color: var(--text-muted);
}

.meta a {
  color: inherit;
}

/* "Originally published on LinkedIn, 31 August 2026." Present, not
   prominent — this site is the permanent archive either way. */
.origin {
  font-family: var(--font-sans);
  font-size: var(--text-sm);
  color: var(--text-light);
  margin-block-start: var(--space-6);
  padding-block-start: var(--space-3);
  border-block-start: 1px solid var(--surface-border);
}

.kind {
  font-family: var(--font-sans);
  font-size: var(--text-xs);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-light);
}

/* --- Listings --------------------------------------------------------- */
/*
 * Writing is the product, so a listing is a list: title, kind, date, one
 * line. No image cards. The rule between entries is the only decoration.
 */

.listing {
  list-style: none;
  margin: 0;
  padding: 0;
}

.listing > li {
  padding-block: var(--space-5);
  border-block-end: 1px solid var(--surface-border);
}

.listing > li:first-child {
  padding-block-start: 0;
}

.entry__title {
  font-size: var(--text-lg);
  line-height: var(--lh-snug);
  font-weight: var(--weight-semibold);
  margin: 0 0 var(--space-2);
}

.entry__title a {
  color: var(--text-primary);
  text-decoration: none;
}

.entry__title a:hover {
  color: var(--accent-base);
  text-decoration: underline;
  text-underline-offset: 0.18em;
}

.entry__summary {
  margin-block: var(--space-2) 0;
  color: var(--text-muted);
  font-size: var(--text-sm);
  line-height: var(--lh-normal);
}

/* --- Ideas ------------------------------------------------------------ */
/*
 * An Idea is a question first. On an index it reads as the question with
 * its explanation underneath — closer to a notebook than a taxonomy.
 */

.idea__question {
  font-size: var(--text-xl);
  line-height: var(--lh-snug);
  font-weight: var(--weight-semibold);
  letter-spacing: -0.01em;
  margin: 0 0 var(--space-2);
}

.idea__question a {
  color: var(--text-primary);
  text-decoration: none;
}

.idea__question a:hover {
  color: var(--accent-base);
}

/* --- Sections --------------------------------------------------------- */
/*
 * A homepage or index section. The heading is small and quiet — apparatus
 * telling you what the list below is, not a piece of display type
 * competing with the writing it introduces.
 */

.section {
  margin-block-start: var(--space-8);
}

.section__heading {
  font-family: var(--font-sans);
  font-size: var(--text-xs);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-light);
  margin: 0 0 var(--space-4);
  padding-block-end: var(--space-2);
  border-block-end: 1px solid var(--surface-border);
}

.section__more {
  margin-block-start: var(--space-4);
  font-family: var(--font-sans);
  font-size: var(--text-sm);
}

.section__more a {
  color: var(--accent-base);
  text-decoration-line: underline;
  text-underline-offset: 0.18em;
}

/* --- Filters ---------------------------------------------------------- */
/*
 * Links, not controls. Each is a real URL, so it can be shared, crawled
 * and reached with the back button — which is also why the current one is
 * marked with `aria-current` rather than only a colour.
 */

.filters {
  margin-block: var(--space-5) var(--space-6);
  padding-block-end: var(--space-4);
  border-block-end: 1px solid var(--surface-border);
}

.filters__row {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2) var(--space-4);
  list-style: none;
  margin: 0;
  padding: 0;
  font-family: var(--font-sans);
  font-size: var(--text-sm);
}

.filters__row + .filters__row {
  margin-block-start: var(--space-3);
}

.filters a {
  color: var(--text-muted);
  text-decoration: none;
}

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

.filters a[aria-current="true"] {
  color: var(--text-primary);
  text-decoration: underline;
  text-underline-offset: 0.25em;
}

/* --- Related thinking ------------------------------------------------- */

.related {
  margin-block-start: var(--space-8);
  padding-block-start: var(--space-5);
  border-block-start: 2px solid var(--surface-border);
}

.related__heading {
  font-family: var(--font-sans);
  font-size: var(--text-xs);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-light);
  margin: 0 0 var(--space-4);
}

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

.site-footer {
  border-block-start: 1px solid var(--surface-border);
  padding-block: var(--space-5) var(--space-7);
  font-family: var(--font-sans);
  font-size: var(--text-sm);
  color: var(--text-muted);
}

.site-footer__inner {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3) var(--space-5);
  justify-content: space-between;
}

.site-footer p {
  margin: 0;
}

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

.site-footer a {
  color: var(--text-muted);
  text-decoration: none;
}

.site-footer a:hover {
  color: var(--accent-base);
  text-decoration: underline;
  text-underline-offset: 0.18em;
}

/* --- Small screens ---------------------------------------------------- */
/*
 * The type scale is a touch smaller on a phone, and the display sizes
 * come down harder than body copy does: a 3rem headline on a 375px screen
 * wraps into four lines and stops being a headline.
 */

@media (max-width: 34rem) {
  .page-title {
    font-size: var(--text-2xl);
  }

  .masthead {
    padding-block: var(--space-5) var(--space-4);
  }
}

/* --- Motion ----------------------------------------------------------- */
/*
 * There is very little motion to reduce, which is the point. This exists
 * so that anything added later inherits the courtesy by default.
 */

@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

/* --- Print ------------------------------------------------------------ */
/*
 * People print essays. The apparatus is not worth a sheet of paper.
 */

@media print {
  .masthead,
  .site-footer,
  .related,
  .skip-link {
    display: none;
  }

  body {
    background: none;
  }

  .prose a {
    text-decoration: underline;
  }
}

/* --- Search ----------------------------------------------------------- */
/*
 * Two forms, one purpose. The footer one is present on every page and
 * deliberately quiet — search is for when you already know what you are
 * after, not a competing way to browse. The one on /search is the same
 * control given room, because that page is about nothing else.
 *
 * Both are ordinary GET forms. The query lands in the URL, so a result
 * list can be bookmarked, shared and reached with the back button.
 */

.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

.site-search {
  display: flex;
  gap: var(--space-2);
  align-items: center;
}

.site-search__input,
.search__input {
  font-family: var(--font-sans);
  font-size: var(--text-sm);
  color: var(--text-primary);
  background: var(--surface-bg);
  border: 1px solid var(--surface-border);
  border-radius: var(--radius-sm);
  padding: var(--space-2) var(--space-3);
}

.site-search__input {
  inline-size: 12ch;
  transition: inline-size 120ms ease;
}

/* Grows on focus rather than taking the room permanently. */
.site-search__input:focus {
  inline-size: 20ch;
}

.site-search__submit,
.search__submit {
  font-family: var(--font-sans);
  font-size: var(--text-sm);
  font-weight: var(--weight-semibold);
  color: var(--text-on-accent);
  background: var(--accent-base);
  border: 1px solid transparent;
  border-radius: var(--radius-sm);
  padding: var(--space-2) var(--space-4);
  cursor: pointer;
}

.site-search__submit:hover,
.search__submit:hover {
  background: var(--accent-hover);
}

.search {
  margin-block-end: var(--space-8);
  max-inline-size: var(--measure-prose);
}

.search__label {
  display: block;
  font-family: var(--font-sans);
  font-size: var(--text-sm);
  color: var(--text-muted);
  margin-block-end: var(--space-2);
}

.search__row {
  display: flex;
  gap: var(--space-3);
}

.search__input {
  flex: 1 1 auto;
  font-size: var(--text-base);
  min-inline-size: 0;
}

.search__hint {
  font-family: var(--font-sans);
  font-size: var(--text-xs);
  color: var(--text-light);
  margin-block-start: var(--space-3);
}

@media print {
  .site-search,
  .search {
    display: none;
  }
}
