/* fonts.css is linked directly in _includes/head.html, not @imported here — an @import
   serialises the font CSS behind this file on the critical path. */

:root{
  /* shell — dark, dense, mono-led */
  --ink:#121310; --ink-2:#1B1D16; --line:#26281F;
  --paper:#F3F0E7; --dim:#8E9184; --lime:#C9F227; --meta:#7E8175; --line-2:#33362B;
  /* article — bone paper */
  --bone:#F2EFE6; --bone-2:#DBD6C7; --article-ink:#15140F; --tomato:#E8422C;
  /* --tomato measures 3.48:1 on bone: fine for borders, rules and focus rings (3:1 threshold)
     but it FAILS the 4.5:1 text threshold. Small text on bone uses --tomato-ink (4.76:1),
     same hue, darker value. Do not use --tomato for text under 18px. */
  --tomato-ink:#C13725;

  --ease:cubic-bezier(.2,.8,.3,1);
  --t-press:80ms; --t-hover:180ms;
  --r-sm:3px; --r-md:7px; --r-lg:12px;
  --s1:4px; --s2:8px; --s3:12px; --s4:16px; --s5:24px; --s6:32px; --s7:48px; --s8:72px;

  --mono:"JetBrains Mono",ui-monospace,"SF Mono",Menlo,monospace;
  --display:"Cabinet Grotesk",system-ui,-apple-system,sans-serif;
  --serif:"Source Serif 4",Georgia,serif;
}

*,*::before,*::after{box-sizing:border-box}
html{-webkit-text-size-adjust:100%}
body{margin:0;background:var(--ink);color:var(--paper);
  font:400 15px/1.6 var(--mono);font-feature-settings:"ss02";}
img,video{max-width:100%;height:auto;display:block}
a{color:inherit;text-decoration:none}
h1,h2,h3{margin:0;font-family:var(--display);font-weight:800;letter-spacing:-.03em;line-height:1}

/* Grain. One inline SVG, no image file. */
.grain{position:relative}
.grain::before{content:"";position:absolute;inset:0;pointer-events:none;z-index:0;
  opacity:.06;mix-blend-mode:screen;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='120' height='120'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3'/%3E%3C/filter%3E%3Crect width='120' height='120' filter='url(%23n)'/%3E%3C/svg%3E")}
.grain>*{position:relative;z-index:1}

.wrap{max-width:960px;margin:0 auto;padding:0 var(--s5)}

/* Header */
.site-header{border-bottom:1px solid var(--line)}
.site-header .wrap{display:flex;justify-content:space-between;align-items:center;
  gap:var(--s4);padding-top:var(--s4);padding-bottom:var(--s4);flex-wrap:wrap}
.brand{font-size:12px;letter-spacing:.08em;text-transform:uppercase;color:var(--dim)}
.brand b{color:var(--paper);font-weight:500}
.site-nav{display:flex;flex-wrap:wrap;gap:var(--s4);font-size:12px;letter-spacing:.08em;
  text-transform:uppercase;color:var(--dim)}
.site-nav a[aria-current="page"]{color:var(--lime)}
.site-nav a:hover{color:var(--paper)}

/* Clack toggle — a control, a joke, and a demo of Clackable. */
.clack{display:inline-flex;align-items:center;gap:var(--s2);border:1px solid var(--line);
  border-radius:999px;padding:3px 4px 3px 10px;font:400 10px/1 var(--mono);
  letter-spacing:.07em;text-transform:uppercase;color:var(--dim);background:none;cursor:pointer}
.clack .sw{width:26px;height:15px;border-radius:999px;background:var(--line);position:relative;
  transition:background var(--t-hover) var(--ease)}
.clack .sw::after{content:"";position:absolute;top:2px;left:2px;width:11px;height:11px;
  border-radius:50%;background:var(--paper);transition:transform var(--t-hover) var(--ease)}
/* .clack-on on <html> is a pre-paint stamp from the inline anti-flash guard in head.html —
   it renders the switch correctly before clack.js has run and set aria-pressed itself. */
.clack[aria-pressed="true"] .sw, .clack-on .clack .sw{background:var(--lime)}
.clack[aria-pressed="true"] .sw::after, .clack-on .clack .sw::after{transform:translateX(11px);background:var(--ink)}

/* Section labels */
.lbl{display:flex;justify-content:space-between;gap:var(--s4);
  font:500 10px/1 var(--mono);letter-spacing:.15em;text-transform:uppercase;
  color:var(--meta);border-top:1px solid var(--line);padding-top:var(--s3);margin:var(--s7) 0 0}
/* The first span of a .lbl is an <h2> for screen-reader navigation (see Task 8 fix), but must
   stay pixel-identical to a plain span — override the global h1,h2,h3 display-font rule. */
.lbl h2{font:inherit;font-size:inherit;font-weight:inherit;letter-spacing:inherit;
  color:inherit;margin:0}

/* Rows — the primary unit of the whole site */
.row{display:grid;grid-template-columns:1fr auto;gap:var(--s4);align-items:baseline;
  padding:var(--s3) 0;border-bottom:1px solid var(--ink-2)}
.row-title{font-size:14.5px;font-weight:500}
.row-title em{font-style:normal;font-weight:400;color:var(--meta)}
.row-meta{font-size:11px;color:var(--meta);letter-spacing:.04em;white-space:nowrap}
a.row:hover .row-title{color:var(--lime)}
/* The anchor wraps title + tagline and fills its grid column, so the whole left side of a row
   is one click target rather than just the name. */
.row-title a{display:block}
/* Only the name lights up. The tagline keeps --meta on hover by design — it is supporting text,
   and .row-title em pinning its own colour is what makes that happen, so do not add an
   `inherit` rule here. The whole anchor is still the click target either way. */
.row-title a:hover,.row-title a:focus-visible{color:var(--lime)}
.row-date{font-size:11px;color:var(--meta)}

/* Chunky physical controls: hard offset shadow, press drops 1px. */
.btn{display:inline-flex;align-items:center;gap:var(--s2);font:500 12.5px/1 var(--mono);
  padding:9px 14px;border-radius:var(--r-md);cursor:pointer;
  background:var(--lime);color:var(--ink);border:1.5px solid var(--ink);
  box-shadow:3px 3px 0 rgba(201,242,39,.28);
  transition:transform var(--t-press) var(--ease),box-shadow var(--t-press) var(--ease)}
.btn.ghost{background:transparent;color:var(--paper);border-color:var(--line-2);
  box-shadow:3px 3px 0 rgba(255,255,255,.07)}
.btn:active{transform:translateY(1px);box-shadow:1px 1px 0 rgba(201,242,39,.28)}
.btn.ghost:active{box-shadow:1px 1px 0 rgba(255,255,255,.07)}

.copy{font:400 11px/1 var(--mono);color:var(--dim);border:1px dashed var(--line-2);
  border-radius:var(--r-md);padding:8px 10px;display:flex;justify-content:space-between;
  gap:var(--s4);width:100%;min-width:0;background:none;cursor:pointer;text-align:left;
  transition:transform var(--t-press) var(--ease)}
.copy:active{transform:translateY(1px)}
.copy b{color:var(--lime);font-weight:500}
.copy>span{min-width:0;overflow-wrap:anywhere}

/* Inline copy control for list rows — keeps a row to one line (unlike .copy, which is a
   full-width block used only on project detail pages). Always visible: a hover-only
   control is unreachable for touch and confusing for keyboard users. */
.copy-inline{font:inherit;font-size:inherit;color:var(--lime);background:none;border:0;
  padding:0;margin:0;cursor:pointer;transition:transform var(--t-press) var(--ease)}
.copy-inline:active{transform:translateY(1px)}

/* Focus must always be obvious in a dense keyboard-navigable list. */
:focus-visible{outline:2px solid var(--lime);outline-offset:2px}

/* Hero. Knockout is shell-only — lime never appears on bone (contrast). */
.hero{padding:var(--s8) 0 var(--s7)}
/* Index/section pages: shorter tail than the homepage hero. A class, not an inline style,
   so the project layout can reuse it instead of copying a declaration. */
.hero-tight{padding-bottom:var(--s5)}
.hero h1{font-size:clamp(30px,6vw,50px);line-height:.99;max-width:16em}
.hero h1 .knock{display:inline-block;color:var(--ink);background:var(--lime);
  padding:0 var(--s2);border-radius:var(--r-sm);transform:rotate(-2.2deg)}
.hero .dek{color:var(--dim);font-size:14.5px;max-width:34em;margin:var(--s4) 0 0}
.hero-cta{display:flex;gap:var(--s3);flex-wrap:wrap;margin-top:var(--s5)}

.chips{display:flex;gap:var(--s2);flex-wrap:wrap;margin-top:var(--s4)}
.chip{border:1px solid var(--line);border-radius:var(--r-sm);padding:3px 8px;
  font-size:10.5px;color:var(--dim);letter-spacing:.05em}
.chip[aria-pressed="true"]{border-color:var(--lime);color:var(--lime)}

.site-footer{border-top:1px solid var(--line);margin-top:var(--s8);
  padding:var(--s5) 0 var(--s7);color:var(--dim);font-size:12px}
.site-footer a:hover{color:var(--lime)}
.site-footer ul{list-style:none;padding:0;margin:0;display:flex;gap:var(--s4);flex-wrap:wrap}

/* Prose on the dark shell — project descriptions only. Article bodies use article.css. */
.prose-dark{max-width:60ch;color:var(--dim);font-size:14.5px;line-height:1.7;
  padding:var(--s5) 0 0}
.prose-dark p{margin:0 0 var(--s4)}
.prose-dark strong{color:var(--paper);font-weight:500}
.prose-dark a{color:var(--lime);text-decoration:underline;text-underline-offset:2px}
.prose-dark code{background:var(--ink-2);padding:2px 5px;border-radius:var(--r-sm);
  color:var(--paper);font-size:.9em}
.prose-dark pre{background:var(--ink-2);padding:var(--s4);border-radius:var(--r-md);
  overflow-x:auto;font-size:13px}
.prose-dark pre code{background:none;padding:0}
.prose-dark ul,.prose-dark ol{padding-left:1.3em;margin:0 0 var(--s4)}

/* Homepage bio paragraph — same treatment as prose-dark's dim/width/spacing, own class
   because it's a single line of text, not a prose block. */
.bio{color:var(--dim);max-width:34em;padding:var(--s4) 0}

/* Reveals. DEFAULT IS VISIBLE — see plan note. Only enhances. */
@supports (animation-timeline:view()){
  @media (prefers-reduced-motion:no-preference){
    @keyframes rise{from{opacity:0;transform:translateY(10px)}to{opacity:1;transform:none}}
    .reveal{animation:rise .5s var(--ease) both;animation-timeline:view();
      animation-range:entry 0% cover 22%}
  }
}
@media (prefers-reduced-motion:no-preference){
  @view-transition{navigation:auto}
}
@media (max-width:640px){
  .row{grid-template-columns:1fr;gap:var(--s1)}
  .wrap{padding:0 var(--s4)}
}
