/* Source Serif 4 for headings. Material loads `font.text` and `font.code`
 * from mkdocs.yml but nothing else, so the heading face is fetched here. */
@import url("https://fonts.googleapis.com/css2?family=Source+Serif+4:opsz,wght@8..60,400;8..60,600&display=swap");

/* Wider content column. The dashboards are 800–1200 px natively, so
 * Material's default 61rem grid squeezes them; 1400px gives the embeds room
 * and the scale-to-fit script then fills whatever is left. */
.md-grid {
  max-width: 1400px;
}

/* Reproduced paper figures, on the Figures page.
 *
 * Exported at 1400 px wide to match the content column, so they never need
 * upscaling; `width: 100%` lets them shrink on narrow screens and
 * `height: auto` keeps the aspect ratio. The prose beneath each one is
 * ordinary body text — these figures are the subject of their sections
 * rather than apparatus alongside them, so they are not set as captions. */
.md-typeset img.paper-figure {
  display: block;
  width: 100%;
  height: auto;
  margin: 1.2rem 0;
  border: 1px solid var(--md-default-fg-color--lightest);
  border-radius: 0.15rem;
}

/* A link to a figure that opens it in place — see
 * docs/javascripts/figure-modal.js. Styled as a link rather than a button:
 * it *is* a link, and it still navigates if the script never runs. The
 * small mark after it hints that it opens without leaving the page, and is
 * only shown once the script has announced itself. */
.figure-js a.figure-pop::after {
  content: "⤢";
  margin-left: 0.25em;
  font-size: 0.85em;
  text-decoration: none;
  display: inline-block;
}

.figure-dialog {
  max-width: min(60rem, calc(100vw - 2rem));
  max-height: calc(100vh - 3rem);
  padding: 1rem 1.1rem 0.8rem;
  border: 1px solid var(--md-default-fg-color--lighter);
  border-radius: 0.3rem;
  background: var(--md-default-bg-color);
  color: var(--md-default-fg-color);
  box-shadow: 0 0.2rem 1.2rem rgba(0, 0, 0, 0.25);
  overflow: auto;
}

.figure-dialog::backdrop {
  background: rgba(0, 0, 0, 0.55);
}

.figure-dialog__title {
  margin: 0 0 0.6rem;
  font-size: 0.8rem;
  font-weight: 700;
}

.figure-dialog__img {
  display: block;
  width: 100%;
  height: auto;
  border: 1px solid var(--md-default-fg-color--lightest);
  border-radius: 0.15rem;
}

.figure-dialog__actions {
  display: flex;
  gap: 0.8rem;
  align-items: center;
  justify-content: space-between;
  margin: 0.8rem 0 0;
  font-size: 0.72rem;
}

.figure-dialog__full {
  color: var(--md-accent-fg-color);
}

.figure-dialog__close {
  font: inherit;
  padding: 0.3em 0.9em;
  color: var(--md-primary-fg-color);
  background: transparent;
  border: 1px solid var(--md-default-fg-color--lighter);
  border-radius: 1em;
  cursor: pointer;
  white-space: nowrap;
}

.figure-dialog__close:hover,
.figure-dialog__close:focus-visible {
  color: var(--md-primary-bg-color);
  background: var(--md-primary-fg-color);
  border-color: var(--md-primary-fg-color);
}

/* Body text one step up from Material's default 0.8rem — the pages are
 * long-form prose, and 0.8rem reads small on a wide column. Everything else
 * (headings, admonitions, tables) is sized in em off this, so they follow. */
.md-typeset {
  font-size: 0.9rem;
}

/* Keep the left sidebar's own type from growing with the body text. */
.md-nav {
  font-size: 0.75rem;
}

/* Material sets tables to 0.64rem regardless of body size, which left the
 * glossary's abbreviation table noticeably smaller than the prose around it.
 * Match the body instead — these tables are content, not dense data grids. */
.md-typeset table:not([class]) {
  font-size: 0.85rem;
}

/* Abbreviations get a hover tooltip via the `abbr` extension. Mark them so
 * a reader can see there is something to hover over. */
.md-typeset abbr {
  text-decoration: underline dotted;
  text-underline-offset: 0.2em;
  cursor: help;
  border-bottom: none;
}

/* …except inside a link, where the pointer must still say "clickable" and
   the link's own underline should win. */
.md-typeset a abbr {
  cursor: pointer;
  text-decoration: none;
}

/* The home page's dashboard cards. Material's grid asks for 16rem (320px)
   per card, which in our content column yields an unbalanced 2+2+1; three
   across lets the five cards sit 3+2, and small screens still wrap to one.

   The column count is stated outright rather than left to `auto-fit` with a
   rem minimum: `rem` follows the reader's default font size, so a reader
   browsing at 20px instead of 16px silently loses the third column. The
   76.25em breakpoint is Material's own — it is where the second sidebar
   appears and the content column stops growing. */
.md-typeset .grid.cards {
  grid-template-columns: 1fr;
}

@media screen and (min-width: 45em) {
  .md-typeset .grid.cards { grid-template-columns: repeat(2, 1fr); }
}

@media screen and (min-width: 76.25em) {
  .md-typeset .grid.cards { grid-template-columns: repeat(3, 1fr); }
}

/* Scale-to-fit wrapper for the Tableau embeds.
 *
 * docs/javascripts/tableau-fit.js sets `height` and `overflow` inline once it
 * knows the scale factor; the rules here are what applies before that runs
 * and what the JS does not own. Keep the fallback paragraph OUTSIDE this
 * element — the JS clips the wrapper to the scaled viz height, so anything
 * else inside would be hidden. */
.tableau-fit {
  position: relative;
  width: 100%;
  margin: 1.2rem 0 0.4rem;
  border: 1px solid var(--md-default-fg-color--lightest);
  border-radius: 0.2rem;
  background: var(--md-default-bg-color);
  /* Before the JS runs, clip rather than letting a full-size viz overflow
     the column; the JS replaces this with the exact scaled height. */
  overflow: hidden;
  /* Give the box its shape (and the skeleton text somewhere to sit) before
     tableau-fit.js measures the real scaled height — which is always taller
     than this, so the min never fights the script. */
  min-height: 12rem;
}

.tableau-fit tableau-viz {
  display: block;
  /* Positioned so it paints above the ::before skeleton text — the viz's
     iframe covers the message the moment Tableau draws. */
  position: relative;
}

/* Loading skeleton — visual-identity.md: "Loading skeleton text on
   .tableau-fit while Tableau paints." The message lives in the wrapper's
   own ::before layer, BEHIND the viz, so nothing has to dismiss it: the
   iframe's opaque background covers it on first paint. If the Embedding
   API never loads (blocked, offline, JS off), the text stays put and the
   escape-hatch link below the wrapper is the way out. */
.tableau-fit::before {
  content: "Loading the interactive dashboard from Tableau Public…";
  position: absolute;
  inset: 0;
  display: flex;
  justify-content: center;
  align-items: flex-start;
  padding-top: 5rem;
  font-size: 0.75rem;
  color: var(--md-default-fg-color--light);
  animation: tableau-skeleton-pulse 2.4s ease-in-out infinite;
}

@keyframes tableau-skeleton-pulse {
  50% { opacity: 0.4; }
}

@media (prefers-reduced-motion: reduce) {
  .tableau-fit::before {
    animation: none;
  }
}

/* The escape hatch under each embed — a plain Markdown link, so it stays
   useful with JavaScript disabled or if the embedding API fails to load,
   and it reaches the full-size dashboard where the page shows the narrow
   web variant. Markdown wraps it in a <p>, so the spacing lives there and
   the muted styling on the link itself. */
.tableau-fit + p {
  margin: 0.35rem 0 1.6rem;
}

a.embed-fallback {
  font-size: 0.75rem;
  color: var(--md-default-fg-color--light);
}

/* "How to cite" — the button, and the modal it opens.
 *
 * Behaviour lives in docs/javascripts/cite-modal.js; these rules are the
 * two states it switches between. The button is hidden until the script
 * announces itself with `cite-js` on <html>, and the citation block is
 * hidden until the script moves it inside the dialog — so with JavaScript
 * off (where a <noscript> rule in includes/cite.md re-reveals the block)
 * the page shows the citation inline and no dead buttons. */
.cite-open {
  display: none;
  font: inherit;
  font-size: 0.7rem;
  line-height: 1.2;
  padding: 0.3em 0.75em;
  color: var(--md-accent-fg-color);
  background: transparent;
  border: 1px solid var(--md-accent-fg-color);
  border-radius: 1em;
  cursor: pointer;
  white-space: nowrap;
  transition: background-color 125ms, color 125ms;
}

.cite-js .cite-open {
  display: inline-block;
}

.cite-open:hover,
.cite-open:focus-visible {
  color: var(--md-accent-bg-color);
  background: var(--md-accent-fg-color);
}

/* Sits on the escape-hatch line under an embed; the small offset keeps it
   optically level with that line's smaller text. */
.tableau-fit + p .cite-open {
  margin-left: 0.6rem;
  vertical-align: 0.05rem;
}

/* Under the page title, and again at the foot of the page, the button is
   its own block and carries the surrounding rhythm. */
p.cite-open-row {
  margin: 0.6rem 0 1.4rem;
}

.cite-source {
  display: none;
}

.cite-dialog {
  max-width: min(40rem, calc(100vw - 2rem));
  padding: 1.2rem 1.4rem 0.9rem;
  border: 1px solid var(--md-default-fg-color--lighter);
  border-radius: 0.3rem;
  background: var(--md-default-bg-color);
  color: var(--md-default-fg-color);
  box-shadow: 0 0.2rem 1.2rem rgba(0, 0, 0, 0.25);
}

.cite-dialog::backdrop {
  background: rgba(0, 0, 0, 0.45);
}

/* Inside the dialog the block is the content, so it shows; and the
   md-typeset class the script adds gives it Material's own typography. */
.cite-dialog .cite-source {
  display: block;
}

.cite-dialog .cite-source > :first-child {
  margin-top: 0;
}

.cite-dialog .cite-source > :last-child {
  margin-bottom: 0;
}

.cite-dialog__close {
  display: block;
  margin: 1rem 0 0 auto;
  font: inherit;
  font-size: 0.7rem;
  padding: 0.3em 0.9em;
  color: var(--md-primary-fg-color);
  background: transparent;
  border: 1px solid var(--md-default-fg-color--lighter);
  border-radius: 1em;
  cursor: pointer;
}

.cite-dialog__close:hover,
.cite-dialog__close:focus-visible {
  color: var(--md-primary-bg-color);
  background: var(--md-primary-fg-color);
  border-color: var(--md-primary-fg-color);
}


/* ==========================================================================
   Identity (2026-09-16)
   --------------------------------------------------------------------------
   The six scarp classes already govern every mark on every dashboard, but
   until now the site's own chrome was Material's stock indigo — a colour that
   means nothing here. These rules put the paper's palette into the frame:
   a six-band rule under the header, a class dot beside each dashboard in the
   sidebar, and the accent taken from the palette rather than a preset.

   Deliberate limit, carried from notes/design-review-2026-08-16.md: the
   palette is IDENTITY, never the sole carrier of meaning in chrome. #009ffa
   and #f47820 fall below 3:1 on white and Simple/PR-Collapse are ΔE 2.9 apart
   under deuteranopia, so links, buttons and focus rings all use #3f67b1
   (Monoclinal Collapse), the one member that clears 4.5:1.
   ========================================================================== */

:root {
  --egr-monoclinal:      #009ffa;
  --egr-monoclinal-coll: #3f67b1;
  --egr-pressure:        #f47820;
  --egr-pressure-coll:   #af773e;
  --egr-simple:          #ed2024;
  --egr-simple-coll:     #9f1d20;
  --egr-ink:             #1d2230;
}

/* `primary: custom` / `accent: custom` in mkdocs.yml defer to these. */
[data-md-color-primary="custom"] {
  --md-primary-fg-color:        var(--egr-ink);
  --md-primary-fg-color--light: #2c3444;
  --md-primary-fg-color--dark:  #141821;
  --md-primary-bg-color:        #fff;
  --md-primary-bg-color--light: rgba(255, 255, 255, .7);

  /* Body links. Material derives this from the primary colour
     (`--md-typeset-a-color: var(--md-primary-fg-color)`), which would make
     every link the same near-black as the surrounding text. It has to be
     redefined here rather than on `:root`: the theme sets it on
     `[data-md-color-scheme=default]`, which lands on <body> and so beats
     anything inherited from <html>. */
  --md-typeset-a-color:         var(--egr-monoclinal-coll);
}

[data-md-color-accent="custom"] {
  --md-accent-fg-color:             var(--egr-monoclinal-coll);
  --md-accent-fg-color--transparent: rgba(63, 103, 177, .1);
  --md-accent-bg-color:             #fff;
  --md-accent-bg-color--light:      rgba(255, 255, 255, .7);
}

/* The spine: the six classes, in paper order, as a rule under the header.
   A reader meets the encoding here, before any legend asks them to know it. */
.md-header {
  position: sticky;
}

.md-header::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 3px;
  background: linear-gradient(
    to right,
    var(--egr-monoclinal)       0     16.67%,
    var(--egr-monoclinal-coll)  16.67% 33.33%,
    var(--egr-pressure)         33.33% 50%,
    var(--egr-pressure-coll)    50%    66.67%,
    var(--egr-simple)           66.67% 83.33%,
    var(--egr-simple-coll)      83.33% 100%
  );
}

/* Headings in the serif. The register the site is accompanying is a journal
   article, not a tool's manual. Body copy stays in the sans. */
.md-typeset h1,
.md-typeset h2,
.md-typeset h3,
.md-typeset h4 {
  font-family: "Source Serif 4", Georgia, "Times New Roman", serif;
  font-weight: 600;
  letter-spacing: -0.01em;
}

.md-typeset h1 {
  color: var(--md-default-fg-color);
  line-height: 1.18;
}

/* A class dot beside each dashboard in the sidebar, matched to the hue that
   dashboard carries in its own charts.

   Two things make this fiddly. `.md-nav__link` is a flex container with
   `justify-content: space-between`, so a `::before` on the link itself gets
   pushed to the far edge instead of sitting next to its label; the dot has to
   hang off the inner `.md-ellipsis` span, where it stays in the label's own
   inline flow. And the nav hrefs are relative, so they differ from page to
   page ("./" on the dashboard itself, "../slip-regression/" from a sibling,
   "dashboards/slip-regression/" from home) — matching on href only works from
   one page. Dashboards is the third top-level nav entry, which fixes the id
   MkDocs generates for it, so the dots key off list position instead. */
.md-nav[aria-labelledby="__nav_3_label"] > .md-nav__list
  > .md-nav__item > .md-nav__link .md-ellipsis::before {
  content: "";
  display: inline-block;
  width: .45em;
  height: .45em;
  margin-right: .55em;
  border-radius: 50%;
  vertical-align: middle;
  background: var(--md-default-fg-color--lighter);
}

.md-nav[aria-labelledby="__nav_3_label"] > .md-nav__list
  > .md-nav__item:nth-child(1) > .md-nav__link .md-ellipsis::before { background: var(--egr-monoclinal); }
.md-nav[aria-labelledby="__nav_3_label"] > .md-nav__list
  > .md-nav__item:nth-child(2) > .md-nav__link .md-ellipsis::before { background: var(--egr-pressure); }
.md-nav[aria-labelledby="__nav_3_label"] > .md-nav__list
  > .md-nav__item:nth-child(3) > .md-nav__link .md-ellipsis::before { background: var(--egr-monoclinal-coll); }
.md-nav[aria-labelledby="__nav_3_label"] > .md-nav__list
  > .md-nav__item:nth-child(4) > .md-nav__link .md-ellipsis::before { background: var(--egr-simple); }
.md-nav[aria-labelledby="__nav_3_label"] > .md-nav__list
  > .md-nav__item:nth-child(5) > .md-nav__link .md-ellipsis::before { background: var(--egr-pressure-coll); }

/* The five dashboard cards on the home page. Material's 16rem minimum leaves
   them two across in this column, which reads as a list with a hole in it;
   12rem gets three across and keeps the fifth from stranding. Each card
   carries its dashboard's class colour as a top rule — the same hue as its
   sidebar dot and as its marks on the dashboard itself, so the three agree.
   The rule is decoration on top of the link text, never the only thing
   telling the cards apart. */
.md-typeset .grid.cards > ul > li {
  border-top: 0.15rem solid var(--md-default-fg-color--lighter);
}

.md-typeset .grid.cards > ul > li:nth-child(1) { border-top-color: var(--egr-monoclinal); }
.md-typeset .grid.cards > ul > li:nth-child(2) { border-top-color: var(--egr-pressure); }
.md-typeset .grid.cards > ul > li:nth-child(3) { border-top-color: var(--egr-monoclinal-coll); }
.md-typeset .grid.cards > ul > li:nth-child(4) { border-top-color: var(--egr-simple); }
.md-typeset .grid.cards > ul > li:nth-child(5) { border-top-color: var(--egr-pressure-coll); }

/* A measure for running prose. The 1400px grid exists for the embeds (see the
   top of this file); text set the full width of it is unreadable. Only direct
   children are constrained, so `.tableau-fit`, tables and figures keep the
   full column. */
.md-typeset > p,
.md-typeset > ul,
.md-typeset > ol,
.md-typeset > blockquote,
.md-typeset > h1,
.md-typeset > h2,
.md-typeset > h3 {
  max-width: 74ch;
}

.md-typeset > p {
  line-height: 1.68;
  text-wrap: pretty;
}
