/*
  Ledger: "the spec". Sometype Mono for headings, section numbers,
  labels, meta lines, tables, figures and code; Atkinson Hyperlegible Next for
  running prose. A clean paper ground, a heavy ink hanging rule, gold kept to the dots,
  the table's ruled head and one light fill, ledger green for links and the
  insight panel, debit red for the caveat. It should read like a well-set
  specification: the structure is the ledger, the prose is a book.

  From St. Clair AI, Lahe Styles (https://stclair.ai/lahe-styles.html),
  version 1.1.1. This style's page: https://stclair.ai/lahe-styles/ledger.html

  Loads AFTER lib/templates/document.css. It self-hosts its fonts from
  ./fonts/, sets its own raw palette, points the base's colour roles and
  settings at it, retunes the heading scale for a monospace, and adds rule
  blocks only where no token reaches the thing. Its layout, the spec sheet
  with a sticky label column, is the last block in the file, so this one file
  is the whole style over the base.

  This was the "mixed" direction, the one Ken picked. The all-mono direction
  did not meet the high-design bar and is kept in directions/.

  Where it came from. Tear sheet E, Ledger, and its review: "unique and not
  like slop", but a whole page of it is a lot, and the rows work best for dense
  lists (projects/agent_storefront/tearsheets/REVIEW_NOTES.md). This direction
  takes that literally: mono wherever the page is a list or a figure, a quiet
  serif wherever it is prose. E's olive gold is replaced by a warmer gold,
  because the antique gold on H read as green in review.

  Measured contrast. Every number from
  lib/templates/styles/ledger/scripts/contrast.py, which is the only place these
  are produced. Floors: 4.5:1 for body and anything under 24px, 3.0:1 for a
  drawn mark or rule.

  BEGIN MEASURED
    body text on the page ground                #1c2a1f on #fcfbf5    14.47:1
    secondary copy and the lede                 #4a574c on #fcfbf5     7.34:1
    section numbers, table heads, meta          #5a655b on #fcfbf5     5.88:1
    a boxed table head on the raised ground     #5a655b on #f3f0e2     5.33:1
    a link in running prose                     #1d6b3f on #fcfbf5     6.28:1
    body text on the raised ground              #1c2a1f on #f3f0e2    13.12:1
    body text on a boxed table's alternate row  #1c2a1f on #f8f6ed    13.85:1
    body text in the deep paper panel           #1c2a1f on #f3f0e2    13.12:1
    body text on the green tint and code        #1c2a1f on #e2eee3    12.55:1
    body text on the red tint                   #1c2a1f on #f5e1d9    11.89:1
    the green insight label on its tint         #1d6b3f on #e2eee3     5.45:1
    the red caveat label on its tint            #9a2f1c on #f5e1d9     5.95:1
    white on the ink band and callout           #ffffff on #1c2a1f    15.00:1
    secondary copy on the ink band              #e6e2cf on #1c2a1f    11.53:1
    the section number on the ink band          #d6d3c0 on #1c2a1f     9.95:1
    the dot bullet on the ink band              #d6d3c0 on #1c2a1f     9.95:1
    white on the green band and callout         #ffffff on #1d6b3f     6.51:1
    the vellum number on the green band         #e6e2cf on #1d6b3f     5.00:1
    white on the red band and callout           #ffffff on #9a2f1c     7.51:1
    the section number on the red band          #d6d3c0 on #9a2f1c     4.98:1
    ink on the gold callout                     #1c2a1f on #d9a83a     6.86:1
    the today pill: page ground on ink          #fcfbf5 on #1c2a1f    14.47:1
    the dark gold dot on the ground             #8c6410 on #fcfbf5     5.13:1
    the dark gold dot in the deep paper panel   #8c6410 on #f3f0e2     4.66:1
    the dark gold all-day label, 12px           #8c6410 on #fcfbf5     5.13:1
    the ink hanging rule                        #1c2a1f on #fcfbf5    14.47:1
    the plate caption on the raised strip       #4a574c on #f3f0e2     6.66:1
    the error panel's debit red label on its tint#9a2f1c on #f5e1d9     5.95:1
    the double gold rule under a stat or quote  #a97c14 on #fcfbf5     3.63:1
    the dark gold step number, small text       #8c6410 on #fcfbf5     5.13:1
  END MEASURED

  Pairs tried and dropped, with their numbers, are listed in contrast.py under
  REJECTED.
*/

/* ---------- fonts, self-hosted ----------
   A style has to be a folder the switcher can point at, and a folder that
   reaches the network for its type renders wrong on a plane, behind a proxy, or
   in a PDF export. So the files sit in fonts/ beside this file.

   One file per family and style, not one per weight. Google's css2 endpoint
   returns a single latin variable woff2 covering the whole weight axis, so each
   rule declares the range it covers.

   | File                                             | Family                     | Style  | Range      | Google version |
   | ------------------------------------------------ | -------------------------- | ------ | ---------- | -------------- |
   | sometype-mono-variable.woff2                     | Sometype Mono              | normal | 400 to 700 | v4             |
   | sometype-mono-italic-variable.woff2              | Sometype Mono              | italic | 400 to 700 | v4             |
   | atkinson-hyperlegible-next-variable.woff2         | Atkinson Hyperlegible Next | normal | 200 to 800 | v1             |
   | atkinson-hyperlegible-next-italic-variable.woff2  | Atkinson Hyperlegible Next | italic | 200 to 800 | v1             |

   The italics are vendored because an <em> with no italic face gets a slanted
   roman from the browser, which is visibly wrong in a monospace.

   All SIL Open Font License 1.1. fonts/LICENSE carries the licence and both
   copyright lines.

   To update: fetch the css2 URL with a browser User-Agent so Google returns
   woff2 blocks, pull the url() out of each latin block, copy the files over
   these, and update the version column above.

     curl -H "User-Agent: Mozilla/5.0 ... Chrome/126.0 Safari/537.36" \
       "https://fonts.googleapis.com/css2?family=Sometype+Mono:ital,wght@0,400..700;1,400..700&family=Atkinson+Hyperlegible+Next:ital,wght@0,200..800;1,200..800&display=swap"
*/

@font-face {
  font-family: "Sometype Mono";
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url("./fonts/sometype-mono-variable.woff2") format("woff2");
}

@font-face {
  font-family: "Sometype Mono";
  font-style: italic;
  font-weight: 400 700;
  font-display: swap;
  src: url("./fonts/sometype-mono-italic-variable.woff2") format("woff2");
}

@font-face {
  font-family: "Atkinson Hyperlegible Next";
  font-style: normal;
  font-weight: 200 800;
  font-display: swap;
  src: url("./fonts/atkinson-hyperlegible-next-variable.woff2") format("woff2");
}

@font-face {
  font-family: "Atkinson Hyperlegible Next";
  font-style: italic;
  font-weight: 200 800;
  font-display: swap;
  src: url("./fonts/atkinson-hyperlegible-next-italic-variable.woff2") format("woff2");
}


:root{
  /* ---------- type ----------
     Atkinson Hyperlegible Next for body, because a long document in mono
     tires the eye: every letter takes the same width, so words lose their
     shapes. Ken picked it (2026-09-21) over Source Serif 4 and three other
     candidates on lib/templates/styles/ledger/scripts/build_body_faces.py's
     comparison sheet; see DESIGN.md for why. The heading scale comes down a
     step because a mono title at the base's 52px wraps after two or three
     words. */
  --font-display:"Sometype Mono",ui-monospace,SFMono-Regular,Menlo,monospace;
  --font-body:"Atkinson Hyperlegible Next",system-ui,sans-serif;
  --font-mono:"Sometype Mono",ui-monospace,SFMono-Regular,Menlo,monospace;
  --w-display:600;
  --w-bold:700;

  --text-h1:clamp(30px,3.6vw,42px);
  --text-h2:clamp(22px,2.4vw,28px);
  --text-h3:clamp(18px,1.8vw,20px);
  --text-figure:21px;

  /* A ch is the width of the body face's zero, and a sans zero runs wider
     than a serif's, so the base's 68ch measure sets prose noticeably wider
     under Atkinson than it did under Source Serif 4: at 68ch the page measured
     about 83 characters on a full line. Narrowed until a full line lands in
     the 65-72 character range (measured about 67-68 at this value). */
  --read:48ch;

  /* ---------- the palette, in Ledger's own names ---------- */
  --paper:#fcfbf5;             /* E's page, a touch cleaner than the book's parchment */
  --paper-deep:#f3f0e2;        /* the raised ground and the default panel */
  --paper-stripe:#f8f6ed;      /* the boxed table's alternate rows */
  --ruling:#d8cfb4;            /* hairlines only, never text */
  --ink:#1c2a1f;               /* E's green-black ink */
  --ink-soft:#4a574c;
  --ink-faint:#5a655b;
  /* Gold is one warmth at three lightnesses, picked by ground. All three sit
     at hue 41 to 42 with high saturation, so they read as gold, not olive. */
  --gold:#d9a83a;              /* a fill carrying ink; under the mark floor on paper */
  --gold-rule:#a97c14;         /* the table head's double rule: clears 3:1, not 4.5 */
  --gold-mark:#8c6410;         /* dots, numerals, the 12px all-day label */
  --ledger-green:#1d6b3f;
  --ledger-green-deep:#155230;
  --green-tint:#e2eee3;
  --debit-red:#9a2f1c;
  --debit-red-deep:#7a2415;
  --red-tint:#f5e1d9;
  --vellum:#e6e2cf;            /* secondary copy on a fill */
  --vellum-dim:#d6d3c0;        /* section numbers and dots on the ink band */

  /* Families for the specimen's palette view; the format is explained where
     system-tokens.css declares the house version. */
  --palette-families:"paper paper-deep paper-stripe ruling: The page, the raised ground and default panel, alternate rows, hairlines \
    | ink ink-soft ink-faint vellum vellum-dim: Body text, the hanging rule, the band, and the light text on it \
    | gold gold-rule gold-mark: Dots and numerals, the table head's ruling, the one light fill \
    | ledger-green ledger-green-deep green-tint: Links, the insight panel, code, the accent band \
    | debit-red debit-red-deep red-tint: Emphasis: the caveat, the emphasis band and callout";

  /* ---------- roles ---------- */
  --surface:var(--paper);
  --surface-raised:var(--paper-deep);
  --on-surface:var(--ink);
  --on-surface-soft:var(--ink-soft);
  --on-surface-faint:var(--ink-faint);
  --border:var(--ruling);

  --accent:var(--ledger-green);
  --accent-hover:var(--ledger-green-deep);
  --accent-tint:var(--green-tint);
  --link:var(--ledger-green);
  --focus:var(--ledger-green);

  --mark:var(--gold-mark);
  --fill:var(--gold);
  --on-fill:var(--ink);
  --tint:var(--paper-deep);
  --emphasis:var(--debit-red);
  --emphasis-hover:var(--debit-red-deep);
  --emphasis-tint:var(--red-tint);

  --structure:var(--ink);
  --on-structure:#ffffff;
  --on-structure-soft:var(--vellum);
  --on-structure-faint:var(--vellum-dim);

  /* ---------- lines and radius ----------
     A 2px ink hanging rule, as on E: rules are structural, and a heavy mono
     heading wants a rule of matching weight. Square corners. */
  --divider:2px solid var(--ink);
  --line:1px solid var(--ruling);
  --line-ink:1px solid var(--ink);
  --r:0px;
  --r-lg:0px;

  /* ---------- the base's settings ----------
     Mono letters sit in fixed cells, and the base's display tightening makes
     the cells collide, so headings are set at 0. A caption is a label, so it
     is typed in the mono. The table head takes the accounting book's ruled
     head: a double gold rule, and the column names in full ink, since they
     are read, not skimmed past. */
  --tracking-heading:0;
  --font-caption:var(--font-mono);
  --thead-color:var(--on-surface);
  --thead-rule:3px double var(--gold-rule);
  --thead-rule-boxed:3px double var(--gold-rule);
}

/* ---------- the facts figure ----------
   Headings are untracked through --tracking-heading; the facts figure is a
   label, not a heading, so it is named here for the same reason. */
.facts dt{letter-spacing:0}

/* ---------- labels and meta lines in mono ----------
   The base sets these in the body face. Here the body face is the serif, so a
   caption or a date would read as prose. Mono is the spec's voice for anything
   that labels rather than explains. */
.masthead .meta,
.checkin .checkin-head .time,
.cal-event,
.cal-month-events li,
body > footer{font-family:var(--font-mono)}

/* ---------- the ledger table ----------
   Tables are mono, at the small size. The base sets tables at body size, but
   a monospace at the same nominal size reads larger and runs about a fifth
   wider than the prose around it; this is the same reasoning the base
   already applies to code. The head's double gold rule and full ink are the
   settings above. A single ink rule closes the last row, so the table reads
   as totalled. */
table{font-family:var(--font-mono);font-size:var(--text-small);font-variant-numeric:tabular-nums lining-nums}
tbody tr:last-child td{border-bottom:var(--line-ink)}

/* The base lets a cell break anywhere, so a raw URL cannot widen the page. In
   an auto-sized table that also shrinks each cell's narrowest width to one
   letter, and the long notes column then squeezes "Row label" and "2 weeks"
   onto two lines. break-word still breaks a long URL but only when it overflows,
   so short cells keep their width. Heads stay on one line, as a ruled book's do. */
td{overflow-wrap:break-word}
thead th{white-space:nowrap}

/* A cell that explains is prose, so it takes the prose face. On a real
   document (Lahe's own CLI reference) the description column runs four and
   five lines a cell, and five lines of a monospace at table size is the
   tiring read this style exists to avoid. What labels or counts stays mono:
   the head, the first column (the row's label), any figure marked .num, and
   the total row. Inline code in a cell holds together, so a flag such as
   --state-dir never breaks at its own hyphen. The first column is left free
   to wrap: it holds the row's label, which can be a whole command, and held
   on one line it pushed the table past the column. */
td{font-family:var(--font-body)}
td:first-child,td.num,tfoot td{font-family:var(--font-mono)}
td:not(:first-child) code{white-space:nowrap}

/* The boxed table: an ink box, the raised head, alternate rows. */
table.boxed{border:var(--line-ink)}
table.boxed tbody tr:nth-child(even) td{background:var(--paper-stripe)}
table.boxed tr:last-child td{border-bottom:0}

/* ---------- the accent band's section number ----------
   The base dims white to .72 here. On ledger green that blend measures under
   4.5 (REJECTED in contrast.py), so the number takes vellum instead. */
.band--cobalt .sheet-head .n{color:var(--on-structure-soft);opacity:1}

/* ---------- list markers inside a band ---------- */
.band ul li::before{background:var(--on-structure-faint)}
.band ol li::before{color:var(--on-structure-faint)}

/* =========================================================================
   COMPONENTS: the 1.1.0 set, in ledger terms.

   The same voice as the rest of the sheet: mono for anything that labels or
   counts, the quiet sans for anything that explains, an ink box where the
   base draws a hairline box, and the double gold rule wherever a figure is
   ruled off.
   ========================================================================= */

:root{
  /* Mono figures run wide: at the base's 38px, "11 days" broke onto two lines
     in a four-up row of the entry column. */
  --text-stat:clamp(24px,2.4vw,30px);
  --text-stat-large:clamp(40px,4.6vw,52px);
  /* Every picture is an exhibit pasted onto the sheet: the 1px ink box the
     boxed table and the sequence already use. */
  --image-frame:var(--line-ink);
  /* Debit red is this style's red, so a failure is written in it rather than
     in the base's second, slightly different red. The error panel keeps its
     full border, which is what tells it apart from the emphasis panel. */
  --danger:var(--debit-red);
  --danger-tint:var(--red-tint);
}

/* ---------- stat tiles ----------
   The label is a column head (mono, faint), the figure is mono with tabular
   digits, and the large figure is ruled off under its number by the double
   gold rule, the way a total is in a book. The large tile is an ink box like
   the boxed table. */
.stat-label{font-family:var(--font-mono)}
.stat--large{border:var(--line-ink)}
.stat--large .stat-value{justify-self:start;padding-bottom:var(--s2);border-bottom:var(--thead-rule)}

/* ---------- pull quote ----------
   A quote is prose, so it is set in the prose face, larger, rather than in
   the mono: five lines of a monospace at quote size read as shouting. The
   attribution is a label, so it is mono. The ruled version is ruled off with
   the table head's double gold rule. */
blockquote.pullquote p{font-family:var(--font-body);font-weight:var(--w-bold);letter-spacing:0;line-height:1.3}
blockquote.pullquote footer{font-family:var(--font-mono)}
blockquote.pullquote.pullquote--ruled{border-block:var(--thead-rule)}

/* ---------- step sequence ----------
   The step numbers are entry numbers: dark gold, two digits, the same as the
   section's own number in the label column. */
ol.sequence > li::before{content:counter(seq, decimal-leading-zero);font-family:var(--font-mono);color:var(--mark)}

/* ---------- data table ----------
   The total is ruled the way an accountant rules it: a single ink line above
   and a double ink line below. */
tfoot td{border-top:var(--line-ink)}
/* :is() lifts this to the boxed table's own last-row rule, which drops the
   bottom border, so the double rule shows in both tables. */
:is(table,table.boxed) tfoot tr:last-child td{border-bottom:3px double var(--ink)}

/* ---------- figure on a plate, and the option cards ----------
   Ink boxes, like the boxed table. The plate's caption strip is the table
   head turned over: the raised ground, under the double gold rule. */
figure.plate,.option{border:var(--line-ink)}
figure.plate figcaption{background:var(--surface-raised);border-top:var(--thead-rule-boxed)}
/* Two plates side by side stretch to the taller one, so the caption strip
   takes up the slack rather than leaving a band of page ground under it. */
figure.plate{display:flex;flex-direction:column}
figure.plate figcaption{flex:1}

/* =========================================================================
   LAYOUT: the spec sheet.

   Everything above sets colour, type and the table's ruling. Everything
   below changes structure only, on the shared markup: the section head, the
   page grid, alignment, the opening, and rhythm. It reads the base's
   --layout-label.

     1. Every section is two columns. The number and heading sit in a narrow
        left column and the content runs in the wide right one, so the page
        reads like a specification or a price sheet: the label on the left,
        the entry on the right.
     2. The label column is sticky. As the entry scrolls, its number and
        heading stay in view at the top of the left column, the way a spec
        sheet's label reads beside every line of its entry.
     3. A thin ink rule runs across the top of each section, the full width
        of both columns: a ruled line between entries, not a bar over a
        heading.
     4. The number is an entry number in the mono, above the heading, and the
        heading comes down to a label's size, since the left column is narrow.
     5. The opening snaps to the same two columns: the title across both, the
        lede in the right column with a "Summary" label in the left.
     6. Denser than the house rhythm: a spec sheet is read by scanning down
        the left column, so the entries sit closer together.
     7. Under 820px the columns stack: the label above its entry, the rule
        still across the top, and nothing is sticky.
   ========================================================================= */

:root{
  --layout-label:14rem;   /* the label column; matches the base default, stated so a change there does not move this page */
}

html{counter-reset:entry}
/* Only a section's own head counts as an entry. The medium head carries an
   .n too, but it holds a label, not a section number. */
.sheet-head:not(.sheet-head--medium):has(.n),.fold-head:has(.n){counter-increment:entry}

/* ---------- the head: entry number over a label-size heading ---------- */
.sheet-head{
  display:flex;
  flex-direction:column;
  align-items:flex-start;
  gap:var(--s2);
  border-top:0;
  padding-top:0;
}
.sheet-head h2,details.fold summary.fold-head h2,.checkin .checkin-head h2{font-size:var(--text-h3);line-height:1.25}
:is(.sheet-head,.fold-head) .n{order:-1;font-size:0;line-height:1}
/* The base sizes the fold's number with a longer selector, so the fold is
   named in full here or its "Section N" text would print beside the numeral. */
details.fold summary.fold-head .n{font-size:0}
:is(.sheet-head,.fold-head) .n::before{
  content:"\00A7\00A0" counter(entry, decimal-leading-zero);
  font-family:var(--font-mono);
  font-size:var(--text-small);
  color:var(--mark);
}
.band :is(.sheet-head,.fold-head) .n::before{color:var(--on-structure-faint)}

/* ---------- the two smaller heads ----------
   A sub-entry inside the entry column, not a second label column. The medium
   head is a row again: the heading on the left, its label on the right in the
   mono, under the 1px ink rule. The small head is a heading on a hairline.
   Both headings are the mono at body size, a step under the section's own. */
.sheet-head--medium{flex-direction:row;justify-content:space-between;align-items:baseline;border-top:var(--line-ink);padding-top:var(--s3)}
.sheet-head--small{border-top:var(--line);padding-top:var(--s2)}
:is(.sheet-head--medium,.sheet-head--small) :is(h3,h4){font-size:var(--text-body);line-height:1.3}
.sheet-head--medium .n{order:0;font-family:var(--font-mono);font-size:var(--text-meta);line-height:1.3;color:var(--on-surface-faint)}
.sheet-head--medium .n::before{content:none}

/* ---------- the rule between entries ----------
   Drawn by a pseudo-element that is a grid item across both columns, so the
   rule stops at the column's edges; a border on the section would run out
   into its side padding. */
section.sheet,.band > div:not(.band){padding-block:var(--s6)}
:is(section.sheet,.band > div)::before{
  content:"";
  display:block;
  border-top:var(--line-ink);
  margin-bottom:var(--s5);
}
.band > div::before{border-top-color:var(--on-structure)}
details.fold summary.fold-head,.checkin .checkin-head{border-top:var(--line-ink);padding-top:var(--s5)}
details.fold{padding-block-start:var(--s6)}

@media (min-width:821px){
  section.sheet,.band > div:not(.band){
    display:grid;
    grid-template-columns:[label] var(--layout-label) [entry] minmax(0,1fr);
    column-gap:var(--gutter);
    align-items:start;
  }
  :is(section.sheet,.band > div)::before{grid-column:1 / -1}
  :is(section.sheet,.band > div) > *{grid-column:entry}
  /* The head holds the left column for the whole entry and stays in view
     while the entry scrolls, the way a spec sheet's label reads beside every
     line of its entry. The long row span is what keeps the column clear:
     auto-placement puts every other child in the right column, one row each. */
  :is(section.sheet,.band > div) > .sheet-head:not(.sheet-head--medium,.sheet-head--small){
    grid-column:label;
    grid-row:2 / span 60;
    margin:0;
    position:sticky;
    top:var(--s4);
  }

  /* The fold and the check-in keep their own shape, so their head's number
     takes the label column's width and the body starts on the entry edge. */
  details.fold summary.fold-head{justify-content:flex-start;column-gap:var(--gutter)}
  details.fold summary.fold-head .n{order:-2;flex:0 0 var(--layout-label)}
  details.fold summary.fold-head .fold-arrow{order:-1}
  details.fold .fold-body{padding-inline-start:calc(var(--layout-label) + var(--gutter))}

  /* ---------- the opening, on the same two columns ---------- */
  .masthead,.hero{
    display:grid;
    grid-template-columns:[label] var(--layout-label) [entry] minmax(0,1fr);
    column-gap:var(--gutter);
  }
  .masthead > *{grid-column:entry}
  .hero > h1{grid-column:1 / -1;max-width:none}
  /* Everything in the hero after the title sits in the entry column, not
     only the lede. A Markdown document rendered by Lahe puts all it has
     before the first H2 into the hero (paragraphs, lists, a table), and
     auto-placement would otherwise drop every other block into the narrow
     label column, one row each. The label column holds only its label. */
  .hero > :not(h1){grid-column:entry}
  .hero::before{
    content:"Summary";
    grid-column:label;
    grid-row:2;
    padding-top:var(--s2);
    font-family:var(--font-mono);
    font-size:var(--text-meta);
    color:var(--on-surface-faint);
  }
  /* A hero with nothing but its title has nothing to summarise. */
  .hero:not(:has(> :not(h1)))::before{content:none}

  /* ---------- the full-width image ----------
     Breaking out of the entry column means spanning the label column too:
     the picture runs the full width of the sheet, edge to edge with the rule
     between entries, rather than to the page edge, so the page keeps its two
     column edges. Its caption comes back into the entry column. */
  figure.bleed{max-width:var(--maxw);margin-inline:auto;padding-inline:var(--gutter)}
  .bleed > :is(img,picture,svg,video){border:var(--image-frame)}
  .bleed > figcaption{padding-inline:calc(var(--layout-label) + var(--gutter)) 0}
}
