/* =========================================================================
   elimdesign.dev — styles
   Plain CSS, hand-editable. No framework, no build step.

   HOW THIS FILE IS ORGANISED
   1. CONFIG          — colours, type, spacing. Edit these first.
   2. RESET / BASE
   3. LAYOUT          — the left-weighted column
   4. HEADER          — the hand-drawn "e" mark + nav
   5. PROSE & NOTES   — the writing, which is the whole point
   6. FOOTER
   7. AMBIENT GRAIN   — the faint paper texture (motion lives in §8 + main.js)
   8. MOTION          — every animated effect, each labelled so you can dial
                        it down or delete it outright.
   ========================================================================= */


/* =========================================================================
   1. CONFIG  — the knobs. Greyscale-forward, WARM greys (ink on paper).
   ------------------------------------------------------------------------
   The ACCENT is NOT set here — it is computed from the local time of day in
   main.js (ochre at midday, terracotta late at night) and injected as
   --accent / --accent-dk. If JS is off, the fallbacks below are used.
   ========================================================================= */
:root {
  /* --- warm greys, light mode (the primary, most-considered palette) --- */
  --paper:        #f4f2ee;   /* off-white base, never pure #fff           */
  --paper-2:      #ece9e3;   /* very slightly deeper, for the top bar etc */
  --ink:          #1a1916;   /* near-black text, never pure #000          */
  --ink-soft:     #514d45;   /* secondary text                            */
  --ink-faint:    #8a8479;   /* dates, metadata, muted asides             */
  --rule:         #d8d3c9;   /* 1px hairline colour (warm)                */

  /* --- accent (link colour only). Fallback if JS doesn't run. --------- */
  --accent:       #a8772e;   /* muted ochre — overwritten by main.js      */
  --accent-dk:    #c89a52;   /* lighter accent for dark mode              */

  /* --- type --------------------------------------------------------- */
  --font-body: 'Newsreader', Georgia, 'Times New Roman', serif;
  --font-mono: ui-monospace, 'SF Mono', 'Cascadia Code', 'Roboto Mono',
               Menlo, Consolas, monospace;

  /* --- measure & rhythm --------------------------------------------- */
  --measure: 70ch;           /* max line length — narrow, but not cramped */
  --bias:    0.42;           /* column placement: 0 = hard left,         */
                             /* 0.5 = dead centre. 0.42 = a gentle lean. */
  --step:    1.5rem;         /* base vertical rhythm                     */

  /* --- grain --------------------------------------------------------- */
  --grain-opacity: 0.05;     /* paper texture strength (light mode)      */

  color-scheme: light;
}

/* --- dark mode. Still WARM — a dim room, not a blue "dark-mode UI". ---
   Light is primary; dark is a considerate second draft, not the default. */
:root[data-theme="dark"] {
  --paper:        #16150f;   /* warm near-black, faint green-brown cast   */
  --paper-2:      #1d1b14;
  --ink:          #e7e2d6;   /* warm off-white text                       */
  --ink-soft:     #b3ac9c;
  --ink-faint:    #756f60;
  --rule:         #2c2920;
  --accent:       var(--accent-dk);
  --grain-opacity: 0.07;     /* texture reads a touch stronger on dark    */
  color-scheme: dark;
}


/* =========================================================================
   2. RESET / BASE
   ========================================================================= */
*, *::before, *::after { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--font-body);
  font-optical-sizing: auto;
  font-weight: 400;
  font-size: clamp(1.05rem, 0.92rem + 0.55vw, 1.3rem);
  line-height: 1.62;
  text-rendering: optimizeLegibility;
  -webkit-font-smoothing: antialiased;
  /* gentle colour shift when the time-accent or theme changes underfoot */
  transition: background-color 600ms ease, color 600ms ease;
}

a {
  color: var(--accent);
  text-decoration: none;
  /* underline on hover only — no buttons pretending to be links */
}
a:hover { text-decoration: underline; text-underline-offset: 0.18em; }

h1, h2, h3 { font-weight: 500; line-height: 1.2; }

::selection { background: var(--accent); color: var(--paper); }


/* =========================================================================
   3. LAYOUT — one narrow column, weighted LEFT (asymmetry is welcome).
   ========================================================================= */
.page {
  max-width: var(--measure);
  /* Sit the column slightly LEFT of centre — keeps the asymmetry without
     stranding it in the corner. --bias controls the lean: it puts that
     fraction of the leftover space on the left, the rest on the right.
     The max() floor keeps a sane gutter on narrow screens. */
  margin-block: 0;
  margin-left: max(1.4rem, calc((100% - var(--measure)) * var(--bias)));
  margin-right: auto;
  padding: clamp(2rem, 6vh, 4.5rem) 1.4rem 6rem;
}

.stack > * + * { margin-top: var(--step); }


/* =========================================================================
   4. HEADER — the hand-drawn "e" mark + quiet nav.
   The mark is a personal mark, not a logo. No box, no circle.
   ========================================================================= */
.masthead {
  display: flex;
  align-items: baseline;
  gap: 1.5rem;
  margin-bottom: clamp(2.5rem, 7vh, 5rem);
}

.mark {
  flex: none;
  display: block;
  width: 34px;
  height: 34px;
  color: var(--ink);          /* the stroke inherits this                 */
  transform: translateY(4px); /* sit it on the nav baseline               */
}
.mark svg { display: block; width: 100%; height: 100%; overflow: visible; }
.mark path {
  fill: none;
  stroke: currentColor;
  stroke-width: 2.4;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.nav {
  display: flex;
  flex-wrap: wrap;
  gap: 0.2rem 1.25rem;
  font-family: var(--font-mono);
  font-size: 0.82rem;
  letter-spacing: 0.01em;
}
.nav a { color: var(--ink-soft); }
.nav a:hover { color: var(--accent); }
.nav a[aria-current="page"] { color: var(--ink); }
.nav a[aria-current="page"]::before { content: "· "; color: var(--accent); }

/* theme toggle — text, not a chunky button */
.theme-toggle {
  margin-left: auto;
  font-family: var(--font-mono);
  font-size: 0.82rem;
  color: var(--ink-faint);
  background: none;
  border: 0;
  padding: 0;
  cursor: pointer;
}
.theme-toggle:hover { color: var(--accent); }


/* =========================================================================
   5. PROSE & NOTES — let the writing be the focus.
   ========================================================================= */
.intro p { color: var(--ink); max-width: 58ch; }
.intro p + p { margin-top: var(--step); }

.lede { font-size: 1.15em; }

h1.title {
  font-size: clamp(1.8rem, 1.4rem + 1.6vw, 2.5rem);
  font-weight: 500;
  letter-spacing: -0.01em;
  margin: 0 0 0.4rem;
}
.subtitle {
  font-family: var(--font-mono);
  font-size: 0.8rem;
  color: var(--ink-faint);
  margin: 0 0 2.5rem;
}

/* section heading sat above a hairline */
.section-head {
  font-family: var(--font-mono);
  font-size: 0.78rem;
  font-weight: 400;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-faint);
  padding-top: 1.4rem;
  border-top: 1px solid var(--rule);   /* hairline divider, not a card */
  margin: 3rem 0 0.5rem;
}

/* --- the notes list: a changelog of a brain --- */
.notes { list-style: none; margin: 0; padding: 0; }
.note {
  display: grid;
  grid-template-columns: 7.5rem 1fr;
  gap: 0.2rem 1.5rem;
  padding: 1.4rem 0;
  border-top: 1px solid var(--rule);   /* hairline between entries     */
}
.note:first-of-type { border-top: 0; }
.note__date {
  font-family: var(--font-mono);
  font-size: 0.78rem;
  color: var(--ink-faint);
  padding-top: 0.35rem;
  white-space: nowrap;
}
.note__title { font-size: 1.1rem; font-weight: 500; margin: 0 0 0.15rem; }
.note__line  { margin: 0; color: var(--ink-soft); max-width: 52ch; }

/* on narrow screens the date stacks above the entry */
@media (max-width: 34rem) {
  .note { grid-template-columns: 1fr; gap: 0.35rem; }
  .note__date { padding-top: 0; }
}

/* full diary entries (notes.html) — a little more room to breathe */
.entry { padding: 1.8rem 0; border-top: 1px solid var(--rule); }
.entry:first-of-type { border-top: 0; }
.entry__meta {
  font-family: var(--font-mono);
  font-size: 0.78rem;
  color: var(--ink-faint);
  margin: 0 0 0.5rem;
}
.entry h3 { margin: 0 0 0.6rem; font-size: 1.3rem; }
.entry p { margin: 0 0 0.9rem; }
.entry p:last-child { margin-bottom: 0; }

/* --- uses list: plain rows, gear + a short aside --- */
.uses { list-style: none; margin: 0; padding: 0; }
.uses li {
  padding: 0.9rem 0;
  border-top: 1px solid var(--rule);
}
.uses li:first-child { border-top: 0; }
.uses b { font-weight: 500; }
.uses .aside { color: var(--ink-soft); }
.uses .meta { font-family: var(--font-mono); font-size: 0.78rem; color: var(--ink-faint); }


/* =========================================================================
   6. FOOTER — email + one dry line. Nothing else.
   ========================================================================= */
.site-footer {
  margin-top: 5rem;
  padding-top: 1.4rem;
  border-top: 1px solid var(--rule);
  font-family: var(--font-mono);
  font-size: 0.78rem;
  color: var(--ink-faint);
  line-height: 1.7;
}
.site-footer a { color: var(--ink-soft); }
.site-footer a:hover { color: var(--accent); }
.site-footer .whisper { display: block; margin-top: 0.4rem; }


/* =========================================================================
   7. AMBIENT GRAIN — faint paper/noise texture over everything.
   The drift animation itself lives in §8 so all motion is in one place.
   ========================================================================= */
.grain {
  position: fixed;
  /* oversized so the slow drift never exposes an edge */
  inset: -150px;
  z-index: -1;
  pointer-events: none;
  opacity: var(--grain-opacity);
  /* a small tiled SVG fractal-noise field */
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
  background-size: 160px 160px;
}
:root[data-theme="dark"] .grain { mix-blend-mode: screen; }


/* =========================================================================
   8. MOTION — every animated effect lives here. Each block is labelled.
   Dial intensity with the numbers noted, or delete a block to remove it.
   Global rule: if the visitor asked for less motion, give them none.
   ========================================================================= */

/* ---- (a) top read-progress hairline -----------------------------------
   A 1px line at the very top of the viewport, in the accent colour,
   scaled by scroll position from main.js. Remove this block + its <div>
   in the HTML to drop it.                                                */
.progress {
  position: fixed;
  top: 0; left: 0;
  height: 1px;
  width: 100%;
  background: var(--accent);
  transform: scaleX(0);
  transform-origin: 0 50%;
  z-index: 10;
  /* the tiny smoothing between scroll frames; raise for laggier feel */
  transition: transform 80ms linear;
}

/* ---- (b) the "e" mark draws itself once on load -----------------------
   stroke-dashoffset is set to the path length in main.js, then released
   to 0 over this duration. Change 1.2s to speed up / slow down the draw. */
.mark path.draw {
  transition: stroke-dashoffset 1.2s ease-out;
}

/* ---- (c) ambient grain drift ------------------------------------------
   A very slow, almost-subliminal wander. 90s cycle. Paused when the tab
   is hidden or reduced-motion is on (handled in main.js via .is-paused).
   Lower the translate distances for even less movement.                  */
@keyframes grain-drift {
  0%   { transform: translate(0, 0); }
  25%  { transform: translate(-14px, 8px); }
  50%  { transform: translate(8px, -12px); }
  75%  { transform: translate(10px, 6px); }
  100% { transform: translate(0, 0); }
}
.grain { animation: grain-drift 90s ease-in-out infinite; }
.grain.is-paused { animation-play-state: paused; }

/* ---- (d) scroll reveal -------------------------------------------------
   Elements tagged .reveal start a touch lower + transparent, then settle
   when they scroll into view (main.js adds .is-in, staggered per element).
   Tune: translateY distance (10px) and duration (500ms).

   NOTE: the hidden start-state is scoped to .js — set on <html> by a tiny
   inline script in each page's <head>. So if JavaScript never runs, the
   content is simply visible (no blank page), which is the whole point of a
   readable, progressively-enhanced site.                                  */
.js .reveal {
  opacity: 0;
  transform: translateY(10px);
  transition: opacity 500ms ease-out, transform 500ms ease-out;
  /* per-element stagger is set inline by main.js as --reveal-delay */
  transition-delay: var(--reveal-delay, 0ms);
  will-change: opacity, transform;
}
.js .reveal.is-in { opacity: 1; transform: none; }


/* ---- REDUCED MOTION: switch everything above OFF ----------------------
   No drift, no draw-in, no reveal travel, no progress smoothing.
   Content still fully visible — we only remove the movement.             */
@media (prefers-reduced-motion: reduce) {
  .grain { animation: none; }
  .mark path.draw { transition: none; stroke-dashoffset: 0 !important; }
  .reveal, .js .reveal { opacity: 1; transform: none; transition: none; }
  .progress { transition: none; }
  body { transition: none; }
}
