CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

Project Overview

Personal academic website for Andrew M. Camp (andrewmcamp.com), built with Quarto and deployed on Netlify. Fully static — no databases, no build-time JS frameworks.

Commands

quarto preview          # Local dev server with hot reload
quarto render           # Build site to _site/

Deployment is automatic: Netlify builds and deploys from the GitHub repo on push to main. Do not use quarto publish.

Architecture

Site Framework

  • Quarto static site generator with .qmd (Quarto Markdown) content files
  • Dual theme: Flatly (light) / Darkly (dark) via _quarto.yml, with a dark-mode flash prevention script in the HTML header
  • Design tokens in _brand.yml — colors, typography (Archivo for headings and body, JetBrains Mono code). The look follows the “Modernist” system from the Claude Design project (claude.ai/design/p/74bf3e60-…): light ground, near-black ink, one brick accent, 2px rules, zero corner radius, no shadows. Per-mode values (light/dark) are baked in theme.scss as --amc-* custom properties, including neutral (--amc-n100…n900) and accent (--amc-a100…a800) ramps
  • Single SCSS file at _assets/theme/theme.scss (~1,250 lines) handles all custom styling; it compiles twice (once per theme) and uses $_is-dark: lightness($body-bg) < 50% to branch light/dark values at compile time

Shared layout components (theme.scss)

All five main pages use page-layout: custom and build their own sections from these classes, one per artboard in the design project: - .page-wrap / .landing-wrap — the 1240px column with 40px side padding (20px on phones) - .page-masthead — kicker (.page-kicker), display title (.page-title), lead (.page-lead), 2px rule beneath. Modifiers --about (portrait beside copy) and --cv (download button at the baseline) - .rowgrid — date column beside a body column, hairline rows under a 2px rule (About timeline --about, CV entries, CV teaching --tight); .rowgrid-label spans both columns - .lattice-frame + .lattice + .lattice-cell — modular grid drawn with hairlines (About affiliations, Contact, Home featured papers as .spotlight-*) - .tag (-accent / -outline / -neutral) and .btn (-primary / -ghost) follow the Modernist component set - body:has(.page-layout-custom) is a flex column so the footer pins to the viewport bottom (Quarto’s fixed 132px chrome allowance is too small for this nav + footer)

Pages

Page File Notes
Landing index.qmd Kicker, display headline, summary, then “Recent Research” over a lattice of featured papers (Home artboard)
About about.qmd Masthead with square portrait, .rowgrid--about timeline, affiliations lattice, JSON-LD structured data
Research writing.qmd Three listings (peer-reviewed / working papers / reports) beside a sticky filter rail
Contact contact.qmd Lattice with a full-width email cell over four profile cells
CV cv.qmd Masthead with PDF download button; each section is an h2 over a .rowgrid

Publication System

  • Each publication is a .qmd file in writings/ with YAML frontmatter: title, date, author, categories, tags, abstract, and optional resource links (pdf, link, slides, appendix, brief, code)
  • categories control type grouping: peer-reviewed, working-paper, reports, featured
  • tags are research topics used for filtering (e.g., teacher-labor-market, four-day-school-week)
  • Publications render through the EJS template _assets/html/pubs.ejs as .pub-item rows: year, type tag plus subtitle as a neutral tag (unless it repeats the type label), title linked to spotlight / link / pdf, full author list with Camp bolded, a <details> abstract, and text links (Summary / PDF / Working Paper / DOI or Link / Slides / Supplemental / Brief / Code). Topic tags are not shown per item; they drive the filters
  • Featured items use spotlight field pointing to a detail page in writings/spotlight/
  • Paper detail pages (writings/spotlight/*.qmd) are the only pages still using Quarto’s title banner (.quarto-title-banner, an ink band); they were not part of the design project

Filter System (_assets/js/filters.js)

  • Vanilla JS, no dependencies. Builds a rail into #filter-sidebar on writing.qmd from the rendered items: Type from each .research-section‘s data-type/data-label, Year and Topic from the items’ data-year/data-tags (no hardcoded lists)
  • All three groups are multi-select toggle pills (.tag buttons); empty means “all”. Shows “Showing X of Y” and a Clear button when anything is active
  • Items and empty sections get the hidden attribute; the SCSS has a global [hidden] { display: none !important } because grid/flex display rules would otherwise override it
  • One rail only: below 992px it moves above the list (order: -1) instead of sticking

Page Mastheads

  • Main pages set title-block-banner: false and write their own .page-masthead; the title field still feeds <title> and the description field feeds <head>. .page-layout-custom #title-block-header is hidden in SCSS
  • title-block-banner: true remains in _quarto.yml for the paper detail pages under writings/spotlight/

Key Conventions

  • CSS class prefixes: shared .page-*, .rowgrid*, .lattice*, .tag*, .btn*; per page .landing-*, .spotlight-*, .research-*, .filter-*, .pub-*, .contact-*, .cv-*, .about-*
  • Design source: the Claude Design project’s artboards are the spec for layout and copy; site content (dates, journal names, reviewer list) stays the source of truth where the two disagree
  • File naming: kebab-case for .qmd files matching the publication title
  • Author formatting: comma-separated in frontmatter; Andrew M. Camp is bolded in rendered output by the EJS template
  • Quarto version: pinned at 1.6.43 in netlify.toml
  • Extension: _extensions/schochastics/academicons provides academic social icons