/* The shared design system: components and the token plumbing.
 *
 * No colour is defined here. Colours come from a **theme bundle**
 * (assets/stylesheets/themes.css, generated from themes/*.yaml), and a book's
 * subject tint arrives as --tb-book-* values that the bundle composes in. This
 * file owns everything that is not a theme: the mapping onto Material's
 * variables, the figure and booklet components, and the house typography.
 *
 * See SHAPE.md, "Theme bundles".
 */

:root {
  /* Scheme-independent, and not part of any bundle unless a bundle overrides it. */
  --tb-measure: 70ch;
  --tb-radius: 8px;
  --tb-font-body: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  --tb-font-display: "Iowan Old Style", Charter, Georgia, "Times New Roman", serif;
  --tb-font-mono: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
}

/* A book tints its diagrams by setting its accent, unless it sets its own. */
[data-md-color-scheme] {
  --tb-fig-accent: var(--tb-accent);
}

/* Tell the browser which way round the native widgets are, so a `<select>`, a
 * range track and a scrollbar are drawn for the scheme the reader chose. Without
 * it the platform default is light, and a figure's own control rendered as a
 * white box with black text on a dark page — measured, not assumed: every
 * `<select>` inside a figure computed `color: rgb(0, 0, 0)` and
 * `background-color: rgb(239, 239, 239)` in both schemes.
 *
 * `color-scheme` is the standard switch for this, and it is set from the same
 * attribute `prefs.py` writes before the first paint, so it never flashes. */
[data-md-color-scheme="default"] {
  color-scheme: light;
}
[data-md-color-scheme="slate"] {
  color-scheme: dark;
}

/* Map the tokens onto Material's variable names. Deliberately
 * scheme-independent: anything that differs between light and dark is a token,
 * set by a bundle.
 *
 * Only the variables a component here still reads are declared. The names began
 * as Material's, but the shared stylesheet and the booklet widget read them, and
 * themes.css keys its tokens off `[data-md-color-scheme]`, so the attribute and
 * the names it needs stay. Six Material-only variables were deleted with the
 * renderer — `--md-primary-fg-color--light`, `--md-accent-fg-color`,
 * `--md-typeset-a-color`, `--md-code-bg-color`, `--md-primary-bg-color` and
 * `--md-primary-bg-color--light` — because nothing read them any more.
 *
 * Two of those were fixes, not decoration: the dark-mode link and the header's
 * ink on the accent. Material's palette.css beat the bare
 * `[data-md-color-scheme]` selector at (0,2,0), so both had to be restated at
 * that specificity. Material is gone and nothing consumed them, so the
 * restatement went too. The fixes themselves survive where they are now made:
 * shell.css paints links from `--tb-link` (`a { color: var(--tb-link) }`) and the
 * masthead title from `--tb-ink`, both straight from the bundle with no
 * third-party rule to beat. The Settings dialog's focus ring still names
 * `--md-accent-fg-color` with `--tb-accent` as its fallback — the same value, so
 * it is unchanged. */
[data-md-color-scheme] {
  --md-default-bg-color: var(--tb-paper);
  --md-default-fg-color: var(--tb-ink);
  --md-default-fg-color--light: var(--tb-ink-soft);
  --md-default-fg-color--lighter: var(--tb-ink-lighter);
  --md-default-fg-color--lightest: var(--tb-rule);
  --md-primary-fg-color: var(--tb-accent);
}

/* Typography: the faces themselves are bundle tokens; sizes are shared, so a
 * bundle changes the voice without changing the reading measure. */
.md-typeset {
  font-family: var(--tb-font-body);
  font-size: 1.0625rem; /* ~17px */
  line-height: 1.65;
}

.md-typeset h1,
.md-typeset h2,
.md-typeset h3,
.md-typeset h4 {
  font-family: var(--tb-font-display);
  letter-spacing: -0.01em;
}

/* Measure: 45-90 characters (Butterick); 50-75 optimal (Baymard). */
.md-typeset > p,
.md-typeset > ul,
.md-typeset > ol,
.md-typeset > blockquote {
  max-width: var(--tb-measure);
}

/* Maths is browser-rendered MathML; keep it aligned with the body text. */
.md-typeset math {
  font-size: 1.05em;
}

/* Interactive figures read as instrument panels, not decoration. */
.md-typeset maths-figure {
  display: block;
  max-width: 46rem;
  margin: 1.4rem 0;
  padding: 1rem 1.1rem;
  border: 1px solid var(--md-default-fg-color--lightest);
  border-radius: 6px;
  background: color-mix(in srgb, var(--md-default-bg-color) 92%, var(--md-default-fg-color) 8%);
}

.md-typeset maths-figure figcaption,
.md-typeset maths-figure .caption {
  font-size: 0.9rem;
  color: var(--md-default-fg-color--light);
}

/* Progressive-disclosure hints. */
.md-typeset details {
  max-width: var(--tb-measure);
  margin: 0.6rem 0;
  border: 1px solid var(--md-default-fg-color--lightest);
  border-radius: 6px;
  padding: 0.35rem 0.8rem;
}

.md-typeset details > summary {
  cursor: pointer;
  font-weight: 600;
}

.math-error {
  color: var(--tb-fig-warn);
  font-family: var(--tb-font-mono);
}

/* Figure colours come from the scheme variables above, so every figure adapts to
   dark mode and to a future palette change without editing the figure module. */
.fig-accent {
  fill: var(--tb-fig-accent);
  stroke: var(--tb-fig-accent);
}
.fig-warn {
  fill: var(--tb-fig-warn);
  stroke: var(--tb-fig-warn);
}
.fig-good {
  fill: var(--tb-fig-good);
  stroke: var(--tb-fig-good);
}
.fig-ink {
  fill: currentColor;
  stroke: currentColor;
}
.fig-grid {
  fill: none;
  stroke: var(--tb-fig-grid);
}
.fig-line {
  fill: none;
  stroke: var(--tb-fig-accent);
  stroke-width: 2;
}
/* A `text-*` class is for words, and SVG text is painted with `fill`, not
   `color`. Setting only `color` left every `<text class="text-accent">` painted
   black — its initial fill — which is invisible on the dark scheme at 1.4:1.
   Both properties are set, so the class means the same thing in HTML and in SVG.
   `.fig-*` is for shapes: it sets `fill` and `stroke` for a line or an area. */
.text-accent {
  color: var(--tb-fig-accent);
  fill: currentColor;
}
.text-warn {
  color: var(--tb-fig-warn);
  fill: currentColor;
}
.text-good {
  color: var(--tb-fig-good);
  fill: currentColor;
}
.text-ink {
  color: var(--tb-ink);
  fill: currentColor;
}

/* ------------------------------------------------------------------ */
/* Form controls inside a figure                                       */
/* ------------------------------------------------------------------ */

/* A form control is a user-agent widget: without a rule it takes the platform's
   colours, not the reader's theme. `color-scheme` (above) makes it follow light or
   dark, which is not the same thing as following *our* light or dark — it gave a
   figure's `<select>` `rgb(0, 0, 0)` on `rgb(239, 239, 239)` in the light scheme,
   white on `rgb(107, 107, 107)` in the dark one, and a `<input type="number">`
   that was a white box sitting on a dark panel. None of it was wrong enough to
   fail a contrast check and all of it looked like a different website.

   So the controls are painted from the same tokens as everything else. `--tb-ink`
   on `--tb-paper` is the same pairing as body text, so a control cannot be less
   readable than the prose around it, in any bundle or either scheme. */
maths-figure select,
maths-figure input:not([type="range"]):not([type="checkbox"]):not([type="radio"]),
maths-figure button {
  font: inherit;
  color: var(--tb-ink);
  background-color: var(--tb-paper);
  border: 1px solid var(--tb-rule);
  border-radius: 4px;
  padding: 0.15rem 0.35rem;
}

/* The dropdown list is painted by the platform from the option's own colours, and
   a transparent background there means the platform picks — which is how black
   text ends up on a dark list. */
maths-figure option {
  color: var(--tb-ink);
  background-color: var(--tb-paper);
}

/* A range draws its track in `color` and its filled part in `accent-color`, so
   both are set: the track is a gridline, and the filled part is the accent. */
maths-figure input[type="range"] {
  accent-color: var(--tb-fig-accent);
  color: var(--tb-fig-grid);
  background: transparent;
  border: 0;
  padding: 0;
  vertical-align: middle;
}

maths-figure input[type="checkbox"],
maths-figure input[type="radio"] {
  accent-color: var(--tb-fig-accent);
}

/* A figure's own label is plain text with no class of its own, so it is given the
   panel's ink here. `.readout` is deliberately *not* set: several figures colour
   theirs with `text-accent`, and a rule in this file would out-rank that class and
   repaint them all the same. */
maths-figure label {
  color: var(--tb-ink);
}

/* ------------------------------------------------------------------ */
/* The "Prove it to me" affordance                                     */
/* ------------------------------------------------------------------ */

/* A claim the book states without proving links to the proof. The element is an
   `<a>` and nothing else: the proof is a page, so the affordance works with
   scripting off, and no dialog or panel is needed to reach it. The left border is
   the accent rather than a colour of its own, so it follows the reader's bundle
   and the subject tint, and `--tb-rule` keeps the rest quiet. */
.prove {
  margin: 1.3rem 0;
  padding: 0.7rem 0.95rem;
  border: 1px solid var(--tb-rule);
  border-left: 3px solid var(--tb-fig-accent);
  border-radius: 6px;
  background: color-mix(in srgb, var(--tb-accent) 6%, transparent);
}
.prove__link {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.5rem;
  text-decoration: none;
}
.prove__ask {
  font-weight: 600;
  color: var(--tb-fig-accent);
  white-space: nowrap;
}
/* The arrow is drawn from the text rather than an icon file, so it cannot go
   missing from a book's asset tree and it inherits the accent. */
.prove__ask::after {
  content: "\2192";
  margin-left: 0.3rem;
  display: inline-block;
}
.prove__title {
  color: var(--tb-ink-soft);
}
.prove__link:hover .prove__ask,
.prove__link:focus-visible .prove__ask {
  text-decoration: underline;
}
.prove__note {
  margin: 0.5rem 0 0;
  font-size: 0.9rem;
  color: var(--tb-ink-soft);
}
.prove__badge {
  font-weight: 600;
  color: var(--tb-fig-warn);
}
.prove__badge::after {
  content: " —";
}

/* ------------------------------------------------------------------ */
/* Formulae & tables booklet                                           */
/* ------------------------------------------------------------------ */

.bk-fab {
  position: fixed;
  right: 1.1rem;
  bottom: 1.1rem;
  z-index: 30;
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.6rem 0.9rem;
  border: 1px solid var(--md-primary-fg-color--dark);
  border-radius: 999px;
  background: var(--md-primary-fg-color);
  /* The label is knocked out of the accent fill, so it uses the bundle's
   * dedicated on-accent ink, not the paper: a bundle's paper can sit too close
   * to its own accent to read (omarchy light 4.34:1, gruvbox light 4.40:1). */
  color: var(--tb-accent-ink);
  font: 600 0.9rem/1 system-ui, sans-serif;
  cursor: pointer;
  box-shadow: 0 4px 14px color-mix(in srgb, var(--md-default-fg-color) 22%, transparent);
}
.bk-fab:hover { filter: brightness(1.06); }
.bk-fab [aria-hidden] { font-size: 1.1rem; }
.bk-fab__label { font-size: 0.82rem; }

.bk-panel {
  position: fixed;
  right: 1.1rem;
  bottom: 4.6rem;
  z-index: 31;
  display: flex;
  flex-direction: column;
  width: min(430px, calc(100vw - 2rem));
  height: min(72vh, 660px);
  min-width: 320px;
  min-height: 280px;
  border: 1px solid var(--md-default-fg-color--lightest);
  border-radius: 12px;
  background: var(--md-default-bg-color);
  color: var(--md-default-fg-color);
  box-shadow: 0 12px 40px color-mix(in srgb, var(--md-default-fg-color) 28%, transparent);
  overflow: hidden;
}
.bk-panel[hidden] { display: none; }

.bk-bar {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.5rem 0.6rem;
  border-bottom: 1px solid var(--md-default-fg-color--lightest);
  background: var(--md-primary-fg-color);
  color: var(--tb-accent-ink);
  cursor: grab;
  touch-action: none;
}
.bk-bar:active { cursor: grabbing; }
.bk-grip {
  width: 14px;
  height: 14px;
  flex: none;
  background-image: radial-gradient(currentColor 1.2px, transparent 1.2px);
  background-size: 5px 5px;
  opacity: 0.6;
}
.bk-title { margin: 0; font-size: 0.95rem; font-weight: 700; flex: 1; }
.bk-bar__tools { display: flex; align-items: center; gap: 0.4rem; }
.bk-field { font-size: 0.72rem; display: flex; align-items: center; gap: 0.25rem; }
.bk-field select {
  font-size: 0.75rem;
  padding: 0.1rem 0.2rem;
  border-radius: 4px;
  border: 1px solid color-mix(in srgb, currentColor 40%, transparent);
  background: color-mix(in srgb, currentColor 12%, transparent);
  color: inherit;
}
.bk-icon {
  border: 0;
  background: transparent;
  color: inherit;
  font-size: 1rem;
  cursor: pointer;
  padding: 0.15rem 0.35rem;
  border-radius: 4px;
}
.bk-icon:hover { background: color-mix(in srgb, currentColor 18%, transparent); }

.bk-toolbar {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
  padding: 0.5rem 0.6rem 0.3rem;
}
.bk-search {
  flex: 1 1 10rem;
  padding: 0.35rem 0.5rem;
  border: 1px solid var(--md-default-fg-color--lightest);
  border-radius: 6px;
  background: var(--md-default-bg-color);
  color: inherit;
  font-size: 0.85rem;
}
.bk-chips { display: flex; gap: 0.3rem; }
.bk-chip {
  font-size: 0.72rem;
  padding: 0.2rem 0.5rem;
  border-radius: 999px;
  border: 1px solid var(--md-default-fg-color--lightest);
  background: transparent;
  color: var(--md-default-fg-color--light);
  cursor: pointer;
}
.bk-chip[aria-pressed="true"] {
  background: var(--md-primary-fg-color);
  border-color: var(--md-primary-fg-color);
  color: var(--tb-accent-ink);
}

.bk-tabs {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  padding: 0 0.6rem;
  border-bottom: 1px solid var(--md-default-fg-color--lightest);
}
.bk-tab {
  border: 0;
  background: transparent;
  color: var(--md-default-fg-color--light);
  font: 600 0.82rem/2.2 system-ui, sans-serif;
  border-bottom: 2px solid transparent;
  cursor: pointer;
}
.bk-tab[aria-selected="true"] {
  color: var(--md-default-fg-color);
  border-bottom-color: var(--md-primary-fg-color);
}
.bk-count { margin-left: auto; font-size: 0.72rem; color: var(--md-default-fg-color--light); }

.bk-content { flex: 1; overflow: auto; padding: 0.5rem 0.7rem 0.8rem; }
.bk-section h3 {
  margin: 0.8rem 0 0.4rem;
  font-size: 0.78rem;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--md-default-fg-color--light);
}
.bk-item {
  padding: 0.45rem 0.55rem;
  margin-bottom: 0.35rem;
  border: 1px solid var(--md-default-fg-color--lightest);
  border-left: 3px solid var(--md-primary-fg-color);
  border-radius: 6px;
}
.bk-item[data-group="question"] { border-left-color: var(--tb-fig-warn); }
.bk-item[data-group="know"] { border-left-color: var(--tb-fig-good); }
.bk-item__formula { overflow-x: auto; }
.bk-item__meta { display: flex; align-items: center; gap: 0.5rem; margin-top: 0.25rem; }
.bk-item__name { font-size: 0.8rem; font-weight: 600; }
.bk-item__note { margin: 0.25rem 0 0; font-size: 0.74rem; color: var(--md-default-fg-color--light); }
.bk-badge {
  margin-left: auto;
  font-size: 0.66rem;
  padding: 0.05rem 0.4rem;
  border-radius: 999px;
  white-space: nowrap;
}
.bk-badge--accent { background: color-mix(in srgb, var(--md-primary-fg-color) 18%, transparent); }
.bk-badge--muted { background: color-mix(in srgb, var(--tb-fig-warn) 20%, transparent); }
.bk-badge--warn { background: color-mix(in srgb, var(--tb-fig-good) 20%, transparent); }
.bk-empty { color: var(--md-default-fg-color--light); font-size: 0.85rem; }
.bk-table { width: 100%; border-collapse: collapse; font-size: 0.8rem; }
.bk-table th, .bk-table td { border: 1px solid var(--md-default-fg-color--lightest); padding: 0.25rem 0.4rem; text-align: left; }
.bk-table thead th { background: color-mix(in srgb, var(--md-default-fg-color) 6%, transparent); }

.bk-foot {
  padding: 0.35rem 0.7rem;
  border-top: 1px solid var(--md-default-fg-color--lightest);
  font-size: 0.68rem;
  color: var(--md-default-fg-color--light);
}
.bk-resize {
  position: absolute;
  right: 0;
  bottom: 0;
  width: 18px;
  height: 18px;
  cursor: nwse-resize;
  background: linear-gradient(135deg, transparent 50%, var(--md-default-fg-color--lighter) 50%);
  touch-action: none;
}

/* Mobile: bottom sheet instead of a floating window. */
@media (max-width: 719px) {
  .bk-panel {
    left: 0;
    right: 0;
    bottom: 0;
    width: auto;
    height: min(82vh, 700px);
    border-radius: 16px 16px 0 0;
  }
  .bk-resize { display: none; }
  .bk-bar { cursor: default; border-radius: 16px 16px 0 0; }
}

/* Document Picture-in-Picture window. */
.bk-popout-body { margin: 0; background: var(--md-default-bg-color); }
.bk-popout-body .bk-panel {
  position: static;
  width: 100%;
  height: 100vh;
  border-radius: 0;
  box-shadow: none;
}

/* ------------------------------------------------------------------ */
/* Print                                                               */
/* ------------------------------------------------------------------ */

/* Printing drops the browser chrome and the pointer. This block turns the page
 * into a sheet: no navigation furniture, one readable measure, and worked
 * examples that stay whole. It declares no colour, so a theme bundle and the
 * book tint still decide everything on paper exactly as they do on screen. */
@media print {
  /* Navigation, search, tabs and footer are for a viewport, not a sheet. The
   * booklet button and panel are fixed overlays, so without this they print
   * over the text on every page.
   *
   * These are the BESPOKE shell's class names (templates/page.html), not
   * Material's. The MkDocs shell was deleted and its `.md-header`/`.md-sidebar`/
   * `.md-search` rules quietly stopped matching anything, so printing a page
   * included the masthead, the sidebar and the search box. `.md-typeset` and
   * `.md-content` stay because the content column still carries both: the
   * reader-facing typography is shared with the landing page. */
  .masthead,
  .sidebar,
  .search,
  .skip,
  .bk-fab,
  .bk-panel {
    display: none !important;
  }

  /* The content column now has the whole width. Give it one measure and centre
   * it, so line length on paper matches the screen rather than the sheet. */
  .layout {
    display: block;
    margin: 0;
    padding: 0;
  }
  .md-typeset {
    max-width: var(--tb-measure);
    margin: 0 auto;
  }

  /* A table wider than the page must read, not sit inside a scroll box that
   * cannot scroll on paper. */
  .md-typeset__scrollwrap,
  .table-scroll { overflow: visible; }

  /* Worked examples should not split across a page break. `break-inside` is a
   * hint: an item taller than a page is still broken by the paginator, so a
   * long answer block cannot overflow the sheet. The `page-break-*` aliases
   * cover engines that predate the fragmentation properties. */
  .md-typeset table,
  .md-typeset__scrollwrap,
  .md-typeset details,
  .md-typeset maths-figure,
  .md-typeset figure {
    break-inside: avoid;
    page-break-inside: avoid;
  }
  .md-typeset h1,
  .md-typeset h2,
  .md-typeset h3,
  .md-typeset h4,
  .md-typeset details > summary {
    break-after: avoid;
    page-break-after: avoid;
  }
  .md-typeset thead {
    display: table-header-group; /* repeat a table's header if it must break */
  }
  .md-typeset p {
    orphans: 2;
    widows: 2;
  }

  /* Practice answers live in <details>. A browser does not lay out the content
   * of a closed detail, and a printed page cannot be clicked, so `details`
   * prints exactly as the reader left it. We deliberately do not force closed
   * details open: these pages are low-stakes retrieval, and printing every
   * answer beside its question would remove the retrieval. A reader who wants
   * an answer opens that detail before printing; the `break-inside: avoid`
   * above then keeps it whole. Open and closed alike keep the summary marker,
   * so a reader can see there is something to unfold. */

  /* Hover does not exist on paper, so links are underlined rather than left to
   * a colour a grayscale or mono printer may drop. */
  .md-typeset a {
    text-decoration: underline;
  }
}

/* A comfortable sheet margin; the printer's own headers and page numbers stay. */
@page {
  margin: 18mm 16mm;
}
