/* Styles for the public share page rendered by functions/s/[token].ts.
 *
 * Deliberately a linked stylesheet in public/ rather than an inline <style> block: the page's own
 * CSP holds style-src 'self', which refuses an inline block (style-src-attr covers only style="…"
 * attributes). A non-hashed name is required because the Function cannot read the build manifest.
 *
 * The palette and the type below are the site's, not an approximation of it. They started as one
 * and drifted: the accent was mint (#6ee7b7) against the brand's cyan, five more tokens were off by
 * a shade, and the page fell back to whatever sans and mono the visitor's OS supplies. The generated
 * preview card (src/share/card.ts) never drifted, so a reader met a cyan Space Grotesk card on
 * Reddit and landed on a mint system-font page — the two halves of one share disagreeing with each
 * other. Every value here is copied verbatim from the @theme block in src/styles/global.css and
 * held there by shareStyles.test.ts, which fails if the two ever diverge again.
 */

/* Self-hosted rather than linked from the Astro build's hashed /_astro/*.woff2: a Pages Function
 * cannot read the build manifest, so these need stable paths. font-src 'self' already allows them.
 * swap, so the text is readable while they load — the site's own fontsource CSS does the same. */
@font-face {
  font-family: "Space Grotesk";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("/f/space-grotesk-400.woff2") format("woff2");
}
@font-face {
  font-family: "Space Grotesk";
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url("/f/space-grotesk-700.woff2") format("woff2");
}
@font-face {
  font-family: "JetBrains Mono";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("/f/jetbrains-mono-400.woff2") format("woff2");
}
@font-face {
  font-family: "Inter Variable";
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url("/f/inter-variable.woff2") format("woff2");
}

:root {
  color-scheme: dark;

  --bg: #07090d;
  --panel: #0d1219;
  --border: #17202b;
  --text: #c9d2e0;
  --heading: #e6edf7;
  --muted: #7f8da0;
  --accent: #26c6da;
  --pnlpos: #3fb950;
  --pnlneg: #f85149;

  --font-display: "Space Grotesk", ui-sans-serif, system-ui, sans-serif;
  --font-mono: "JetBrains Mono", ui-monospace, "SF Mono", Menlo, monospace;
  --font-sans: "Inter Variable", "Inter", ui-sans-serif, system-ui, sans-serif;

  /* The group rule: between the heavy rule and the row hairline. */
  --rule: color-mix(in oklab, var(--muted) 40%, transparent);
  /* A figure and its note, marked for a moment. */
  --marked: color-mix(in oklab, var(--accent) 14%, transparent);
}
* { box-sizing: border-box; }
body { margin: 0; background: var(--bg); color: var(--text);
  font-family: var(--font-sans); line-height: 1.6; -webkit-font-smoothing: antialiased; }
/* A measured page also loads the site's stylesheet, first, so this page keeps its own look: the
   site's base rules balance headings, tidy paragraphs and scroll smoothly, and its reset removes
   link underlines. */
html { scroll-behavior: auto; scroll-padding-top: 1rem; scrollbar-color: var(--border) var(--bg); }
p { text-wrap: wrap; }
h1 { text-wrap: balance; }
::selection { background: color-mix(in oklab, var(--accent) 35%, transparent); color: var(--heading); }
:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 2px; }

.wrap { max-width: 46rem; margin: 0 auto; padding: 3rem 1.25rem 4rem; }
body:has(#consent-banner:not([hidden])) .wrap { padding-bottom: 9rem; }

/* The two error pages in handler.ts use these. */
.eyebrow { margin: 0; font-family: var(--font-mono); font-size: 0.7rem;
  letter-spacing: 0.2em; text-transform: uppercase; color: var(--accent); }
.cta { margin: 2rem 0 0; }
.cta a { color: var(--accent); text-decoration: none; font-weight: 600; }
h1 { margin: 0.75rem 0 0; font-family: var(--font-display); font-weight: 700;
  font-size: 2rem; line-height: 1.2; color: var(--heading); }

/* The sheet. One table and one figure, ruled like a page from a statistical yearbook: a heavy rule
 * above and below, a lighter one over each group, hairlines between rows. The rules do the work tiles
 * used to do, so nothing on this page sits in a box. */
.wrap.sheet { max-width: 77.5rem; padding: 1.75rem 1.25rem 3rem; }

.sheet-head { display: grid; grid-template-columns: minmax(0, 1fr); row-gap: 1rem;
  padding-bottom: 1rem; border-bottom: 2px solid var(--heading); }
.sheet-head h1 { margin: 0; font-size: clamp(1.625rem, 1.25rem + 1.2vw, 2.25rem); line-height: 1.15;
  letter-spacing: -0.015em; overflow-wrap: anywhere; }
.basis { margin: 0.5rem 0 0; font-size: 1rem; line-height: 1.5; color: var(--text); }
.basis strong { font-weight: 600; color: var(--heading); }
.basis .date { white-space: nowrap; }
.asof { margin: 0.125rem 0 0; font-size: 0.875rem; line-height: 1.5; color: var(--muted); }

/* The quiet credit: the only thing on the sheet that is about us. After the title in the markup, so a
 * stranger on a phone reads what the run was before they read who made the page. */
.credit { justify-self: start; display: inline-flex; align-items: center; gap: 0.4rem;
  padding: 0.25rem 0; font-size: 0.8125rem; line-height: 1.25; color: var(--muted); text-decoration: none; }
.credit svg { display: block; width: 0.95rem; height: 0.95rem; color: var(--accent); }
.credit:hover { color: var(--heading); }

.sheet-body { display: grid; grid-template-columns: minmax(0, 1fr); row-gap: 1.75rem; margin-top: 1rem; }
.cap { margin: 0 0 0.75rem; font-size: 0.8125rem; line-height: 1.4; color: var(--muted); }

/* ---- The table ---- */
.figures { width: 100%; border-collapse: collapse; }
/* For a screen reader. On screen, the first group's name opens the table on its own. */
.table-caption { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
.figures th, .figures td { padding: 0.3125rem 0; border-bottom: 1px solid var(--border);
  text-align: left; font-size: 0.875rem; font-weight: 400; line-height: 1.4; color: var(--text); }
.figures td { position: relative; padding-right: 1.125rem; text-align: right; white-space: nowrap;
  font-family: var(--font-mono); font-size: 0.875rem; color: var(--heading); font-variant-numeric: tabular-nums; }
/* Words rather than a figure, so the label face, and free to wrap. */
.figures td.words { white-space: normal; font-family: var(--font-sans); }
/* A narrow screen prints each note under its row, and only a narrow screen. See the block below. */
.figures .row-note, .fig-note { display: none; }
.figures .group th { padding: 0.8125rem 0 0.3125rem; border-bottom-color: var(--rule);
  font-family: var(--font-display); font-weight: 700; font-size: 0.8125rem; color: var(--heading); }
.figures tbody:first-of-type .group th { padding-top: 0.125rem; }

/* The return and the worst fall lead at the same size, in the display face the app's MetricTile sets
 * its values in. Every other figure is in the mono. */
.figures .lead th { padding-block: 0.5rem; vertical-align: baseline; color: var(--heading); }
.figures .lead td { padding-block: 0.5rem; vertical-align: baseline; font-family: var(--font-display);
  font-weight: 700; font-size: 1.625rem; line-height: 1.1; letter-spacing: -0.01em; }

/* Gain and loss carry the app's colours, by the app's rule — see metricList in src/share/render.ts,
 * which decides the tone once for this page and the preview card together. */
.figures td.pos { color: var(--pnlpos); }
.figures td.neg { color: var(--pnlneg); }
.figures td.neutral { color: var(--heading); }

/* The marker hangs in a space of its own, so the digits still line up at the right edge. */
.note-ref { position: static; font-family: var(--font-mono); font-size: 0.6875rem; font-weight: 400;
  letter-spacing: 0; line-height: 1; vertical-align: baseline; }
.note-ref a, a.note-key { position: relative; color: var(--accent); text-decoration: none; }
.note-ref a:hover, a.note-key:hover { text-decoration: underline; text-underline-offset: 0.2em; }
.note-refs { display: inline-flex; gap: 0.25rem; }
/* Exactly the width of the cell's right padding, so two letters stay inside the table's rule. */
.figures .note-refs { position: absolute; top: 0.25rem; right: 0; width: 1.125rem; }
.figures .lead .note-refs { top: 0.5rem; }
.cap .note-refs { position: relative; top: -0.3em; margin-left: 0.25rem; }
/* Every target is at least 24px each way, bigger than its glyph. Two side by side reach outward, over the
 * digits on one side and the column gap on the other, so neither covers the other's letter. */
.note-ref a::after, a.note-key::after { content: ""; position: absolute; inset: -0.5rem -0.5625rem; }
.note-ref:first-child:not(:last-child) a::after { left: -1.0625rem; right: -0.125rem; }
.note-ref:last-child:not(:first-child) a::after { left: -0.125rem; right: -0.9375rem; }

/* ---- The figure ---- */
.fig { margin: 0; min-width: 0; }
.fig-none { margin: 0; padding: 3rem 1rem; border-block: 1px solid var(--border); font-size: 0.875rem; color: var(--muted); }
/* The margins are the gutters the labels hang in: the scale on the left, the end of the line and the
 * start on the right. A label out here can never collide with the curve. */
.fig-plot { position: relative; margin-left: 2.75rem; margin-right: 4.25rem; }
.fig-plot-equity { height: 14rem; }
.fig-plot-band { height: 3.5rem; margin-top: 1.625rem; }
.fig-plot-axis { height: 1rem; margin-top: 1.625rem; }
.fig-layer { position: absolute; inset: 0; display: block; width: 100%; height: 100%; overflow: visible; }

.fig-grid { stroke: var(--border); stroke-width: 1; shape-rendering: crispEdges; }
.fig-zero { stroke: var(--rule); stroke-width: 1; shape-rendering: crispEdges; }
.fig-start { stroke: var(--muted); stroke-width: 1; stroke-dasharray: 3 4; shape-rendering: crispEdges; }
.fig-area { fill: color-mix(in oklab, var(--accent) 9%, transparent); }
.fig-curve { fill: none; stroke: var(--accent); stroke-width: 2; stroke-linejoin: round; stroke-linecap: round; }
.fig-band { fill: color-mix(in oklab, var(--muted) 30%, transparent); }
.fig-worst { stroke: var(--muted); stroke-width: 1; shape-rendering: crispEdges; }
.fig-end-dot { fill: var(--accent); stroke: var(--bg); stroke-width: 2; transform-box: fill-box; transform-origin: center; }
.fig-mark { cursor: default; }
.fig-hit { fill: transparent; stroke: transparent; stroke-width: 14; pointer-events: all; }

.fig-tick { font: 400 0.6875rem var(--font-mono); fill: var(--muted); font-variant-numeric: tabular-nums; }
.fig-label { font: 400 0.75rem var(--font-mono); fill: var(--text); font-variant-numeric: tabular-nums; }
.fig-label-end { fill: var(--heading); }
.fig-label-start { fill: var(--muted); }

/* ---- The notes ---- */
/* The short rule is a footnote's own: it says what follows belongs to what came before. */
.apparatus { min-width: 0; }
.apparatus::before { content: ""; display: block; width: 4rem; margin-bottom: 0.625rem; border-top: 1px solid var(--rule); }
.notes { margin: 0; padding: 0; list-style: none; font-size: 0.875rem; line-height: 1.5; color: var(--text); }
.notes li { display: grid; grid-template-columns: 1.125rem minmax(0, 1fr); max-width: 36rem; padding: 0.1875rem 0.375rem;
  margin-inline: -0.375rem; border-radius: 2px; break-inside: avoid; }
.note-key { align-self: start; font-family: var(--font-mono); font-size: 0.8125rem; color: var(--accent); }
.limits { margin: 0.625rem 0 0; max-width: 34rem; font-size: 0.8125rem; line-height: 1.5; color: var(--muted); }

.sheet-foot { margin-top: 1.5rem; padding-top: 0.75rem; border-top: 2px solid var(--heading); }
.report { margin: 0; font-size: 0.78rem; color: var(--muted); }
.report a { color: var(--muted); text-decoration: underline; text-underline-offset: 0.2em; }
.report button { margin-left: 0.5rem; padding: 0; border: 0; background: none; color: var(--muted); font: inherit;
  text-decoration: underline; text-underline-offset: 0.2em; cursor: pointer; }
.report a:hover, .report button:hover { color: var(--heading); }

/* ---- The cross-references ----
 * A row, the mark it describes on the figure, and the note that qualifies it point at each other, so a
 * reader can check that the table and the chart agree. All of it is CSS, because a page with no
 * measurement runs no script at all. A row's data-mark and data-note come from render.ts, and the note
 * ids are fixed there because the letters are not. */
.figures tr:not(.group):hover th { color: var(--heading); }
.figures tr:not(.group):hover th, .figures tr:not(.group):hover td { border-bottom-color: var(--rule); }

.figures tr:target > * { background: var(--marked); }

/* A row lights its mark on the figure. */
.sheet:has([data-mark="end"]:hover) .fig-end-dot,
.fig-mark-end:hover .fig-end-dot { transform: scale(1.6); }
.sheet:has([data-mark="end"]:hover) .fig-label-end,
.sheet:has([data-mark="start"]:hover) .fig-label-start,
.sheet:has([data-mark="worst"]:hover) .fig-label-worst,
.fig-mark:hover .fig-label { fill: var(--accent); }
.sheet:has([data-mark="start"]:hover) .fig-start,
.sheet:has([data-mark="worst"]:hover) .fig-worst,
.fig-mark:hover .fig-start,
.fig-mark:hover .fig-worst { stroke: var(--accent); }

/* A mark on the figure lights its row. */
.sheet:has(.fig-mark-end:hover) [data-mark="end"] > *,
.sheet:has(.fig-mark-start:hover) [data-mark="start"] > *,
.sheet:has(.fig-mark-worst:hover) [data-mark="worst"] > * { background: var(--marked); }

/* A row lights its note, for a pointer on the row or the keyboard on its marker. */
.notes li:target,
.sheet:has([data-note~="basis"]:is(:hover, :focus-within)) #note-basis,
.sheet:has([data-note~="raised"]:is(:hover, :focus-within)) #note-raised,
.sheet:has([data-note~="refused"]:is(:hover, :focus-within)) #note-refused,
.sheet:has([data-note~="sampled"]:is(:hover, :focus-within)) #note-sampled,
.sheet:has(.note-ref a[href="#note-rebase"]:is(:hover, :focus-visible)) #note-rebase { background: var(--marked); }

/* A note lights what it qualifies. */
.sheet:has(#note-basis:is(:hover, :target, :focus-within)) [data-note~="basis"] > *,
.sheet:has(#note-raised:is(:hover, :target, :focus-within)) [data-note~="raised"] > *,
.sheet:has(#note-refused:is(:hover, :target, :focus-within)) [data-note~="refused"] > *,
.sheet:has(#note-sampled:is(:hover, :target, :focus-within)) [data-note~="sampled"] > * { background: var(--marked); }
.sheet:has(#note-sampled:is(:hover, :target, :focus-within)) .fig-label-worst { fill: var(--accent); }
.sheet:has(#note-sampled:is(:hover, :target, :focus-within)) .fig-worst { stroke: var(--accent); }
.sheet:has(#note-rebase:is(:hover, :target, :focus-within)) .fig-curve,
.fig:target .fig-curve { stroke-width: 3; }

/* ---- Narrow screens ----
 * Below the two-column layout the table and the list of notes would be a screen apart, so each note moves
 * to the row it qualifies, or to the chart's caption. With the note right there the letters have nothing
 * left to do, so they go too, and the figures take back the space the letters kept clear. A note with no
 * row to sit under has no data-inline and stays in the list. */
@media (max-width: 53.99rem) {
  .figures .row-note { display: table-row; }
  .figures .row-note td { position: static; padding: 0 0 0.5rem; white-space: normal; text-align: left;
    font-family: var(--font-sans); font-size: 0.8125rem; line-height: 1.45; color: var(--text); }
  .figures tr:has(+ .row-note) > * { border-bottom: 0; }
  .figures td { padding-right: 0; }
  .note-refs, .notes li[data-inline] { display: none; }
  .fig-note { display: block; margin-top: 0.25rem; color: var(--text); }
}

/* The narrowest phones have room for every second label on the time axis. */
@media (max-width: 23.5rem) {
  .fig-tick-alt { display: none; }
}

/* ---- Wider screens ----
 * The table comes first in the markup and the notes straight after it, so on a phone the return and the
 * worst fall are on the first screen and the caveats are next, with the figure after them. From here the
 * table takes the left column and the figure and notes stack to its right, with everything on the first
 * screen at 1440 by 900. */
@media (min-width: 54rem) {
  .wrap.sheet { padding-inline: 1.5rem; }
  .sheet-head { grid-template-columns: minmax(0, 1fr) auto; column-gap: 2.5rem; }
  .credit { align-self: start; margin-top: 0.5rem; }
  .sheet-body { grid-template-columns: minmax(0, 24rem) minmax(0, 1fr); grid-template-rows: auto 1fr;
    grid-template-areas: "table fig" "table apparatus"; column-gap: clamp(2rem, 4vw, 3.5rem); row-gap: 1.25rem; }
  /* align-self, or a short table stretches its rows to the height of the figure beside it. */
  .figures { grid-area: table; align-self: start; }
  .fig { grid-area: fig; }
  .apparatus { grid-area: apparatus; }
  .fig-plot { margin-left: 3rem; margin-right: 4.75rem; }
  .fig-plot-equity { height: clamp(15rem, 34vh, 22rem); }
  .fig-plot-band { height: 4.25rem; }
}
@media (min-width: 75rem) {
  .sheet-body { grid-template-columns: minmax(0, 28rem) minmax(0, 1fr); }
  /* Two short columns hold a readable measure and keep the notes on the first screen. */
  .notes { columns: 2; column-gap: 2rem; }
}

/* The one moment of motion: the lines draw in from the start of the run, once. They rest visible, so
 * with motion reduced, or before the stylesheet applies, nothing is ever hidden. */
@media (prefers-reduced-motion: no-preference) {
  .fig-lines { animation: fig-reveal 900ms cubic-bezier(0.16, 1, 0.3, 1) both; }
  @keyframes fig-reveal {
    from { clip-path: inset(-5% 100% -5% -1%); }
    to { clip-path: inset(-5% -1% -5% -1%); }
  }
  .notes li, .figures th, .figures td { transition: background-color 120ms ease-out, border-color 120ms ease-out; }
  .fig-end-dot { transition: transform 120ms ease-out; }
}

/* A sheet is a thing people print or save as a PDF, and a dark ground wastes the ink. */
@media print {
  :root { color-scheme: light; --bg: white; --border: silver; --text: black; --heading: black; --muted: dimgray;
    --accent: black; --pnlpos: black; --pnlneg: black; --rule: gray; }
  #consent-banner, .report button { display: none; }
  .fig-lines { animation: none; }
}
