/* Self-contained on purpose: this folder is also the zip the owner unpacks, so it
   cannot reach for the main site's stylesheet one directory up. */

/* --- design tokens (task 15.8) -----------------------------------------------------
   The same restraint as the main site, in a file that cannot share its stylesheet: this
   folder is also the zip the owner unpacks, so it may not reach one directory up.

   One accent, and it is not green. Green and red mean exactly one thing here - a return
   above or below zero - and an accent that shared the colour would make every heading
   read as a verdict. Anything computed from too few bets still gets no colour at all.

   Dark mode is a full token swap rather than a filter, so the neutrality rule survives
   it: a grey number stays grey, and a red one stays legible. */

:root {
  --ink: #16181d;
  --muted: #62666f;
  --line: #e3e5e9;
  --bg: #f7f8fa;
  --panel: #ffffff;
  --panel-2: #eef0f4;

  --accent: #2c5fd0;
  --accent-soft: #e8eefc;
  --accent-ink: #17436e;

  --pos: #0f7a46;
  --neg: #b3261e;
  --warn-bg: #fff6e5;
  --warn-line: #e0b46a;
  --warn-ink: #9a5b06;

  --gap-no-data: #fdf3f3;
  --gap-never-priced: #f4f0fa;
  --gap-off: #f2f2f2;

  --t-xs: .74rem;
  --t-sm: .84rem;
  --t-base: 15px;
  --t-md: 1rem;
  --t-lg: 1.15rem;
  --t-xl: 1.6rem;

  --radius: 8px;
  --radius-sm: 5px;
}

@media (prefers-color-scheme: dark) {
  :root {
    --ink: #e7e9ee;
    --muted: #9aa0ab;
    --line: #2b2f37;
    --bg: #101216;
    --panel: #171a20;
    --panel-2: #1d212a;

    --accent: #7aa2f7;
    --accent-soft: #1b2540;
    --accent-ink: #b9cdfb;

    --pos: #4ec08a;
    --neg: #f07c74;
    --warn-bg: #2a2113;
    --warn-line: #6b5320;
    --warn-ink: #dba33a;

    --gap-no-data: #2a1a1a;
    --gap-never-priced: #211b2c;
    --gap-off: #1c1f25;
  }
}

* { box-sizing: border-box; }

body {
  margin: 0 auto;
  padding: 1.5rem 1.25rem 4rem;
  max-width: 1180px;
  font: 15px/1.55 -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  color: var(--ink);
  background: var(--bg);
}

h1 { font-size: 1.6rem; margin: 0 0 .4rem; }
h2 { font-size: 1.15rem; margin: 2.2rem 0 .5rem; }
h3 { font-size: 1rem; margin: 0 0 .1rem; }
h4 { font-size: .92rem; margin: 0 0 .4rem; }

.lead { max-width: 62rem; margin: 0; }
.hint, .fineprint { color: var(--muted); max-width: 62rem; }
.fineprint { font-size: .84rem; }
code { background: var(--panel-2); padding: 0 .25em; border-radius: 3px; font-size: .9em; }

section { border-top: 1px solid var(--line); padding-top: .3rem; }

/* The warning block is meant to be read, so it is not styled as decoration. */
.warn {
  background: var(--warn-bg);
  border: 1px solid var(--warn-line);
  border-radius: 6px;
  padding: .8rem 1rem;
  margin: 1.4rem 0;
}
.warn h2 { margin: 0 0 .4rem; font-size: 1rem; color: var(--warn-ink); }
.warn p { margin: .45rem 0; max-width: 62rem; }

/* --- 14.4 two windows, never merged ------------------------------------------------ */

.windows { display: flex; gap: 1rem; flex-wrap: wrap; }
.window {
  flex: 1 1 460px;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 6px;
  padding: .8rem 1rem 1rem;
}
.subtitle { color: var(--muted); font-size: .85rem; margin: 0 0 .6rem; }

table { border-collapse: collapse; width: 100%; margin: .5rem 0; font-size: .89rem; }
caption { text-align: left; font-weight: 600; padding: .4rem 0 .2rem; }
th, td { text-align: left; padding: .3rem .4rem; border-bottom: 1px solid var(--line); }
thead th { font-size: .8rem; color: var(--muted); font-weight: 600; }
tbody th { font-weight: 500; }
.money td, .accuracy td { vertical-align: top; }

.need {
  display: block;
  font-size: .76rem;
  color: var(--muted);
}
.pin {
  font-size: .7rem;
  background: var(--accent-soft);
  border-radius: 3px;
  padding: 0 .3em;
  color: var(--accent-ink);
}
tr.baseline { background: var(--panel-2); }

.roi { font-variant-numeric: tabular-nums; font-weight: 600; }
.roi.pos { color: var(--pos); }
.roi.neg { color: var(--neg); }
/* A return computed from a handful of bets gets no colour at all, on purpose. */
.roi.thin, .roi.none { color: var(--muted); font-weight: 500; }
.thin-label { display: block; font-size: .74rem; font-weight: 400; }

.pos { color: var(--pos); }
.neg { color: var(--neg); }

/* --- 14.3 sliders ------------------------------------------------------------------ */

.controls { display: flex; align-items: center; gap: .6rem; flex-wrap: wrap; }
button {
  font: inherit;
  padding: .35rem .8rem;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  background: var(--panel);
  color: var(--ink);
  cursor: pointer;
}
button:hover { background: var(--panel-2); }

#weight-panel { display: flex; gap: .8rem; flex-wrap: wrap; }
.pool {
  flex: 1 1 340px;
  border: 1px solid var(--line);
  border-radius: 6px;
  background: var(--panel);
  padding: .4rem .8rem .7rem;
}
legend { font-weight: 600; font-size: .92rem; }
.budget { font-weight: 400; color: var(--muted); font-size: .82rem; }
.budget em { font-style: normal; }
.master { display: block; font-size: .8rem; color: var(--muted); margin-bottom: .4rem; }
.master input { width: 100%; }

/* Two rows per component: the name gets the full width, because "% punktów po 2.
   serwisie" truncated to "% pu..." is not a label, and three of them in a column are
   indistinguishable. */
.component {
  display: grid;
  grid-template-columns: 1fr auto auto;
  grid-template-areas: "name name name" "slider points exclude";
  align-items: center;
  gap: .1rem .5rem;
  font-size: .84rem;
  padding: .25rem 0;
  border-top: 1px solid var(--line);
}
.component.off { opacity: .5; }
.component .name { grid-area: name; font-size: .82rem; }
.component .weight { grid-area: slider; width: 100%; }
.points { grid-area: points; font-variant-numeric: tabular-nums; color: var(--ink); white-space: nowrap; }
.points em { font-style: normal; color: var(--muted); font-size: .78rem; }
.exclude { grid-area: exclude; white-space: nowrap; font-size: .78rem; color: var(--muted); }

/* --- 14.5 slices ------------------------------------------------------------------- */

.filters { display: flex; gap: .8rem; flex-wrap: wrap; margin: .6rem 0; }
.filters label { font-size: .82rem; color: var(--muted); display: flex; gap: .3rem; align-items: center; }
select, input[type="number"] { font: inherit; font-size: .85rem; padding: .18rem .3rem; }
input[type="number"] { width: 6.5rem; }

.slice { max-width: 44rem; }
.verdict { max-width: 62rem; border-left: 3px solid var(--line); padding-left: .7rem; }
.verdict.candidate { border-color: var(--pos); }
.verdict.overfit { border-color: var(--warn-line); }
.empty { color: var(--muted); }

/* --- 14.6 matches ------------------------------------------------------------------ */

#match-table { font-size: .84rem; background: var(--panel); }
tr.match { cursor: pointer; }
tr.match:hover { background: var(--accent-soft); }
.verdict-pick { font-weight: 600; }
.verdict-pass { color: var(--muted); }

.breakdown { display: flex; gap: 1rem; flex-wrap: wrap; padding: .5rem 0; }
.side { flex: 1 1 380px; }
.side table { font-size: .8rem; }
/* The three kinds of gap stay visually apart, as on the main site. */
tr.no-data th, tr.no-data td { background: var(--gap-no-data); }
tr.never-priced th, tr.never-priced td { background: var(--gap-never-priced); }
tr.off th, tr.off td { background: var(--gap-off); color: var(--muted); }

footer { border-top: 1px solid var(--line); margin-top: 2.5rem; padding-top: .8rem; color: var(--muted); font-size: .85rem; }

/* --- 15.5 "nothing happens when I move the sliders" -------------------------------
   It always did. Everything on the page recomputes on every input event; what was
   missing was any way to see it. Three things fix that: the movement counter, the
   "SPEC x -> y" marker on each headline figure, and a reset that is visible without
   scrolling to the weights. */

#movement { margin: .8rem 0 .2rem; }
.movement {
  margin: 0;
  padding: .6rem .8rem;
  border-radius: 6px;
  border: 1px solid var(--line);
  border-left: 3px solid var(--accent);
  background: var(--panel);
  font-size: .92rem;
}
/* No change is a result, not an error, so it is stated calmly rather than in red. */
.movement.quiet { border-left-color: var(--muted); color: var(--muted); }
.movement strong { color: var(--ink); }

.was {
  display: block;
  font-size: .74rem;
  color: var(--muted);
  white-space: nowrap;
}
.was .now { color: var(--ink); }

button.primary {
  border-color: var(--accent);
  color: var(--accent-ink);
  font-weight: 600;
}
button.primary:hover { background: var(--accent-soft); }
.sticky-reset { margin: .5rem 0 .9rem; }

/* --- 15.5 phones -----------------------------------------------------------------
   calculator.css had no media query at all, which meant the owner most likely opened
   an 1180px layout on a phone: sliders a few pixels wide, a ten-column table scrolled
   off the right edge, and numbers he could not compare. Below this width the tables
   stop being tables and become one card per row, and every cell brings its column
   heading with it through data-label. */

@media (max-width: 720px) {
  body { padding: 1rem .8rem 3rem; }
  h1 { font-size: 1.35rem; }
  h2 { font-size: 1.05rem; margin-top: 1.6rem; }

  .windows { gap: .8rem; }
  .window { flex: 1 1 100%; padding: .7rem .8rem .8rem; }

  .filters { flex-direction: column; align-items: stretch; gap: .5rem; }
  .filters label { display: grid; gap: .2rem; }
  select, input[type="number"] { width: 100%; font-size: 16px; }

  .controls { gap: .5rem; }
  .controls button { flex: 1 1 auto; padding: .5rem .8rem; }
  .sticky-reset .fineprint { flex: 1 1 100%; }

  /* One card per row. The heading travels down into the cell, because the header row
     is gone and a bare "1,45" says nothing. */
  table tr:has(> td[data-label]) {
    display: block;
    border: 1px solid var(--line);
    border-radius: 8px;
    background: var(--panel);
    padding: .5rem .65rem;
    margin-bottom: .55rem;
  }
  table td[data-label], table th[data-label] {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: 1rem;
    border: none;
    padding: .18rem 0;
    text-align: right;
  }
  table td[data-label]::before, table th[data-label]::before {
    content: attr(data-label);
    color: var(--muted);
    font-size: .72rem;
    text-transform: uppercase;
    letter-spacing: .03em;
    text-align: left;
    flex: 0 0 auto;
  }
  /* The first cell of a card is its title and keeps the whole width. */
  table tr:has(> td[data-label]) > *:first-child {
    display: block;
    text-align: left;
    font-weight: 600;
    border-bottom: 1px solid var(--line);
    margin-bottom: .3rem;
    padding-bottom: .3rem;
  }
  table tr:has(> td[data-label]) > *:first-child::before {
    display: block;
    font-weight: 400;
  }
  /* The accuracy table has no thead at all - its rows carry their own labels and fold
     by the same rule. Only tables whose cells were labelled lose their header row. */
  table thead:has(~ tbody td[data-label]) { display: none; }

  .was { white-space: normal; text-align: right; }
  .need { text-align: right; }

  /* Sliders are the point of this page, so they get the width. */
  .component {
    grid-template-columns: 1fr auto;
    grid-template-areas: "name name" "slider slider" "points exclude";
    gap: .25rem .5rem;
    padding: .45rem 0;
  }
  .component .weight { height: 1.6rem; }
  #weight-panel { gap: .6rem; }
  .pool { flex: 1 1 100%; }

  .breakdown { gap: .6rem; }
  .side { flex: 1 1 100%; }
}

/* Whoever asked for less motion gets none of it. */
@media (prefers-reduced-motion: reduce) {
  * { animation-duration: .001ms !important; animation-iteration-count: 1 !important;
      transition-duration: .001ms !important; scroll-behavior: auto !important; }
}

/* --- 15.4b the live threshold sweep ----------------------------------------------
   Two lines, one per window, never averaged. Where the sample falls below the
   neutrality threshold the line goes grey and dashed: it has to stop looking like
   evidence exactly where it stops being evidence. */

.chart { margin: .6rem 0 .8rem; }
.chart svg { width: 100%; height: auto; max-width: 660px; display: block; }
.grid { stroke: var(--line); }
.grid.zero { stroke: var(--muted); }
.tick { font-size: 10px; fill: var(--muted); }
.tick.spec { fill: var(--warn-ink); }
.spec-line { stroke: var(--warn-ink); stroke-dasharray: 4 3; }

.sweep-tuning { stroke: var(--accent); stroke-width: 2; fill: none; }
.sweep-validation { stroke: var(--warn-ink); stroke-width: 2; fill: none; }
.sweep-thin { stroke: var(--muted); stroke-width: 1.5; stroke-dasharray: 4 3; fill: none; }
.dot-tuning { fill: var(--accent); }
.dot-validation { fill: var(--warn-ink); }
.dot-thin { fill: var(--panel); stroke: var(--muted); }

.legend-row { font-size: .8rem; color: var(--muted); margin-top: .3rem; }
.legend-row .key {
  display: inline-block; width: 14px; height: 3px; margin: 0 4px 3px 10px;
  vertical-align: middle;
}
.legend-row .key.tuning { background: var(--accent); }
.legend-row .key.validation { background: var(--warn-ink); }
.legend-row .key.thin { background: var(--muted); }

table.sweep { max-width: 44rem; }
table.sweep tr.spec-row th, table.sweep tr.spec-row td { background: var(--warn-bg); }

/* --- 15.8 the visual layer --------------------------------------------------------
   Sections become cards, the type sits on one scale, and the only movement on the page
   is a single 200 ms flash on a value that just changed. Nothing loops, nothing
   bounces, and a reader who asked for less motion gets none of it. */

section {
  background: var(--panel);
  border: 1px solid var(--line);
  border-top: 1px solid var(--line);
  border-radius: var(--radius);
  padding: .9rem 1.1rem 1.1rem;
  margin: 1rem 0;
}
h1 { font-size: var(--t-xl); letter-spacing: -.02em; }
h2 { font-size: var(--t-lg); margin: 0 0 .4rem; }
h3 { font-size: var(--t-md); }

table { background: var(--bg); border: 1px solid var(--line); border-radius: var(--radius-sm); }
.window { background: var(--bg); }
.pool { background: var(--bg); }
#match-table { background: var(--bg); }

select, input[type="number"] {
  color: var(--ink);
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
}

/* The same focus ring on everything, because the keyboard is not a niche. */
a:focus-visible, button:focus-visible, select:focus-visible,
input:focus-visible, [tabindex]:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: 4px;
}

/* Icons are drawn, not downloaded: an icon font would be a network dependency, and this
   folder is opened from a disk with no network at all. */
.icon {
  width: 1em; height: 1em; flex: 0 0 auto;
  vertical-align: -.125em; fill: none;
  stroke: currentColor; stroke-width: 2;
  stroke-linecap: round; stroke-linejoin: round;
}

/* A value that just changed flashes once. Bound to the slider's `change` event, not to
   `input`: flashing on every pixel of a drag is exactly the "nothing may blink" the
   brief rules out. */
@keyframes flash-change {
  from { background: var(--accent-soft); }
  to { background: transparent; }
}
.flash { animation: flash-change .2s ease-out; border-radius: 3px; }

/* --- 15.9 the loading notice ------------------------------------------------------
   8.5 MB arrive as four script tags, and until they have parsed the page is empty
   headings - which reads as broken rather than busy. This says what is happening, and
   the script removes it once there is something to replace it with.

   Deliberately not a spinner. A spinner loops forever, and the one motion rule on this
   project is that nothing does; a sentence answers the same question and answers it
   better, because it also says how long and why. */

.boot {
  margin: 1rem 0;
  padding: .7rem .9rem;
  border: 1px solid var(--line);
  border-left: 3px solid var(--accent);
  border-radius: var(--radius-sm);
  background: var(--panel);
  color: var(--muted);
  font-size: var(--t-sm);
  max-width: 62rem;
}
