/* ══════════════════════════════════════════════════════════════════════════
   samfarmerbuilds.com — page CSS

   Derived from the Claude Design file
     "Sam Farmer - Broadsheet v3 responsive.dc.html"
     (project eb7c7439-3eb7-46c8-abc0-9b03bbd6760d)
   which builds on the Modernist design system in assets/css/modernist.css.

   The design file carries its layout as inline style attributes on a canvas
   component; those are lifted here into classes with the same values. Its
   runtime theme override (a JS applyTheme on the root element) is baked into
   the :root block below.

   Masthead variant A (role masthead) and the Cream shade are the chosen
   options; the design ships variant B and three other shades behind switches.

   One deliberate departure runs through the whole file: the design draws its
   structure with rules, and most of them are gone here — only the masthead
   and footer rules are left, with space doing the separating everywhere else.
   Each place it happens is commented. See docs/design-system.md, "Deliberate
   departures from the design file".
   ══════════════════════════════════════════════════════════════════════ */

/* — Archivo, self-hosted. Variable face, one file per subset, wght 100–900. — */
@font-face {
  font-family: 'Archivo';
  font-style: normal;
  font-weight: 100 900;
  font-stretch: 100%;
  font-display: swap;
  src: url('/assets/fonts/archivo-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Archivo';
  font-style: normal;
  font-weight: 100 900;
  font-stretch: 100%;
  font-display: swap;
  src: url('/assets/fonts/archivo-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

/* ── Theme ────────────────────────────────────────────────────────────────
   The design's applyTheme(), evaluated for mode "Light" / shade "Cream" /
   accent #ec3013 and written out as static values. These deliberately
   override the Modernist defaults loaded by modernist.css — change the
   shade by swapping the four ground colours, the accent by swapping three.
   ─────────────────────────────────────────────────────────────────────── */
:root {
  --paper-ground: #e7ddc9;   /* shade.ground — what the page floats on */
  --color-bg: #ffffff;       /* shade.paper  — the page itself */
  --color-surface: #f2ece0;  /* shade.n2 */
  --color-text: #201e1d;     /* ink */
  --color-divider: color-mix(in oklab, #201e1d 40%, transparent);

  --color-neutral-200: #f2ece0;
  --color-neutral-300: #e7ddc9;
  --color-neutral-400: #c8bda6;

  --color-accent: #ec3013;
  --color-accent-600: color-mix(in oklab, #ec3013 86%, #201e1d);
  /* accentText — the deep step, for accent-coloured TEXT at body size */
  --color-accent-700: color-mix(in oklab, #ec3013 74%, #201e1d);
  --color-accent-800: color-mix(in oklab, #ec3013 74%, #201e1d);

  --page-max: 1100px;
  --pad: 48px;   /* the page's inner gutter; 20px below 720 */
}

body { margin: 0; background: var(--paper-ground); color: var(--color-text); }

/* ── Dark mode ────────────────────────────────────────────────────────────
   The design file's `mode: Dark` branch of applyTheme(), transcribed. The
   shade (Cream/Bone/…) does not apply in dark — those ground colours are
   fixed, and only the accent carries over. The accent's text step is mixed
   toward white here rather than toward ink, so accent-coloured body text
   stays legible on the dark ground.

   Follows the OS setting by default, with no JavaScript. `data-theme` on
   <html> overrides it in either direction, so a toggle can be added later
   without touching these rules.

   THE TWO TOKEN BLOCKS BELOW MUST BE KEPT IDENTICAL.
   ─────────────────────────────────────────────────────────────────────── */
:root { color-scheme: light dark; }

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --paper-ground: #211f1e;   /* what the page floats on */
    --color-bg: #2b2827;       /* the page itself */
    --color-surface: #333030;
    --color-text: #f2efec;
    --color-divider: color-mix(in oklab, #f2efec 34%, transparent);

    --color-neutral-200: #332f2e;
    --color-neutral-300: #3d3937;
    --color-neutral-400: #4d4846;

    --color-accent: #ec3013;
    --color-accent-600: color-mix(in oklab, #ec3013 86%, #ffffff);
    --color-accent-700: color-mix(in oklab, #ec3013 74%, #ffffff);
    --color-accent-800: color-mix(in oklab, #ec3013 74%, #ffffff);
  }
  :root:not([data-theme="light"]) { color-scheme: dark; }
}

:root[data-theme="dark"] {
    --paper-ground: #211f1e;   /* what the page floats on */
    --color-bg: #2b2827;       /* the page itself */
    --color-surface: #333030;
    --color-text: #f2efec;
    --color-divider: color-mix(in oklab, #f2efec 34%, transparent);

    --color-neutral-200: #332f2e;
    --color-neutral-300: #3d3937;
    --color-neutral-400: #4d4846;

    --color-accent: #ec3013;
    --color-accent-600: color-mix(in oklab, #ec3013 86%, #ffffff);
    --color-accent-700: color-mix(in oklab, #ec3013 74%, #ffffff);
    --color-accent-800: color-mix(in oklab, #ec3013 74%, #ffffff);
  color-scheme: dark;
}

/* ── Shell: the page as a sheet of paper on a tinted ground ─────────────── */
.sam-shell {
  min-height: 100vh; padding: 40px 20px;
  display: flex; flex-direction: column; align-items: center; gap: 40px;
  background: var(--paper-ground);
}
.sam-page {
  width: 100%; max-width: var(--page-max);
  background: var(--color-bg); padding: 0 0 40px;
}
.sam-pad { padding: 0 var(--pad); }

/* skip link — not in the design file; added because the site has real
   navigation and a keyboard user needs past it */
.skip-link {
  position: absolute; left: -9999px; top: 0; z-index: 10;
  background: var(--color-accent); color: var(--color-bg);
  font-family: var(--font-heading); font-weight: 800;
  font-size: 14px; line-height: 2; padding: 0 12px; text-decoration: none;
}
.skip-link:focus { left: 0; }

/* ── Masthead B — inverted name block ───────────────────────────────────
   The name sits in its own cell beside a bar carrying the rotating role line
   and the nav. Full width of the page card — it has its own gutters rather
   than sitting inside .sam-pad.

   Everything in the bar sits on the name's baseline: the row aligns on
   baselines rather than centres, so ARCHITECT & the nav line up with the
   foot of "Sam Farmer" instead of floating at the middle of a taller cell.
   That is also why the cell no longer stretches — there is no vertical rule
   left for it to draw.
   ─────────────────────────────────────────────────────────────────────── */
.sam-headerB {
  display: flex; align-items: baseline;
  border-bottom: 2px solid var(--color-text);
}
.sam-headerB-name {
  padding: 16px 28px 14px var(--pad);
  display: flex; align-items: baseline;
}
.sam-headerB-name a { text-decoration: none; }
.sam-headerB-name span {
  font-family: var(--font-heading); font-weight: 800;
  font-size: clamp(28px, 7vw, 34px); line-height: 40px;
  letter-spacing: -0.03em; color: var(--color-accent);
}
.sam-headerB-bar {
  flex: 1; display: flex; justify-content: space-between; align-items: baseline;
  padding: 0 var(--pad) 0 0; gap: 20px;
}
.sam-headerB .sam-nav { padding-bottom: 0; }

.sam-roleline {
  /* margin:0 is load-bearing: this is a <p>, and modernist.css gives p a 12px
     bottom margin, which would deepen the bar below the baseline everything
     else in the masthead sits on. The design uses a bare <div>. */
  margin: 0;
  display: flex; align-items: baseline; gap: 6px;
  font-family: var(--font-heading); font-weight: 800; font-size: 13px;
  letter-spacing: 0.14em; text-transform: uppercase;
}
.sam-roles { height: 18px; overflow: hidden; }
/* the rotator is written for THREE roles plus a repeat of the first (four
   18px slots). Adding a role means extending both the list and these
   keyframes — see _config.yml masthead.roles */
.sam-roles-track { animation: samSwapB 9s cubic-bezier(.7, 0, .2, 1) infinite; }
.sam-roles-track > span { display: block; height: 18px; }
@keyframes samSwapB {
  0%, 26%   { transform: translateY(0); }
  33%, 59%  { transform: translateY(-18px); }
  66%, 92%  { transform: translateY(-36px); }
  100%      { transform: translateY(-54px); }
}

/* ── Nav ───────────────────────────────────────────────────────────────── */
.sam-nav {
  display: flex; gap: 22px; font-size: 13px;
  font-family: var(--font-heading); font-weight: 600; padding-bottom: 4px;
}
/* underlined, per the design — these inherit modernist.css's `a` rules and
   the design file does not turn the underline off */
.sam-nav a { white-space: nowrap; color: var(--color-accent); }
.sam-nav a[aria-current="page"] { color: var(--color-text); }

/* ── Intro ─────────────────────────────────────────────────────────────── */
.sam-intro {
  /* the design seated a bio paragraph and a note beside the headline; both
     are gone, so the headline has the full content width to itself. */
  padding: 32px 0;
}
.sam-intro h1 {
  margin: 0; font-size: clamp(34px, 7vw, 60px); line-height: 0.94;
  letter-spacing: -0.035em; text-wrap: pretty;
  /* lighter than the system's 800 display weight — Archivo is a variable face
     and the full 100–900 range is self-hosted, so this is a free change.
     600 is a weight the design system already uses (.sam-rowtitle, .sam-nav). */
  font-weight: 600;
}
/* ── Lead: featured piece + the writing list ─────────────────────────────
   The two columns are held apart by the gap rather than by a vertical rule,
   so the gap has to be wide enough to read as a division on its own.
   ─────────────────────────────────────────────────────────────────────── */
.sam-lead { display: grid; grid-template-columns: 2fr 1fr; column-gap: clamp(32px, 5vw, 64px); }
.sam-lead-main {
  padding: 20px 0 32px;
  display: flex; flex-direction: column; gap: 16px;
}
.sam-kicker {
  font-family: var(--font-heading); font-weight: 800; font-size: 12px;
  letter-spacing: 0.1em; text-transform: uppercase;
}
.sam-lead-main h2 {
  margin: 0; font-size: clamp(28px, 5.5vw, 42px); line-height: 1.02;
  letter-spacing: -0.025em; text-wrap: pretty;
}
.sam-lead-main p { margin: 0; font-size: 16.5px; line-height: 1.65; text-wrap: pretty; }
.sam-lead-main .btn { align-self: flex-start; justify-content: flex-start; min-height: 44px; }
.sam-lead-side { padding: 20px 0 32px; display: flex; flex-direction: column; }
.sam-lead-side-head {
  display: flex; justify-content: space-between; align-items: baseline;
  padding-bottom: 12px;
}

/* one row in a list of writing — separated by space, not by a hairline, so
   the padding is doing the work the rule used to do */
.sam-row {
  display: flex; flex-direction: column; gap: 2px; padding: 14px 0;
  text-decoration: none; color: var(--color-text);
}
.sam-row-date { font-size: 11px; font-variant-numeric: tabular-nums; }
.sam-row-line { display: flex; gap: 6px; align-items: baseline; }
.sam-hand {
  color: var(--color-accent); font-size: 13px;
  opacity: 0; transform: translateX(-6px); transition: all .16s ease;
}
.sam-row:hover .sam-hand, .sam-row:focus-visible .sam-hand { opacity: 1; transform: translateX(0); }
.sam-rowtitle {
  font-family: var(--font-heading); font-weight: 600; font-size: 15px; line-height: 1.25;
}
.sam-row:hover .sam-rowtitle, .sam-row:focus-visible .sam-rowtitle { color: var(--color-accent-700); }
.sam-all { padding-top: 14px; font-size: 12px; }

/* ── Built: the project grid ───────────────────────────────────────────── */
/* no section rule above it, so the break has to be carried by the space */
.sam-built-wrap { display: flex; flex-direction: column; gap: 20px; padding-top: 56px; }
.sam-built-head {
  display: flex; justify-content: space-between; align-items: baseline; gap: 20px;
}
.sam-built { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: clamp(20px, 3vw, 32px); }
.sam-card {
  display: flex; flex-direction: column; gap: 12px; min-width: 0;
  text-decoration: none; color: var(--color-text);
}
.sam-shot {
  aspect-ratio: 4 / 3; background: var(--color-neutral-200);
  border: 1px solid var(--color-neutral-400); min-width: 0; overflow: hidden;
}
.sam-shot img { width: 100%; height: 100%; object-fit: cover; }
.sam-card-title { font-family: var(--font-heading); font-weight: 800; font-size: 21px; line-height: 1.15; }
.sam-card:hover .sam-card-title { color: var(--color-accent-700); }
.sam-card-desc { font-size: 13.5px; line-height: 1.6; }
.sam-card-meta { font-size: 11px; letter-spacing: 0.06em; text-transform: uppercase; }

/* ── Footer ────────────────────────────────────────────────────────────── */
.sam-footer {
  /* the last rule on the page, and the only one below the masthead, so it
     needs more room above it than it did when others set the rhythm */
  border-top: 2px solid var(--color-text); margin-top: 60px; padding-top: 20px;
  display: flex; justify-content: space-between; align-items: baseline; gap: 32px;
  /* The masthead rule runs the full width of the page card; the footer sits
     inside .sam-pad, so its rule would stop a gutter short at each end and
     the two would not read as the same line. Pull the box out to the card's
     edges and put the gutter back as padding, so the rule matches the
     masthead's while the content stays on the same left edge as everything
     above it. */
  margin-left: calc(-1 * var(--pad)); margin-right: calc(-1 * var(--pad));
  padding-left: var(--pad); padding-right: var(--pad);
}
.sam-footer-meta { display: flex; gap: 12px; align-items: baseline; }

/* — light/dark toggle, first item in the footer —
   The icon shown is the state you are switching TO: a moon while light, a sun
   while dark. Both are in the DOM and CSS picks one, so the right icon paints
   without JavaScript. The button itself is hidden unless JS is available,
   because without it clicking does nothing. */
.sam-theme {
  display: none;  /* revealed by .has-js */
  align-items: center; justify-content: center;
  padding: 0; border: 0; background: none; cursor: pointer;
  color: var(--color-accent);
  /* pull the icon onto the text baseline of the name beside it */
  align-self: center; line-height: 0;
}
.has-js .sam-theme { display: inline-flex; }
.sam-theme:hover { color: var(--color-accent-700); }
.sam-theme:focus-visible { outline: 2px solid var(--color-accent); outline-offset: 2px; }
.sam-theme svg { display: block; }

/* default (light): offer the moon */
.sam-theme .i-sun { display: none; }
.sam-theme .i-moon { display: block; }
/* dark by OS preference, unless explicitly overridden to light */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .sam-theme .i-sun { display: block; }
  :root:not([data-theme="light"]) .sam-theme .i-moon { display: none; }
}
/* explicit choice wins in both directions */
:root[data-theme="dark"] .sam-theme .i-sun { display: block; }
:root[data-theme="dark"] .sam-theme .i-moon { display: none; }
:root[data-theme="light"] .sam-theme .i-sun { display: none; }
:root[data-theme="light"] .sam-theme .i-moon { display: block; }
.sam-footer-name {
  font-family: var(--font-heading); font-weight: 800; font-size: 13px;
  letter-spacing: 0.12em; text-transform: uppercase; white-space: nowrap;
}
.sam-footer-note { font-size: 11.5px; line-height: 1.6; white-space: nowrap; }
.sam-footer .sam-nav { justify-content: flex-end; align-items: baseline; padding-bottom: 0; }

/* ── Article ───────────────────────────────────────────────────────────── */
.sam-article { padding: 36px var(--pad) 0; }
.sam-article-head { display: flex; flex-direction: column; gap: 20px; }
.sam-article-head h1 {
  margin: 0; font-size: clamp(34px, 7vw, 60px); line-height: 0.96;
  letter-spacing: -0.035em; text-wrap: pretty;
}
.sam-article-meta { font-size: 12.5px; line-height: 1.7; font-variant-numeric: tabular-nums; }
.sam-lede { margin: 0; font-size: clamp(17px, 2.4vw, 19.5px); line-height: 1.5; text-wrap: pretty; }

/* prose — the design sets its body paragraphs at 16.5/1.72; the rest of the
   Markdown vocabulary is extended from that in the same voice */
.prose { font-size: 16.5px; line-height: 1.72; text-wrap: pretty; }
.prose > :first-child { margin-top: 0; }
.prose p, .prose ul, .prose ol { margin: 0 0 20px; }
.prose h2, .prose h3, .prose h4 {
  font-family: var(--font-heading); font-weight: 800;
  letter-spacing: -0.025em; line-height: 1.15; margin: 36px 0 12px;
}
.prose h2 { font-size: 28px; }
.prose h3 { font-size: 21px; }
.prose h4 { font-size: 17px; }
.prose a { color: var(--color-accent-700); text-underline-offset: 3px; }
.prose strong { font-weight: 600; }
.prose ul { list-style: none; padding-left: 0; }
.prose ul > li { position: relative; padding-left: 22px; }
.prose ul > li::before {
  content: ""; position: absolute; left: 0; top: 0.62em;
  width: 6px; height: 6px; background: var(--color-accent);
}
.prose ol { padding-left: 22px; }
.prose li + li { margin-top: 8px; }
.prose blockquote {
  margin: 28px 0; padding-left: 16px; border-left: 2px solid var(--color-accent);
}
.prose blockquote p:last-child { margin-bottom: 0; }
.prose code { background: var(--color-surface); padding: 0 4px; font-size: 14px; }
.prose pre {
  background: var(--color-surface); padding: 14px 16px; margin: 28px 0;
  font-size: 14px; line-height: 1.6; overflow-x: auto;
}
.prose pre code { background: none; padding: 0; }
.prose hr { height: 2px; border: 0; background: var(--color-divider); margin: 32px 0; }
.prose img { width: 100%; height: auto; }
.prose figure { margin: 28px 0; }
.prose figcaption { font-size: 11.5px; line-height: 1.6; margin-top: 6px; }
.prose table { width: 100%; border-collapse: collapse; font-size: 15px; margin: 28px 0; }

/* photos carried over with a post from its original platform */
.sam-post-images {
  display: grid; gap: 16px; margin: 32px 0 0;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
}
.sam-post-figure { margin: 0; }
.sam-post-figure img {
  width: 100%; height: auto; display: block;
  /* a frame, not a rule: the screenshots are mostly white and would bleed
     into the page without an edge. Kept, but as a hairline. */
  border: 1px solid var(--color-neutral-400);
}
.sam-post-source {
  font-size: 13px; margin: 32px 0 0;
}

/* the "Next" rail under an article */
.sam-next {
  display: flex; gap: 20px; align-items: baseline;
  padding-top: 4px; margin-top: 8px; flex-wrap: wrap;
}
.sam-next-label {
  font-family: var(--font-heading); font-weight: 800; font-size: 11px;
  letter-spacing: 0.1em; text-transform: uppercase;
}
.sam-next a { font-family: var(--font-heading); font-weight: 600; font-size: 17px; }

/* ── Index pages ───────────────────────────────────────────────────────── */
.sam-index { padding-top: 32px; }
.sam-index-rows { display: flex; flex-direction: column; }
.sam-index-rows .sam-row { padding: 20px 0; }
.sam-index-rows .sam-rowtitle { font-size: 19px; }
.sam-index-excerpt { font-size: 14px; line-height: 1.6; margin: 4px 0 0; }

/* ── Responsive ────────────────────────────────────────────────────────────
   The design file's own collapse, with its !important overrides dropped —
   they exist only to beat the canvas's inline styles, which no longer apply
   here because the layout lives in classes.
   ─────────────────────────────────────────────────────────────────────── */
@media (max-width: 1000px) {
  .sam-intro { grid-template-columns: minmax(0, 1fr); align-items: start; }
  .sam-lead { grid-template-columns: minmax(0, 1fr); }
  .sam-lead-main { padding: 20px 0 8px; }
  .sam-lead-side { padding: 24px 0 28px; }
  .sam-built { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  /* stacked, so there is no baseline to share — the two halves sit as rows */
  .sam-headerB { flex-direction: column; align-items: stretch; }
  .sam-headerB-name { padding: 16px 32px 8px; }
  .sam-headerB-name span { white-space: nowrap; }
  .sam-headerB-bar {
    flex-direction: column; align-items: flex-start;
    gap: 10px; padding: 0 32px 14px;
  }
  .sam-nav { flex-wrap: wrap; gap: 4px 18px; justify-content: flex-start; }
}
@media (max-width: 720px) {
  :root { --pad: 20px; }
  .sam-shell { padding: 0; gap: 0; }
  .sam-page { width: 100%; }
  .sam-headerB-name { padding: 16px 20px 8px; }
  .sam-headerB-bar { padding: 0 20px 14px; }
  .sam-nav a { min-height: 44px; display: flex; align-items: center; }
  .sam-built { grid-template-columns: minmax(0, 1fr); }
  .sam-footer { flex-direction: column; align-items: flex-start; gap: 18px; }
  .sam-footer-meta { flex-direction: column; gap: 4px; }
  .sam-footer-note { white-space: normal; }
  .sam-built-note { display: none; }
  .sam-row { min-height: 44px; justify-content: center; }
  .sam-hand { opacity: 1; transform: none; }
}

/* Not in the design file. The role rotator loops forever, so it must be
   stoppable for anyone who has asked the OS to reduce motion. */
@media (prefers-reduced-motion: reduce) {
  .sam-roles-track { animation: none; }
  .sam-hand { transition: none; }
}
