/* CSE 135 HW4 — reporting dashboard styles.
 *
 * Hand-written and deliberately small. This is a dashboard whose subject is page
 * weight; pulling in a CSS framework to style it would undercut the argument it
 * exists to make. Charts come from Charts.css (6 KB gzipped); this file is the
 * rest, and there is no JavaScript on any page. */

:root {
  --bg: #f6f7f9;
  --surface: #fff;
  --ink: #1b1f24;
  --ink-soft: #5a6470;
  --line: #dfe3e8;
  --accent: #2f6fed;
  --accent-soft: #eaf0fe;
  --warn-bg: #fff6e5;
  --warn-line: #f0c675;
  --radius: 8px;
}

/* ---------------------------------------------------------------- palette --
 *
 * Declared on BOTH :root and .charts-css, and that duplication is load-bearing.
 *
 * Charts.css sets --color-1..10 on `.charts-css` itself — the <table>. Custom
 * properties resolve by inheritance, and the nearest ancestor that declares one
 * wins, so inside the table Charts.css's own red/orange/yellow palette beat a
 * :root declaration no matter what the source order or specificity was. The bars
 * came out in Charts.css's colours while the legend swatches — which live in the
 * <figcaption>, OUTSIDE the table — inherited ours from :root. Same markup, same
 * variable names, completely different colours.
 *
 * Re-declaring on `.charts-css` puts our values on the same element Charts.css
 * targets; app.css loads second, so ours wins on source order at equal
 * specificity. :root still covers the legend.
 *
 * One hue family, ordered light-to-dark, so a stacked bar reads as a sequence of
 * phases rather than an unordered set of categories.
 */
:root,
.charts-css {
  --color-1: #123a75;
  --color-2: #1d5aa8;
  --color-3: #2f6fed;
  --color-4: #6d9bf1;
  --color-5: #a8c4f7;
  --color-6: #cbdbfa;
  --color-7: #8a94a6;
  --color-8: #c2c8d2;
  --color-9: #e2e6ec;
  /* Charts.css defines a 10th; chart_color() wraps at 9, but a stray reference
     should not fall through to its orange. */
  --color-10: #f0f2f5;

  /* Contrast partner for each palette entry, for a marker drawn ON TOP of that
     colour. The winning phase can be any of the nine, so the marker cannot pick a
     single colour and hope: white vanishes on --color-9, near-black vanishes on
     --color-1. Pairing them here keeps the palette and its contrast in one place. */
  --oc-1: #ffffff;  --oc-2: #ffffff;  --oc-3: #ffffff;
  --oc-4: #ffffff;  --oc-5: #1b1f24;  --oc-6: #1b1f24;
  --oc-7: #ffffff;  --oc-8: #1b1f24;  --oc-9: #1b1f24;
  --oc-10: #1b1f24;
}

* { box-sizing: border-box; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font: 15px/1.55 -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
        "Helvetica Neue", Arial, sans-serif;
}

/* ------------------------------------------------------------------- chrome */

.topbar { background: var(--surface); border-bottom: 1px solid var(--line); }
.topbar-inner {
  max-width: 1100px; margin: 0 auto; padding: 0 20px;
  display: flex; align-items: center; gap: 24px; min-height: 56px; flex-wrap: wrap;
}
.brand { font-weight: 650; color: var(--ink); text-decoration: none; white-space: nowrap; }
.topbar nav ul { list-style: none; display: flex; gap: 18px; margin: 0; padding: 0; }
.topbar nav a { color: var(--ink-soft); text-decoration: none; }
.topbar nav a:hover { color: var(--ink); }
.topbar nav a[aria-current="page"] { color: var(--accent); font-weight: 600; }
.whoami { margin: 0 0 0 auto; display: flex; align-items: center; gap: 12px;
          color: var(--ink-soft); font-size: 14px; }

.role {
  font-size: 11px; text-transform: uppercase; letter-spacing: .04em;
  padding: 2px 7px; border-radius: 99px; background: var(--accent-soft);
  color: #1b4fbf; font-weight: 600;
}
.role-viewer { background: #eef0f3; color: #5a6470; }

main { max-width: 1100px; margin: 0 auto; padding: 28px 20px 60px; }
main.wide { max-width: 1400px; }
h1 { font-size: 26px; margin: 0 0 4px; letter-spacing: -.01em; }
h2 { font-size: 18px; margin: 0 0 4px; }
.h2-sub { font-size: 15px; }
.subtitle { color: var(--ink-soft); margin: 0 0 24px; }

.pagefoot {
  max-width: 1100px; margin: 0 auto; padding: 0 20px 40px;
  color: var(--ink-soft); font-size: 13px;
}

/* -------------------------------------------------------------------- cards */

.card {
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--radius); padding: 20px; margin-bottom: 22px;
}
.card > h2 + .card-question { margin-top: 2px; }
.card-question { color: var(--ink-soft); font-size: 14px; margin: 0 0 16px; }

/* min() so the track can go below 420px on a narrower viewport. A bare
   minmax(420px, 1fr) forces a 420px column and scrolls the whole page sideways
   on a phone. */
.grid-2 { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 420px), 1fr)); gap: 22px; }
.grid-2 .card { margin-bottom: 0; }

/* ------------------------------------------------------------------ tables */

table.data { border-collapse: collapse; width: 100%; font-size: 14px; }
table.data th, table.data td {
  text-align: left; padding: 8px 10px; border-bottom: 1px solid var(--line);
  white-space: nowrap;
}
table.data th { color: var(--ink-soft); font-weight: 600; font-size: 12px;
                text-transform: uppercase; letter-spacing: .03em; }
table.data td.num, table.data th.num { text-align: right; font-variant-numeric: tabular-nums; }
table.data tbody tr:hover { background: #fafbfc; }
table.data td.wrap { white-space: normal; word-break: break-all; max-width: 460px; }
.scroll-x { overflow-x: auto; }

/* ------------------------------------------------------------------ charts */

.chart-wrap { margin: 8px 0 4px; padding: 0; }
.charts-css { font-size: 13px; }

/* Bar charts encode their value as WIDTH, so height is free to follow content.
   Previously charts.php set an inline height, which made this rule lose and caused
   the bug this file exists to fix: Charts.css puts `display:block` on the table, so
   its <tbody>/<tr> form an anonymous table box that sizes to content and happily
   exceeds a fixed height — and with overflow visible it painted over the legend and
   the coverage badge below instead of pushing them down. */
.charts-css.bar { height: auto; }
.charts-css.bar tbody tr td { min-height: 34px; }

/* Charts.css hides the legend's own colour swatches unless we supply them. */
ul.legend { list-style: none; display: flex; flex-wrap: wrap; gap: 6px 18px;
            padding: 0; margin: 14px 0 0; font-size: 13px; color: var(--ink-soft); }
ul.legend li { display: flex; align-items: center; gap: 7px; }
ul.legend span.swatch { width: 11px; height: 11px; border-radius: 2px; flex: none; }

/* ----------------------------------------------------------- coverage badge */

/* Deliberately prominent rather than a footnote. Every figure on this site is
   computed from however much data happens to exist, and on thin data the honest
   reading is "not yet known" — which is only visible if the sample size is too. */
.coverage {
  display: flex; flex-wrap: wrap; gap: 6px 14px; align-items: baseline;
  font-size: 12.5px; color: var(--ink-soft);
  border-top: 1px dashed var(--line); margin-top: 16px; padding-top: 10px;
}
.coverage b { color: var(--ink); font-weight: 600; }
.coverage .caveat {
  background: var(--warn-bg); border: 1px solid var(--warn-line);
  border-radius: 5px; padding: 2px 8px; color: #7a5312;
}

/* ------------------------------------------------------------------ verdict */

.verdict {
  border: 1px solid var(--accent); background: var(--accent-soft);
  border-radius: var(--radius); padding: 18px 20px; margin-bottom: 22px;
}
.verdict h2 { margin-bottom: 6px; }
.verdict .headline { font-size: 20px; font-weight: 650; margin: 0 0 6px; }
.verdict p { margin: 0 0 8px; }
.verdict p:last-child { margin-bottom: 0; }

/* ------------------------------------------------------------------- forms */

form.stack { display: grid; gap: 14px; }
label { font-weight: 600; font-size: 13px; }

/* A field label now WRAPS its own control, so it is the group container rather
   than a caption sitting above one. Column flex puts the text back on top; the
   bare text node becomes an anonymous flex item, which is exactly what we want. */
label.field { display: flex; flex-direction: column; gap: 5px; margin: 0; }
p.field { margin: 0; display: flex; align-items: flex-end; }
input[type=text], input[type=email], input[type=password], select {
  width: 100%; padding: 9px 11px; border: 1px solid var(--line);
  border-radius: 6px; font: inherit; background: #fff;
}
input:focus, select:focus { outline: 2px solid var(--accent); outline-offset: -1px; border-color: var(--accent); }

.btn {
  display: inline-block; padding: 9px 16px; border-radius: 6px; border: 1px solid var(--accent);
  background: var(--accent); color: #fff; font: inherit; font-weight: 600;
  cursor: pointer; text-decoration: none;
}
.btn:hover { filter: brightness(1.07); }
.btn-quiet { background: transparent; color: var(--ink-soft); border-color: var(--line); font-weight: 500; }
.btn-quiet:hover { color: var(--ink); }
.btn-danger { background: #c0392b; border-color: #c0392b; }
.btn-small { padding: 5px 10px; font-size: 13px; }

.filters { display: flex; flex-wrap: wrap; gap: 12px; align-items: flex-end;
           background: var(--surface); border: 1px solid var(--line);
           border-radius: var(--radius); padding: 14px 16px; margin-bottom: 22px; }
.filters .field { min-width: 150px; }

.notice { border-radius: 6px; padding: 10px 14px; margin-bottom: 18px; font-size: 14px; }
.notice-error { background: #fdecea; border: 1px solid #f5b7b1; color: #922b21; }
.notice-ok    { background: #eafaf1; border: 1px solid #a9dfbf; color: #1e6b45; }

/* ------------------------------------------------------- reports (HW5) */

.report-scope { color: var(--ink-soft); font-size: 14px; margin: 0 0 16px; }
.section-badge { vertical-align: middle; margin-left: 8px; }
h1 .section-badge { font-size: 11px; }

/* "Save this view" sits collapsed under the scope line; <details> needs no script. */
details.save-view { margin: 0 0 22px; border: 1px solid var(--line); border-radius: var(--radius);
                    background: var(--surface); }
details.save-view summary { cursor: pointer; padding: 10px 16px; font-weight: 600; font-size: 14px;
                            color: var(--accent); list-style: revert; }
details.save-view[open] summary { border-bottom: 1px solid var(--line); }
.save-form { display: grid; gap: 12px; padding: 14px 16px; }
textarea { width: 100%; padding: 9px 11px; border: 1px solid var(--line); border-radius: 6px;
           font: inherit; background: #fff; resize: vertical; }
textarea:focus { outline: 2px solid var(--accent); outline-offset: -1px; border-color: var(--accent); }
.export-form { margin: -6px 0 18px; }

/* Section checkboxes on the user form. */
fieldset.sections { border: 1px solid var(--line); border-radius: 6px; padding: 8px 12px 10px;
                    margin: 0; min-width: 260px; }
fieldset.sections legend { font-weight: 600; font-size: 13px; padding: 0 4px; }
fieldset.sections label.check { display: inline-flex; align-items: center; gap: 6px;
                                font-weight: 500; font-size: 14px; margin-right: 14px; }
fieldset.sections input[type=checkbox] { margin: 0; }

/* ------------------------------------------------- bare pages (login/logout) */

body.bare { display: flex; align-items: center; justify-content: center; min-height: 100vh; }
.card-narrow {
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius);
  padding: 30px; width: 100%; max-width: 380px; margin: 20px;
}
.card-narrow h1 { font-size: 21px; margin-bottom: 18px; }

/* --------------------------------------------------------------- error page */

body.error-page { display: flex; align-items: center; justify-content: center; min-height: 100vh; text-align: center; }
.error-code { font-size: 56px; font-weight: 700; color: var(--line); margin: 0; line-height: 1; }

/* ------------------------------------------------------------ a11y + chart */

/* Chart captions: present for screen readers, redundant on screen where the
   surrounding heading already says the same thing. */
.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* Charts.css ships .tooltip styling but leaves the reveal to the page, so that a
   chart can opt out. Ours reveal on hover and on keyboard focus. */
.charts-css td:hover .tooltip,
.charts-css td:focus-within .tooltip { opacity: 1; visibility: visible; }

/* The phase the report names as the answer.
 *
 * outline rather than border: a border participates in layout, and these cells are
 * flex items whose width is calc(100% * var(--size)) — adding one risks nudging the
 * segment. An outline never affects layout.
 *
 * outline-offset: -2px pulls the 2px band to sit entirely INSIDE the segment's
 * edge. At offset 0 the outline paints outward from the border edge and would
 * overlap the neighbouring phase; negative offset keeps it flush against the edge
 * with no spill in either direction.
 *
 * Marked rather than recoloured, because position in the stack encodes the load
 * timeline and the colour encodes which phase it is. Neither can be spent on
 * emphasis without breaking the thing the chart is for.
 */
.charts-css.bar tbody tr td.is-winner {
  outline: 2px dotted var(--outline-color, #fff);
  outline-offset: -2px;
}
ul.legend li.is-winner span.swatch {
  outline: 2px dotted var(--outline-color, #fff);
  outline-offset: -2px;
}
ul.legend li.is-winner { color: var(--ink); font-weight: 600; }

/* Segment labels: legible against the darker end of the palette. */
/* The trigger for the overflow: without nowrap, "78.0 ms" wraps to three lines
   inside a narrow segment and inflates the whole row. Clipping keeps a label that
   cannot fit from changing the layout — the exact value is still available in the
   tooltip, which is a SIBLING of .data and so is never clipped by this. */
.charts-css .data {
  color: #fff; font-size: 11.5px; text-shadow: 0 1px 2px rgba(0,0,0,.35);
  white-space: nowrap;
}
.charts-css.bar tbody tr td .data { max-width: 100%; overflow: hidden; }
.charts-css.column .data { color: var(--ink); text-shadow: none; }

/* Column charts label the x-axis, so those headers are horizontal and compete for
   width with each other. Keep them on one line and let them shrink. */
.charts-css.column tbody tr th {
  font-size: 11px; white-space: nowrap; overflow: hidden;
  text-overflow: ellipsis; text-align: center;
}

/* Those axis labels are position:absolute with a negative block-end margin, so
   they render OUTSIDE the table's own box. Without this the legend in the
   figcaption below starts immediately after the box and lands on top of them. */
.charts-css.column { margin-bottom: 2.25rem; }

/* figcaption holds the colour key; it needs no default indent or italics. */
.chart-wrap figcaption { margin: 0; }

/* Row headers should read as labels, not as table headings. */
.charts-css th[scope="row"] {
  font-weight: 500; font-size: 12.5px; color: var(--ink-soft);
  text-align: right; padding-right: 10px; white-space: nowrap;
  overflow: hidden; text-overflow: ellipsis;
}

/* ------------------------------------------------------------- print / PDF */

/* export.php prints a saved report through headless Chromium, which applies print
   media. Everything interactive goes; every card stays whole on its page. */
@media print {
  body { background: #fff; color: #000; font-size: 12.5px; }
  .topbar, .pagefoot, details.save-view, .export-form, .filters,
  .report-scope a, .notice-ok, .charts-css .tooltip { display: none !important; }
  main, main.wide { max-width: none; padding: 0; }
  .card, .verdict { break-inside: avoid; page-break-inside: avoid; box-shadow: none; }
  .grid-2 { display: block; }
  .grid-2 .card { margin-bottom: 16px; }
  .scroll-x { overflow: visible; }
  table.data th, table.data td { white-space: normal; }
  a { color: inherit; text-decoration: none; }
}
