/* ==========================================================================
   1. Reset (Josh Comeau style)
   ========================================================================== */

*, *::before, *::after {
  box-sizing: border-box;
}

:where(body, h1, h2, h3, h4, h5, h6, p, ul, ol, figure, blockquote) {
  margin: 0;
}

body {
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
}

img, picture, video, canvas, svg {
  display: block;
  max-width: 100%;
}

input, button, textarea, select {
  font: inherit;
}

p, h1, h2, h3, h4, h5, h6 {
  overflow-wrap: break-word;
}

h1, h2, h3, h4, h5, h6 {
  text-wrap: balance;
}

p {
  text-wrap: pretty;
}

/* ==========================================================================
   2. Design tokens
   ========================================================================== */

:root {
  --color-bg:      #fff;
  --color-text:    #000;
  --color-heading: #15171a;
  --color-link:    #1e66f5;
  --color-muted:   #6c6f85;
  --color-rule:    #bcc0cc;
  --color-code-bg: #e6e9ef;

  /* In-content link highlight underline */
  --content-link-color:       rgba(56, 156, 255, .15);
  --content-link-color-hover: rgba(56, 156, 255, .4);

  /* Spacing scale — fluid */
  --space-1: clamp(0.25rem, 0.2rem + 0.25vw, 0.375rem);
  --space-2: clamp(0.5rem,  0.4rem + 0.5vw,  0.75rem);
  --space-3: clamp(0.75rem, 0.65rem + 0.5vw, 1rem);
  --space-4: clamp(1rem,    0.85rem + 0.75vw, 1.5rem);
  --space-5: clamp(1.5rem,  1.25rem + 1.25vw, 2.5rem);
  --space-6: clamp(2.5rem,  2rem + 2.5vw,    4rem);

  /* Type scale — fluid */
  --text-sm:   clamp(0.8125rem, 0.78rem + 0.17vw, 0.9375rem);
  --text-base: clamp(1rem,      0.95rem + 0.25vw,  1.125rem);
  --text-lg:   clamp(1.125rem,  1.05rem + 0.375vw, 1.375rem);
  --text-xl:   clamp(1.375rem,  1.2rem  + 0.875vw, 1.875rem);
  --text-2xl:  clamp(1.75rem,   1.5rem  + 1.25vw,  2.5rem);

  /* Font stacks */
  --font-serif: Georgia, "Times New Roman", serif;
  --font-mono:  ui-monospace, "Cascadia Code", "Source Code Pro", Menlo, Consolas, monospace;

  /* Layout */
  --measure: 68ch;
  --radius:  3px;
}

/* ==========================================================================
   3. Base element styles
   ========================================================================== */

body {
  background-color: var(--color-bg);
  color: var(--color-text);
  font-family: var(--font-serif);
  font-size: var(--text-base);
  padding-block: var(--space-5);
  padding-inline: var(--space-4);
}

h1, h2, h3, h4, h5, h6 {
  color: var(--color-heading);
  font-weight: 400;
}

h1 {
  font-size: var(--text-2xl);
  line-height: 1.15;
  margin-block-end: var(--space-4);
}

h2 {
  font-size: var(--text-xl);
  line-height: 1.2;
  margin-block-end: var(--space-3);
  margin-block-start: var(--space-5);
}

h3 {
  font-size: var(--text-lg);
  line-height: 1.25;
  font-weight: 500;
  margin-block-end: var(--space-2);
  margin-block-start: var(--space-4);
}

h4, h5, h6 {
  font-size: var(--text-base);
  line-height: 1.3;
  font-weight: 500;
  margin-block-end: var(--space-2);
  margin-block-start: var(--space-3);
}

p {
  margin-block-end: var(--space-3);

  &:last-child {
    margin-block-end: 0;
  }
}

a {
  color: var(--color-link);
  text-decoration: none;

  &:hover {
    text-decoration: underline;
    text-underline-offset: 0.15em;
  }
}

ul, ol {
  padding-inline-start: var(--space-4);
  margin-block-end: var(--space-3);
}

li {
  margin-block-end: var(--space-1);
}

blockquote {
  border-inline-start: 3px solid var(--color-rule);
  padding-inline-start: var(--space-3);
  color: var(--color-muted);
  font-style: italic;
  margin-block: var(--space-3);
}

code {
  font-family: var(--font-mono);
  font-size: var(--text-sm);
  background-color: var(--color-code-bg);
  padding: 0.1em 0.3em;
  border-radius: var(--radius);
}

pre {
  font-family: var(--font-mono);
  font-size: var(--text-sm);
  background-color: var(--color-code-bg);
  padding: var(--space-3);
  border-radius: var(--radius);
  overflow-x: auto;
  margin-block: var(--space-3);

  & code {
    background: none;
    padding: 0;
    border-radius: 0;
  }
}

hr {
  border: none;
  border-block-start: 1px solid var(--color-rule);
  margin-block: var(--space-5);
}

img {
  border-radius: var(--radius);
}

figure {
  margin-block: var(--space-4);

  & figcaption {
    font-size: var(--text-sm);
    color: var(--color-muted);
    font-style: italic;
    text-align: center;
    margin-block-start: var(--space-2);
  }
}

/* ==========================================================================
   4. Layout primitives
   ========================================================================== */

body {
  display: flex;
  flex-direction: column;
  align-items: center;
}

.site-header {
  width: min(var(--measure), 100%);
  text-align: center;
  margin-block-end: var(--space-6);
}

/* Site name is chrome, not a document heading — styled to read as a title. */
.site-title {
  display: block;
  color: var(--color-heading);
  font-size: var(--text-xl);
  line-height: 1.2;
  text-decoration: none;
  margin-block-end: var(--space-2);
}

/* Nav is a list; separators come from CSS so they stay out of the
   markup and out of each link's accessible name. */
.site-nav {
  font-size: var(--text-sm);

  & ul {
    display: flex;
    justify-content: center;
    list-style: none;
    padding: 0;
    margin: 0;
  }

  & li {
    margin: 0;
  }

  & li + li::before {
    content: "•";
    color: var(--color-rule);
    margin-inline: var(--space-2);
  }

  & a {
    color: var(--color-muted);

    &:hover {
      color: var(--color-text);
    }
  }
}

main, article, section {
  width: min(var(--measure), 100%);
}

.site-footer {
  width: min(var(--measure), 100%);
  margin-block-start: var(--space-6);
  padding-block: var(--space-6);
  text-align: center;
}

/* ==========================================================================
   5. Components
   ========================================================================== */

/* In-content links (highlight underline). Scoped to article prose. */
article a {
  color: var(--color-text);
  text-decoration: underline;
  text-decoration-color: var(--content-link-color);
  text-decoration-skip-ink: none;
  text-decoration-thickness: 1rem;
  text-underline-offset: -0.7rem;
  transition: text-decoration 0.3s;

  &:hover {
    text-decoration-color: var(--content-link-color-hover);
    text-decoration-thickness: 1.8rem;
    text-underline-offset: -1.3rem;
  }
}

/* Blog index */

.post-list {
  list-style: none;
  padding: 0;
  margin: 0;

  & li {
    display: flex;
    align-items: baseline;
    gap: var(--space-2);
    margin-block-end: var(--space-2);
  }

  & .title {
    color: var(--color-text);
    text-decoration: none;
    flex-shrink: 0;

    &:hover {
      text-decoration: underline;
      text-underline-offset: 0.15em;
    }
  }

  & .leader {
    flex: 1;
    border-block-end: 1px dotted var(--color-rule);
    transform: translateY(-0.25em);
    min-width: var(--space-4);
  }

  & .date {
    color: var(--color-muted);
    font-size: var(--text-sm);
    flex-shrink: 0;
  }
}

/* Prev/next post navigation */

/* Width stays on the base font size — `--measure` is in `ch`, so setting
   it on a smaller-font element would compute a narrower column than the
   article above it. */
.prev-next {
  width: min(var(--measure), 100%);
  margin-block-start: var(--space-6);
  padding-block-start: var(--space-4);
  border-block-start: 1px solid var(--color-rule);

  & ul {
    display: flex;
    justify-content: space-between;
    gap: var(--space-4);
    list-style: none;
    padding: 0;
    margin: 0;
    font-size: var(--text-sm);
  }

  & li {
    margin: 0;
  }

  & a {
    color: var(--color-muted);

    &:hover {
      color: var(--color-text);
    }
  }

  /* Direction arrows are presentation — kept in CSS so they stay out of
     each link's accessible name. `:has(a)` keeps the arrow from showing
     on an empty slot: Zine's `:if` drops an element's body, not its tag. */
  & .prev:has(a)::before {
    content: "←";
    margin-inline-end: var(--space-1);
  }

  & .next:has(a) {
    margin-inline-start: auto;
    text-align: end;

    &::after {
      content: "→";
      margin-inline-start: var(--space-1);
    }
  }
}

/* CV page.
   ==========================================================================
   Bespoke layout, scoped entirely under `.cv` so none of it bleeds into the
   prose pages. This is why there is still only one stylesheet: a second file
   would duplicate the tokens below and let the two drift.

   The palette here is FiveFathoms, which differs from the site palette on
   purpose — the CV is a document, not a page of the blog. Tokens are declared
   locally rather than on :root so the scoping is enforced by the cascade.

   Markup comes from scripts/cv-html.lua; class names are defined there. */

.cv {
  --cv-ink:      #1E2A32;
  --cv-depth:    #2E7FA6;
  --cv-gridline: #C9D8DF;
  --cv-muted:    #5a6b76;

  /* Wider than --measure: entries are scannable rows, not running prose. */
  width: min(78ch, 100%);
  color: var(--cv-ink);

  h2 {
    margin-block: var(--space-5) var(--space-2);
    padding-block-end: var(--space-1);
    border-block-end: 1px solid var(--cv-gridline);
    color: var(--cv-depth);
    font-size: var(--text-base);
    letter-spacing: 0.08em;
    text-transform: uppercase;
  }

  h3 {
    margin: 0;
    font-size: var(--text-base);
  }

  /* .cv-entry is an <article>, so the site's prose `article a` highlight
     underline applies here and reads as a thick blue bar. A CV wants quiet
     links, so reset the inherited decoration rather than restyling it. */
  a {
    color: var(--cv-depth);
    text-decoration: underline;
    text-decoration-color: var(--cv-gridline);
    text-decoration-thickness: 1px;
    text-underline-offset: 2px;

    &:hover {
      text-decoration-color: var(--cv-depth);
      text-decoration-thickness: 1px;
      text-underline-offset: 2px;
    }
  }

  ul:not(.cv-contact) {
    margin-block: var(--space-2);
    padding-inline-start: var(--space-4);
  }

  li {
    margin-block: var(--space-1);
  }
}

.cv-header {
  h1 {
    margin: 0;
    color: var(--cv-ink);
  }
}

.cv-role {
  color: var(--cv-muted);
  font-size: var(--text-lg);
}

.cv-contact {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-1) var(--space-3);
  margin-block-start: var(--space-2);
  padding: 0;
  list-style: none;
  font-size: var(--text-sm);
}

.cv-entry {
  margin-block-start: var(--space-4);
}

/* Area and level share a line, as they do in the PDF; keywords run beneath. */
.cv-skill {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: 0 var(--space-3);
  margin-block-start: var(--space-3);
}

/* Org and dates share a line, mirroring the PDF's single-line adjacency. */
.cv-entry-meta {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: var(--space-1) var(--space-3);
  color: var(--cv-muted);
  font-size: var(--text-sm);
}

.cv-entry-org {
  font-weight: 700;
}

.cv-entry-note {
  font-size: var(--text-sm);
  overflow-wrap: anywhere;
}

.cv-skill-level {
  align-self: baseline;
  color: var(--cv-muted);
  font-size: var(--text-sm);
}

.cv-skill .cv-keywords {
  grid-column: 1 / -1;
}

.cv-keywords {
  color: var(--cv-muted);
  font-size: var(--text-sm);
}

.cv-rows {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: var(--space-1) var(--space-3);
  margin-block: var(--space-2);

  dt {
    font-weight: 700;
  }

  dd {
    margin: 0;
  }
}

.cv-download {
  margin-block-start: var(--space-5);
  padding-block-start: var(--space-3);
  border-block-start: 1px solid var(--cv-gridline);
  font-size: var(--text-sm);
}

/* Print. A deliberate exception to the project's "no print styles" rule: a CV
   people can print from the browser is the whole point of the HTML version.
   Site chrome and the download link are noise on paper. */
@media print {
  .site-header, .site-footer, .cv-download {
    display: none;
  }

  /* Web type sizes put this on 4 sheets; the LaTeX PDF fits 2. Drop to a print
     scale so a browser print is not wasteful. This block only affects paper. */
  .cv {
    width: 100%;
    color: #000;
    font-size: 9.5pt;
    line-height: 1.35;
  }

  .cv h1 {
    font-size: 17pt;
  }

  .cv h2 {
    margin-block: 10pt 4pt;
    font-size: 10pt;
  }

  .cv h3, .cv .cv-role {
    font-size: 10pt;
  }

  .cv-entry {
    margin-block-start: 8pt;
  }

  .cv-skill {
    margin-block-start: 5pt;
  }

  .cv li {
    margin-block: 1pt;
  }

  .cv a {
    color: #000;
    text-decoration: none;
  }

  .cv-entry, .cv-skill {
    break-inside: avoid;
  }

  .cv h2 {
    break-after: avoid;
  }
}

/* ==========================================================================
   6. Syntax highlighting (Catppuccin Latte, via Zine flow-syntax)
   ==========================================================================
   Zine emits tree-sitter capture names as CSS classes on tokens inside
   <code class="<lang>">. flow-syntax converts dots to underscores
   (e.g. `punctuation.bracket` -> `.punctuation_bracket`). Capture names
   are conventional across grammars, so one rule set covers all languages.
*/

pre code {
  /* Catppuccin Latte palette — scoped to code blocks only */
  --ctp-rosewater: #dc8a78;
  --ctp-pink:      #ea76cb;
  --ctp-mauve:     #8839ef;
  --ctp-red:       #d20f39;
  --ctp-maroon:    #e64553;
  --ctp-peach:     #fe640b;
  --ctp-yellow:    #df8e1d;
  --ctp-green:     #40a02b;
  --ctp-teal:      #179299;
  --ctp-sky:       #04a5e5;
  --ctp-sapphire:  #209fb5;
  --ctp-blue:      #1e66f5;
  --ctp-text:      #4c4f69;
  --ctp-overlay2:  #7c7f93;

  color: var(--ctp-text);

  & .keyword,
  & .keyword_control,
  & .type_builtin {
    color: var(--ctp-mauve);
  }
  & .keyword_control_conditional {
    color: var(--ctp-mauve);
    font-style: italic;
  }
  & .namespace {
    color: var(--ctp-yellow);
    font-style: italic;
  }
  & .type,
  & .attribute {
    color: var(--ctp-yellow);
  }
  & .type_enum_variant,
  & .constant_character {
    color: var(--ctp-teal);
  }
  & .constructor,
  & .label {
    color: var(--ctp-sapphire);
  }
  & .constant,
  & .field {
    color: var(--ctp-peach);
  }
  & .constant_character_escape,
  & .string_regexp {
    color: var(--ctp-pink);
  }
  & .string,
  & .markup_raw {
    color: var(--ctp-green);
  }
  & .string_special,
  & .function,
  & .tag,
  & .special,
  & .variable_other_member {
    color: var(--ctp-blue);
  }
  & .string_special_symbol,
  & .variable_builtin {
    color: var(--ctp-red);
  }
  & .comment {
    color: var(--ctp-overlay2);
    font-style: italic;
  }
  & .variable {
    color: var(--ctp-text);
  }
  & .variable_parameter {
    color: var(--ctp-maroon);
    font-style: italic;
  }
  & .punctuation,
  & .punctuation_bracket,
  & .punctuation_delimiter {
    color: var(--ctp-overlay2);
  }
  & .punctuation_special,
  & .operator {
    color: var(--ctp-sky);
  }
  & .function_macro {
    color: var(--ctp-rosewater);
  }
  /* Tree-sitter parse errors — declared last so it wins when combined
     with another capture class (e.g. `class="error punctuation_bracket"`). */
  & .error {
    color: var(--ctp-red);
    text-decoration: underline wavy var(--ctp-red);
    text-underline-offset: 0.15em;
  }
}
