/* ---------------------------------------------------------------
   Assay — working stylesheet

   Design rules
   1. Colour is reserved for verdicts. Grades and pass/warn/fail are
      the only coloured things on the page. If everything is coloured,
      nothing reads as a judgement.
   2. Prose is centred. Data is not — findings rows stay left-aligned
      because a column of numbers you have to re-find the start of is
      a column of numbers nobody reads.

   Typefaces are self-hosted and declared in fonts.css. Adding another
   face means adding a file, not a link to someone else's server — the
   privacy page promises no third-party requests, so keep it that way.
   --------------------------------------------------------------- */

:root {
  --bg:        #0a0c0f;
  --surface:   #13161b;
  --surface-2: #171b21;
  --border:    #262c35;
  --border-lit:#333b46;
  --text:      #e9ecf1;
  --muted:     #8d95a1;
  --dim:       #5e6672;

  /* Brand gold — the mark only. Assaying is a gold-purity test, so the
     mark earns its colour. Kept deliberately paler than --warn so a
     verdict is never confused with branding. */
  --brand: #f0d9a0;

  /* Verdict colours — used nowhere else */
  --pass: #45c08a;
  --warn: #e0952f;
  --fail: #e0645a;

  --display: "Space Grotesk", "Inter", sans-serif;
  --sans: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
  --mono: "JetBrains Mono", ui-monospace, "Cascadia Mono", Consolas, monospace;

  --wrap: 1000px;

  /* Reusable card treatment — subtle top-lit gradient plus depth */
  --card-bg: linear-gradient(180deg, var(--surface-2) 0%, var(--surface) 100%);
  --card-shadow: 0 1px 0 rgba(255, 255, 255, 0.04) inset,
                 0 12px 32px rgba(0, 0, 0, 0.45);
}

* { box-sizing: border-box; }

/* The hidden attribute is only a UA-stylesheet `display: none`, so any
   explicit display rule silently beats it. This bit the upload form: the
   file input and the submit button were both marked hidden and both shown
   anyway, because `.btn` and the file-input rule set a display. Keep this
   above everything else. */
[hidden] { display: none !important; }

html { scroll-behavior: smooth; }

/* The topbar is sticky, so anchors need to clear it. */
[id] { scroll-margin-top: 104px; }

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
}

/* Selection uses the mark's gold. It is not a verdict colour, so this
   does not break rule 1 — and the alternative is the browser's default
   blue, which belongs to no design at all. */
::selection {
  background: rgba(240, 217, 160, 0.22);
  color: var(--text);
}

/* The scrollbar is part of the page on a dark design. Left alone it is a
   bright strip down the side of everything. */
* {
  scrollbar-width: thin;
  scrollbar-color: var(--border-lit) transparent;
}
*::-webkit-scrollbar { width: 10px; height: 10px; }
*::-webkit-scrollbar-track { background: transparent; }
*::-webkit-scrollbar-thumb {
  background: var(--border-lit);
  border-radius: 6px;
  border: 2px solid var(--bg);
}
*::-webkit-scrollbar-thumb:hover { background: var(--dim); }

/* Stops a headline leaving one word stranded on its own line. Ignored by
   browsers that do not have it, which simply get today's behaviour. */
h1, h2, .lede, .verdict-line { text-wrap: balance; }

/* --- Focus ------------------------------------------------------------
   There were two focus styles in this stylesheet and a keyboard user
   could see neither. Every interactive thing gets the same ring, in the
   mark's gold so it never reads as a verdict. :focus-visible rather than
   :focus, so a mouse click does not leave a ring behind. */
:where(a, button, summary, [tabindex], input, textarea, select):focus-visible {
  outline: 2px solid var(--brand);
  outline-offset: 3px;
  border-radius: 4px;
}

/* The file input is visually hidden and driven by its label, so the ring
   has to be moved onto the label or it lands on nothing. */
#export:focus-visible + label[for="export"] {
  outline: 2px solid var(--brand);
  outline-offset: 3px;
}

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: var(--sans);
  font-size: 16px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
}

.wrap {
  max-width: var(--wrap);
  margin: 0 auto;
  padding: 0 24px;
}

.mono { font-family: var(--mono); font-variant-numeric: tabular-nums; }
.muted { color: var(--muted); }

h1, h2, h3 {
  font-family: var(--display);
  line-height: 1.12;
  margin: 0;
  letter-spacing: -0.02em;
}

/* --- Top bar ---------------------------------------------------- */

/* The bar sits ABOVE the page — lighter than the background, not the
   same colour as it, or it reads as empty space with a line under it. */
.topbar {
  border-bottom: 1px solid var(--border-lit);
  position: sticky;
  top: 0;
  background: rgba(21, 25, 31, 0.92);
  backdrop-filter: blur(12px);
  box-shadow: 0 1px 0 rgba(255, 255, 255, 0.05) inset,
              0 8px 24px rgba(0, 0, 0, 0.5);
  z-index: 10;
}

.topbar-inner {
  display: flex;
  align-items: center;
  gap: 18px;
  height: 84px;
}

.wordmark {
  display: flex;
  align-items: center;
  gap: 12px;
  font-family: var(--display);
  font-weight: 700;
  letter-spacing: 0.26em;
  font-size: 26px;
  color: #ffffff;
  text-decoration: none;
  text-shadow: 0 0 24px rgba(255, 255, 255, 0.18);
}

.wordmark .mark {
  width: 32px;
  height: 32px;
  flex-shrink: 0;
  color: var(--brand);
  filter: drop-shadow(0 0 12px rgba(240, 217, 160, 0.4));
}

/* Says what the thing is, and stops the left half of the bar
   from being one word floating in space. */
.tagline {
  font-family: var(--mono);
  font-size: 12px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--dim);
  padding-left: 18px;
  border-left: 1px solid var(--border-lit);
  white-space: nowrap;
}

.topnav {
  display: flex;
  align-items: center;
  gap: 28px;
  margin-left: auto;
}

.topnav a {
  color: var(--muted);
  text-decoration: none;
  font-size: 14px;
}

.topnav a:hover { color: var(--text); }

/* --- Buttons ---------------------------------------------------- */

.btn {
  font-family: var(--sans);
  font-size: 14px;
  font-weight: 500;
  padding: 9px 18px;
  border-radius: 7px;
  border: 1px solid var(--border);
  cursor: pointer;
  text-decoration: none;
  display: inline-block;
  transition: border-color 0.15s ease, transform 0.15s ease;
}

.btn-ghost { background: transparent; color: var(--muted); }
.btn-ghost:hover { border-color: var(--border-lit); }

.btn-primary {
  background: var(--text);
  color: var(--bg);
  border-color: var(--text);
  font-weight: 600;
  padding: 12px 26px;
  font-size: 15px;
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.5);
}

.btn-primary:disabled { opacity: 0.3; cursor: not-allowed; box-shadow: none; }

.btn-sm { padding: 9px 18px; font-size: 14px; }

/* --- Hero (centred) --------------------------------------------- */

.hero {
  padding: 72px 0 40px;
  text-align: center;
  position: relative;
  overflow: hidden;
}

/* Soft light source behind the headline, so the page has a top. */
.hero::before {
  content: "";
  position: absolute;
  top: -320px;
  left: 50%;
  transform: translateX(-50%);
  width: 900px;
  height: 620px;
  background: radial-gradient(ellipse at center, rgba(120, 145, 185, 0.10) 0%, transparent 65%);
  pointer-events: none;
}

.hero .wrap { position: relative; }

.eyebrow {
  font-family: var(--mono);
  font-size: 12px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--dim);
  margin: 0 0 18px;
}

.hero h1 {
  font-size: clamp(38px, 5.6vw, 58px);
  font-weight: 700;
  margin-bottom: 20px;
}

.lede {
  font-size: 17px;
  line-height: 1.55;
  color: var(--muted);
  max-width: 540px;
  margin: 0 auto 32px;
}

/* --- Upload dropzone (visual only for now) ---------------------- */

/* The dropzone is a target, not a panel — it should look roughly like
   the thing you drag a file onto, and no taller. */
.upload {
  border: 1px dashed var(--border-lit);
  border-radius: 14px;
  background: var(--card-bg);
  box-shadow: var(--card-shadow);
  padding: 36px 28px;
  max-width: 620px;
  margin: 0 auto;
  transition: border-color 0.15s ease, background 0.15s ease;
}

.upload-inner { text-align: center; }

/* The drag target is the hallmark, not a generic circled arrow: the
   same shape the grade is struck into, so the thing you drop a file on
   and the thing you get back are visibly the same system. It fills in on
   drag-over, which is the state change worth having here. */
.upload-icon {
  width: 44px;
  height: 44px;
  margin: 0 auto 12px;
  display: grid;
  place-items: center;
  color: var(--muted);
  transition: color 0.15s ease, transform 0.15s ease;
}

.upload-icon svg { width: 100%; height: 100%; }

.upload-icon .hallmark-fill {
  fill: currentColor;
  opacity: 0.25;
  transition: opacity 0.15s ease;
}

.upload.is-dragging .upload-icon {
  color: var(--brand);
  transform: scale(1.06);
}

.upload.is-dragging .upload-icon .hallmark-fill { opacity: 1; }

@media (prefers-reduced-motion: reduce) {
  .upload-icon { transition: color 0.15s ease; }
  .upload.is-dragging .upload-icon { transform: none; }
}

.upload-title { font-size: 16px; font-weight: 500; margin: 0 0 5px; }
.upload-hint { font-size: 13px; color: var(--dim); margin: 0 0 18px; }

.upload-note {
  font-size: 13px;
  color: var(--dim);
  text-align: center;
  margin: 14px 0 0;
}

.upload.is-dragging {
  border-color: var(--brand);
  background: linear-gradient(180deg, rgba(240, 217, 160, 0.06), var(--surface));
}

/* Only seen when JavaScript hasn't run; the enhanced path replaces it
   with the styled label. */
.upload input[type="file"] {
  max-width: 260px;
  margin: 0 auto 14px;
  display: block;
  font-size: 13px;
  color: var(--muted);
}

.upload-chosen {
  font-family: var(--mono);
  font-size: 14px;
  color: var(--text);
  margin: 0 0 16px;
  word-break: break-all;
}

.alert {
  background: rgba(224, 100, 90, 0.10);
  border: 1px solid rgba(224, 100, 90, 0.4);
  color: var(--text);
  border-radius: 10px;
  padding: 14px 18px;
  margin: 0 auto 24px;
  max-width: 620px;
  font-size: 15px;
  text-align: left;
}

.counter {
  font-size: 11px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--dim);
  text-align: center;
  margin: 32px 0 0;
}

/* --- Section furniture ------------------------------------------ */

.section-label {
  font-family: var(--mono);
  font-size: 12px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--dim);
  margin: 0 0 12px;
  text-align: center;
}

.section-note {
  font-size: 15px;
  color: var(--muted);
  text-align: center;
  max-width: 460px;
  margin: 0 auto 28px;
}

/* --- Sample scorecard ------------------------------------------- */

.sample { padding: 32px 0 72px; }

.scorecard {
  background: var(--card-bg);
  border: 1px solid var(--border);
  border-radius: 14px;
  box-shadow: var(--card-shadow);
  padding: 40px 36px 36px;
}

/* The landing page shows a filled-in scorecard so a visitor can see the
   output before handing over a file. It has to be unmistakably a sample
   and not mistaken for their own result. */
.scorecard.is-example { position: relative; }

.example-badge {
  position: absolute;
  top: 14px;
  left: 16px;
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--dim);
  border: 1px solid var(--border-lit);
  border-radius: 4px;
  padding: 3px 8px;
}

/* Grade stacked above the title, both centred. */
.scorecard-head {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 20px;
  margin-bottom: 28px;
  text-align: center;
}

/* --- The grade, struck rather than printed ---------------------------
   This is the one thing Assay makes that nobody else does, so it should
   be unmistakable. An assay is a purity test and a hallmark is the stamp
   struck into metal once it passes, which is where the shape comes from.

   The letter sits inside a lozenge outline, lit from the top and inset at
   the bottom so it reads as pressed into the surface instead of sitting
   on it. The colour still comes entirely from the verdict classes below;
   nothing here tints it. */
.grade {
  position: relative;
  width: 116px;
  height: 116px;
  flex-shrink: 0;
  border-radius: 16px;
  display: grid;
  place-items: center;
  font-family: var(--display);
  font-size: 52px;
  font-weight: 700;
  isolation: isolate;
}

/* The hallmark itself, behind the letter. currentColor means it always
   agrees with the verdict without another rule per grade. */
/* Inset far enough that the rotated square's corners stay inside the
   badge. A square of side s has a diagonal of s * 1.414, so at inset 12
   on a 104px badge the diamond measured 113px across and its points
   pushed out past the edges — which read as two shapes colliding rather
   than one mark struck into the other. 20px on 116px leaves the diagonal
   at 107px, with clearance on every side. */
.grade::before {
  content: "";
  position: absolute;
  inset: 20px;
  z-index: -1;
  border: 1.5px solid currentColor;
  opacity: 0.3;
  transform: rotate(45deg);
  border-radius: 3px;
}

/* Struck, not printed: a light top edge and a shadow cast inward from
   the bottom, which is what a stamped impression does to the light. */
.grade::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  border-radius: 16px;
  pointer-events: none;
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.14),
    inset 0 -10px 20px -12px rgba(0, 0, 0, 0.85);
}

.grade-mark {
  display: block;
  width: 116px;
  height: 1px;
  margin: 14px auto 0;
  background: linear-gradient(
    90deg,
    transparent,
    rgba(240, 217, 160, 0.55) 30%,
    rgba(240, 217, 160, 0.55) 70%,
    transparent
  );
}

/* --- Hallmark divider -------------------------------------------------
   A hairline that breaks around the mark. Used between sections instead
   of a plain rule, so the motif recurs down the page rather than sitting
   in the header on its own. */
.hallmark-rule {
  display: flex;
  align-items: center;
  gap: 16px;
  margin: 0 auto;
  max-width: 620px;
  color: var(--border-lit);
}

.hallmark-rule::before,
.hallmark-rule::after {
  content: "";
  flex: 1;
  height: 1px;
  background: linear-gradient(90deg, transparent, var(--border) 50%, transparent);
}

.hallmark-rule svg {
  width: 14px;
  height: 14px;
  flex-shrink: 0;
  color: var(--brand);
  opacity: 0.55;
}

@media (max-width: 640px) {
  .grade { width: 96px; height: 96px; font-size: 46px; }
  .grade::before { inset: 16px; }
  .grade-mark { width: 96px; }
}

.grade-a {
  color: var(--pass);
  background: linear-gradient(180deg, rgba(69, 192, 138, 0.20), rgba(69, 192, 138, 0.06));
  border: 1px solid rgba(69, 192, 138, 0.35);
  box-shadow: 0 0 40px rgba(69, 192, 138, 0.18);
}

.grade-c {
  color: var(--warn);
  background: linear-gradient(180deg, rgba(224, 149, 47, 0.20), rgba(224, 149, 47, 0.06));
  border: 1px solid rgba(224, 149, 47, 0.35);
  box-shadow: 0 0 40px rgba(224, 149, 47, 0.18);
}

.grade-d,
.grade-f {
  color: var(--fail);
  background: linear-gradient(180deg, rgba(224, 100, 90, 0.20), rgba(224, 100, 90, 0.06));
  border: 1px solid rgba(224, 100, 90, 0.35);
  box-shadow: 0 0 40px rgba(224, 100, 90, 0.18);
}

.scorecard-title h2 { font-size: 24px; font-weight: 600; margin-bottom: 6px; }
.scorecard-title p { font-size: 13px; margin: 0; letter-spacing: 0.02em; }

.verdict-line {
  font-size: 18px;
  line-height: 1.55;
  max-width: 660px;
  margin: 0 auto 32px;
  text-align: center;
}

/* Findings stay left-aligned — this is data, not prose. */
.findings {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 1px;
  background: var(--border);
  border: 1px solid var(--border);
  border-radius: 10px;
  overflow: hidden;
  text-align: left;
}

.finding { background: var(--surface-2); }

/* Left edge bar tints each row without colouring the text. */
.finding.pass { box-shadow: inset 2px 0 0 var(--pass); }
.finding.warn { box-shadow: inset 2px 0 0 var(--warn); }
.finding.fail { box-shadow: inset 2px 0 0 var(--fail); }
.finding.unknown { box-shadow: inset 2px 0 0 var(--dim); }

/* Each row expands to its reasoning. Native <details> rather than
   scripted panels: it works with JavaScript off, it is keyboard
   operable, and browser find-in-page can open a closed row. */
.finding summary {
  display: flex;
  gap: 18px;
  align-items: baseline;
  padding: 16px 20px;
  cursor: pointer;
  list-style: none;
  transition: background 0.15s ease;
}

.finding summary::-webkit-details-marker { display: none; }
.finding summary:hover { background: rgba(255, 255, 255, 0.028); }

.finding summary:focus-visible {
  outline: 2px solid var(--border-lit);
  outline-offset: -2px;
}

.finding-mark {
  font-family: var(--mono);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.1em;
  flex-shrink: 0;
  width: 44px;
}

.finding.pass .finding-mark { color: var(--pass); }
.finding.warn .finding-mark { color: var(--warn); }
.finding.fail .finding-mark { color: var(--fail); }
.finding.unknown .finding-mark { color: var(--dim); }

.finding-text { font-size: 15px; color: var(--muted); flex: 1; }
.finding-text strong { color: var(--text); font-weight: 600; }

/* Chevron, drawn in CSS so there is no icon file to load. */
.finding-toggle {
  flex-shrink: 0;
  width: 8px;
  height: 8px;
  margin-left: 8px;
  align-self: center;
  border-right: 1.5px solid var(--dim);
  border-bottom: 1.5px solid var(--dim);
  transform: rotate(45deg) translate(-2px, -2px);
  transition: transform 0.18s ease, border-color 0.15s ease;
}

.finding summary:hover .finding-toggle { border-color: var(--text); }

.finding details[open] .finding-toggle {
  transform: rotate(-135deg) translate(-2px, -2px);
}

@media (prefers-reduced-motion: reduce) {
  .finding-toggle { transition: none; }
}

.finding-detail {
  font-size: 15px;
  line-height: 1.6;
  color: var(--muted);
  margin: 0;
  padding: 0 20px 20px 82px;
}

.findings-hint {
  font-size: 13px;
  color: var(--dim);
  text-align: center;
  margin: 16px 0 0;
}

/* --- The four checks -------------------------------------------- */

.checks { padding: 48px 0 104px; }

.check-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 20px;
}

.check {
  background: var(--card-bg);
  border: 1px solid var(--border);
  border-radius: 14px;
  box-shadow: var(--card-shadow);
  padding: 32px 28px;
  text-align: center;
  transition: border-color 0.18s ease, transform 0.18s ease;
}

.check:hover {
  border-color: var(--border-lit);
  transform: translateY(-2px);
}

.check-number { font-size: 12px; color: var(--dim); margin: 0 0 16px; }
.check h3 { font-size: 19px; font-weight: 600; margin-bottom: 10px; }

.check-question {
  font-family: var(--display);
  font-size: 15px;
  color: var(--text);
  margin: 0 0 14px;
}

.check-detail { font-size: 14px; color: var(--muted); margin: 0; }

/* --- Report page ------------------------------------------------ */

.report { padding: 56px 0 96px; }

.grade-b { color: var(--pass); background: linear-gradient(180deg, rgba(69, 192, 138, 0.20), rgba(69, 192, 138, 0.06)); border: 1px solid rgba(69, 192, 138, 0.35); box-shadow: 0 0 40px rgba(69, 192, 138, 0.18); }

.scorecard-title h1 { font-size: 26px; font-weight: 600; margin-bottom: 6px; }

/* Headline figures */
.figures {
  display: grid;
  grid-template-columns: repeat(6, 1fr);
  gap: 1px;
  background: var(--border);
  border: 1px solid var(--border);
  border-radius: 12px;
  overflow: hidden;
  margin: 24px 0 0;
}

.figure { background: var(--surface); padding: 20px 14px; text-align: center; }

.figure-value {
  font-size: 22px;
  font-weight: 600;
  color: var(--text);
  margin: 0 0 4px;
}

.figure-label {
  font-size: 11px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--dim);
  margin: 0;
}

.note {
  font-size: 14px;
  color: var(--dim);
  text-align: center;
  margin: 20px auto 0;
  max-width: 640px;
}

/* Equity curve */

.curve {
  margin: 32px 0 0;
  padding: 24px 24px 18px;
  background: var(--card-bg);
  border: 1px solid var(--border);
  border-radius: 12px;
  box-shadow: var(--card-shadow);
}

.curve-head {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  align-items: baseline;
  gap: 10px;
  margin-bottom: 16px;
}

.curve-head .section-label { margin: 0; text-align: left; }
.curve-meta { font-size: 12px; color: var(--dim); }

/* Uniform scaling: the labels inside must not be stretched. */
.curve-svg {
  width: 100%;
  height: auto;
  display: block;
}

.curve-axis {
  font-family: var(--mono);
  font-size: 15px;
  fill: var(--dim);
}

.curve-final {
  font-family: var(--mono);
  font-size: 16px;
  font-weight: 600;
  fill: var(--text);
}

.curve-tag {
  font-family: var(--sans);
  font-size: 15px;
  fill: var(--fail);
}

.curve-grid {
  stroke: var(--border-lit);
  stroke-width: 1;
  stroke-dasharray: 2 5;
}

/* The line is data, so it stays neutral. The drawdown band is a
   judgement, so it gets colour. */
.curve-line {
  fill: none;
  stroke: var(--text);
  stroke-width: 1.5;
  vector-effect: non-scaling-stroke;
  stroke-linejoin: round;
}

.curve-area { fill: rgba(233, 236, 241, 0.06); stroke: none; }

.curve-zero {
  stroke: var(--border-lit);
  stroke-width: 1;
  stroke-dasharray: 3 4;
  vector-effect: non-scaling-stroke;
}

.curve-dd { fill: rgba(224, 100, 90, 0.13); }

.curve-key {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 12px;
  color: var(--dim);
  margin: 14px 0 0;
}

.curve-key-swatch {
  width: 22px;
  height: 10px;
  border-radius: 2px;
  background: rgba(224, 100, 90, 0.28);
  flex-shrink: 0;
}

/* Recent reports, populated from localStorage */

.recent { margin: 48px auto 0; max-width: 620px; text-align: left; }
.recent .section-label { text-align: left; margin-bottom: 12px; }

.recent-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 1px;
  background: var(--border);
  border: 1px solid var(--border);
  border-radius: 10px;
  overflow: hidden;
}

.recent-item a {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 12px 16px;
  background: var(--surface-2);
  text-decoration: none;
  transition: background 0.15s ease;
}

.recent-item a:hover { background: rgba(255, 255, 255, 0.035); }

.recent-grade {
  font-family: var(--display);
  font-weight: 700;
  font-size: 15px;
  width: 26px;
  height: 26px;
  border-radius: 5px;
  display: grid;
  place-items: center;
  flex-shrink: 0;
  box-shadow: none;
}

.recent-title {
  color: var(--text);
  font-size: 15px;
  flex: 1;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.recent-meta { color: var(--dim); font-size: 12px; flex-shrink: 0; }

.recent-note { font-size: 12px; color: var(--dim); margin: 12px 0 0; }

/* Client report builder form */

.studio-form { margin-top: 32px; }

.field { display: block; margin-bottom: 24px; }

.field-label {
  display: block;
  font-size: 14px;
  font-weight: 500;
  color: var(--text);
  margin-bottom: 6px;
}

.field select,
.field input[type="text"],
.field textarea {
  width: 100%;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: 8px;
  color: var(--text);
  font-family: var(--sans);
  font-size: 15px;
  padding: 10px 14px;
}

.field input[type="file"] { color: var(--muted); font-size: 14px; }

.field input:focus,
.field textarea:focus { outline: none; border-color: var(--border-lit); }

.field-hint { display: block; font-size: 13px; color: var(--dim); margin-top: 6px; }

.field-row { display: grid; grid-template-columns: repeat(3, 1fr); gap: 16px; }
.field-row .field { margin-bottom: 24px; }

@media (max-width: 640px) {
  .field-row { grid-template-columns: 1fr; }
}

.linkish {
  background: none;
  border: 0;
  padding: 0;
  color: var(--muted);
  font: inherit;
  text-decoration: underline;
  cursor: pointer;
}

.linkish:hover { color: var(--text); }

/* Share */
.share { margin-top: 64px; }

.share-card {
  width: 100%;
  height: auto;
  border-radius: 12px;
  border: 1px solid var(--border);
  box-shadow: var(--card-shadow);
  display: block;
}

.share-note { font-size: 14px; color: var(--muted); margin: 18px 0 0; word-break: break-all; }
.share-note a { color: var(--brand); }

.again { margin-top: 56px; }

/* --- Legal pages ------------------------------------------------ */

.legal { padding: 72px 0 96px; text-align: left; }
.legal .wrap { max-width: 720px; }

.legal .eyebrow { text-align: left; }
.legal h1 { font-size: clamp(34px, 5vw, 46px); font-weight: 700; margin-bottom: 24px; }
.legal .lede { margin: 0 0 48px; max-width: none; }

.legal h2 {
  font-size: 20px;
  font-weight: 600;
  margin: 44px 0 12px;
  padding-top: 24px;
  border-top: 1px solid var(--border);
}

.legal p { color: var(--muted); font-size: 16px; margin: 0 0 14px; }
.legal p strong { color: var(--text); }
.legal .mono { color: var(--text); font-size: 14px; }

.legal-list { color: var(--muted); font-size: 16px; margin: 0 0 16px; padding-left: 20px; }
.legal-list li { margin-bottom: 8px; }

.legal-note {
  border-left: 2px solid var(--border-lit);
  padding-left: 16px;
  font-size: 15px;
}

.legal-formula {
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 14px 18px;
  font-size: 14px;
  color: var(--text);
  overflow-x: auto;
}

/* Was a single button; the 404 page puts two side by side, and
   inline-block gives them a 4px word-space and a baseline mismatch. */
.legal .again {
  margin-top: 48px;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 12px;
}

/* --- Footer ----------------------------------------------------- */

.footer {
  border-top: 1px solid var(--border);
  padding: 40px 0 60px;
  text-align: center;
}

.disclaimer {
  font-size: 13px;
  color: var(--dim);
  max-width: 620px;
  margin: 0 auto 18px;
}

.copyright {
  font-family: var(--mono);
  font-size: 12px;
  color: var(--dim);
  margin: 0;
}

.copyright a { color: var(--muted); text-decoration: none; }
.copyright a:hover { color: var(--text); }

/* --- Small screens ---------------------------------------------- */

@media (max-width: 940px) {
  .tagline { display: none; }
  .topnav a:not(.btn) { display: none; }
}

/* --- Print -------------------------------------------------------
   The report is the deliverable, so "Save as PDF" from the browser
   should produce something worth keeping: black on white, every
   finding expanded, and none of the site furniture.
   ----------------------------------------------------------------- */

@media print {
  @page { margin: 16mm; }

  :root {
    --text: #101418;
    --muted: #3d4550;
    --dim: #6b7280;
    --border: #d4d8de;
    --border-lit: #b8bec7;
    --surface: #ffffff;
    --surface-2: #ffffff;
    --card-bg: #ffffff;
    --card-shadow: none;
  }

  body { background: #ffffff; color: #101418; }

  .topbar,
  .topnav,
  .hero,
  .checks,
  .share,
  .again,
  .recent,
  .findings-hint,
  .curve-key,
  .footer .copyright { display: none !important; }

  .report { padding: 0; }
  .wrap { max-width: none; padding: 0; }

  .scorecard,
  .curve,
  .figures {
    border: 1px solid #d4d8de;
    box-shadow: none;
    break-inside: avoid;
  }

  /* Print every finding open, whatever the reader left collapsed. */
  .finding details > *:not(summary) { display: block !important; }
  .finding summary { cursor: default; }
  .finding-toggle { display: none !important; }
  .finding { break-inside: avoid; }

  .curve-line { stroke: #101418; }
  .curve-area { fill: rgba(16, 20, 24, 0.06); }
  .curve-dd { fill: rgba(224, 100, 90, 0.18); }

  .grade { box-shadow: none; }

  .footer { border-top: 1px solid #d4d8de; }
  .disclaimer { color: #6b7280; }

  a[href]::after { content: ""; }
}

@media (max-width: 860px) {
  .figures { grid-template-columns: repeat(3, 1fr); }
}

@media (max-width: 720px) {
  .hero { padding: 60px 0 52px; }
  .figures { grid-template-columns: repeat(2, 1fr); }
  .finding summary { padding: 14px 16px; gap: 12px; }
  .finding-detail { padding: 0 16px 18px 16px; }
  .check-grid { grid-template-columns: 1fr; }
  .scorecard { padding: 28px 20px; }
  .topbar-inner { height: 68px; }
  .wordmark { font-size: 20px; letter-spacing: 0.2em; }
  .wordmark .mark { width: 25px; height: 25px; }
  .verdict-line { font-size: 16px; }
}


/* --- Equity curve, drawn rather than presented ------------------------
   The moment the report earns its keep, so it is worth a second of the
   reader's attention. pathLength="1" on the polyline normalises its
   length regardless of how many trades it holds, so one dasharray works
   for every report and no JavaScript has to measure anything.

   It runs once, forwards, and leaves the line exactly where it would
   have been anyway — so if the animation never runs, nothing is lost.
   That matters more than usual here: the chart is part of a document
   people print. */
@keyframes curve-draw {
  from { stroke-dashoffset: 1; }
  to   { stroke-dashoffset: 0; }
}

.curve-line[pathLength] {
  stroke-dasharray: 1;
  stroke-dashoffset: 0;
  animation: curve-draw 1.1s ease-out both;
}

@media (prefers-reduced-motion: reduce) {
  .curve-line[pathLength] { animation: none; stroke-dashoffset: 0; }
}

@media print {
  .curve-line[pathLength] { animation: none; stroke-dashoffset: 0; }
}


/* --- Arrival ----------------------------------------------------------
   A staged entrance rather than a splash screen. Everything below is
   already in the DOM and already interactive when this runs: the page is
   never gated on an animation, because the visitor arriving from a forum
   link has one question and making them wait to ask it is a poor trade.

   Every rule here is switched off wholesale for reduced motion at the
   bottom of this section, and none of it changes a final position — if
   it never runs, the page is exactly the page. */

@keyframes rise {
  from { opacity: 0; transform: translateY(14px); }
  to   { opacity: 1; transform: none; }
}

/* The mark is struck, not faded: it overshoots slightly and settles,
   which is what a stamp hitting metal looks like. */
@keyframes strike {
  0%   { opacity: 0; transform: scale(2.1) rotate(-12deg); }
  55%  { opacity: 1; transform: scale(0.92) rotate(2deg); }
  100% { opacity: 1; transform: none; }
}

.hero .eyebrow,
.hero h1,
.hero .lede,
.hero .upload,
.hero .upload-note {
  animation: rise 0.55s cubic-bezier(0.22, 0.8, 0.3, 1) both;
}

.hero .eyebrow     { animation-delay: 0.04s; }
.hero h1           { animation-delay: 0.12s; }
.hero .lede        { animation-delay: 0.22s; }
.hero .upload      { animation-delay: 0.32s; }
.hero .upload-note { animation-delay: 0.40s; }

.wordmark .mark {
  animation: strike 0.45s cubic-bezier(0.3, 1.4, 0.5, 1) both;
  transform-origin: center;
}

/* --- Intro ------------------------------------------------------------
   Shown once per session, and only when JavaScript has decided it should
   be: the class is set on <html> by a tiny script in the head, before
   first paint, so the page never flashes underneath it. No script, no
   class, no overlay — which is also what a reduced-motion visitor and
   every returning visitor get. */

.intro-overlay {
  position: fixed;
  inset: 0;
  z-index: 100;
  display: none;
  place-items: center;
  background: var(--bg);
}

.intro .intro-overlay { display: grid; }

.intro-overlay-inner { text-align: center; }

/* The three parts arrive in order rather than as one block: the mark is
   struck, then the name, then the question. Sized to fill the screen it
   is sitting on — it is the only thing there, so being modest about it
   just reads as small. */
.intro-overlay .mark {
  width: clamp(72px, 14vw, 104px);
  height: clamp(72px, 14vw, 104px);
  color: var(--brand);
  animation: strike 0.6s cubic-bezier(0.3, 1.4, 0.5, 1) both;
}

.intro-word {
  font-family: var(--display);
  font-size: clamp(38px, 9vw, 62px);
  font-weight: 700;
  letter-spacing: 0.30em;
  margin: 26px 0 14px;
  /* Letter-spacing is applied after the last character too, so without
     this the word sits left of centre by half a space. */
  padding-left: 0.30em;
  animation: rise 0.55s ease-out 0.34s both;
}

.intro-goal {
  font-family: var(--mono);
  font-size: clamp(13px, 2.6vw, 16px);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--dim);
  margin: 0;
  animation: rise 0.55s ease-out 0.5s both;
}

/* The overlay clears itself in CSS, and that is deliberate.

   An earlier version had JavaScript remove it and paused the hero
   underneath while it was up. If anything in the script block below it
   had thrown, the overlay would have stayed forever over a hero frozen
   at opacity 0 — a permanently blank page, caused by a decoration. So
   the exit is an animation with a fill, which cannot fail to finish, and
   the script only makes it faster and records that it has been seen. */
@keyframes intro-out {
  to { opacity: 0; visibility: hidden; }
}

.intro .intro-overlay {
  display: grid;
  animation: intro-out 0.45s ease 1.9s both;
}

/* Skipped early: overtake the timed exit rather than wait for it. */
.intro-overlay.is-leaving {
  animation: none;
  opacity: 0;
  visibility: hidden;
  transition: opacity 0.3s ease;
  pointer-events: none;
}

/* Under the overlay the hero waits, but by delay rather than by pause —
   a delay always resolves. Dropping .intro re-runs these with the short
   delays above, which is what a skip should look like. */
.intro .hero .eyebrow     { animation-delay: 1.95s; }
.intro .hero h1           { animation-delay: 2.03s; }
.intro .hero .lede        { animation-delay: 2.13s; }
.intro .hero .upload      { animation-delay: 2.23s; }
.intro .hero .upload-note { animation-delay: 2.31s; }

/* --- Findings, revealed as they arrive -------------------------------- */
.finding.will-reveal { opacity: 0; transform: translateY(10px); }

.finding.is-revealed {
  opacity: 1;
  transform: none;
  transition: opacity 0.4s ease-out, transform 0.4s ease-out;
}

@media (prefers-reduced-motion: reduce) {
  .hero .eyebrow,
  .hero h1,
  .hero .lede,
  .hero .upload,
  .hero .upload-note,
  .wordmark .mark,
  .intro-overlay .mark,
  .intro-word,
  .intro-goal { animation: none; }

  .finding.will-reveal { opacity: 1; transform: none; }
  .intro-overlay.is-leaving { transition: none; }
}

@media print {
  .intro-overlay { display: none !important; }
  .finding.will-reveal { opacity: 1; transform: none; }
}


/* --- The same export, read two ways ----------------------------------
   The landing page asserts that a strategy tester gives numbers and never
   a verdict. This shows it rather than claiming it, with one strategy's
   real figures on both sides.

   The left panel is deliberately plain. It is not a straw man — those
   numbers are true, and the point is that being true is not the same as
   being enough. */
.versus { padding: 8px 0 64px; }

.versus-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 20px;
  align-items: stretch;
  max-width: 900px;
  margin: 0 auto;
}

.versus-panel {
  background: var(--card-bg);
  border: 1px solid var(--border);
  border-radius: 14px;
  padding: 26px 24px;
  display: flex;
  flex-direction: column;
}

/* The verdict side carries the weight — a lit border and the depth the
   plain side does not get. */
.versus-panel.is-assay {
  border-color: var(--border-lit);
  box-shadow: var(--card-shadow);
}

.versus-head {
  font-size: 11px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--dim);
  margin: 0 0 18px;
}

.versus-figures { margin: 0; }

.versus-figures > div {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 16px;
  padding: 11px 0;
  border-bottom: 1px solid var(--border);
}

.versus-figures > div:last-child { border-bottom: 0; }
.versus-figures dt { color: var(--muted); font-size: 15px; }

.versus-figures dd {
  margin: 0;
  font-size: 19px;
  color: var(--text);
  font-variant-numeric: tabular-nums;
}

.versus-verdict {
  font-size: 17px;
  line-height: 1.5;
  margin: 0 0 18px;
}

.versus-points {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 12px;
}

/* Two columns, so each row must have exactly two children. The text
   after the mark is wrapped in a span for that reason: left bare, every
   <strong> inside it became a grid item of its own alongside the
   anonymous text runs either side, and a sentence with two of them was
   dealt out across three rows. */
.versus-points li {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 10px;
  align-items: start;
  font-size: 14px;
  line-height: 1.5;
  color: var(--muted);
}

.versus-points strong { color: var(--text); font-weight: 600; }

/* The verdict colours are scoped to .finding, and these rows are not
   findings. Without this the marks render grey, which loses the one
   distinction the panel exists to draw. */
.versus-points li.pass .finding-mark { color: var(--pass); }
.versus-points li.warn .finding-mark { color: var(--warn); }
.versus-points li.fail .finding-mark { color: var(--fail); }

.versus-foot {
  font-size: 13px;
  color: var(--dim);
  margin: 18px 0 0;
  padding-top: 16px;
  border-top: 1px solid var(--border);
}

/* Verdict side last on a phone, so the answer follows the numbers
   rather than sitting above them. */
@media (max-width: 720px) {
  .versus-grid { grid-template-columns: 1fr; }
}

/* --- Grade distribution ----------------------------------------------
   Evidence rather than a claim, which is the only marketing this product
   is allowed to do. It also gives a grade meaning: a B reads differently
   once you can see what most submissions get. */
.distribution { max-width: 620px; margin: 0 auto; }

/* The grade classes exist to draw a scorecard badge, so they carry a
   background, a border and a glow. Here only the colour is wanted. */
.dist-col,
.dist-letter {
  background: none;
  border: 0;
  box-shadow: none;
  border-radius: 0;
}

.dist-letter { border-top: 1px solid var(--border); }

.dist-bars {
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  gap: 10px;
  align-items: end;
  height: 132px;
  margin-bottom: 10px;
}

.dist-col {
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  height: 100%;
  gap: 8px;
}

.dist-share {
  font-family: var(--mono);
  font-size: 12px;
  color: var(--muted);
  text-align: center;
  font-variant-numeric: tabular-nums;
}

.dist-bar {
  border-radius: 5px 5px 0 0;
  min-height: 3px;
  background: currentColor;
  opacity: 0.55;
}

.dist-labels {
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  gap: 10px;
}

.dist-letter {
  font-family: var(--display);
  font-size: 15px;
  font-weight: 700;
  text-align: center;
  padding-top: 8px;
  border-top: 1px solid var(--border);
}

.dist-note {
  text-align: center;
  font-size: 13px;
  color: var(--dim);
  margin: 16px 0 0;
}


/* --- Condensed report header ------------------------------------------
   Sits under the top bar once the scorecard has scrolled away. Hidden
   until script says otherwise, so without JavaScript it never appears
   and the page is unchanged. */
.report-bar {
  position: sticky;
  top: 68px;
  z-index: 20;
  background: rgba(10, 12, 15, 0.92);
  backdrop-filter: blur(8px);
  border-bottom: 1px solid var(--border);
}

.report-bar-inner {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 10px 0;
}

.report-bar-grade {
  width: 30px;
  height: 30px;
  flex-shrink: 0;
  border-radius: 7px;
  display: grid;
  place-items: center;
  font-family: var(--display);
  font-size: 16px;
  font-weight: 700;
  box-shadow: none;
}

.report-bar-title {
  font-weight: 600;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.report-bar-meta {
  margin-left: auto;
  font-size: 13px;
  color: var(--dim);
  flex-shrink: 0;
}

.btn.is-copied {
  color: var(--pass);
  border-color: rgba(69, 192, 138, 0.45);
}

@media (max-width: 640px) {
  .report-bar-meta { display: none; }
}

@media print {
  .report-bar { display: none !important; }
}


/* --- The rest of the example report ----------------------------------
   The landing page showed a grade, a verdict and four findings, which is
   about half of what a report actually contains. Folding the remainder
   in keeps the page short without underselling the thing being sold.

   <details> rather than script: it opens without JavaScript, it is
   keyboard-operable for free, and the print stylesheet can force it
   open. The findings above already use the same element. */
.example-more {
  margin-top: 22px;
  border-top: 1px solid var(--border);
}

.example-more > summary {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  padding: 16px 0 4px;
  cursor: pointer;
  list-style: none;
  font-size: 14px;
  color: var(--muted);
  transition: color 0.15s ease;
}

.example-more > summary::-webkit-details-marker { display: none; }
.example-more > summary:hover { color: var(--text); }

/* The chevron rotates on open, so the control says which way it goes. */
.example-more > summary .finding-toggle { transition: transform 0.2s ease; }
.example-more[open] > summary .finding-toggle { transform: rotate(180deg); }

.example-more[open] > summary { color: var(--text); }

.example-more-body { padding-top: 6px; }

/* Five figures, not six: expectancy is not recoverable from the text on
   this page and is therefore absent rather than guessed. */
.example-more .figures { grid-template-columns: repeat(5, 1fr); }

.example-detail {
  margin: 20px 0 0;
  border: 1px solid var(--border);
  border-radius: 12px;
  overflow: hidden;
}

.example-detail > div {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 16px;
  padding: 12px 18px;
  border-bottom: 1px solid var(--border);
  background: var(--surface);
}

.example-detail > div:last-child { border-bottom: 0; }
.example-detail dt { color: var(--muted); font-size: 14px; }

.example-detail dd {
  margin: 0;
  font-size: 14px;
  color: var(--text);
  font-variant-numeric: tabular-nums;
}

.example-more-note {
  font-size: 13px;
  line-height: 1.6;
  color: var(--dim);
  margin: 18px 0 0;
  text-align: center;
}

@media (max-width: 720px) {
  .example-more .figures { grid-template-columns: repeat(2, 1fr); }
  .example-detail > div { flex-direction: column; gap: 2px; }
}

@media print {
  .example-more[open] > summary .finding-toggle { transform: none; }
}


/* --- Reporting a problem with a report -------------------------------
   Quiet by design. It should be findable by someone who has spotted a
   wrong number and invisible to everyone else, so it sits at the very
   bottom, below the actions, in the muted register the footer uses. */
.correction {
  margin-top: 48px;
  padding-top: 28px;
  border-top: 1px solid var(--border);
  text-align: center;
}

.correction-text {
  font-size: 14px;
  line-height: 1.6;
  color: var(--muted);
  max-width: 520px;
  margin: 0 auto 18px;
}

.correction-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 14px;
  margin: 0;
}

.correction-address {
  font-size: 13px;
  color: var(--dim);
}

/* A printed report is a document, not a page you can click. The address
   still matters, so it stays; the button does not. */
@media print {
  .correction-actions .btn { display: none; }
  .correction { break-inside: avoid; }
}


/* The grade, inline with the verdict sentence on the comparison panel.
   Small: the scorecard below is where it gets to be the headline. */
.versus-grade {
  display: inline-grid;
  place-items: center;
  width: 30px;
  height: 30px;
  border-radius: 7px;
  margin-right: 8px;
  vertical-align: -6px;
  font-family: var(--display);
  font-size: 16px;
  font-weight: 700;
  box-shadow: none;
}

.versus-verdict { line-height: 1.55; }
