/* Sid's Musings — black, Hanken Grotesk, Newsreader italics, #FF5A1F accent,
   tuned for long-form reading. */
:root{
  --reg:#FF5A1F;
  --dim:#8A8A84;
  --ink:#CFCFC9;      /* body text: softer than pure white for long reads */
  --rule:rgba(255,255,255,.14);
}
*{box-sizing:border-box}
html{background:#000;scroll-behavior:smooth}
body{
  margin:0;background:#000;color:var(--ink);
  font-family:"Hanken Grotesk",system-ui,sans-serif;
  -webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility;
  min-height:100vh;
}
::selection{background:var(--reg);color:#fff}

/* ---------- top nav ---------- */
.top{
  position:fixed;top:0;left:0;right:0;z-index:10;
  display:flex;justify-content:space-between;align-items:baseline;
  padding:24px 32px;pointer-events:none;
  background:linear-gradient(to bottom, rgba(0,0,0,.92), transparent);
}
.top a{
  pointer-events:auto;text-decoration:none;color:var(--dim);
  font-size:13px;letter-spacing:.04em;transition:color .2s;
}
.top a:hover{color:#fff}
.top .wordmark{
  font-family:"Newsreader",Georgia,serif;font-style:italic;
  font-size:17px;letter-spacing:0;color:#B9B9B2;
}
.top .wordmark:hover{color:#fff}

/* ---------- entrance ---------- */
@keyframes rise{from{opacity:0;transform:translateY(14px);filter:blur(6px)}
                to{opacity:1;transform:none;filter:blur(0)}}
.rise{animation:rise .7s cubic-bezier(.23,1,.32,1) both}
.rise-2{animation-delay:.08s}
.rise-3{animation-delay:.16s}
@media (prefers-reduced-motion:reduce){.rise{animation:none}}

/* ---------- blog index ---------- */
.index{max-width:680px;margin:0 auto;padding:150px 24px 110px}
.index-title{
  font-family:"Newsreader",Georgia,serif;font-weight:500;
  font-size:clamp(38px,6vw,52px);line-height:1.05;letter-spacing:-.015em;
  color:#fff;margin:0;
}
.index-lede{
  font-family:"Newsreader",Georgia,serif;font-style:italic;
  font-size:19px;color:var(--dim);margin:14px 0 0;line-height:1.5;
}
.post-list{margin-top:64px}
.post-card{
  display:block;text-decoration:none;color:inherit;
  padding:28px 0;border-top:1px solid var(--rule);
}
.post-card time{
  font-family:"Newsreader",Georgia,serif;font-style:italic;
  font-size:15px;color:var(--dim);
}
.post-card h2{
  font-family:"Newsreader",Georgia,serif;font-weight:500;
  font-size:26px;line-height:1.25;letter-spacing:-.01em;
  color:#fff;margin:6px 0 8px;transition:color .2s;
}
.post-card h2::after{
  content:"→";display:inline-block;margin-left:8px;opacity:0;
  transform:translateX(-6px);font-family:"Hanken Grotesk",sans-serif;
  transition:opacity .2s ease, transform .25s cubic-bezier(.2,.7,.3,1);
}
.post-card:hover h2::after{opacity:1;transform:translateX(0)}
.post-card p{
  margin:0;font-size:15.5px;font-weight:300;line-height:1.6;color:#B9B9B2;
}
.empty{
  margin-top:64px;padding-top:28px;border-top:1px solid var(--rule);
  font-family:"Newsreader",Georgia,serif;font-style:italic;
  font-size:17px;color:var(--dim);
}

/* ---------- post page ---------- */
.post{max-width:680px;margin:0 auto;padding:150px 24px 110px}
.post-title{
  font-family:"Newsreader",Georgia,serif;font-weight:500;
  font-size:clamp(34px,6vw,48px);line-height:1.12;letter-spacing:-.015em;
  color:#fff;margin:0 0 16px;text-wrap:balance;
}
.post-meta{
  font-family:"Newsreader",Georgia,serif;font-style:italic;
  font-size:17px;color:var(--dim);margin:0 0 64px;
}

/* ---------- article body ---------- */
.post-body{font-size:17.5px;font-weight:300;line-height:1.4;letter-spacing:.001em}
.post-body > :first-child{margin-top:0}
.post-body p{margin:0 0 1.6em}

.post-body h1,
.post-body h2{
  font-family:"Newsreader",Georgia,serif;font-weight:500;
  font-size:29px;line-height:1.22;letter-spacing:-.01em;color:#fff;
  margin:2.4em 0 .75em;text-wrap:balance;
}
.post-body h3{
  font-family:"Newsreader",Georgia,serif;font-style:italic;font-weight:500;
  font-size:22px;line-height:1.3;color:#fff;margin:2.2em 0 .65em;
}
.post-body h4{
  font-size:15px;font-weight:600;letter-spacing:.1em;text-transform:uppercase;
  color:#B9B9B2;margin:2.2em 0 .8em;
}

.post-body a{
  color:#fff;text-decoration:none;
  border-bottom:1px solid rgba(255,255,255,.3);
  transition:color .2s, border-color .2s;
}
.post-body a:hover{color:var(--reg);border-bottom-color:var(--reg)}
.post-body strong{font-weight:600;color:#fff}
.post-body em{font-family:"Newsreader",Georgia,serif;font-style:italic;font-size:1.045em}

.post-body blockquote{
  margin:2.4em 0;padding:2px 0 2px 28px;
  border-left:1px solid var(--reg);
  font-family:"Newsreader",Georgia,serif;font-style:italic;
  font-size:21px;line-height:1.55;color:#E9E9E3;
}
.post-body blockquote p{margin:0 0 .8em;}
.post-body blockquote p:last-child{margin-bottom:0}
.post-body blockquote em{font-size:1em}
/* Verse: a quote whose line breaks are meaningful. post.html tags any
   blockquote whose source lines are short/hard-wrapped, so poetry keeps its
   lineation without turning on `breaks` for ordinary prose. */
.post-body blockquote.verse p{line-height:1.5}
.post-body blockquote.verse strong{
  display:block;margin-top:1em;font-weight:400;
  font-size:.85em;letter-spacing:.02em;color:var(--dim);
}

.post-body figure{margin:2.6em 0}
.post-body img{max-width:100%;height:auto;display:block;margin:0 auto}
.post-body figcaption,
.post-body p.caption{
  font-family:"Newsreader",Georgia,serif;font-style:italic;
  font-size:15.5px;line-height:1.5;color:var(--dim);
  text-align:center;margin:14px auto 0;max-width:520px;
}
.post-body p.caption{margin-top:-1.2em;margin-bottom:2.4em}
.post-body p.caption em{font-size:1em}

.post-body ul,.post-body ol{margin:0 0 1.6em;padding-left:1.35em}
.post-body li{margin-bottom:.55em}
.post-body li::marker{color:var(--dim)}
.post-body li p{margin-bottom:.55em}

.post-body code{
  font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;
  font-size:.85em;color:#E9E9E3;
  background:rgba(255,255,255,.07);border:1px solid rgba(255,255,255,.09);
  padding:2px 6px;border-radius:3px;
}
.post-body pre{
  background:#0A0A0A;border:1px solid var(--rule);
  padding:20px 24px;margin:2.2em 0;overflow-x:auto;line-height:1.65;
}
.post-body pre code{
  background:none;border:0;padding:0;border-radius:0;
  font-size:13.5px;color:#D5D5D0;
}

.post-body hr{
  border:0;border-top:1px solid var(--rule);
  width:120px;margin:3.4em auto;
}

.post-body table{
  width:100%;border-collapse:collapse;margin:2.2em 0;
  font-size:15px;display:block;overflow-x:auto;
}
.post-body th{
  font-weight:500;color:#fff;text-align:left;
  border-bottom:1px solid rgba(255,255,255,.3);padding:10px 16px 10px 0;
}
.post-body td{border-bottom:1px solid var(--rule);padding:10px 16px 10px 0;color:#B9B9B2}

/* ---------- post footer ---------- */
.post-end{
  margin-top:88px;padding-top:26px;border-top:1px solid var(--rule);
  display:flex;justify-content:space-between;align-items:baseline;
  font-size:13px;color:var(--dim);
}
.post-end a{color:#DDD;text-decoration:none;border-bottom:1px solid rgba(255,255,255,.25);transition:color .2s,border-color .2s}
.post-end a:hover{color:var(--reg);border-bottom-color:var(--reg)}
.post-end .sig{font-family:"Newsreader",Georgia,serif;font-style:italic;font-size:15px}

#post-err{
  display:none;margin-top:40px;padding:16px 20px;border:1px solid var(--reg);
  font-size:14px;line-height:1.6;color:#fff;
}

/* ---------- animated brush strokes ----------
   Anatomy: <figure class="brush"> wraps an inline SVG. Strokes are white ink
   on black, painted with tapered variable-width bristle paths. Elements that
   should *paint themselves on* carry pathLength="1" + class "stroke" so dash
   units are normalized and one shared keyframe serves every path. Everything
   is paused until post.html's IntersectionObserver adds .in-view; clicking a
   figure repaints it. Per-element choreography via CSS vars: --d delay,
   --dur duration, --o target opacity. */
figure.brush{margin:3.2em 0;cursor:pointer}
/* A figure that is simply present and only loops (no paint-on, no replay):
   its loops run immediately rather than waiting on the scroll trigger. */
figure.brush.still{cursor:default}
figure.brush.still *{animation-play-state:running}
/* Nothing fades in here — the drawing is already finished, so motes start at
   their resting opacity and only drift. Fading while moving is what made the
   first frames look jumpy. */
figure.brush.still .mote{
  opacity:var(--o,1);
  animation:brush-mote var(--mote-dur,9s) ease-in-out var(--d,0s) infinite alternate;
}
/* Name the properties actually animated (not `transform`) so the hint applies,
   and so the first frames aren't spent promoting these layers. */
figure.brush.still .sway{will-change:rotate}
figure.brush.still .mote{will-change:translate}
figure.brush svg{display:block;width:100%;height:auto;color:#EDEDE8;overflow:visible}

/* A painted stroke is a filled outline, not a stroked line — that's what lets
   it taper. Reveal is still a dash trick: the shape is *outlined* with a fat
   dashed stroke that unspools, and the fill fades in just behind the tip. */
.brush .stroke{
  fill:currentColor;fill-opacity:0;
  stroke:currentColor;stroke-width:0;
  animation:brush-ink var(--dur,1.1s) cubic-bezier(.35,.02,.2,1) var(--d,0s) forwards;
  animation-play-state:paused;
  transform-box:fill-box;transform-origin:var(--ox,0%) var(--oy,50%);
}
/* Wet edge: a faint halo that trails the stroke so the ink looks absorbed
   rather than printed. Purely decorative — always paired, never alone. */
.brush .wet{filter:url(#brush-wet)}

/* A hairline stroke (dry brush, hatching, a thin trailing flick) is drawn as
   a real stroked path — it traces on with the normalized-dash technique. */
.brush .hair{
  fill:none;stroke:currentColor;stroke-width:1.6;
  stroke-linecap:round;stroke-linejoin:round;
  stroke-dasharray:1;stroke-dashoffset:1;
  animation:brush-draw var(--dur,.9s) cubic-bezier(.35,.02,.2,1) var(--d,0s) forwards;
  animation-play-state:paused;
}
.brush .thin{stroke-width:.9}
/* Washes / groups: fade to --o. A bare <path class="fade"> is a filled wash,
   so it needs the ink fill; set fill="none" inline for a fading outline. */
.brush .fade{
  opacity:0;fill:currentColor;
  animation:brush-fade .9s ease var(--d,0s) forwards;
  animation-play-state:paused;
}
/* Spatter / dry-bristle speckle: fades in slightly late, gives the stroke grit */
.brush .grit{
  opacity:0;fill:currentColor;
  animation:brush-fade .7s ease var(--d,1.4s) forwards;
  animation-play-state:paused;
}
.brush .lbl{
  opacity:0;fill:#EDEDE8;
  font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;
  letter-spacing:.08em;
  animation:brush-rise .7s cubic-bezier(.23,1,.32,1) var(--d,2s) forwards;
  animation-play-state:paused;
}
.brush .lbl-dim{fill:#8A8A84}
.brush .serif{
  font-family:"Newsreader",Georgia,serif;font-style:italic;
  letter-spacing:0;fill:#8A8A84;
}
.brush .accent{stroke:var(--reg)}
.brush .accent-fill{fill:var(--reg)}
/* Living layers — at most 2–3 per drawing. */
.brush .flow{
  fill:none;stroke:var(--reg);stroke-width:1.6;stroke-linecap:round;
  stroke-dasharray:3 9;opacity:0;
  animation:brush-fade .8s ease var(--d,2.6s) forwards,
            brush-march 1.1s linear var(--d,2.6s) infinite;
  animation-play-state:paused,paused;
}
.brush .pulse{
  opacity:0;
  animation:brush-fade .6s ease var(--d,2.4s) forwards,
            brush-pulse 1.8s ease-in-out calc(var(--d,2.4s) + .6s) infinite alternate;
  animation-play-state:paused,paused;
}
/* Breathing ink: a settled stroke that keeps drifting a hair, like wet paper.
   Animates the individual `translate`/`rotate` properties rather than
   `transform`, so it composes with .stroke's paint-on (which owns `transform`)
   instead of overriding it. */
.brush .drift{
  transform-box:fill-box;transform-origin:center;
  animation:brush-drift var(--drift-dur,7s) ease-in-out var(--drift-d,3s) infinite alternate;
  animation-play-state:paused;
}
/* On a painted stroke, drift must not clobber the paint-on: re-declare both,
   ink first. --dur/--d stay the stroke's; drift reads --drift-dur/--drift-d. */
.brush .stroke.drift{
  animation:brush-ink var(--dur,1.1s) cubic-bezier(.35,.02,.2,1) var(--d,0s) forwards,
            brush-drift var(--drift-dur,7s) ease-in-out var(--drift-d,3s) infinite alternate;
  animation-play-state:paused,paused;
}
/* Ink that is simply *there* — no paint-on, no reveal. For figures that should
   read as a finished drawing the moment they appear, and only move. Combine
   freely with .sway / .mote; those own `rotate`/`translate`, not `opacity`. */
.brush .ink{
  fill:none;stroke:currentColor;stroke-width:1.6;
  stroke-linecap:round;stroke-linejoin:round;
  opacity:var(--o,1);
}
.brush .ink.thin{stroke-width:.9}

/* Wind: pivots from the base of the element's own box (a stem's root) rather
   than its centre, so a flower bends instead of wobbling. Like drift, it uses
   `rotate` — never `transform` — so it composes on top of .hair/.stroke.
   Give neighbouring stems different --sway-dur and a --sway-d offset; matched
   phases read as a rigid prop, not a breeze. */
.brush .sway{
  transform-box:fill-box;transform-origin:var(--sway-x,50%) 100%;
  animation:brush-sway var(--sway-dur,4s) ease-in-out var(--sway-d,0s) infinite alternate;
  animation-play-state:paused;
}
.brush .hair.sway{
  animation:brush-draw var(--dur,.9s) cubic-bezier(.35,.02,.2,1) var(--d,0s) forwards,
            brush-sway var(--sway-dur,4s) ease-in-out var(--sway-d,0s) infinite alternate;
  animation-play-state:paused,paused;
}
.brush .stroke.sway{
  animation:brush-ink var(--dur,1.1s) cubic-bezier(.35,.02,.2,1) var(--d,0s) forwards,
            brush-sway var(--sway-dur,4s) ease-in-out var(--sway-d,0s) infinite alternate;
  animation-play-state:paused,paused;
}
/* Airborne motes: seed, pollen, a torn blade of grass. Fades in, then loops a
   slow lateral drift with a little lift. Vary --mote-x/--mote-y per particle. */
.brush .mote{
  opacity:0;fill:currentColor;
  animation:brush-fade 1.2s ease var(--d,2s) forwards,
            brush-mote var(--mote-dur,9s) ease-in-out var(--d,2s) infinite alternate;
  animation-play-state:paused,paused;
}
.brush .spin{
  transform-box:fill-box;transform-origin:center;opacity:0;
  animation:brush-fade .6s ease var(--d,3s) forwards,
            brush-spin var(--dur,16s) linear var(--d,3s) infinite;
  animation-play-state:paused,paused;
}
.brush .orbit{
  opacity:0;  /* element must set offset-path:path('…') inline */
  animation:brush-fade .6s ease var(--d,3s) forwards,
            brush-orbit var(--dur,10s) linear var(--d,3s) infinite;
  animation-play-state:paused,paused;
}
/* Unpause. Specificity must beat every rule above that declares
   animation-play-state — .brush .stroke.drift is 0-3-0, so repeating
   .in-view lifts this to 0-4-1 and it wins outright rather than relying on
   source order. */
figure.brush.in-view.in-view.in-view *{animation-play-state:running}
/* click-to-repaint: momentarily strip animations so re-adding restarts them
   (toggling play-state alone can't rewind a finished animation) */
figure.brush.replay *{animation:none!important}   /* !important clears both the
   shorthand and the play-state above, whatever their specificity */

/* Ink lands: the stroke scales along its own length from the entry point out,
   fading up as it goes — reads as a loaded brush pressed and pulled. */
@keyframes brush-ink{
  from{fill-opacity:0;transform:scaleX(.04)}
  60%{fill-opacity:var(--o,1)}
  to{fill-opacity:var(--o,1);transform:scaleX(1)}
}
@keyframes brush-draw{to{stroke-dashoffset:0}}
@keyframes brush-fade{to{opacity:var(--o,1)}}
@keyframes brush-rise{from{opacity:0;transform:translateY(6px)}to{opacity:1;transform:none}}
@keyframes brush-march{to{stroke-dashoffset:-12}}
@keyframes brush-pulse{from{opacity:1}to{opacity:.35}}
@keyframes brush-drift{from{translate:0 0;rotate:0deg}
                       to{translate:0 -2px;rotate:.35deg}}
@keyframes brush-sway{from{rotate:calc(var(--sway,2.6deg) * -1)}
                      to{rotate:var(--sway,2.6deg)}}
@keyframes brush-mote{from{translate:0 0}
                      to{translate:var(--mote-x,26px) var(--mote-y,-14px)}}
@keyframes brush-spin{to{transform:rotate(360deg)}}
@keyframes brush-orbit{to{offset-distance:100%}}

@media (prefers-reduced-motion:reduce){
  .brush .stroke{animation:none;fill-opacity:var(--o,1);transform:none}
  .brush .hair{animation:none;stroke-dashoffset:0}
  .brush .fade,.brush .grit{animation:none;opacity:var(--o,1)}
  .brush .lbl{animation:none;opacity:1}
  .brush .flow{animation:none;opacity:var(--o,1)}
  .brush .pulse,.brush .spin,.brush .orbit{animation:none;opacity:1}
  .brush .drift{animation:none;transform:none}
  .brush .sway{animation:none;rotate:0deg}
  .brush .hair.sway{animation:none;stroke-dashoffset:0;rotate:0deg}
  .brush .stroke.sway{animation:none;fill-opacity:var(--o,1);transform:none;rotate:0deg}
  .brush .mote{animation:none;opacity:var(--o,1);translate:none}
}

@media (max-width:700px){
  .top{padding:18px 20px}
  .index,.post{padding-top:120px}
  .post-body{font-size:16.5px}
  .post-body blockquote{font-size:19px;padding-left:20px}
}
