/* ============================================================
   styles.css — every visual decision on the site lives here.

   CSS = "Cascading Style Sheets." Each rule has two parts:

       .site-head {  padding: 20px;  }
       ^selector     ^property: value

   The SELECTOR says which elements to style (".site-head" means
   'anything with class="site-head"'), and the block says how.
   "Cascading" means later/more-specific rules can override
   earlier ones — that's the whole trick of the language.

   THE LAYOUT, IN ONE SENTENCE: one centred column, capped at
   720px for reading, with the retro-computer character kept as
   trim — pixel typeface, olive rules, small icons, hard square
   focus outlines — instead of as a pretend desktop.

   Order of this file:
     1. fonts        5. home page
     2. palette      6. writing archive
     3. reset + a11y 7. article + shared prose
     4. header/nav   8. projects / now / footer / responsive
   ============================================================ */

/* ===== 1. Self-hosted fonts ==================================
   @font-face teaches the browser a font by pointing at a file we
   serve ourselves (fonts/ in this repo) — no Google request, no
   third-party privacy leak, no outage risk. font-display:swap
   means "show text in a fallback font immediately, swap when the
   real one arrives" (never invisible text).
   Pixelify Sans is a VARIABLE font: one file covers every weight
   from 400–700 (that's what the two-number weight range means). */
@font-face {
  font-family: "Pixelify Sans";
  src: url("fonts/pixelify-var.woff2") format("woff2");
  font-weight: 400 700;
  font-display: swap;
}
@font-face {
  font-family: "IBM Plex Mono";
  src: url("fonts/plexmono-400.woff2") format("woff2");
  font-weight: 400;
  font-display: swap;
}
@font-face {
  font-family: "IBM Plex Mono";
  src: url("fonts/plexmono-500.woff2") format("woff2");
  font-weight: 500;
  font-display: swap;
}
@font-face {
  font-family: "IBM Plex Mono";
  src: url("fonts/plexmono-600.woff2") format("woff2");
  font-weight: 600;
  font-display: swap;
}

/* ===== 2. Palette and type ===================================
   :root = the whole document. Variables defined here (the names
   starting with --) are readable everywhere below via var(...).
   Change --olive here and every olive thing on the site changes.
   This is the site's entire palette and type system in one place. */
:root {
  --paper:     #f4f1e8;  /* page background                    */
  --surface:   #e5e0d2;  /* callout / quote / code background  */
  --ink:       #26251f;  /* body text (near-black)             */
  /* Muted text is a touch darker than the design study asked
     for. Measured: the study's #77736a is 4.19:1 against this
     cream, under the 4.5:1 accessibility floor for small text.
     This one is 4.96:1 and reads the same. */
  --ink-soft:  #6b685c;  /* dates, captions, secondary text    */
  --olive:     #667346;  /* links and accents — 4.5:1 on paper */
  --olive-dim: #8c9472;  /* decoration only: rules, shadows    */
  --rule:      rgba(38, 37, 31, 0.16); /* hairlines            */

  /* Font stacks: try the first font; fall back rightward if it
     hasn't loaded. --pixel for display text, --mono for body. */
  --pixel: "Pixelify Sans", "IBM Plex Mono", monospace;
  --mono:  "IBM Plex Mono", "Courier New", monospace;

  /* Two widths do all the layout work: --reading is the essay
     column, --wide is everything roomier (archive, now page). */
  --reading: 720px;
  --wide: 860px;
  --gutter: 24px;
}

/* Dark theme. prefers-color-scheme reads the reader's OS setting
   — no toggle to find, no preference to store. Near-black rather
   than pure black, and a lighter olive so links stay legible. */
@media (prefers-color-scheme: dark) {
  :root {
    --paper:     #11110f;
    --surface:   #282821;
    --ink:       #f3efe5;
    --ink-soft:  #aaa69d;
    --olive:     #a7b47a;
    --olive-dim: #6e7652;
    --rule:      rgba(243, 239, 229, 0.18);
  }
}

/* ===== 3. Reset and accessibility ============================
   Browsers ship default margins/paddings that differ between
   browsers; zeroing them makes layout predictable.
   box-sizing:border-box makes width INCLUDE padding and border —
   the sane way to reason about box sizes. */
* { box-sizing: border-box; margin: 0; padding: 0; }

html {
  /* Clicking an in-page link glides instead of jumping… */
  scroll-behavior: smooth;
  -webkit-text-size-adjust: 100%;
}
/* …unless the reader has asked their system for less motion. */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  * { animation: none !important; transition: none !important; }
}

body {
  font-family: var(--mono);
  font-size: 17px;
  line-height: 1.7;
  color: var(--ink);
  background: var(--paper);
  -webkit-font-smoothing: antialiased;
  -webkit-tap-highlight-color: transparent; /* no grey flash on mobile taps */
  /* The page is a top-to-bottom stack: header, content, footer.
     min-height + flex:1 on <main> pins the footer to the bottom
     even when a page is short. */
  min-height: 100vh;
  display: flex;
  flex-direction: column;
}

svg { display: block; } /* kills stray gaps under inline SVGs */
img { max-width: 100%; height: auto; }

/* Subtle paper grain over everything.
   ::after is a PSEUDO-ELEMENT — a phantom box CSS invents so you
   can add decoration without touching the HTML. This one is a
   fixed, click-through sheet of 4px checkerboard at ~1.5%
   opacity: just enough texture to feel like paper. */
body::after {
  content: "";
  position: fixed;
  inset: 0;               /* shorthand: top/right/bottom/left = 0 */
  pointer-events: none;   /* clicks pass straight through it */
  z-index: 1;
  opacity: 0.5;
  background-image: repeating-conic-gradient(rgba(38, 37, 31, 0.015) 0% 25%, transparent 0% 50%);
  background-size: 4px 4px;
}
@media (prefers-color-scheme: dark) {
  body::after { background-image: repeating-conic-gradient(rgba(243, 239, 229, 0.02) 0% 25%, transparent 0% 50%); }
}

/* Keyboard focus. :focus-visible fires only for keyboard focus
   (Tab), not mouse clicks — so keyboard users get a clear ring
   and mouse users never see it. Square, never rounded: that's
   the retro-computer detail doing quiet work. */
:focus-visible {
  outline: 2px solid var(--olive);
  outline-offset: 3px;
  border-radius: 0;
}
main:focus { outline: none; } /* the skip link targets it; no ring needed */

/* The skip link: off-screen until a keyboard reaches it. */
.skip {
  position: absolute;
  left: -9999px;
  z-index: 20;
  padding: 10px 16px;
  background: var(--paper);
  border: 2px solid var(--ink);
  color: var(--ink);
  font-family: var(--pixel);
  text-decoration: none;
}
.skip:focus { left: 12px; top: 12px; }

/* Shared link treatment: olive, with an underline that sits far
   enough below the text to stay readable. */
a { color: var(--olive); }
a:hover { text-decoration-thickness: 2px; }

/* The tiny uppercase labels used above sections and callouts —
   the "status label" flavour of the old operating system, kept. */
.eyebrow {
  font-family: var(--pixel);
  font-size: 12px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-soft);
}

/* Two container widths, both centred, both with the same gutter
   so nothing ever touches the edge of a phone screen. */
.wrap { width: 100%; max-width: var(--wide); margin: 0 auto; padding: 0 var(--gutter); }
.wrap-read { width: 100%; max-width: var(--reading); margin: 0 auto; padding: 0 var(--gutter); }

main { flex: 1; position: relative; z-index: 2; padding: 56px 0 80px; }

/* ===== 4. Header and navigation ==============================
   A single quiet row: pixel mark on the left, sections on the
   right, one hairline underneath. It does not stick to the top —
   nothing should compete with the writing while you read. */
.site-head {
  position: relative;
  z-index: 3;
  border-bottom: 1px solid var(--rule);
}
.head-inner {
  width: 100%;
  max-width: var(--wide);
  margin: 0 auto;
  padding: 18px var(--gutter);
  display: flex;
  align-items: center;
  gap: 16px;
}
.mark { color: var(--ink); flex: none; }
.mark svg { width: 26px; height: 26px; }
.mark:hover { color: var(--olive); }

.site-nav {
  margin-left: auto;         /* pushes the links to the right edge */
  display: flex;
  gap: 26px;
}
.site-nav a {
  font-family: var(--pixel);
  font-size: 16px;
  color: var(--ink);
  text-decoration: none;
  padding: 2px 0;
  border-bottom: 2px solid transparent;
}
.site-nav a:hover { color: var(--olive); border-bottom-color: var(--olive-dim); }
/* script.js adds .current to whichever section you're in. */
.site-nav a.current { color: var(--olive); border-bottom-color: var(--olive); }

/* The hamburger is hidden on wide screens (see the responsive
   block at the bottom, which turns it on). */
.menu-btn {
  display: none;
  margin-left: auto;
  background: none;
  border: 2px solid var(--rule);
  color: var(--ink);
  padding: 6px;
  cursor: pointer;
}
.menu-btn svg { width: 20px; height: 20px; }

/* ===== 5. Home page ==========================================
   The one place the site raises its voice: an oversized pixel
   nameplate with a restrained olive offset shadow, then straight
   into plain paragraphs. */
.hero { text-align: center; padding-bottom: 8px; }

.hero-hello {
  font-family: var(--mono);
  font-size: 15px;
  color: var(--ink-soft);
  margin-bottom: 18px;
}

.hero-title {
  font-family: var(--pixel);
  font-weight: 700;
  /* clamp(min, preferred, max): 40px on a small phone, growing
     with the viewport, never past 88px. One line of CSS replaces
     a stack of breakpoints. */
  font-size: clamp(40px, 10vw, 88px);
  line-height: 1.04;
  letter-spacing: 0.01em;
  text-transform: uppercase;
  /* The offset shadow — the one piece of the old desktop mockup
     that survives at full volume. No blur: a hard pixel edge. */
  text-shadow: 4px 4px 0 var(--olive-dim);
  margin: 0 auto 22px;
  max-width: 12ch;   /* forces the name to break into 2–3 lines */
}

.hero-sub {
  font-size: 16px;
  color: var(--ink-soft);
  max-width: 46ch;
  margin: 0 auto 34px;
}

.hero-rule {
  border: 0;
  border-top: 1px solid var(--rule);
  margin: 0 auto 34px;
  max-width: 120px;
}

/* "Recently written" — the short list under the introduction. */
.recent { margin-top: 54px; padding-top: 26px; border-top: 1px solid var(--rule); }
.recent-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 16px;
  margin-bottom: 18px;
}
.recent-head a { font-family: var(--pixel); font-size: 14px; text-decoration: none; }
.recent-head a:hover { text-decoration: underline; }

.recent-item {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 20px;
  padding: 11px 0;
  border-bottom: 1px solid var(--rule);
  text-decoration: none;
  color: var(--ink);
}
.recent-item:last-child { border-bottom: 0; }
.recent-item .t { font-family: var(--pixel); font-size: 19px; color: var(--olive); }
.recent-item:hover .t { text-decoration: underline; text-underline-offset: 3px; }
.recent-item .d { font-size: 13px; color: var(--ink-soft); white-space: nowrap; }

/* ===== 6. Writing archive ====================================
   Grouped by year, newest first. Each entry: a big linked title,
   a date pinned to the right, and a sentence or two underneath. */
.year {
  font-family: var(--pixel);
  font-size: 34px;
  text-align: center;
  color: var(--ink);
  margin: 54px 0 10px;
}
.year:first-of-type { margin-top: 18px; }

.entry { padding: 26px 0; border-top: 1px solid var(--rule); }
.entry-top {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 24px;
}
.entry-title {
  font-family: var(--pixel);
  font-weight: 600;
  font-size: clamp(22px, 3.4vw, 28px);
  line-height: 1.25;
  color: var(--olive);
  text-decoration: none;
}
.entry-title:hover { text-decoration: underline; text-underline-offset: 4px; }
/* Date and topic sit together on the right, stacked. */
.entry-meta {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 3px;
  flex: none;
  text-align: right;
}
.entry-date, .entry-tag {
  font-size: 12px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  white-space: nowrap;
}
.entry-date { color: var(--ink-soft); }
.entry-tag { font-size: 11px; color: var(--olive); }
.entry-desc { margin-top: 10px; color: var(--ink); max-width: 62ch; }

/* ===== 7. Article and shared prose ===========================
   Everything a body of text needs, defined once and reused by
   the article, About, Contact and the archive descriptions. */
.post-head { margin-bottom: 36px; }
.post-title {
  font-family: var(--pixel);
  font-weight: 700;
  font-size: clamp(30px, 5.5vw, 46px);
  line-height: 1.15;
  margin-bottom: 14px;
}
/* Title, date, topic — the simple metadata row under the title. */
.post-meta {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px 18px;
  padding-bottom: 14px;
  border-bottom: 1px solid var(--rule);
  font-size: 12px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-soft);
}
.post-meta .topic { color: var(--olive); }

/* .prose is the wrapper around any rendered body text. Styling
   the CHILDREN of one class (rather than every <p> on the site)
   keeps the rules from leaking into headers and navigation. */
.prose > * + * { margin-top: 1.35em; }  /* even rhythm, no orphan margins */
.prose p { max-width: 68ch; }
.prose a { text-underline-offset: 3px; }

.prose h2 {
  font-family: var(--pixel);
  font-weight: 600;
  font-size: 25px;
  line-height: 1.3;
  margin-top: 2em;
  padding-bottom: 6px;
  /* The olive underline under section headings — inherited from
     the old design, one of the details worth keeping. */
  border-bottom: 2px solid var(--olive-dim);
}

.prose ul { padding-left: 1.2em; max-width: 68ch; }
.prose li { margin-top: 0.4em; }
.prose li::marker { color: var(--olive-dim); }

.prose blockquote {
  border-left: 3px solid var(--olive-dim);
  background: var(--surface);
  padding: 14px 20px;
  max-width: 68ch;
}
.prose blockquote p + p { margin-top: 0.8em; }

.prose img {
  display: block;
  width: 100%;
  border: 2px solid var(--ink);  /* the hard retro frame */
}
/* Captions and other small print inside a body of text. */
.prose .cap {
  font-size: 13px;
  color: var(--ink-soft);
  margin-top: 0.6em;
}

/* Optional labelled callout — "ARCHIVE NOTE", "SOURCE". Not used
   by any post yet; the style is here so one can be added without
   touching CSS again. */
.callout {
  background: var(--surface);
  border-left: 3px solid var(--olive);
  padding: 16px 20px;
}
.callout .eyebrow { display: block; margin-bottom: 6px; }

/* The row at the foot of an article. */
.post-foot {
  margin-top: 52px;
  padding-top: 20px;
  border-top: 1px solid var(--rule);
  font-family: var(--pixel);
  font-size: 15px;
}
.post-foot a { text-decoration: none; }
.post-foot a:hover { text-decoration: underline; }

/* ===== 8. Projects, Now, footer, page headings ================ */

/* Every section that isn't the home page opens the same way:
   a small label, a big pixel title, a hairline. */
.page-head { margin-bottom: 34px; }
.page-title {
  font-family: var(--pixel);
  font-weight: 700;
  font-size: clamp(30px, 5.5vw, 46px);
  line-height: 1.15;
  margin: 6px 0 14px;
}
.page-note { color: var(--ink-soft); font-size: 15px; max-width: 60ch; }

/* Projects use the same list language as the archive — no
   folder grid, no second visual system to learn. */
.project {
  display: block;
  padding: 22px 0;
  border-top: 1px solid var(--rule);
  text-decoration: none;
  color: var(--ink);
}
.project-top {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 20px;
}
.project-name {
  font-family: var(--pixel);
  font-size: 24px;
  color: var(--olive);
}
.project:hover .project-name { text-decoration: underline; text-underline-offset: 4px; }
/* The padlock label on password-protected projects. The lock is
   real: the server (Caddy) asks for the password, not this CSS. */
.project-status {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-size: 11px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-soft);
  white-space: nowrap;
  flex: none;
}
.project-status svg { width: 13px; height: 13px; }
.project-note { margin-top: 8px; color: var(--ink-soft); font-size: 15px; }

/* Now page: sections flow into columns on a wide screen and
   stack on a narrow one, without any breakpoint maths. */
.now-cols { columns: 2; column-gap: 46px; }
.now-sec { break-inside: avoid; margin-bottom: 30px; }
.now-sec h2 {
  font-family: var(--pixel);
  font-size: 20px;
  font-weight: 600;
  padding-bottom: 5px;
  margin-bottom: 10px;
  border-bottom: 2px solid var(--olive-dim);
}
.now-sec ul { list-style: none; }
.now-sec li { padding: 3px 0; }
.now-sec li::before { content: "· "; color: var(--olive-dim); }

.empty-note { color: var(--ink-soft); padding: 20px 0; }

.site-foot {
  position: relative;
  z-index: 2;
  border-top: 1px solid var(--rule);
  padding: 22px 0 30px;
}
.foot-inner {
  width: 100%;
  max-width: var(--wide);
  margin: 0 auto;
  padding: 0 var(--gutter);
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 10px 20px;
  font-size: 13px;
  color: var(--ink-soft);
}
.foot-name { font-family: var(--pixel); font-size: 14px; }
.foot-links { display: flex; gap: 18px; }
.foot-links a { text-decoration: none; }
.foot-links a:hover { text-decoration: underline; }

/* ===== Responsive ============================================
   One breakpoint, because the layout is one column already. What
   changes on a phone: the navigation collapses behind the button,
   the Now page becomes a single column, and the type eases down.
   Nothing is hidden — the mobile site has everything the desktop
   site has. */
@media (max-width: 720px) {
  :root { --gutter: 20px; }
  body { font-size: 16px; }
  main { padding: 34px 0 56px; }

  .menu-btn { display: block; }

  /* Closed by default on phones; script.js adds .open to the
     <nav> when the button is pressed. flex-basis:100% pushes the
     menu onto its own row underneath the header. */
  .site-nav {
    display: none;
    flex-basis: 100%;
    flex-direction: column;
    gap: 0;
    margin: 10px 0 0;
    border-top: 1px solid var(--rule);
  }
  .site-nav.open { display: flex; }
  .site-nav a {
    padding: 12px 0;
    border-bottom: 1px solid var(--rule);
    border-top: 0;
  }
  .site-nav a.current { border-bottom-color: var(--rule); }
  .head-inner { flex-wrap: wrap; }

  .hero-title { text-shadow: 3px 3px 0 var(--olive-dim); max-width: 10ch; }
  .year { font-size: 27px; margin-top: 40px; }

  /* Titles and dates stop sharing a line — the date drops
     underneath rather than squeezing the title into a column. */
  .entry-top, .project-top, .recent-item { flex-direction: column; gap: 6px; }
  .entry-meta, .recent-item .d { order: -1; }  /* date first, then title */
  .entry-meta { flex-direction: row; align-items: baseline; gap: 10px; text-align: left; }

  .now-cols { columns: 1; }
  .foot-inner { flex-direction: column; align-items: flex-start; }
}

/* Print: drop the furniture, keep the words. */
@media print {
  .site-head, .site-foot, .post-foot, body::after { display: none; }
  body { color: #000; background: #fff; font-size: 12pt; }
  main { padding: 0; }
}
