/* ==========================================================================
   Dr Dow - site styles
   Methodology: CUBE CSS (Composition, Utility, Block, Exception)
   Layout: flexbox reflow (Every Layout Sidebar/Stack/Cluster), no fixed
   breakpoints - components wrap based on their own available space.
   ========================================================================== */

/* --------------------------------------------------------------------------
   Root - design tokens
   -------------------------------------------------------------------------- */

:root {
  /* Colour */
  --color-white: #ffffff;
  --color-sage-light: #dce0d5;
  --color-sage-dark: #bfc6b2;
  --color-heading: #2d4608;
  --color-text: #0b0b0a;
  --color-nav-muted: #6b6b6b;
  --color-pattern-red: #ee3749;
  --color-pattern-green: #1a5a33;
  --color-pattern-brown: #4c2413;
  --color-pattern-gold: #a89040;
  --color-button-green: #367752;
  --color-error-light: #fbe6e6;

  /* Type */
  --font-display: "Playfair Display", didot, "Bodoni MT", georgia, serif;
  --font-body: "Segoe UI", "Helvetica Neue", Arial, sans-serif;

  --text-s: clamp(0.875rem, 0.83rem + 0.2vw, 1rem);
  --text-base: clamp(1rem, 0.95rem + 0.25vw, 1.125rem);
  --text-m: clamp(1.25rem, 1.1rem + 0.6vw, 1.5rem);
  --text-l: clamp(1.75rem, 1.4rem + 1.5vw, 2.5rem);
  --text-xl: clamp(2.25rem, 1.6rem + 2.75vw, 3.75rem);

  /* Space */
  --space-3xs: clamp(0.25rem, 0.22rem + 0.15vw, 0.375rem);
  --space-2xs: clamp(0.5rem, 0.45rem + 0.25vw, 0.625rem);
  --space-xs: clamp(0.75rem, 0.68rem + 0.3vw, 1rem);
  --space-s: clamp(1rem, 0.9rem + 0.5vw, 1.5rem);
  --space-m: clamp(1.5rem, 1.3rem + 1vw, 2.25rem);
  --space-l: clamp(2rem, 1.6rem + 1.75vw, 3rem);
  --space-xl: clamp(3rem, 2.4rem + 2.75vw, 4.5rem);
  --space-2xl: clamp(4rem, 3.1rem + 4vw, 6rem);

  /* Layout padding: tight on phones, reaching --space-l's full size on
     wide screens - the frame and its sections both use these, so a
     fixed --space-l would double up on a narrow screen. */
  --space-gutter: clamp(0.5rem, -0.5rem + 4vw, 3rem);
  --space-section: clamp(1.25rem, 0.5rem + 3.5vw, 3rem);

  /* Layout */
  --content-max: 105rem;
  --content-narrow: 70rem;
  --measure: 65ch;
  --pattern-strip-width: clamp(1.5rem, 1rem + 2vw, 2.75rem);

  /* Borders */
  --border-thin: 1px;
  --radius-s: 0.25rem;
  --radius-pill: 9999px;
}

/* --------------------------------------------------------------------------
   Base
   -------------------------------------------------------------------------- */

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

body {
  margin: 0;
  font-family: var(--font-body);
  font-size: var(--text-base);
  color: var(--color-text);
  background-color: var(--color-white);
  line-height: 1.5;
}

img {
  max-width: 100%;
  height: auto;
  display: block;
  background-color: var(--color-sage-light);
}

a {
  color: inherit;
}

h1,
h2 {
  font-family: var(--font-display);
  color: var(--color-heading);
  text-transform: uppercase;
  line-height: 1.1;
  margin: 0;
}

h1 {
  font-size: var(--text-xl);
}

h2 {
  font-size: var(--text-l);
}

/* --------------------------------------------------------------------------
   Composition - reusable layout primitives
   -------------------------------------------------------------------------- */

/* Stack: consistent vertical rhythm between direct children */
.stack > * + * {
  margin-block-start: var(--space-s);
}

/* Cluster: wrapping row of items with consistent gap */
.cluster {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-s);
  margin: 0;
  padding: 0;
  list-style: none;
}

/* Sidebar-style reflow: a fixed-ish column plus a flexible one that
   reflows to full width once the row can no longer fit both comfortably.
   No breakpoints - driven entirely by flex-basis/flex-grow. Modifiers are
   explicit classes rather than :first-child/:last-child, so either side
   can come first in markup (reading order stays main-content-first). */
.reflow {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-l);
}

.reflow-fixed {
  flex-basis: 20rem;
  flex-grow: 1;
}

.reflow-flex {
  flex-basis: 0;
  flex-grow: 999;
  min-width: 50%;
}

/* --------------------------------------------------------------------------
   Utility
   -------------------------------------------------------------------------- */

/* Read out by screen readers but not shown, e.g. "(opens in a new tab)". */
.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* --------------------------------------------------------------------------
   Block - site header
   -------------------------------------------------------------------------- */

/* Flex, not grid: each group (nav / logo / nav) keeps its natural width
   (flex-shrink: 0) rather than being squeezed into a fixed track, so a
   group that doesn't fit wraps onto its own line whole instead of
   crushing its links into several cramped lines. Equal flex-grow on the
   two nav groups keeps the logo visually centred whenever there's room
   to spare; min-width: fit-content stops a group being squeezed below
   its natural width (or the screen's, if narrower), so it wraps as a
   whole instead. Narrow states fall back to a centred stack, where
   exact centring no longer matters. No breakpoint needed either way. */
.site-header {
  display: flex;
  flex-wrap: wrap;
  align-items: start;
  justify-content: center;
  gap: var(--space-2xs) var(--space-l);
  padding: var(--space-s) var(--space-l);
  border-bottom: var(--border-thin) solid var(--color-sage-dark);
}

.site-header .site-nav {
  flex: 1 0 0%;
  min-width: fit-content;
}

.site-header .site-nav .cluster {
  justify-content: center;
}

.site-header .site-nav:first-child .cluster {
  justify-content: start;
}

.site-header .site-nav:last-child .cluster {
  justify-content: end;
}

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

.site-nav a:hover,
.site-nav a[aria-current] {
  color: var(--color-text);
}

.site-logo {
  flex: 0 0 auto;
  margin: 0;
  font-family: var(--font-display);
  font-size: var(--text-m);
  letter-spacing: 0.05em;
  text-transform: uppercase;
  text-align: center;
}

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

/* --------------------------------------------------------------------------
   Block - decorative pattern strip
   Reused wherever the site bleeds the pattern off a viewport edge.
   -------------------------------------------------------------------------- */

.pattern-strip {
  width: var(--pattern-strip-width);
  background-image: url("dr-dow/stripe.webp");
  background-repeat: repeat-y;
  background-size: 100% auto;
}

/* Sits at the edge of .page-content (its positioning parent) rather than
   the true viewport edge, so the strip stays attached to the content
   frame once that frame is width-constrained and centred. */
.pattern-strip-left,
.pattern-strip-right {
  position: absolute;
  top: 0;
  bottom: 0;
}

.pattern-strip-left {
  left: 0;
}

.pattern-strip-right {
  right: 0;
}

/* --------------------------------------------------------------------------
   Block - page content
   Wraps everything below the header. Width-constrained and centred so
   content stays readable on very wide screens; the two pattern strips
   are positioned relative to this frame and move with it.
   -------------------------------------------------------------------------- */

.page-content {
  position: relative;
  max-width: var(--content-max);
  margin-inline: auto;
  padding: var(--space-section) calc(var(--space-gutter) + var(--pattern-strip-width));
}

/* --------------------------------------------------------------------------
   Block - homepage layout
   Proportional two-thirds/one-third split (uses .reflow for the row's
   display/wrap/gap, with its own flex-grow ratio rather than the
   .reflow-fixed/.reflow-flex modifiers - those give a small fixed-width
   sidebar, this wants both columns scaling together). Drops to a single
   column once the row can no longer fit both comfortably - no
   breakpoints, purely a function of available width.
   -------------------------------------------------------------------------- */

.home-layout {
  gap: var(--space-gutter);
}

.home-main {
  flex: 2 1 0%;
  min-width: 50%;
}

.home-rail {
  flex: 1 1 0%;
  min-width: 16rem;
  display: flex;
  flex-direction: column;
}

/* --------------------------------------------------------------------------
   Block - hero
   Also composed with .reflow - see markup.
   -------------------------------------------------------------------------- */

.hero {
  padding: var(--space-section) var(--space-gutter);
}

.hero-media {
  max-width: 26rem;
}

.hero-media img {
  aspect-ratio: 4 / 5;
  object-fit: cover;
}

.button-link {
  display: inline-block;
  font-family: inherit;
  background: none;
  cursor: pointer;
  padding: var(--space-3xs) var(--space-s);
  border: var(--border-thin) solid var(--color-heading);
  border-radius: var(--radius-pill);
  font-size: var(--text-s);
  text-decoration: none;
  color: var(--color-heading);
}

/* --------------------------------------------------------------------------
   Block - project teaser (about page, under the bio)
   -------------------------------------------------------------------------- */

.project {
  align-items: center;
  gap: var(--space-m);
}

.project-media {
  flex-basis: 10rem;
  max-width: 14rem;
  aspect-ratio: 1;
  object-fit: cover;
  border-radius: var(--space-2xs);
}

.project-content h2 {
  font-size: var(--text-m);
}

/* --------------------------------------------------------------------------
   Block - entry feed (homepage "latest from..." sections)
   -------------------------------------------------------------------------- */

.entry-feed {
  padding: var(--space-section) var(--space-gutter);
}

.entry-feed + .entry-feed {
  border-top: var(--border-thin) solid var(--color-sage-dark);
}

.entry-feed-header {
  justify-content: space-between;
  margin-block-end: var(--space-m);
}

.entry-feed-header h2 {
  font-size: var(--text-m);
}

.text-link {
  font-size: var(--text-s);
  text-decoration: underline;
}

/* Grid auto-fill rather than flex-wrap, so a lone card on the last row
   keeps the same width as the rest instead of stretching. */
.entry-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(16rem, 100%), 1fr));
  gap: var(--space-m);
}

/* Homepage feeds: auto-fit collapses the empty tracks, so a feed's
   card(s) span the full width of whichever column the feed sits in. */
.entry-feed .entry-grid {
  grid-template-columns: repeat(auto-fit, minmax(min(16rem, 100%), 1fr));
}

.entry-card-link {
  display: block;
  text-decoration: none;
  color: inherit;
}

.entry-card-media {
  aspect-ratio: 4 / 3;
  background-color: var(--color-sage-light);
  margin-block-end: var(--space-2xs);
}

/* Featured feed (Heirs of Slavery, main column): photo and text side by
   side, matching the hero's proportions - the text drops beneath the
   photo once there isn't room for both. */
.entry-feed-feature .entry-card-link {
  display: flex;
  flex-wrap: wrap;
  align-items: start;
  gap: var(--space-l);
}

.entry-feed-feature .entry-card-media {
  flex: 1 1 20rem;
  max-width: 26rem;
  margin: 0;
}

.entry-feed-feature .entry-card-text {
  flex: 999 1 0;
  min-width: min(18rem, 100%);
}

.entry-card-media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* Portrait photos lose their top and bottom in the 4:3 frame - favour
     the upper part, where heads usually are. */
  object-position: 50% 25%;
}

.entry-card-title {
  font-family: var(--font-display);
  color: var(--color-heading);
  text-transform: uppercase;
  font-size: var(--text-m);
  margin: 0;
}

.entry-card-date,
.entry-more-date {
  font-size: var(--text-s);
  color: var(--color-nav-muted);
  margin-block-start: var(--space-3xs);
}

/* Compact headline/date links beneath a homepage feed's card. */
.entry-more {
  margin: var(--space-m) 0 0;
  padding: 0;
  list-style: none;
}

.entry-more-item {
  border-top: var(--border-thin) solid var(--color-sage-dark);
}

.entry-more-link {
  display: block;
  padding-block: var(--space-s);
  text-decoration: none;
}

.entry-more-title {
  font-family: var(--font-display);
  font-size: var(--text-base);
  color: var(--color-heading);
  text-transform: uppercase;
  line-height: 1.3;
  margin: 0;
}

.entry-more-date {
  margin-block-end: 0;
}

.entry-more-link:hover .entry-more-title {
  text-decoration: underline;
}

/* --------------------------------------------------------------------------
   Block - listing pages (/travel/, /talks/ ...), also 404 and contact
   -------------------------------------------------------------------------- */

.listing {
  padding: var(--space-section) var(--space-gutter);
}

.listing-intro {
  max-inline-size: var(--measure);
  font-size: var(--text-m);
  line-height: 1.4;
}

.listing-group {
  margin-block-start: var(--space-l);
}

.listing-group h2 {
  font-size: var(--text-m);
}

/* --------------------------------------------------------------------------
   Block - single entry / talk
   -------------------------------------------------------------------------- */

.entry {
  max-width: var(--content-narrow);
  margin-inline: auto;
  padding-block: var(--space-l);
}

.entry-header {
  max-width: var(--measure);
}

.entry-header > * + * {
  margin-block-start: var(--space-2xs);
}

.entry-header p {
  margin-block-end: 0;
}

.entry-standfirst {
  font-size: var(--text-m);
  line-height: 1.4;
}

.entry-meta {
  font-size: var(--text-s);
  color: var(--color-nav-muted);
}

/* Blog entry / talk body: photos in a left column at their natural
   shape (most are portrait - phone shots and scans), text alongside.
   Proportional 2:3 split; once both minimums no longer fit, the photos
   drop above the text at full width. No breakpoints. */
.entry-body {
  display: flex;
  flex-wrap: wrap;
  align-items: start;
  gap: var(--space-l);
}

.entry-photos {
  flex: 2 1 0;
  min-width: min(16rem, 100%);
  display: flex;
  flex-direction: column;
  gap: var(--space-s);
}

.entry-body .prose {
  flex: 3 1 0;
  min-width: min(22rem, 100%);
}

/* Photo article: each photo with its caption beside it, alternating
   sides; the caption drops underneath once there isn't room. */
.photo-story {
  display: flex;
  flex-wrap: wrap;
  align-items: end;
  gap: var(--space-s) var(--space-m);
  margin: 0;
  padding-block: var(--space-m);
}

.photo-story + .photo-story {
  border-top: var(--border-thin) solid var(--color-sage-dark);
}

.photo-story:nth-of-type(even) {
  flex-direction: row-reverse;
}

.photo-story img {
  flex: 3 1 24rem;
  min-width: 0;
}

.photo-story figcaption {
  flex: 1 1 14rem;
  font-size: var(--text-s);
}

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

.prose > * {
  margin-block: 0;
}

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

.prose a {
  overflow-wrap: anywhere;
}

.video-embed {
  display: block;
  width: 100%;
  aspect-ratio: 16 / 9;
  border: 0;
}

/* Admin preview notice (alisonstuff/preview.php), above the entry. */
.preview-banner {
  max-width: var(--content-narrow);
  margin: var(--space-m) auto 0;
  padding: var(--space-xs) var(--space-s);
  background-color: var(--color-sage-light);
  border-left: var(--space-3xs) solid var(--color-pattern-gold);
  font-size: var(--text-s);
}

/* --------------------------------------------------------------------------
   Block - contact form
   -------------------------------------------------------------------------- */

.contact-form {
  max-width: 40rem;
}

.form-field {
  display: flex;
  flex-direction: column;
  gap: var(--space-3xs);
}

.form-field label {
  font-size: var(--text-s);
}

.form-field input,
.form-field textarea {
  font: inherit;
  padding: var(--space-2xs);
  border: var(--border-thin) solid var(--color-sage-dark);
  border-radius: var(--space-3xs);
}

.form-field [aria-invalid="true"] {
  border-color: var(--color-pattern-red);
}

.form-error {
  margin: 0;
  font-size: var(--text-s);
  color: var(--color-pattern-red);
}

/* Honeypot field for spam bots - off-screen rather than display: none,
   which some bots detect and skip. */
.form-trap {
  position: absolute;
  left: -100vw;
}

.notice {
  max-width: 40rem;
  padding: var(--space-s);
  background-color: var(--color-sage-light);
}

.notice-error {
  border-left: var(--space-3xs) solid var(--color-pattern-red);
}

/* --------------------------------------------------------------------------
   Block - site footer
   -------------------------------------------------------------------------- */

.site-footer {
  padding: var(--space-m) var(--space-l);
  border-top: var(--border-thin) solid var(--color-sage-dark);
  text-align: center;
}

.site-footer p {
  margin: 0;
  font-size: var(--text-s);
  color: var(--color-nav-muted);
}
