/*
 * Shared application styles: design tokens, layout, and every
 * component used across more than one page.
 *
 * Extracted from base.html so the page carries no inline <style>,
 * which is what lets the Content-Security-Policy drop 'unsafe-inline'
 * from style-src (see CONTENT_SECURITY_POLICY in web/app.py).
 *
 * Deliberately NOT extracted from report_download.html: that template
 * is rendered to a file and bundled into the download zip, then
 * opened from disk. A <link> to /static would resolve to nothing
 * there, so its styles must stay inline to keep the report
 * self-contained - and no CSP applies to it, since it is never served
 * as a response.
 */
/*
 * Tokens match site/index.html (datamadeclean.com) exactly -
 * this is the app wearing the same brand as its own marketing
 * site, not a separate visual identity. --clean/--good share
 * the site's "clean" green (its established success colour);
 * --messy is "messy" red; --soon/--soon-soft/--soon-line are
 * "soon" amber, reused here for "needs review" the same way
 * the marketing site's own before/after mockup uses it for
 * exactly that meaning (see .flag in site/index.html).
 */
:root {
    color-scheme: light;
    --bg: #f6f7f9;
    --surface: #ffffff;
    --grid-line: #e1e4ea;
    --ink: #131b2e;
    --ink-soft: #57617a;
    --ink-faint: #8a93a8;
    --clean: #1f9d77;
    --clean-soft: #e6f5ef;
    --clean-line: #bfe4d5;
    --good: #1f9d77;
    --messy: #c1443b;
    --messy-soft: #fbeae8;
    --messy-line: #f0c7c2;
    --soon: #b45309;
    --soon-soft: #fef3c7;
    --soon-line: #fcd34d;
    --radius: 6px;
    --font-mono: 'IBM Plex Mono', ui-monospace, monospace;
    --font-sans: 'IBM Plex Sans', -apple-system, "Segoe UI", Arial, sans-serif;
}
* { box-sizing: border-box; }
body {
    font-family: var(--font-sans);
    background: var(--bg);
    color: var(--ink);
    margin: 0;
    line-height: 1.5;
    -webkit-font-smoothing: antialiased;
    /* Full-bleed alternating bands (see .section-band.alt in
       upload.css) break out of main's centered max-width via 100vw,
       which on some browsers is a hair wider than the viewport once a
       scrollbar is present - this stops that showing up as a
       horizontal scrollbar rather than actually changing any layout. */
    overflow-x: hidden;
}
main {
    max-width: 800px;
    margin: 0 auto;
    padding: 2.25rem 1.5rem 3rem;
}
/* Wider content column for table-heavy pages (results,
   uploads) - the default 800px is fine for forms/prose, but
   forces every real-data table (often 6+ columns) into
   horizontal scrolling almost immediately. */
main.wide {
    max-width: 1200px;
}
h1 {
    font-family: var(--font-mono);
    font-weight: 600;
    letter-spacing: -0.01em;
    font-size: 1.5rem;
    margin-bottom: 0.3rem;
}
.subtitle {
    color: var(--ink-soft);
    margin-top: 0;
    margin-bottom: 1.75rem;
}
.card {
    background: var(--surface);
    border: 1px solid var(--grid-line);
    border-radius: var(--radius);
    padding: 1.4rem 1.5rem;
    margin-bottom: 1.25rem;
}
.card h2 {
    font-family: var(--font-mono);
    font-size: 1rem;
    font-weight: 600;
    margin: 0 0 1rem 0;
}
label {
    display: block;
    font-size: 0.9rem;
    font-weight: 600;
    margin-bottom: 0.35rem;
}
input[type="text"], input[type="email"], input[type="file"], input[type="password"], select {
    font: inherit;
    font-size: 0.9rem;
    padding: 0.5rem 0.6rem;
    border: 1px solid var(--grid-line);
    border-radius: var(--radius);
    background: var(--bg);
    color: var(--ink);
}
select { cursor: pointer; }
input[type="checkbox"], input[type="radio"] {
    accent-color: var(--clean);
}
.field {
    margin-bottom: 1rem;
}
button, .button {
    font: inherit;
    font-family: var(--font-sans);
    font-weight: 600;
    font-size: 0.9rem;
    background: var(--ink);
    color: var(--bg);
    border: 1px solid transparent;
    border-radius: var(--radius);
    padding: 0.65rem 1.2rem;
    cursor: pointer;
    text-decoration: none;
    display: inline-block;
}
button:hover, .button:hover {
    background: #000;
}
.button-small {
    font-size: 0.8rem;
    padding: 0.35rem 0.75rem;
}
.button-secondary {
    background: transparent;
    color: var(--ink);
    border: 1px solid var(--grid-line);
}
.button-secondary:hover {
    background: var(--surface);
    border-color: var(--ink-faint);
}
button:disabled, .button:disabled {
    opacity: 0.45;
    cursor: not-allowed;
}
/* Hover styling isn't blocked by the disabled attribute the way
   clicking is - without this a disabled button still visibly darkens
   or fills in on hover, which reads as clickable when it isn't. */
button:disabled:hover, .button:disabled:hover {
    background: var(--ink);
}
.button-secondary:disabled:hover {
    background: transparent;
    border-color: var(--grid-line);
}
.inline-form {
    display: inline;
}
.issue-group {
    border: 1px solid var(--grid-line);
    border-radius: var(--radius);
    background: var(--surface);
    margin-bottom: 0.75rem;
    overflow: hidden;
}
.issue-group-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    padding: 0.85rem 1.1rem;
    border-left: 3px solid var(--soon);
    cursor: pointer;
    list-style: none;
    flex-wrap: wrap;
}
.issue-group-header::-webkit-details-marker {
    display: none;
}
.issue-group-header::before {
    content: "▸";
    margin-right: 0.5rem;
    color: var(--ink-faint);
}
.issue-group[open] > .issue-group-header::before {
    content: "▾";
}
.issue-group-header .actions {
    display: flex;
    gap: 0.5rem;
    flex-shrink: 0;
}
.issue-group table {
    margin: 0;
}
.issue-group table td, .issue-group table th {
    padding: 0.65rem 1.1rem;
}
.row-detail {
    margin: 0.4rem 0 0.6rem 0;
    font-size: 0.85rem;
}
.row-detail summary {
    cursor: pointer;
    color: var(--clean);
    font-weight: 600;
}
.row-detail table {
    margin-top: 0.5rem;
}
.issue-actions {
    display: flex;
    gap: 0.4rem;
    margin-top: 0.4rem;
}
.manual-form {
    display: flex;
    align-items: flex-end;
    flex-wrap: wrap;
    gap: 0.5rem;
    margin-top: 0.5rem;
    padding-top: 0.5rem;
    border-top: 1px dashed var(--grid-line);
}
.manual-form label {
    font-size: 0.75rem;
    font-weight: 500;
    color: var(--ink-soft);
    margin-bottom: 0;
}
.manual-form input[type="text"] {
    display: block;
    margin-top: 0.15rem;
    width: 9rem;
}
.error {
    background: var(--messy-soft);
    border: 1px solid var(--messy-line);
    color: var(--messy);
    border-radius: var(--radius);
    padding: 0.75rem 1rem;
    margin-bottom: 1.25rem;
    font-size: 0.9rem;
}
table {
    width: 100%;
    border-collapse: collapse;
    font-size: 0.9rem;
}
.table-scroll {
    overflow-x: auto;
}
th, td {
    text-align: left;
    padding: 0.5rem 0.6rem;
    border-bottom: 1px solid var(--grid-line);
}
th {
    color: var(--ink-faint);
    font-weight: 600;
    font-size: 0.76rem;
    text-transform: uppercase;
    letter-spacing: 0.05em;
}
.badge {
    display: inline-flex;
    align-items: center;
    font-size: 0.68rem;
    font-weight: 700;
    letter-spacing: 0.03em;
    text-transform: uppercase;
    padding: 0.15rem 0.55rem;
    border-radius: 999px;
    white-space: nowrap;
}
.badge-error {
    color: var(--messy);
    background: var(--messy-soft);
    border: 1px solid var(--messy-line);
}
.badge-warning {
    color: var(--soon);
    background: var(--soon-soft);
    border: 1px solid var(--soon-line);
}
.badge-pro {
    color: var(--clean);
    background: var(--clean-soft);
    border: 1px solid var(--clean-line);
}
.stat-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
    gap: 1rem;
}
.stat {
    text-align: left;
}
.stat .value {
    font-family: var(--font-mono);
    font-variant-numeric: tabular-nums;
    font-size: 1.35rem;
    font-weight: 600;
}
.stat .label {
    color: var(--ink-soft);
    font-size: 0.8rem;
}
.delta-up { color: var(--good); }
.delta-down { color: var(--messy); }
.muted { color: var(--ink-soft); }
footer {
    text-align: center;
    color: var(--ink-faint);
    font-size: 0.8rem;
    margin: 2rem 0 2.5rem;
}
header.app-nav {
    position: sticky;
    top: 0;
    z-index: 10;
    display: flex;
    align-items: center;
    gap: 1.75rem;
    padding: 0.9rem 1.5rem;
    background: rgba(246,247,249,0.92);
    backdrop-filter: blur(8px);
    border-bottom: 1px solid var(--grid-line);
    flex-wrap: wrap;
}
header.app-nav .logo {
    font-family: var(--font-mono);
    font-weight: 700;
    font-size: 1rem;
    letter-spacing: -0.01em;
    text-decoration: none;
    color: var(--ink);
}
header.app-nav .logo .dot { color: var(--clean); }
header.app-nav .plinks {
    display: flex;
    gap: 1.3rem;
    margin-right: auto;
    font-size: 0.86rem;
}
header.app-nav .plinks a {
    text-decoration: none;
    color: var(--ink-soft);
    font-weight: 500;
}
header.app-nav .plinks a:hover { color: var(--ink); }
header.app-nav .plinks a.current { color: var(--ink); font-weight: 600; }
header.app-nav .who {
    display: flex;
    align-items: center;
    gap: 0.85rem;
    font-size: 0.83rem;
    color: var(--ink-soft);
}
header.app-nav .who a { color: var(--ink-soft); text-decoration: none; }
header.app-nav .who a:hover { color: var(--ink); }
header.app-nav .who form { display: inline; }
button.link {
    font: inherit;
    font-weight: 500;
    background: none;
    color: var(--ink-soft);
    border: none;
    padding: 0;
    cursor: pointer;
}
button.link:hover {
    color: var(--ink);
}
code {
    font-family: var(--font-mono);
    font-size: 0.85em;
    background: var(--bg);
    border: 1px solid var(--grid-line);
    border-radius: 4px;
    padding: 0.05rem 0.35rem;
}


/* ----------------------------------------------------------------
 * Utilities replacing what used to be inline style= attributes.
 *
 * These exist because a Content-Security-Policy that allows
 * 'unsafe-inline' for style-src has to allow it for every element on
 * every page - there is no way to permit "just these few". Moving
 * them here is what lets the policy drop it (see
 * CONTENT_SECURITY_POLICY in web/app.py).
 *
 * Values are carried over exactly as they were. Several of the
 * spacing figures are close without being equal (0.25 / 0.35 /
 * 0.4rem); consolidating them would have been a silent restyle
 * riding along with a security change, so they are kept apart.
 * ---------------------------------------------------------------- */

/* Replaces nine separate `style="margin-top:0"` attributes on the
   heading that opens a card. A rule rather than a class, because the
   condition it depends on - being the card's first element - is
   already expressible in CSS. */
.card > h2:first-child { margin-top: 0; }

/* Status and danger treatments. */
.card-success { border-color: var(--good); color: var(--good); }
.card-danger { border-color: var(--messy); }
.text-danger { color: var(--messy); }
.button-danger { border-color: var(--messy); color: var(--messy); }

/* Vertical rhythm. */
.pull-up { margin-top: -0.5rem; }
.pull-up-sm { margin-top: -0.25rem; }
.mt-xs { margin-top: 0.25rem; }
.mt-sm { margin-top: 0.35rem; }
/* Distinct from .mt-sm on purpose: the original attribute said
   0.4rem, and rounding it into 0.35rem would be a restyle. */
.mt-sm-plus { margin-top: 0.4rem; }
.mt-md { margin-top: 0.5rem; }
.mt-lg { margin-top: 0.75rem; }
.mt-xl { margin-top: 1rem; }
.mt-2xl { margin-top: 1.25rem; }
.mt-3xl { margin-top: 1.5rem; }
.mb-xl { margin-bottom: 1rem; }

/* One-offs. */
/* Doubled class, not !important, and both choices matter.
   Doubled because a plain `.is-hidden` ties on specificity with
   component rules like `.column-strip { display: grid }` in
   upload.css, which loads later and would therefore win - leaving an
   element that should start hidden visible on load. Not !important
   because the JavaScript shows and hides these by assigning
   element.style.display, and !important in a stylesheet beats an
   inline style, which would make them impossible to show again.
   0,2,0 sits exactly where it needs to: above component rules,
   below inline. */
.is-hidden.is-hidden { display: none; }
.inherit-colour { color: inherit; }
.centered { text-align: center; }
.scroll-x { overflow-x: auto; }
.clickable { cursor: pointer; }
.divider-above { border-top: 1px dashed var(--grid-line); padding-top: 0.75rem; }
.hero-title { font-family: var(--font-mono); letter-spacing: -0.01em; text-align: center; }
.hero-lede { max-width: 34rem; margin-left: auto; margin-right: auto; }
