/*
  Document style system, Ken St. Clair
  Spec: docs/document-style-guide.md (read that first; this file is the "how", not the "why")
  Skeleton that demonstrates every component: lib/templates/document-every-component.html

  Standalone. No brand assets in the base system below, drop this file into any
  HTML document and it works with no dependency on St. Clair AI branding.
  An optional, clearly separate brand section for the masthead lives at the
  bottom of this file. Only include that section's markup in a document that
  is an actual St. Clair AI deliverable.

  Two rules govern everything below.

  1. The column is declared once, as a rule about the page (see the next
     block). No component sets its own max-width or inline padding, so a new
     component cannot be off the grid: it never knows where the grid is.
  2. Every colour, font, weight, size and spacing value is a var() from
     system-tokens.css. A pixel value appears only on a border, an outline, a
     stroke width, inside a media query, or with a same-line marker naming the
     geometry it comes from. That is what makes a second style a new token file
     rather than a rewrite of this file.
*/

@import url("system-tokens.css");

/*
  Tokens live in system-tokens.css, shared with the presentation surface. Add
  surface-specific rules below, never redefine a shared token.
*/

/* ---------- the column ----------
   Every direct child of the body sits in the column. A full-bleed band opts
   out (it runs edge to edge) and its inner element opts back in through the
   same rule. Three element types render nothing and are skipped, and
   [data-lahe] is the review layer's own chrome: it lives in the body too, and
   the page must not lay it out.

   A full-width image (.bleed) opts out the same way a band does. Its caption
   opts back in through the second selector, and only the picture itself runs
   edge to edge. */

:is(body, .band) > :not(.band, .bleed, script, style, template, [data-lahe]),
.bleed > :not(img, picture, svg, video){
  max-width:var(--maxw);
  margin-inline:auto;
  padding-inline:var(--gutter);
}

/* ---------- base ---------- */

*{box-sizing:border-box}

body{
  margin:0;
  background:var(--surface);
  color:var(--on-surface);
  font-family:var(--font-body);
  font-size:var(--text-body);
  line-height:1.65;
  -webkit-font-smoothing:antialiased;
}

/* ---------- headings ----------
   A heading carries its own room, sized to its level, so it is correct
   wherever it lands: inside a section, inside rendered Markdown with no
   wrapper at all, or written by an agent who does not know the hero markup.
   The six head wrappers already provide that room, so they zero it, and the
   first child of any padded container drops its top margin so the container's
   padding is the only gap. */

h1,h2,h3,h4,h5,h6{
  font-family:var(--font-heading);
  font-weight:var(--w-heading);
  line-height:var(--lh-heading);
  letter-spacing:var(--tracking-heading);
  /* Sentence case only. Never set a heading in all caps. */
}
h1{font-size:var(--text-h1);margin:var(--section-gap) 0 var(--block-gap)}
h2{font-size:var(--text-h2);margin:var(--section-gap) 0 var(--block-gap)}
h3{font-size:var(--text-h3);margin:var(--section-gap-narrow) 0 var(--s3)}
h4{font-size:var(--text-h4);margin:var(--s5) 0 var(--s2)}
h5{font-size:var(--text-body);margin:var(--s5) 0 var(--s2)}
h6{font-size:var(--text-small);margin:var(--s5) 0 var(--s2);color:var(--on-surface-soft)}

:is(.hero,.sheet-head,.fold-head,.checkin-head,.cols,.icon-row,.sequence,.option,.image-card-body,.media-body) :is(h1,h2,h3,h4,h5,h6){margin:0}
:is(.fold-body,.panel,.insight,.callout,.band,td) > :first-child{margin-top:0}

/* ---------- text ---------- */

p{margin:0 0 var(--block-gap)}
p:last-child{margin-bottom:0}

/* A long unbroken run (a raw URL) wraps rather than widening the page. */
p,li,dd{overflow-wrap:anywhere}
td{overflow-wrap:break-word}   /* break-word keeps whole words when columns size; a long URL still breaks */

a{color:var(--link);text-decoration:underline}
a{
  text-decoration-thickness:1px;   /* px: a hairline underline, not a second rule on the page */
  text-underline-offset:3px;       /* px: clears the descenders at body size */
}
:focus-visible{outline:2px solid var(--focus);outline-offset:3px;border-radius:var(--r)}

/* ---------- plain elements ----------
   Rendered Markdown carries no classes, so every element Markdown can produce
   has a house look with no class needed. The classes further down are
   optional upgrades, not the only way to get the style. */

img{max-width:100%;height:auto}
/* The frame, ground and padding are all nothing in the house; they are tokens
   so a style that prints its figures as plates or drawings sets values. */
figure{margin:var(--block-gap) 0;border:var(--figure-border);background:var(--figure-ground);padding:var(--figure-pad)}
figcaption{margin-top:var(--s2);font-family:var(--font-caption);font-size:var(--text-meta);line-height:1.5;color:var(--caption-color)}
blockquote{
  margin:var(--block-gap) 0;
  padding-left:var(--s4);
  border-left:3px solid var(--border);
  color:var(--on-surface-soft);
}
hr{border:0;border-top:var(--line);margin:var(--section-gap-narrow) 0}

/* Stacked blocks carry their own room, so the markup needs no inline margins. */
:is(.panel,.callout,.insight,.icon-line){margin-bottom:var(--block-gap)}
:is(.panel,.callout,.insight,.icon-line):last-child{margin-bottom:0}

/* ---------- the reading measure ----------
   Prose gets the measure by default and the full-width blocks opt out. The
   container half of the selector is :where(), so its specificity is zero and
   any class below can override it without a fight. */

:where(section.sheet,.fold-body,.checkin,.hero) :where(p,ul,ol,blockquote){max-width:var(--read)}
/* A paragraph that is only an image is a figure, not prose: a chart or a
   screenshot wants the column, not the reading measure. Markdown always wraps
   an image in a paragraph, which is why this is decided here. */
p:has(> img:only-child){max-width:none}
:is(table,.facts,.cols,pre) :is(p,ul,ol,blockquote){max-width:none}

/* ---------- layout helpers ---------- */

.read{max-width:var(--read)}
/* .small and .soft are for captions, footnotes, the footer, and a meta line: never
   for running prose. Body text is one size and one colour, or the page reads as
   two systems. */
.soft{color:var(--on-surface-soft)}
.lede{font-size:var(--text-lede);line-height:1.55;color:var(--on-surface-soft);max-width:none}
.small{font-size:var(--text-small);line-height:1.5}

/* ---------- masthead (unbranded) ----------
   Even an unbranded document can carry a plain meta line: doc type + date,
   no mark, no wordmark. See the brand section at the bottom for the branded
   version. */
.masthead{padding-block:var(--section-gap-narrow) 0}
.masthead .meta{margin-top:var(--s2);font-size:var(--text-meta);color:var(--on-surface-faint)}

/* ---------- hero ----------
   The hero's bottom padding is deliberately small. It used to carry the full
   section-gap on the assumption that the section below would zero its own
   top padding and let the hero supply the room; that broke the moment the
   hero sat on its own coloured ground (a band), because the band's edge, the
   section's top, and the hanging rule all landed on the same pixel. A block
   is correct wherever it lands and carries its own space, so the hero keeps
   a narrow close of its own and the section below always adds its full gap
   on top of it. */

.hero{padding-block:var(--section-gap-narrow) var(--gutter)}
.hero h1{max-width:17ch;margin-bottom:var(--block-gap)}
.hero .lede{max-width:58ch}

/* ---------- the chrome: numbered sections under a hanging rule ----------
   A section carries its vertical rhythm and nothing else. The column comes
   from the page rule at the top of this file, so a section is correct
   wherever it lands in the body and cannot be double-padded by a wrapper.
   That includes the first section: it always pays its own top padding, never
   zero, so it never depends on whatever sits above it (a hero, a band, a
   masthead) to supply the room. */

section.sheet{padding-block:var(--section-gap)}

.sheet-head{
  display:flex;
  gap:var(--block-gap);
  align-items:baseline;         /* section number aligns to the heading's baseline, never the row's bottom */
  justify-content:space-between;
  flex-wrap:wrap;
  border-top:var(--divider);    /* the hanging rule, always full column width, never a short stub */
  padding-top:var(--s3);
  margin-bottom:var(--section-gap-narrow);
}
.sheet-head .n{
  font-family:var(--font-number);
  font-weight:var(--w-display);
  font-size:var(--text-small);
  color:var(--number-color);
}

/* Two smaller levels under the section head. Each drops one thing: the
   medium head's rule is 1px ink instead of the 2px divider and it carries an
   h3 with a label on the right; the small head's rule is a hairline and it
   carries an h4 alone, with no label. Both still run the full column width,
   never a stub. They sit inside a section, after other content, so each pays
   its own top room, and drops it when it is the first thing in its box. */
.sheet-head--medium{
  border-top:var(--line-ink);
  margin-top:var(--section-gap-narrow);
  margin-bottom:var(--gutter);
}
.sheet-head--medium .n{font-size:var(--text-meta)}
.sheet-head--small{
  border-top:var(--line);
  padding-top:var(--s2);
  margin-top:var(--gutter);
  margin-bottom:var(--s3);
}
:is(.sheet-head--medium,.sheet-head--small):first-child{margin-top:0}

/* ---------- facts (a definition-list grid for key figures) ---------- */

.facts{display:grid;grid-template-columns:repeat(3,1fr);gap:var(--section-gap-narrow)}
.facts dt{font-family:var(--font-display);font-weight:var(--w-display);font-size:var(--text-figure);letter-spacing:-.012em;margin-bottom:var(--s2)}
.facts dd{margin:0;font-size:var(--text-body);line-height:1.5;color:var(--on-surface-soft)}

/*
  Facts grid with icons. Use when the three items are genuinely three points
  rather than three columns of text, which is what a facts grid is for. The
  icon sits above the term so the eye lands on it, then the number, then the
  explanation.

  One icon per fact or none at all. Two of three looks like an oversight.
  Use one fill across the row rather than a different colour per fact; three
  colours in one row is decoration, not signal.
*/
/*
  Default icon treatment: a line icon on the term's line. Sized in em so it
  tracks the term's type rather than a fixed pixel value. This is the preferred
  version because the icon sits near the type's cap height and reads as part of
  the line. A circled icon is always larger than the type beside it, which is
  the thing that makes the row look heavier.
*/
.facts--line dt{display:flex; align-items:center; gap:var(--s3)}
.facts--line dt .icon,.facts--line dt svg{width:.88em; height:.88em; color:var(--accent); flex:none}

/*
  Second option: a filled circle on the term's line. Louder, and it puts colour
  on the page without needing a panel or a band. Use it when the document has no
  other accent; prefer the line version otherwise.
*/
.facts--icons dt{display:flex; align-items:center; gap:var(--s3)}
.facts--icons .icon-circle{width:32px; height:32px}   /* px: the contrast floor for white on sage is a 32px circle */
.facts--icons .icon-circle .icon,.facts--icons .icon-circle svg{width:16px; height:16px}   /* px: the glyph inside a 32px circle */

/* ---------- code ---------- */
/*
  Inline code and code blocks. The tint is cobalt, which the guide already
  assigns to code blocks and table headers; ink on it reads 14.39:1.

  The face is whatever --font-mono names, and that token ends in a platform
  fallback stack, so a document that has not loaded the webfont still gets a
  real monospace. Load the face in the head alongside the other two, or omit it
  and accept the fallback; nothing breaks either way.

  Code sits at --text-small against --text-body. A monospace at the same
  nominal size reads larger than the surrounding prose because its characters
  are wider.
*/
code{
  font-family:var(--font-mono);
  font-size:var(--text-small);
  background:var(--accent-tint);
  padding:.1em .35em;
  border-radius:var(--r-code);   /* a corner this small reads as a chip; var(--r) rounds an inline run too far */
}
pre{
  font-family:var(--font-mono);
  font-size:var(--text-small);
  line-height:1.55;
  background:var(--accent-tint);
  padding:var(--s4) var(--s5);
  border-radius:var(--r);
  overflow-x:auto;          /* a long line scrolls rather than breaking the page */
  margin:0 0 var(--block-gap);
}
pre code{background:none; padding:0; font-size:inherit}

/* ---------- tables ----------
   Two styles. See docs/document-style-guide.md for when to use each.
   A table carries space under it, so the paragraph after one is not cramped
   against the last row. */

table{width:100%;border-collapse:collapse;font-size:var(--text-body);margin:0 0 var(--s5)}  /* s5 not block-gap: the prose after a table crowded it at the smaller step */

/* 1. Naked ruled table, the default. No outer border, no header tint. */
thead th{
  font-family:var(--font-thead);
  font-weight:var(--w-display);
  font-size:var(--text-meta);
  color:var(--thead-color);
  text-align:left;
  padding:0 var(--s4) var(--s3) 0;
  border-bottom:var(--thead-rule);
}
td{padding:var(--s4) var(--s4) var(--s4) 0;border-bottom:var(--line);vertical-align:top}
td:last-child,th:last-child{padding-right:0}

/* 2. Bordered box table, tinted header, for dense reference tables
      (a scope-and-duration table, a pricing table). Add class "boxed". */
table.boxed{border:var(--line)}
table.boxed thead th{
  background:var(--surface-raised);
  border-bottom:var(--thead-rule-boxed);
  padding:var(--s3) var(--s4);
}
table.boxed td{padding:var(--s3) var(--s4);border-bottom:var(--line)}
table.boxed tr:last-child td{border-bottom:0}
table.boxed td:last-child,table.boxed th:last-child{padding-right:var(--s4)}

.scrollx{overflow-x:auto;-webkit-overflow-scrolling:touch}

/* 3. Data table, for columns of numbers. Add class "data" to either table
      above: every figure is set in tabular numerals, so digits are the same
      width and a column of them stacks. A cell or head holding a number takes
      class "num" and aligns right, so the decimals and dollar signs line up.
      A total goes in a tfoot row. .num works on its own in any table. */
table.data,.num{font-variant-numeric:tabular-nums}
:is(th,td).num{text-align:right}

/* The total row. Any table's tfoot gets it, class or not, because a total
   row reads the same wherever it is: display weight and a rule above that is
   heavier than the row rules, so it reads as the sum and not as one more
   row. The naked table takes the 2px divider, which wins over the hairline
   under the last body row where the two meet. */
tfoot td{font-weight:var(--w-display);border-top:var(--divider)}
tfoot tr:last-child td{border-bottom:0}
/* The boxed table's total takes the raised ground and a 1px ink rule; the
   boxed table already drops the hairline under its last body row. */
table.boxed tfoot td{background:var(--surface-raised);border-top:var(--line-ink)}

/* ---------- two-column prose ---------- */

.cols{display:grid;grid-template-columns:1fr 1fr;gap:var(--section-gap-narrow)}
.cols h4{margin-bottom:var(--s3)}

/* ---------- lists ----------
   A list with no class gets the house look, because rendered Markdown has no
   classes. A list that carries any class has opted out, which is how .tasks,
   .cal-events and .email-list keep their own shape. Every list, including
   one inside the insight panel, draws its marker at left:0 and starts its
   text at the same inset, so stacked lists line up to the pixel. */

/* Dot-bullet list. Pick one accent colour per list, don't mix cobalt and sage dots. */
ul:where(:not([class]), .dot){list-style:none;padding:0;margin:0 0 var(--block-gap)}
ul:where(:not([class]), .dot) > li{position:relative;padding-left:2.1em;   /* same inset as a numbered list, so text starts on one line when the two stack */margin-bottom:var(--s3);font-size:var(--text-body);line-height:1.5}
ul:where(:not([class]), .dot) > li::before{
  content:"";
  position:absolute;
  left:0;
  top:.6em;
  width:7px;      /* px: the dot's drawn size, fixed so it does not swell with the line */
  height:7px;     /* px: the dot's drawn size */
  border-radius:50%;
  background:var(--mark);
}
ul.dot--cobalt li::before{background:var(--accent)}

/* Numbered steps, optionally two columns for short lines. The numeral is
   drawn by a counter at a fixed inset rather than left to the browser's own
   marker, so every numbered list has the same gap between numeral and text
   as the accent version below. Ken asked for the two to match. */
ol:where(:not([class]), .steps){list-style:none;counter-reset:step;margin:0 0 var(--block-gap);padding-left:0}
ol:where(:not([class]), .steps) > li{counter-increment:step;position:relative;padding-left:2.1em;margin-bottom:var(--s3);font-size:var(--text-body);line-height:1.5;break-inside:avoid}
ol:where(:not([class]), .steps) > li::before{
  content:counter(step) ".";
  position:absolute; left:0; top:0;
  color:var(--on-surface);
}
ol.steps b{font-family:var(--font-display);font-weight:var(--w-display)}
/* A list that starts at a number other than one keeps the browser's own
   numerals, since a CSS counter cannot read the start attribute everywhere
   yet. The text inset stays the same, so it still lines up with its
   neighbours; only the numeral is drawn by the browser. */
ol:where(:not([class]), .steps)[start]{list-style:decimal;padding-left:2.1em}
ol:where(:not([class]), .steps)[start] > li{padding-left:0}
ol:where(:not([class]), .steps)[start] > li::before{content:none}
/* Where the browser can read the start attribute into the counter (Chromium
   can), the list keeps its drawn numeral on the shared line instead. */
@supports (counter-reset: step calc(attr(start type(<integer>), 1) - 1)){
  ol:where(:not([class]), .steps)[start]{list-style:none;padding-left:0;counter-reset:step calc(attr(start type(<integer>), 1) - 1)}
  ol:where(:not([class]), .steps)[start] > li{padding-left:2.1em}
  ol:where(:not([class]), .steps)[start] > li::before{content:counter(step) "."}
}

ol.steps--two-col{columns:2;column-gap:var(--section-gap-narrow)}

/* Checklist, for what is included rather than what to do in order. The
   check is drawn in the mark colour at the list's usual inset, so a
   checklist lines up with a dot list or a numbered list stacked beside it.
   Like the insight icon, it is a mask painted with a token, so a restyle can
   reach its colour. The stroke is 2, since the glyph is drawn smaller than
   an icon beside body text and a thinner line breaks up at that size. */
ul.checklist{list-style:none;padding:0;margin:0 0 var(--block-gap)}
ul.checklist > li{position:relative;padding-left:2.1em;margin-bottom:var(--s3);line-height:1.5}
ul.checklist > li::before{
  content:"";
  position:absolute;
  left:0;
  top:.2em;
  width:1.1em;
  height:1.1em;
  background-color:var(--mark);
  -webkit-mask:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='white' stroke-width='2.25' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 6 9 17l-5-5'/%3E%3C/svg%3E") center / contain no-repeat;
  mask:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='white' stroke-width='2.25' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 6 9 17l-5-5'/%3E%3C/svg%3E") center / contain no-repeat;
}

/* ---------- step sequence, boxed ----------
   An ol for a process whose steps each carry a name and a line of detail.
   Two layouts:
     .sequence          one ink border round the whole set, the steps side
                        by side with hairlines between them. Four steps or
                        fewer; it stacks under the facts grid's width.
     .sequence--rows    ruled rows, the number hanging at the list inset.
                        For more than four steps, or a step that needs more
                        than two lines.
   The number is drawn by a counter in the accent, the structural colour, so
   the markup is only the step's name and its line. The plain numbered list
   (ol.steps) stays: it is for a sequence of sentences, this is for a
   sequence of named stages. */
ol.sequence{
  list-style:none;
  counter-reset:seq;
  margin:0 0 var(--block-gap);
  padding:0;
  max-width:none;   /* a grid, not prose: it opts out of the reading measure like the facts grid */
  display:grid;
  grid-auto-flow:column;
  grid-auto-columns:minmax(0,1fr);
  border:var(--line-ink);
  border-radius:var(--r-lg);
  overflow:hidden;
}
ol.sequence > li{counter-increment:seq;padding:var(--s4) var(--s5) var(--s5);line-height:1.5}
ol.sequence > li + li{border-left:var(--line)}
ol.sequence > li::before{
  content:counter(seq);
  display:block;
  margin-bottom:var(--s3);
  font-family:var(--font-number);
  font-weight:var(--w-display);
  font-size:var(--text-small);
  font-variant-numeric:tabular-nums;
  color:var(--accent);
}
ol.sequence h4{margin-bottom:var(--s1)}
ol.sequence p{margin:0;font-size:var(--text-small);color:var(--on-surface-soft)}

ol.sequence--rows{display:block;border:0;border-radius:0;overflow:visible}
ol.sequence--rows > li{
  display:grid;
  grid-template-columns:2.1em minmax(0,1fr);   /* the numeral column is the list inset every list shares */
  padding:var(--s4) 0;
  border-top:var(--line);
}
ol.sequence--rows > li + li{border-left:0}
ol.sequence--rows > li:last-child{border-bottom:var(--line)}
ol.sequence--rows > li::before{margin:0;font-size:var(--text-body);line-height:var(--lh-heading)}

/* ---------- eyebrow label ----------
   A short faint label above a heading: "Quarterly review", "Option B",
   "Section 2". It carries the heading's top room and the heading after it
   drops its own, so the pair sits where the heading alone would have. No
   rule and no box under it: a stub rule under a label is the device that
   keeps failing. */
.eyebrow{
  margin:var(--section-gap-narrow) 0 var(--s2);
  font-family:var(--font-display);
  font-weight:var(--w-display);
  font-size:var(--text-meta);
  line-height:1.3;
  color:var(--on-surface-faint);
}
.eyebrow:first-child{margin-top:0}
.eyebrow + :is(h1,h2,h3,h4,h5,h6){margin-top:0}

/* ---------- badges ----------
   A small square tag for a status or a category: Open, Done, Draft. Square
   corners in every case; a rounded tag reads as a pill button. Five fills,
   one per badge:
     .badge              ink, the loudest
     .badge--outline     an ink outline on the page ground
     .badge--cobalt      accent on its tint, 5.17:1
     .badge--purple      emphasis on its tint, 10.17:1
     .badge--sage        ink on the sage tint. The sage itself measures
                         4.05:1 on its tint, under the floor at this size,
                         so the word is ink and the dot carries the sage.
   A badge may lead with a status dot (.badge-dot) or a Lucide icon. The
   border is always drawn, transparent where there is none, so every badge
   is the same height. */
.badge{
  display:inline-flex;
  align-items:center;
  gap:var(--s2);
  padding:var(--s1) var(--s2);
  border:1px solid var(--structure);
  border-radius:0;
  background:var(--structure);
  color:var(--on-structure);
  font-family:var(--font-display);
  font-weight:var(--w-display);
  font-size:var(--text-micro);
  line-height:1.4;
  vertical-align:middle;
  white-space:nowrap;
}
.badge--outline{background:var(--surface);color:var(--on-surface)}
.badge--cobalt{background:var(--accent-tint);border-color:transparent;color:var(--accent)}
.badge--purple{background:var(--emphasis-tint);border-color:transparent;color:var(--emphasis)}
.badge--sage{background:var(--tint);border-color:transparent;color:var(--on-surface)}
.badge .icon,.badge svg{width:1.15em;height:1.15em;vertical-align:0}
.badge-dot{
  width:7px;      /* px: the dot's drawn size, the same as a list's dot */
  height:7px;     /* px: the dot's drawn size */
  border-radius:50%;
  flex:none;
  background:var(--mark);
}
.badge:not([class*="badge--"]) .badge-dot{background:currentColor}   /* the ink badge: a sage dot on ink is under the mark floor */
/* A row of badges. */
.badges{display:flex;flex-wrap:wrap;align-items:center;gap:var(--s3);margin:0 0 var(--block-gap)}

/* ---------- stat tiles ----------
   The number-first sibling of the facts grid, which is words-first. Each tile
   is a faint label, a large number in tabular numerals, and one meta line.
   Three looks:
     .stat            a hairline border
     .stat--tint      the default quiet tint instead of the border. A tint
                      is the alternative to a border, never added to it.
     .stat--large     the one number a section is about. It runs the width
                      of its row, with the number on the left and the label
                      and meta beside it.
   No coloured top edge on any of them: that device is what makes a tile read
   as a template. The row fits as many tiles as it holds, up to four across
   in the column, and two across on a phone. */
.stats{
  display:grid;
  grid-template-columns:repeat(auto-fit,minmax(9rem,1fr));
  gap:var(--block-gap);
  margin:0 0 var(--block-gap);
}
.stat{
  border:var(--line);
  border-radius:var(--r-lg);
  padding:var(--s4) var(--s4) var(--s5);
  min-width:0;
}
.stat--tint{background:var(--tint);border-color:transparent}
.stat p{margin:0;max-width:none}
.stat-label{font-size:var(--text-meta);line-height:1.3;color:var(--on-surface-faint)}
.stat .stat-label{margin-bottom:var(--s3)}
.stat-value{
  font-family:var(--font-display);
  font-weight:var(--w-display);
  font-size:var(--text-stat);
  line-height:1;
  letter-spacing:-.02em;
  font-variant-numeric:tabular-nums;
}
.stat .stat-value{margin-bottom:var(--s2)}
.stat-meta{font-size:var(--text-meta);line-height:1.35;color:var(--on-surface-soft)}

.stat--large{
  display:grid;
  grid-template-columns:auto minmax(0,1fr);
  grid-template-areas:"value label" "value meta";
  column-gap:var(--gutter);
  align-items:end;
  padding:var(--gutter) var(--s6);
  margin:0 0 var(--block-gap);
}
.stat--large .stat-label{grid-area:label;align-self:end;margin-bottom:var(--s1);font-size:var(--text-small)}
.stat--large .stat-value{grid-area:value;font-size:var(--text-stat-large);margin:0}
.stat--large .stat-meta{grid-area:meta;align-self:start;font-size:var(--text-small)}

/* ---------- pull quote ----------
   One line of the display face, lifted out of the body. Two looks: plain, or
   ruled above and below with a full-width ink line. Never quotation marks,
   never a coloured side bar; the base blockquote keeps its hairline side
   rule, and this is not that. The line is capped at half the reading
   measure, so it breaks into short lines rather than one long one. */
blockquote.pullquote{
  margin:var(--section-gap-narrow) 0;
  padding:0;
  border:0;
  max-width:none;
  color:var(--on-surface);
}
blockquote.pullquote p{
  max-width:calc(var(--read) / 2);
  margin:0 0 var(--s4);
  font-family:var(--font-display);
  font-weight:var(--w-display);
  font-size:var(--text-quote);
  line-height:1.24;
  letter-spacing:-.012em;
  overflow-wrap:normal;
}
blockquote.pullquote footer{font-size:var(--text-small);line-height:1.5;color:var(--on-surface-soft)}
blockquote.pullquote.pullquote--ruled{border-block:var(--line-ink);padding-block:var(--s5)}

/* ---------- figure with a caption plate ----------
   An image or chart printed on a plate: a hairline frame, the picture with
   room round it, and the caption on its own strip under a hairline, led by a
   bold figure number. Two plates:
     figure.plate          white, the default
     figure.plate--tint    the raised ground behind the picture; the caption
                           strip stays on the page ground
   The plain figure (no class) stays as it is: no frame at all. */
figure.plate{
  padding:0;
  border:var(--line);
  border-radius:var(--r-lg);
  background:var(--surface);
  overflow:hidden;
}
figure.plate > :is(img,svg,picture){
  display:block;
  width:100%;
  height:auto;
  padding:var(--s5) var(--s5) var(--s4);
}
figure.plate--tint > :is(img,svg,picture){background:var(--surface-raised)}
figure.plate figcaption{
  margin:0;
  padding:var(--s3) var(--s5);
  border-top:var(--line);
  font-size:var(--text-small);
  color:var(--on-surface-soft);
}
figure.plate figcaption b{font-family:var(--font-display);font-weight:var(--w-display);color:var(--on-surface)}

/* ---------- option cards ----------
   A grid of cards for a page that asks the reader to pick. Each card holds a
   short label (an eyebrow or a badge), a name, a line or two, and, if it
   helps, a short list. The grid fits as many cards as the column holds and
   stacks on a phone. A recommended option says so with a badge, not with a
   coloured edge. */
.options{
  display:grid;
  grid-template-columns:repeat(auto-fit,minmax(15rem,1fr));
  gap:var(--block-gap);
  margin:0 0 var(--block-gap);
}
.option{
  border:var(--line);
  border-radius:var(--r-lg);
  padding:var(--s5);
  min-width:0;
}
.option > :first-child{margin-top:0}
.option > :last-child{margin-bottom:0}
.option h4{margin-bottom:var(--s2)}
.option .badge{margin-bottom:var(--s3)}
.option p:not(.eyebrow){color:var(--on-surface-soft)}
.option :is(ul,ol) > li{margin-bottom:var(--s2)}

/* ---------- images ----------
   Five ways to place a picture beyond the plain one in the column. Every one
   draws the same frame (--image-frame, a hairline in the house) so a
   screenshot of a white page does not melt into the white page. */

/* Image beside text: a picture and a short block of text side by side, the
   picture taking two fifths. .media--right puts the picture on the right.
   Under the facts grid's width it stacks, picture first either way. */
.media{
  display:grid;
  grid-template-columns:minmax(0,2fr) minmax(0,3fr);
  gap:var(--gutter);
  align-items:start;
  margin:0 0 var(--gutter);
}
.media > img,.media > .peek-pair{border:var(--image-frame);border-radius:var(--image-radius)}
.media > img{display:block;width:100%;height:auto}
.media--right{grid-template-columns:minmax(0,3fr) minmax(0,2fr)}
.media--right > :is(img,.peek-pair){order:2}
.media-body h4{margin-bottom:var(--s2)}

/* Image cards: a picture on top, then a name and a line. Two across by
   default, .image-cards--3 for three. The picture is cropped to one shape so
   a row lines up, anchored at the top, where a screenshot's title is. */
.image-cards{
  display:grid;
  grid-template-columns:repeat(2,minmax(0,1fr));
  gap:var(--block-gap);
  margin:0 0 var(--block-gap);
}
.image-cards--3{grid-template-columns:repeat(3,minmax(0,1fr))}
.image-card{border:var(--image-frame);border-radius:var(--r-lg);overflow:hidden;min-width:0}
.image-card > img{
  display:block;
  width:100%;
  aspect-ratio:16 / 10;
  object-fit:cover;
  object-position:top;
  border-bottom:var(--image-frame);
}
.image-card-body{padding:var(--s4) var(--s5) var(--s5)}
.image-card-body h4{margin-bottom:var(--s1)}
.image-card-body p{margin:0;font-size:var(--text-small);color:var(--on-surface-soft)}

/* Gallery: a grid of figures, each with one caption line. Two-up by default,
   .gallery--3 for three-up. It holds figures, not cards, so there is no box
   round each one, only the picture's frame. Three-up drops to two under the
   facts grid's width; two-up stays two, since a gallery is thumbnails. */
.gallery{
  display:grid;
  grid-template-columns:repeat(2,minmax(0,1fr));
  gap:var(--block-gap);
  margin:0 0 var(--block-gap);
}
.gallery--3{grid-template-columns:repeat(3,minmax(0,1fr))}
.gallery figure{margin:0;min-width:0}
.gallery img{
  display:block;
  width:100%;
  aspect-ratio:4 / 3;
  object-fit:cover;
  object-position:top;
  border:var(--image-frame);
  border-radius:var(--image-radius);
}

/* Full-width image: a picture that runs to the page edge, for a hero shot or
   a wide chart. It works the way a band does: a figure.bleed is a direct
   child of the body, the column rule at the top of this file lets it run
   edge to edge, and its caption comes back into the column. A picture taller
   than most of the screen is cropped from the top. */
figure.bleed{margin:0;padding:0;border:0;background:none}
.bleed > :is(img,picture,svg,video){
  display:block;
  width:100%;
  height:auto;
  max-height:70vh;
  object-fit:cover;
  object-position:top;
  border-block:var(--image-frame);
}
.bleed > figcaption{margin-top:var(--s2)}

/* Peek pair: a main picture filling a frame, with a second one inset at an
   angle, peeking in from the lower right. For showing two views of one thing
   (a page and its table). The pair fills the width it is given and keeps one
   shape, so put it in a grid cell, a .media block or an image card rather
   than across the whole column. The inset carries an ink frame so it reads as
   a second sheet laid on the first. */
.peek-pair{
  position:relative;
  display:block;
  aspect-ratio:16 / 11;
  overflow:hidden;
  background:var(--surface-raised);
  border:var(--image-frame);
  border-radius:var(--image-radius);
}
.peek-pair > img{position:absolute;display:block;height:auto}
.peek-pair > img:first-child{inset:0;width:100%;height:100%;object-fit:cover;object-position:top}
.peek-pair > img + img{
  width:60%;
  right:-7%;
  bottom:-16%;
  transform:rotate(4deg);
  border:var(--line-ink);
}

/* ---------- panel: a tint holding a short aside (one to three sentences) ---------- */

/*
  Tinted panel. Three colourways, all carrying ink at about 14.3:1 and ink-soft
  at about 6.6:1, so the choice is tone rather than contrast:
    sage    the default, quiet, for a caveat or an aside
    cobalt  for something structural, a definition or a scope note
    purple  for the one thing on the page worth pausing on
  One tint per page. Two tinted panels in different colours read as decoration.
*/
.panel{background:var(--tint);padding:var(--gutter);border-radius:var(--r)}
/* The modifier names still say the house hues. They paint through roles, so a
   style never needs to touch them; a follow-up can rename them to the roles. */
.panel--cobalt{background:var(--accent-tint)}
.panel--purple{background:var(--emphasis-tint)}
/*
  The error panel. The one panel that carries the danger red, and only for a
  problem: something failed, is missing, or did not save. Same shape as the
  other three (tint, padding, corner), plus the full 1px border every status
  notice carries, so red never relies on hue alone. The bold lead is the
  label and takes the red; the explanation after it stays ink.
    danger label on its tint   6.26:1
    ink on the danger tint    14.54:1
  It sits outside the one-tint-per-page budget, like every status colour.
*/
.panel--danger{background:var(--danger-tint);border:1px solid var(--danger)}
.panel--danger b{color:var(--danger)}
.panel p:last-child{margin-bottom:0}

/* ---------- insight panel: a tinted panel with a generated label row ---------- */

/*
  A tint carrying a label row (icon plus label) and then the content: a bold
  lead line, and under it either a short numbered list or another sentence or
  two. The label and the icon are generated by CSS, so the markup holds only
  the content.

  Two variants, and two is the limit:
    .insight            cobalt tint, label "Key insight", for the point a
                        reader should carry out of the section
    .insight--caveat    purple tint, label "Caveat", for the limit or the
                        objection attached to what was just said

  Contrast, measured. The label is --text-meta at display weight, under the
  WCAG large-text threshold, so it has to clear 4.5:1 on its own tint:
    cobalt label on cobalt-tint    5.17:1
    purple label on purple-tint   10.17:1
    sage label on sage-tint        4.05:1   fails, so there is no sage variant
  Body text inside is ink: 14.39:1 on cobalt tint, 14.30:1 on purple tint.

  Never give this panel a single-side coloured border. The tint is the device.
*/
.insight{
  position:relative;          /* the icon below is placed against this box */
  margin:var(--gutter) 0;
  padding:var(--gutter);
  border-radius:var(--r);
  max-width:var(--read);
  background:var(--accent-tint);
  font-size:var(--text-body);
  line-height:1.6;
}
.insight--caveat{background:var(--emphasis-tint)}

.insight::before{
  display:block;
  font-family:var(--font-display);
  font-weight:var(--w-display);
  font-size:var(--text-meta);
  margin-bottom:var(--s2);
  padding-left:22px;    /* px: the 16px icon plus its gap, so the label clears it */
  min-height:18px;      /* px: the icon's box, so a one-line label never clips it */
  content:"Key insight";
  color:var(--accent);
}
.insight--caveat::before{
  content:"Caveat";
  color:var(--emphasis);
}

/*
  The icon is a mask, not a background image. A data-URI background has the
  stroke colour written into it as a hex, which puts a colour outside the token
  file and means a restyle cannot reach it. A mask paints the pseudo-element's
  own background-color through the glyph, so the colour is the token and the
  SVG carries only the shape. It sits on ::after rather than ::before because a
  mask clips everything the element paints, and ::before is the label text.
*/
.insight::after{
  content:"";
  position:absolute;
  left:var(--gutter);
  top:calc(var(--gutter) + 3.2px);   /* px: half the label's 22.4px line box less half the 16px icon, which is where background-position:center put it */
  width:16px;                        /* px: the icon's drawn size */
  height:16px;                       /* px: the icon's drawn size */
  background-color:var(--accent);
  -webkit-mask-repeat:no-repeat;
  mask-repeat:no-repeat;
  -webkit-mask-size:contain;
  mask-size:contain;
  -webkit-mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='white' stroke-width='1.75' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M9 18h6'/%3E%3Cpath d='M10 22h4'/%3E%3Cpath d='M15.09 14c.18-.98.65-1.74 1.41-2.5A4.65 4.65 0 0 0 18 8 6 6 0 0 0 6 8c0 1 .23 2.23 1.5 3.5A4.61 4.61 0 0 1 8.91 14'/%3E%3C/svg%3E");
  mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='white' stroke-width='1.75' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M9 18h6'/%3E%3Cpath d='M10 22h4'/%3E%3Cpath d='M15.09 14c.18-.98.65-1.74 1.41-2.5A4.65 4.65 0 0 0 18 8 6 6 0 0 0 6 8c0 1 .23 2.23 1.5 3.5A4.61 4.61 0 0 1 8.91 14'/%3E%3C/svg%3E");
}
.insight--caveat::after{
  background-color:var(--emphasis);
  -webkit-mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='white' stroke-width='1.75' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3Z'/%3E%3Cpath d='M12 9v4'/%3E%3Cpath d='M12 17h.01'/%3E%3C/svg%3E");
  mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='white' stroke-width='1.75' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3Z'/%3E%3Cpath d='M12 9v4'/%3E%3Cpath d='M12 17h.01'/%3E%3C/svg%3E");
}
/*
  Override the label text with data-label when "Key insight" or "Caveat" is
  wrong for the content. The icon and the colour stay with the variant.
  Keep the replacement to two or three words; it is a label, not a heading.
*/
.insight[data-label]::before{content:attr(data-label)}

/* Lists inside the panel use the same inset and drawn markers as every other
   list, so text lines up across the page; only the marker takes the panel's
   colour. */
.insight li{margin:0 0 var(--s2)}
.insight ol > li::before{color:var(--accent)}
.insight--caveat ol > li::before{color:var(--emphasis)}
.insight ul > li::before{background:var(--accent)}
.insight--caveat ul > li::before{background:var(--emphasis)}
.insight > :first-child{margin-top:0}
.insight > :last-child{margin-bottom:0}

/* ---------- callout: a filled, saturated block holding one short line ---------- */

/*
  Four fills. White text on each, with measured contrast:
    ink 16.68:1, purple 11.87:1, cobalt 5.99:1, sage 4.67:1.
  Sage is the tightest and passes only because callout text is short. Do not
  put a long paragraph on sage, and never drop callout text below body size.
  One callout per page. It is the loudest small element available.
*/
.callout{background:var(--structure);color:var(--on-structure);padding:var(--s4) var(--gutter);border-radius:var(--r)}
/* Hue-named modifiers painting through roles; a follow-up can rename them.
   The third fill names its own text colour, because a style's third fill may
   be light enough that it carries ink rather than white. */
.callout--cobalt{background:var(--accent);color:var(--on-accent)}
.callout--purple{background:var(--emphasis);color:var(--on-emphasis)}
.callout--sage{background:var(--fill);color:var(--on-fill)}
.callout p{color:inherit;margin:0}

/* ---------- icons ---------- */
/*
  Any icon set works: Lucide, Font Awesome, Hero Icons. The rules are about
  size, stroke and colour, not about which library. Lucide is the default
  because the web surface already uses it.

  Stroke weight tracks the type it sits beside. 1.75 next to body text,
  2 next to display weights. An icon that is purely decorative gets
  aria-hidden="true". An icon carrying meaning gets a label.
*/
.icon,[data-lucide],svg.lucide{
  width:1.15em; height:1.15em;
  stroke-width:1.75;
  flex:none;
  vertical-align:-.16em;
}

/* Inline icon leading a line of text. */
.icon-line{display:flex; gap:var(--s3); align-items:flex-start}
.icon-line .icon,.icon-line svg{margin-top:.15em; color:var(--on-surface)}

/*
  Icon in a filled circle. The second way to get colour onto a page, and the
  quieter one, since a circle is small.
  Contrast of white on each fill, all above the 4.5 floor:
    ink 16.68:1, purple 11.87:1, cobalt 5.99:1, sage 4.67:1.
  Sage is the tightest. Do not put white on a sage circle smaller than 32px.
*/
.icon-circle{
  width:44px;      /* px: the circle's drawn size, also the tap-target floor */
  height:44px;     /* px: the circle's drawn size */
  border-radius:50%;
  display:grid; place-items:center; flex:none;
  background:var(--structure); color:var(--on-structure);
}
.icon-circle .icon,.icon-circle svg{width:20px; height:20px; vertical-align:0}   /* px: the glyph inside a 44px circle */
/* Hue-named modifiers painting through roles, as with .callout above. */
.icon-circle--cobalt{background:var(--accent);color:var(--on-accent)}
.icon-circle--purple{background:var(--emphasis);color:var(--on-emphasis)}
.icon-circle--sage{background:var(--fill);color:var(--on-fill)}

/*
  The icon reference. Twelve Lucide icons cover what documents need: check,
  arrow-right, file-text, calendar, users, mail, search, terminal,
  git-branch, book-open, clock, triangle-alert. A new one is added to this
  list, and to the skeleton's reference section, before it is used.

  Stroke follows type weight. 1.75 is the default above, for an icon beside
  body text. Beside display type (a heading, a badge, an eyebrow) the letters
  are heavier, so the stroke steps up to 2 to match.

  Four colours, and an icon takes one of them: ink (the default, inherited
  from the text), the accent for structure, the emphasis for the one thing to
  act on, and the mark for status. */
:is(h1,h2,h3,h4,h5,h6,.badge,.eyebrow) :is(.icon,[data-lucide],svg.lucide){stroke-width:2}
/* :is() lifts these above the .icon-line colour, so a colour class wins
   wherever the icon sits. */
:is(.icon,svg,i).icon--cobalt{color:var(--accent)}
:is(.icon,svg,i).icon--purple{color:var(--emphasis)}
:is(.icon,svg,i).icon--sage{color:var(--mark)}
/* The reference grid in the skeleton: each icon at its drawn size over its
   name. */
.icon-set{
  display:grid;
  grid-template-columns:repeat(6,minmax(0,1fr));
  gap:var(--block-gap);
  list-style:none;
  margin:0 0 var(--block-gap);
  padding:0;
  max-width:none;   /* a grid, not prose */
}
.icon-set li{display:flex;overflow-wrap:anywhere;flex-direction:column;align-items:center;gap:var(--s2);text-align:center;font-size:var(--text-meta);line-height:1.3;color:var(--on-surface-faint)}
.icon-set li > :is(.icon,[data-lucide],svg):not([class*="icon--"]){color:var(--on-surface)}
.icon-set code{font-size:var(--text-micro)}
.icon-set :is(.icon,[data-lucide],svg){width:24px;height:24px}   /* px: Lucide's drawn size, one-to-one with its 24-unit grid */

/* A row of icon-circle plus text, for a short list of capabilities or steps. */
.icon-row{display:flex; gap:var(--s4); align-items:flex-start; margin-bottom:var(--gutter)}
.icon-row h4{margin-bottom:var(--s2)}
.icon-row p{margin:0; color:var(--on-surface-soft)}

/* ---------- numbered list, optional coloured numerals ---------- */
/*
  Plain steps leave the numerals in ink. Add .steps--accent to colour them,
  which matches the sage dots on a dot list. Use one or the other in a
  document, not both, or the page starts to look decorated.
*/
ol.steps--accent > li::before{
  font-family:var(--font-display); font-weight:var(--w-display);
  color:var(--mark);
}

/* ---------- folded section ----------
   A native <details>, closed by default. The summary row is the section's
   head, styled the same as a numbered section's: the hanging rule, an h2 at
   full heading size, the section number on the right. A chevron sits on the
   left of the heading, where a disclosure control conventionally lives, and
   turns to point down when the section is open. No text label: "Show" and
   "Hide" beside the heading made the row messy.

   It owns only its top spacing, not the bottom, so a closed section takes no
   more room than its head. The bottom gap lives on .fold-body, which a closed
   <details> does not render at all. */

details.fold{padding-block-start:var(--section-gap)}

details.fold summary.fold-head{
  display:flex;
  align-items:baseline;
  justify-content:space-between;
  gap:var(--s4);
  flex-wrap:wrap;
  min-height:44px;              /* px: the tap-target floor, since the whole row is the control */
  border-top:var(--divider);
  padding-top:var(--s3);
  cursor:pointer;
  list-style:none;
}
details.fold summary.fold-head::-webkit-details-marker{display:none}
details.fold summary.fold-head::marker{content:""}
details.fold summary.fold-head h2{flex:1 1 auto}
details.fold summary.fold-head .n{
  font-family:var(--font-number);
  font-weight:var(--w-display);
  font-size:var(--text-small);
  color:var(--number-color);
  flex:none;
}
details.fold summary.fold-head .fold-arrow{
  flex:none;
  align-self:center;
  width:10px;     /* px: the chevron is drawn from two borders, so its size is geometry */
  height:10px;    /* px: the chevron's drawn size */
  margin-right:var(--s1);
  border-right:2px solid var(--on-surface-faint);
  border-bottom:2px solid var(--on-surface-faint);
  transform:rotate(-45deg);      /* closed: points right */
  transition:transform .15s ease;
}
details.fold[open] summary.fold-head .fold-arrow{transform:rotate(45deg)}   /* open: points down */
details.fold .fold-body{padding-top:var(--section-gap-narrow);padding-bottom:var(--section-gap)}

/* ---------- check-in block ----------
   A timestamped, unnumbered section. On the day page the newest one renders
   open and older ones fold below it using the folded section above. */

.checkin{padding-block:var(--section-gap-narrow)}
.checkin .checkin-head{
  border-top:var(--divider);
  padding-top:var(--s3);
  margin-bottom:var(--gutter);
}
.checkin .checkin-head .time{
  display:block;
  font-size:var(--text-meta);
  line-height:1.5;
  color:var(--on-surface-faint);
  margin-top:var(--s2);
}

/* ---------- calendar grids ----------
   Week view: seven columns, today first. Month view: weeks as rows, held
   inside .scrollx so a narrow screen scrolls the grid rather than the page.
   No drop shadow anywhere in this block; today is marked with a heavier rule
   and a filled day-number label. */

.cal-week{
  display:grid;
  grid-template-columns:repeat(7,1fr);
  gap:var(--s4);
}
.cal-day{
  border-top:var(--line);
  padding-top:var(--s3);
}
.cal-day--today{border-top:var(--divider)}

.cal-day-head{
  display:flex;
  align-items:baseline;
  justify-content:space-between;
  gap:var(--s2);
  margin-bottom:var(--s3);
}
.cal-wd{
  font-family:var(--font-display);
  font-weight:var(--w-display);
  font-size:var(--text-meta);
  color:var(--on-surface-faint);
}
.cal-dn{
  font-family:var(--font-display);
  font-weight:var(--w-display);
  font-size:var(--text-body);
  color:var(--on-surface);
}
.cal-day--today .cal-dn{
  display:inline-flex;
  align-items:center;
  justify-content:center;
  min-width:22px;    /* px: the pill around a two-digit day number */
  height:22px;       /* px: the pill's drawn height */
  padding-inline:var(--s1);
  border-radius:var(--r-pill);
  background:var(--structure);
  color:var(--surface);
}

.cal-events{list-style:none;margin:0;padding:0}
.cal-event{
  display:flex;
  flex-direction:column;
  gap:1px;            /* px: the time and the title are one unit, a hair apart, not two lines */
  margin-bottom:var(--s3);
  font-size:var(--text-meta);
  line-height:1.4;
}
.cal-event:last-child{margin-bottom:0}
.cal-time{
  font-family:var(--font-display);
  font-weight:var(--w-display);
  font-size:var(--text-micro);
  color:var(--on-surface-faint);
}
.cal-event--allday .cal-time{color:var(--mark)}
.cal-title{color:var(--on-surface)}
.cal-account{font-size:var(--text-micro);color:var(--on-surface-faint)}

.cal-open{
  margin:0;
  font-size:var(--text-meta);
  color:var(--on-surface-faint);
}

.cal-month{min-width:560px}   /* px: seven readable columns; under this the grid scrolls instead of crushing */
.cal-month-weekdays{
  display:grid;
  grid-template-columns:repeat(7,1fr);
  gap:var(--s2);
  margin-bottom:var(--s2);
}
.cal-month-weekdays span{
  font-family:var(--font-display);
  font-weight:var(--w-display);
  font-size:var(--text-meta);
  color:var(--on-surface-faint);
}
.cal-month-grid{
  display:grid;
  grid-template-columns:repeat(7,1fr);
  gap:var(--s2);
}
.cal-month-cell{
  min-height:84px;    /* px: a cell holds three event lines before it grows */
  border-top:var(--line);
  padding-top:var(--s2);
}
.cal-month-cell--today{border-top:var(--divider)}
.cal-month-cell--outside{opacity:.4}
.cal-month-cell .cal-dn{
  display:block;
  font-size:var(--text-meta);
  margin-bottom:var(--s1);
}
.cal-month-cell--today .cal-dn{
  display:inline-flex;
  align-items:center;
  justify-content:center;
  min-width:20px;    /* px: the pill around a day number in the tighter month cell */
  height:20px;       /* px: the pill's drawn height */
  padding-inline:var(--s1);
  border-radius:var(--r-pill);
  background:var(--structure);
  color:var(--surface);
}
.cal-month-events{list-style:none;margin:0;padding:0}
.cal-month-events li{
  font-size:var(--text-micro);
  line-height:1.4;
  color:var(--on-surface-soft);
  margin-bottom:2px;    /* px: event lines in a month cell sit almost touching, by design */
  overflow-wrap:anywhere;
}

/* ---------- bands: full-bleed, one per document at most ---------- */

.band{background:var(--structure);color:var(--on-structure);margin-top:var(--section-gap)}
.band > *{padding-block:var(--section-gap)}    /* the band's inner element carries the vertical room; the column comes from the page rule */
.band h2{color:var(--on-structure)}   /* no margin of its own: a band head is a .sheet-head like any other, and a bare h2 takes the base margins */
.band p,.band li{color:var(--on-structure)}          /* full white on a dark band, never a soft grey, contrast holds this way */
.band .sheet-head{border-top-color:var(--on-structure)}
.band .sheet-head .n{color:var(--on-structure-faint)}

/*
  Band colour variants. Ink is the default and the most permissive.
  Measured contrast decides what text each one may carry:

    on ink     white 16.68, soft-ondark 11.59, faint-ondark 7.70, sage-fill 7.38
    on purple  white 11.87, soft-ondark  8.24, faint-ondark 5.48, sage-fill 5.25
    on cobalt  white  5.99, soft-ondark  4.16, faint-ondark 2.76, sage-fill 2.65

  So cobalt is the most constrained despite looking like the safe choice:
  white text only. No grey meta, no sage marks. Purple carries everything ink
  does. Pick the band colour for the document, then obey its row above.
*/
/* Hue-named modifiers painting through roles; a follow-up can rename them. */
.band--cobalt{background:var(--accent)}
.band--cobalt,.band--cobalt :is(h2,p,li){color:var(--on-accent)}
.band--cobalt .sheet-head .n{color:var(--on-structure); opacity:.72}   /* grey fails here, dim white instead */
.band--purple{background:var(--emphasis)}
.band--purple,.band--purple :is(h2,p,li){color:var(--on-emphasis)}
.band--purple .sheet-head .n{color:var(--on-structure-faint)}
.band--cobalt .icon-circle,.band--purple .icon-circle,.band .icon-circle{background:var(--on-structure);color:var(--on-surface)}

/* ---------- footer ----------
   The page footer only. A <footer> inside a card or a component is that
   component's business and keeps its own look. */

body > footer{
  border-top:var(--line);
  margin-top:var(--section-gap);
  padding-block:var(--gutter) var(--section-gap);
  font-size:var(--text-meta);
  color:var(--on-surface-faint);
}
body > footer a{color:var(--on-surface)}

/* ---------- responsive ---------- */

@media (max-width:820px){
  .facts,.cols{grid-template-columns:1fr;gap:var(--gutter)}
  ol.steps--two-col{columns:1}
  section.sheet{padding-block:var(--section-gap-narrow)}

  .cal-week{display:block}
  .cal-day{padding-top:var(--s3);padding-bottom:var(--s3)}
  .cal-day-head{margin-bottom:var(--s2)}

  /* The boxed sequence stacks, hairlines between the steps instead of beside. */
  ol.sequence{grid-auto-flow:row}
  ol.sequence > li + li{border-left:0;border-top:var(--line)}
  ol.sequence--rows > li + li{border-top:var(--line)}

  /* Image beside text stacks, picture first whichever side it sat on. */
  .media,.media--right{grid-template-columns:minmax(0,1fr)}
  .media--right > :is(img,.peek-pair){order:0}
  .image-cards,.image-cards--3{grid-template-columns:minmax(0,1fr)}
  .gallery--3{grid-template-columns:repeat(2,minmax(0,1fr))}
  .icon-set{grid-template-columns:repeat(3,minmax(0,1fr))}

  /* The large stat stacks: label, number, meta, the way a small tile reads. */
  .stat--large{grid-template-columns:minmax(0,1fr);grid-template-areas:"label" "value" "meta";padding:var(--gutter)}
  .stat--large .stat-value{margin-bottom:var(--s2)}
}

@media (prefers-reduced-motion:reduce){
  *{transition:none!important;animation:none!important;scroll-behavior:auto!important}
  details.fold summary.fold-head .fold-arrow{transition:none}
}

@media print{
  .band{-webkit-print-color-adjust:exact;print-color-adjust:exact}
  .callout{-webkit-print-color-adjust:exact;print-color-adjust:exact}
  .insight{-webkit-print-color-adjust:exact;print-color-adjust:exact}
  /*
    Keep-together belongs on a section's head and on the small blocks, not on
    the section. A section longer than a page with break-inside:avoid starts on
    a fresh page and leaves the previous one mostly empty, which made most
    exports worse to help a few.
  */
  .sheet-head{break-after:avoid}
  table,.panel,.insight,.callout{break-inside:avoid}
  .badge,.stat,.stat--tint,.panel--danger{-webkit-print-color-adjust:exact;print-color-adjust:exact}
  .stat,ol.sequence,figure.plate,.option,.image-card,.media,.peek-pair,blockquote.pullquote{break-inside:avoid}
}


/* =========================================================================
   OPTIONAL BRAND SECTION, St. Clair AI documents only.

   Include this markup and the classes below ONLY when the document itself
   is a St. Clair AI deliverable (a client-facing work product, or a page
   that will live on the St. Clair AI site or its sales materials). Every
   other document, briefs, research reports, personal planning docs,
   proposals for other names, omits this section entirely. See
   docs/document-style-guide.md, "The brand layer."

   Mark source: projects/agent_storefront/brand/logo/ (mark.svg or lockup.svg).
   ========================================================================= */

/*
  The logo is a FILE, never rebuilt. Inline lockup.svg on white or
  lockup_on_ink.svg on a dark ground, both from
  projects/agent_storefront/brand/logo/. PNGs at every size and colorway are in
  png/ beside them, browsable via DELIVERY.html.

  Never set the mark beside live wordmark text, and never redraw either. The
  lockup file already carries the correct proportions: mark height equal to the
  wordmark cap height, baseline aligned, correct gap. Hand-assembling it gets
  those wrong, which is why the file exists.

  Full rules, including the Do Not list, are in
  projects/agent_storefront/brand/BRAND_KIT.md.
*/
.mark{display:flex; align-items:center}
/*
  Lockup height is not chosen by eye. BRAND_KIT.md: the lockup's height is
  0.9288 em of the wordmark font size it replaces, which puts the letters at the
  same cap height they had as live text. The masthead wordmark was 19px, so
  0.9288 x 19 = 17.6px. If a surface uses a different wordmark size, recompute
  rather than guessing; too tall and the logo fights the document title.
*/
.mark svg{height:17.6px; width:auto; display:block}   /* px: 0.9288 em of the 19px wordmark it replaces, see above */
