/* Inter, for note titles. `@import` has to be the FIRST rule in the file —
   before the `@font-face` blocks below — or browsers drop it. Fetched rather
   than self-hosted, matching rheo.ohrg.org and ohrg.org; Berkeley Mono is
   self-hosted below because it is licensed and not on any CDN. */
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap');

/* ============================================
   Berkeley Mono

   Four faces, following cftw.ohrg.org. The urls are relative to this
   stylesheet, which rheo emits at `build/html/style.css` — so the files have
   to end up at `build/html/fonts/`. rheo copies no static directories (its
   only asset key is `css_stylesheet`), so the Justfile does that copy after
   compiling; see the note there.
   ============================================ */
@font-face {
  font-family: 'Berkeley Mono';
  src: url('./fonts/BerkeleyMono-Regular.ttf') format('truetype');
  font-weight: 400;
  font-style: normal;
}

@font-face {
  font-family: 'Berkeley Mono';
  src: url('./fonts/BerkeleyMono-Bold.ttf') format('truetype');
  font-weight: 700;
  font-style: normal;
}

@font-face {
  font-family: 'Berkeley Mono';
  src: url('./fonts/BerkeleyMono-Oblique.ttf') format('truetype');
  font-weight: 400;
  font-style: oblique;
}

@font-face {
  font-family: 'Berkeley Mono';
  src: url('./fonts/BerkeleyMono-Bold-Oblique.ttf') format('truetype');
  font-weight: 700;
  font-style: oblique;
}

/* ============================================
   CSS Variables
   ============================================ */
:root {
  --background-color: #fdfdfd;
  --text-color: #1a1a1a;
  --link-color: #1a1a1a;
  --blockquote-border: #e6e6e6;
  --blockquote-text: #606060;
  --muted: #6b6b6b;
  --accent: #b4791a;
  --rule: #e6e6e6;
  /* Two families, split by what a thing IS rather than by where it sits.
     Declared once each because both are wanted in places that share no
     selector, and repeating a stack is how the nav came to be left out of one.

     Berkeley Mono is for site furniture and identifiers — the wordmark, the
     nav, and a note's `[idea:etal]` id. It marks the parts of the page that
     are machinery rather than writing.

     Inter is for everything that is writing: every heading, and a note's own
     title, which is its name. */
  --mono-font: 'Berkeley Mono', monospace;
  --heading-font: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
  /* Nav entries and note ids are the same kind of thing — small mono labels —
     so they are the same size, declared once. In `rem`, not `em`: an id sits
     inside headings of several sizes and inside a `#window` summary the footer
     has already scaled down, and only a root-relative unit comes out the same
     in all of them. */
  --label-size: 0.85rem;
  /* The hover fill a note id takes, so the nav can take the same one. The
     package injects this value as `--idea-link-color` on its OWN elements,
     from `THEME.link-color` in content/template.typ — but the nav has no
     `.idea-*` ancestor to inherit it from, so it is written once more here.
     Keep the two in step. */
  --hover-fill: rgba(230, 140, 0, 0.16);
  /* What an OUTBOUND link's underline takes on hover, where an internal one
     takes `--hover-fill` behind it. Read by rookery's own stylesheet for links
     inside an idea, and by the `a[href^="http"]` rule below for the prose
     outside one, so both halves of the site agree. The accent rather than the
     fill: the fill is translucent, and a 2px line drawn in it barely shows. */
  --idea-external-color: var(--accent);
}

/* ============================================
   Header / nav

   Rendered by `site-header` in content/template.typ, which marks the current
   page `.active`. The anchors are Typst's, wrapped in the class-carrying
   element, so every selector here reaches through to `a` — see the note in
   template.typ about why the hrefs cannot be written by hand.
   ============================================ */
/* Sticky, so the nav is reachable from anywhere in a long page — and these
   pages are long: an idea's own standalone page carries its whole body plus a
   footer, and `concepts` is one page of everything.

   It needs an opaque `background-color` of its own to sit on: `body`'s
   background paints the canvas, not this box, so without one the text
   scrolling underneath would read straight through the bar.

   `padding-top` is what keeps the wordmark off the viewport edge once the bar
   is stuck at `top: 0` — unstuck, it simply adds to `body`'s own top padding.

   The rule under it is the SAME colour as the left rule on an idea and on a
   window, so the site's one horizontal hairline and its many vertical ones
   read as one system. `--hover-fill` is the site-level name for that colour
   (see `:root`); the package injects the identical value as
   `--idea-link-color` on its own elements, and the two are kept in step by
   hand because a package's inline custom properties cannot reach the nav. */
.site-header {
  position: sticky;
  top: 0;
  z-index: 10;
  background-color: var(--background-color);
  border-bottom: 1px solid var(--hover-fill);
  padding-top: 0.6rem;
  margin-bottom: 1.5rem;
}

.site-header-inner {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.6rem 1.5rem;
  padding-bottom: 0.6rem;
}

/* Uppercase, not small-caps. Berkeley Mono is a monospace face: small-caps in
   it are synthesised by the browser, which scales the capitals down and leaves
   them sitting at the wrong weight for the rest of the face. Setting the text
   upper outright gets the real glyphs at their designed proportions. */
.wordmark a {
  font-family: var(--mono-font);
  font-size: 1rem;
  letter-spacing: -0.02em;
  text-transform: uppercase;
  color: var(--text-color);
  text-decoration: none;
}

.wordmark.active a,
.wordmark a:hover {
  color: var(--accent);
}

/* Pushed to the far end of the bar, and allowed to wrap under the wordmark on
   a narrow screen rather than being hidden behind a toggle — three entries fit
   on one line at any width worth designing for. */
.site-nav {
  margin-left: auto;
}

.site-nav ul {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: 0.15rem 1rem;
}

.site-nav li {
  margin: 0;
}

/* Padding and radius on the link itself, not on `:hover` — a padding that
   appeared only on hover would shift the whole bar every time the pointer
   crossed an entry. Only the background changes. Same 2px/3px the package
   gives a note id, so the two fills are the same shape as well as the same
   colour. */
.site-nav a {
  font-family: var(--mono-font);
  font-size: var(--label-size);
  text-transform: uppercase;
  letter-spacing: 0.03em;
  padding: 0 2px;
  border-radius: 3px;
  color: var(--muted);
  text-decoration: none;
}

.site-nav a:hover {
  background-color: var(--hover-fill);
  color: var(--text-color);
}

.site-nav li.active a {
  color: var(--accent);
  font-weight: 600;
}

/* ============================================
   Search

   The bar itself comes from `@rheo/rookery-search`, placed in the header by
   `site-header` in content/template.typ. Nothing here reimplements it: the
   matching, the dropdown and the keyboard handling all ship with the package,
   and this site only dresses them.

   Almost all of it is done by setting the package's `--rookery-search-*`
   properties from this site's own, which is the route to prefer — a property
   is a value the package asked for, where a rule is a value it did not. Only
   the two things it has no property for (the label typography, and the title
   line) are written as rules.

   Those rules DO win, even though the package's stylesheet is linked after this
   one: it wraps everything in `@layer rookery-search`, and unlayered CSS beats
   layered CSS whatever the order or specificity. So if an override here ever
   stops taking, the layer is the thing to check — never reach for `!important`.
   ============================================ */
.rookery-search {
  --rookery-search-fg: var(--text-color);
  --rookery-search-bg: var(--background-color);
  /* The same line an idea draws down its left edge and an outline draws down
     its rows — `--idea-border-color` falls through to the theme's link colour,
     which is this. The bar sits in the header with no `.idea-*` ancestor to
     inherit that from, so it is named here rather than left to the fallback. */
  --rookery-search-border: var(--hover-fill);
  --rookery-search-radius: 3px;
  /* The same fill the nav entries and note ids take, so a highlighted result
     reads as the same gesture as a hovered nav entry. */
  --rookery-search-hover: var(--hover-fill);
  --rookery-search-id-color: var(--muted);
  --rookery-search-width: 12rem;
  /* The input stays narrow enough to sit in the header; the dropdown is free
     to be wider, and has to be — a title and its id share a line. Measured
     against the longest pair this site actually has ("Do I need to use Rheo
     to use rookery?" beside `idea:using-typst`), which is what it takes for
     every result here to sit on one line. A ceiling rather than a width: the
     panel hugs whatever is matching and only reaches this when the longest
     pair is in play. The package shrinks it further to fit a narrow
     viewport. */
  --rookery-search-max-width: 32em;
  --rookery-search-max-height: 24em;
}

/* Mono and small, like the nav beside it: the search box is site furniture,
   not writing, and the two sit in the same row. */
.rookery-search-input {
  font-family: var(--mono-font);
  font-size: var(--label-size);
}

.rookery-search-input::placeholder {
  color: var(--muted);
}

/* A result is a note's name, so it takes Inter like every other note title,
   with the id beside it in mono — the same division of labour the rest of the
   site uses. */
.rookery-search-title {
  font-family: var(--heading-font);
}

.rookery-search-id {
  font-family: var(--mono-font);
}

/* The package already asks for an undecorated row, but it asks from inside
   `@layer rookery-search`, and this stylesheet's own `a { text-decoration:
   underline }` is unlayered — unlayered beats layered whatever the order, so
   the site is the only place that can take the underline back off. A result
   should read as a note's title followed by its id, the way it reads inline,
   and an underline under the whole row makes it read as a link to somewhere
   else. */
.rookery-search-row {
  text-decoration: none;
}

/* The bar is the last thing in the header, hard against the right margin, so
   the dropdown grows LEFTWARD from that edge — the package anchors it left by
   default, which here would push it off the side of the page. Everything else
   about its width is the package's: it sizes to its widest row so a title and
   its id sit on one line, floored at the input's width and capped below.

   The width cap itself is set with the rest of the properties above. */
.rookery-search-results {
  left: auto;
  right: 0;
  box-shadow: 0 2px 6px rgba(0, 0, 0, 0.08);
}

/* ============================================
   Landing page banner
   ============================================ */
.hero {
  margin: 0 0 1.5rem;
}

/* The image element already gets `max-width: 100%` from the Media rules below;
   this makes it fill the measure rather than sit at its intrinsic size, and
   drops the block margin those rules add, since `.hero` owns the spacing. */
.hero img {
  width: 100%;
  border-radius: 3px;
  margin: 0;
}

/* ============================================
   Base Layout
   ============================================ */
/* Every navigational affordance on this site lands on a fragment — an idea's
   `[idea:etal]` permalink, an outline row, a backlink, the Context link — and
   a sticky header would otherwise cover whatever each of them jumped to.
   Clears the bar plus a little air. */
html {
  scroll-padding-top: 4rem;
}

body {
  background-color: var(--background-color);
  color: var(--text-color);
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  font-size: 1em;
  line-height: 1.3;
  margin: 0 auto;
  padding: 50px;
  max-width: 36em;
}

/* ============================================
   Typography
   ============================================ */
/* Site prose headings — small-caps, since these are section labels rather
   than an idea's own name. */
h1, h2, h3, h4, h5, h6 {
  color: var(--text-color);
  font-family: var(--heading-font);
  font-variant: small-caps;
  font-weight: normal;
  margin-top: 1.5em;
  margin-bottom: 0.5em;
}

/* An idea's own title — in the heading font, but set as written, NOT forced
   into small-caps: a title is the note's NAME, and small-caps would relabel
   it rather than just style it. `.idea-title` (inside `#idea`'s own heading)
   and `.idea-window-title` (the same title in a `#window`'s summary, a span only
   because a fold control cannot contain an `<h2>`) show the same title in two
   shapes, so both get it. Declared on the span itself rather than left to
   inherit from the ancestor `h2` above, matching how `.idea-label` already
   overrides its own font rather than relying on inheritance. */
.idea-title,
.idea-window-title {
  font-family: var(--heading-font);
  font-variant: normal;
}

/* A span, not a block: the summary lays its parts out on one line and these
   margins would break that. */
.idea-window-title {
  margin: 0;
}

/* The id, in the family the site keeps for machinery, at the size the nav uses
   — the two are the same kind of small mono label and now match exactly.

   It names font AND size itself rather than inheriting either: in `#idea`'s
   heading it would otherwise take the heading's Inter at heading size, and in
   a `#window`'s summary — no heading at all — the body's sans at the footer's
   reduced size. Three contexts, one appearance.

   Left as written, neither small-caps nor uppercased: `[idea:rookery]` is an
   identifier to be copied verbatim into `#window("...")`, and a reader who
   retyped what an uppercased id appeared to say would get it wrong. */
.idea-label {
  font-family: var(--mono-font);
  font-size: var(--label-size);
  font-variant: normal;
}

/* ============================================
   Links
   ============================================ */
a {
  color: var(--link-color);
  text-decoration: underline;
}

/* Two kinds of link, two weights of response. Staying inside the rookery is
   the ordinary case and keeps the ordinary hover — the whole link dims, the
   same gesture the nav and the note ids make. Leaving is the exceptional one,
   and gets the quieter signal: the underline takes the accent and thickens,
   the text itself untouched. The difference should be felt rather than read,
   which is why it is a change of channel and not a louder version of the same
   change.

   `[href^="http"]` is the test, and it holds because rheo emits every
   in-project link as a depth-relative path — nothing internal carries a
   scheme. Inside an idea, rookery's own stylesheet draws the same distinction
   with the same colours (see `--idea-external-color` below); these rules are
   for the prose that sits outside one. */
a:not([href^="http"]):hover {
  opacity: 0.7;
}

a[href^="http"]:hover {
  text-decoration-color: var(--accent);
  text-decoration-thickness: 2px;
  text-underline-offset: 0.15em;
}

/* ============================================
   Lists
   ============================================ */
ul, ol {
  padding-left: 2em;
  margin: 1em 0;
}

li {}

/* ============================================
   Media
   ============================================ */
img, video {
  max-width: 100%;
  height: auto;
  display: block;
  margin: 1.5em 0;
}

/* ============================================
   Code
   ============================================ */
code {
  font-family: 'Courier New', monospace;
  background-color: #f5f5f5;
  padding: 0.2em 0.4em;
  border-radius: 3px;
  font-size: 0.9em;
}

/* Fenced ```typ blocks: `pre` gets the uniform block background, since an
   inline `code` background only fills each line's glyph box, not a full
   rectangle. `pre code` drops the inline padding/background/radius it would
   otherwise inherit from the rule above. */
pre {
  background-color: #f5f5f5;
  padding: 1em;
  border-radius: 3px;
  overflow-x: auto;
}

pre code {
  background-color: transparent;
  padding: 0;
  border-radius: 0;
  font-size: 1em;
}

/* ============================================
   Blockquotes
   ============================================ */
blockquote {
  margin: 1.5em 0;
  padding-left: 1em;
  border-left: 2px solid var(--blockquote-border);
  color: var(--blockquote-text);
  font-style: italic;
}

hr {
  height: 1px;
  background-color: var(--blockquote-border);
  border: none; /* removes default border */
}

/* ============================================
   Endnotes
   ============================================ */
section[role="doc-endnotes"] {
  margin-top: 2em;
  padding-top: 1em;
  border-top: 1px solid var(--blockquote-border);
}

section[role="doc-endnotes"] ol li a[role="doc-backlink"] {
  padding-right: 0.2em;
}

/* ============================================
   Responsive
   ============================================ */
@media (max-width: 600px) {
  body {
    padding: 12px;
    font-size: 0.9em;
  }

  /* The search goes full-width on its own line. Capping the dropdown's WIDTH
     is not enough at this size: it hangs from the right-hand edge of an input
     that is itself only a few centimetres from the right margin, so a dropdown
     wide enough to hold a title and an id runs off the LEFT of the screen —
     a position problem, which no `max-width` can solve.

     Letting the bar span the header fixes it at the root: the input's own
     edges become the header's, so the dropdown (never narrower than the input,
     never wider than the viewport) lands inside the screen by construction. */
  .rookery-search {
    display: block;
    width: 100%;
  }

  .rookery-search-input {
    width: 100%;
  }
}
