/* ==========================================================================
   Comment Intel — app.css
   Hand-written, no framework, no build step, no CDN. One file, served by
   whitenoise/nginx out of STATIC_ROOT.

   Why no framework: the product's whole visual identity is the PDF that
   report_pipeline/render.py produces. That renderer is ~200 lines of plain CSS
   with a fixed palette; a utility framework would ship 40 KB to reproduce
   something we can express in tokens and then still not match it. So the tokens
   below are lifted from render.py's PAGE_TMPL and extended for screen use:
   the app should read as the same publication as the report it generates.

   Structure:
     1. tokens (light + dark)      6. buttons
     2. reset + base               7. badges, alerts, empty states
     3. layout + header/footer     8. reports (list, detail, job progress)
     4. typography                 9. analytics (stat grid, charts, tables)
     5. cards + forms             10. responsive, print, a11y prefs

   Dark mode is expressed three times on purpose:
     :root                                  -> light default
     @media (prefers-color-scheme: dark)    -> system preference
     :root[data-theme="dark"|"light"]       -> explicit user override, wins both
   The override has to beat the media query in BOTH directions, which is why the
   light block is repeated at the bottom rather than relying on the cascade.
   ========================================================================== */

/* ---------------------------------------------------------------- 1. tokens */
:root {
  color-scheme: light;

  --paper:      #f4f2ee;   /* page background — warm off-white */
  --surface:    #fffefb;   /* cards */
  --surface-2:  #eeeae1;   /* inset panels, table stripes, bar tracks */
  --ink:        #1a1815;   /* primary text */
  --ink-2:      #4a463f;   /* secondary text */
  --muted:      #857e72;   /* labels, meta */
  --soft:       #b3aca0;   /* dividers-as-text, disabled */
  --line:       #e2dbcf;   /* borders */
  --line-2:     #d3cabb;   /* stronger borders (inputs) */

  --teal:       #17605a;   /* primary accent */
  --teal-hover: #114b46;
  --teal-tint:  #e2eeec;
  --terra:      #e4572e;   /* secondary accent */
  --terra-tint: #fbe7de;

  --ok:         #2f7d55;
  --ok-tint:    #e3f0e8;
  --warn:       #9a6a12;
  --warn-tint:  #f7edd8;
  --danger:     #b3392a;
  --danger-tint:#f8e3df;

  --focus:      #17605a;
  /* Foreground for filled buttons. A token rather than a
     `:root[data-theme=dark] .btn { color: … }` override, because that override
     scores (0,3,0) and would beat `.btn--danger` at (0,1,0) regardless of
     source order — repainting the delete button's text dark teal. */
  --btn-fg:     #ffffff;

  --radius:     10px;
  --radius-sm:  7px;
  --radius-pill: 999px;

  --shadow-1: 0 1px 2px rgba(26, 24, 21, .05);
  --shadow-2: 0 1px 2px rgba(26, 24, 21, .05), 0 10px 28px -16px rgba(26, 24, 21, .35);

  --sans: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue",
          Arial, "Noto Sans", sans-serif;
  --mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas,
          "Liberation Mono", monospace;

  --shell:   1080px;
  --shell-narrow: 460px;
  --gap:     clamp(16px, 3.2vw, 28px);
}

/* Dark tokens. Not an inversion: the paper stays warm, the accents lift enough
   to clear WCAG AA on the dark surfaces (#17605a on #1c1a17 is unreadable). */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    color-scheme: dark;

    --paper:      #131110;
    --surface:    #1c1a17;
    --surface-2:  #24211c;
    --ink:        #f2eee5;
    --ink-2:      #cbc4b6;
    --muted:      #9a9284;
    --soft:       #6d665b;
    --line:       #302c25;
    --line-2:     #3d3830;

    --teal:       #5cb8ac;
    --teal-hover: #7fcdc2;
    --teal-tint:  #14312e;
    --terra:      #f28359;
    --terra-tint: #3a201a;

    --ok:         #63b98a;
    --ok-tint:    #16301f;
    --warn:       #d6a34a;
    --warn-tint:  #33280f;
    --danger:     #ef8674;
    --danger-tint:#3a1c18;

    --focus:      #7fcdc2;
    --btn-fg:     #10201e;

    --shadow-1: 0 1px 2px rgba(0, 0, 0, .4);
    --shadow-2: 0 1px 2px rgba(0, 0, 0, .4), 0 10px 28px -16px rgba(0, 0, 0, .8);
  }
}

:root[data-theme="dark"] {
  color-scheme: dark;

  --paper:      #131110;
  --surface:    #1c1a17;
  --surface-2:  #24211c;
  --ink:        #f2eee5;
  --ink-2:      #cbc4b6;
  --muted:      #9a9284;
  --soft:       #6d665b;
  --line:       #302c25;
  --line-2:     #3d3830;

  --teal:       #5cb8ac;
  --teal-hover: #7fcdc2;
  --teal-tint:  #14312e;
  --terra:      #f28359;
  --terra-tint: #3a201a;

  --ok:         #63b98a;
  --ok-tint:    #16301f;
  --warn:       #d6a34a;
  --warn-tint:  #33280f;
  --danger:     #ef8674;
  --danger-tint:#3a1c18;

  --focus:      #7fcdc2;
  --btn-fg:     #10201e;

  --shadow-1: 0 1px 2px rgba(0, 0, 0, .4);
  --shadow-2: 0 1px 2px rgba(0, 0, 0, .4), 0 10px 28px -16px rgba(0, 0, 0, .8);
}

/* Explicit light wins over the system preference. */
:root[data-theme="light"] {
  color-scheme: light;

  --paper:      #f4f2ee;
  --surface:    #fffefb;
  --surface-2:  #eeeae1;
  --ink:        #1a1815;
  --ink-2:      #4a463f;
  --muted:      #857e72;
  --soft:       #b3aca0;
  --line:       #e2dbcf;
  --line-2:     #d3cabb;

  --teal:       #17605a;
  --teal-hover: #114b46;
  --teal-tint:  #e2eeec;
  --terra:      #e4572e;
  --terra-tint: #fbe7de;

  --ok:         #2f7d55;
  --ok-tint:    #e3f0e8;
  --warn:       #9a6a12;
  --warn-tint:  #f7edd8;
  --danger:     #b3392a;
  --danger-tint:#f8e3df;

  --focus:      #17605a;
  --btn-fg:     #ffffff;

  --shadow-1: 0 1px 2px rgba(26, 24, 21, .05);
  --shadow-2: 0 1px 2px rgba(26, 24, 21, .05), 0 10px 28px -16px rgba(26, 24, 21, .35);
}


/* ------------------------------------------------------- 2. reset + base */
*, *::before, *::after { box-sizing: border-box; }

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
}

body {
  margin: 0;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--sans);
  font-size: 16px;
  line-height: 1.55;
  /* Long Instagram URLs and Azerbaijani compounds must never widen the page. */
  overflow-wrap: break-word;
  -webkit-font-smoothing: antialiased;
}

img, svg, video { max-width: 100%; height: auto; }
img { display: block; }

a { color: var(--teal); text-decoration-thickness: 1px; text-underline-offset: 2px; }
a:hover { color: var(--teal-hover); }

hr {
  border: 0;
  border-top: 1px solid var(--line);
  margin: var(--gap) 0;
}

:focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: 2px;
  border-radius: 3px;
}

::selection { background: var(--teal-tint); color: var(--ink); }


/* ------------------------------------------- 3. layout, header and footer */
.shell {
  width: 100%;
  max-width: var(--shell);
  margin-inline: auto;
  padding-inline: clamp(16px, 4vw, 32px);
}

.shell--narrow { max-width: var(--shell-narrow); }

main.main {
  flex: 1 0 auto;
  padding-block: clamp(24px, 5vw, 48px) clamp(40px, 7vw, 72px);
}

.skip-link {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 100;
  background: var(--teal);
  color: var(--btn-fg);
  padding: 10px 16px;
  border-radius: 0 0 var(--radius-sm) 0;
  font-weight: 600;
}
.skip-link:focus { left: 0; color: var(--btn-fg); }

.site-head {
  position: sticky;
  top: 0;
  z-index: 40;
  background: color-mix(in srgb, var(--paper) 88%, transparent);
  backdrop-filter: saturate(150%) blur(10px);
  border-bottom: 1px solid var(--line);
}
/* color-mix is recent; a solid background is the fallback everywhere else. */
@supports not (background: color-mix(in srgb, red 50%, blue)) {
  .site-head { background: var(--paper); }
}

.site-head__inner {
  display: flex;
  align-items: center;
  gap: clamp(10px, 2.5vw, 24px);
  min-height: 62px;
  flex-wrap: wrap;
  padding-block: 8px;
}

.brand {
  display: inline-flex;
  align-items: baseline;
  gap: 8px;
  color: var(--ink);
  text-decoration: none;
  white-space: nowrap;
  margin-right: auto;
}
.brand:hover { color: var(--ink); }
.brand__mark { color: var(--terra); font-size: 13px; line-height: 1; }
.brand__name {
  font-size: 13px;
  font-weight: 800;
  letter-spacing: .16em;
}
.brand__tag {
  font-size: 11.5px;
  font-weight: 500;
  letter-spacing: .02em;
  color: var(--muted);
}

.nav {
  display: flex;
  align-items: center;
  gap: 2px;
  flex-wrap: wrap;
}
.nav a {
  display: inline-block;
  padding: 7px 11px;
  border-radius: var(--radius-sm);
  color: var(--ink-2);
  text-decoration: none;
  font-size: 14.5px;
  font-weight: 500;
  white-space: nowrap;
}
.nav a:hover { background: var(--surface-2); color: var(--ink); }
.nav a[aria-current="page"] {
  background: var(--teal-tint);
  color: var(--teal);
  font-weight: 650;
}

.head-end {
  display: flex;
  align-items: center;
  gap: 6px;
}

/* Native <details> menu: no JS, no focus trap to get wrong, closes on Esc. */
.usermenu { position: relative; }
.usermenu > summary {
  list-style: none;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 6px 10px;
  border: 1px solid var(--line);
  border-radius: var(--radius-pill);
  background: var(--surface);
  font-size: 14px;
  color: var(--ink-2);
  max-width: 42vw;
}
.usermenu > summary::-webkit-details-marker { display: none; }
.usermenu > summary:hover { border-color: var(--line-2); color: var(--ink); }
.usermenu__name {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.usermenu__caret { color: var(--muted); font-size: 10px; }
.usermenu[open] > summary { border-color: var(--line-2); }

.usermenu__panel {
  position: absolute;
  right: 0;
  top: calc(100% + 8px);
  min-width: 232px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--shadow-2);
  padding: 8px;
  z-index: 50;
}
.usermenu__meta {
  padding: 6px 10px 10px;
  border-bottom: 1px solid var(--line);
  margin-bottom: 6px;
}
.usermenu__meta strong { display: block; font-size: 14px; }
.usermenu__meta span { display: block; font-size: 12.5px; color: var(--muted); }
.usermenu__panel a,
.usermenu__panel button {
  display: block;
  width: 100%;
  text-align: start;
  padding: 8px 10px;
  border: 0;
  border-radius: var(--radius-sm);
  background: none;
  color: var(--ink-2);
  font: inherit;
  font-size: 14.5px;
  text-decoration: none;
  cursor: pointer;
}
.usermenu__panel a:hover,
.usermenu__panel button:hover { background: var(--surface-2); color: var(--ink); }

.theme-toggle {
  display: inline-grid;
  place-items: center;
  width: 34px;
  height: 34px;
  padding: 0;
  border: 1px solid var(--line);
  border-radius: var(--radius-pill);
  background: var(--surface);
  color: var(--ink-2);
  cursor: pointer;
  font-size: 15px;
  line-height: 1;
}
.theme-toggle:hover { border-color: var(--line-2); color: var(--ink); }

.site-foot {
  flex: 0 0 auto;
  border-top: 1px solid var(--line);
  padding-block: 20px 28px;
  font-size: 13px;
  color: var(--muted);
}
.site-foot__inner {
  display: flex;
  flex-wrap: wrap;
  gap: 6px 18px;
  align-items: baseline;
  justify-content: space-between;
}
.site-foot a { color: var(--muted); }
.site-foot a:hover { color: var(--ink-2); }


/* ------------------------------------------------------- 4. typography */
h1, h2, h3, h4 {
  margin: 0 0 .4em;
  line-height: 1.15;
  letter-spacing: -0.015em;
  font-weight: 800;
}
h1 { font-size: clamp(26px, 4.4vw, 38px); }
h2 { font-size: clamp(19px, 2.6vw, 23px); }
h3 { font-size: 16.5px; font-weight: 700; letter-spacing: -0.005em; }
p  { margin: 0 0 1em; }
p:last-child { margin-bottom: 0; }

.kicker {
  font-size: 11px;
  font-weight: 800;
  letter-spacing: .22em;
  text-transform: uppercase;
  color: var(--terra);
  margin: 0 0 10px;
}

.lede {
  font-size: 16.5px;
  color: var(--ink-2);
  max-width: 62ch;
}

.muted { color: var(--muted); }
.small { font-size: 13px; }
.mono  { font-family: var(--mono); font-size: .92em; }
.nowrap { white-space: nowrap; }
.url { font-family: var(--mono); font-size: 13px; word-break: break-all; }
.tabular { font-variant-numeric: tabular-nums; }

.page-head {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  justify-content: space-between;
  gap: 14px var(--gap);
  margin-bottom: var(--gap);
  padding-bottom: 14px;
  border-bottom: 2px solid var(--ink);
}
.page-head h1 { margin: 0; }
.page-head__actions { display: flex; gap: 10px; flex-wrap: wrap; }

.section { margin-top: clamp(28px, 5vw, 44px); }
.section__head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: 6px 16px;
  margin-bottom: 14px;
}
.section__head h2 { margin: 0; }
.section__note { font-size: 13px; color: var(--muted); }


/* -------------------------------------------------- 5. cards and forms */
.card {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: clamp(18px, 3vw, 26px);
  box-shadow: var(--shadow-1);
}
.card + .card { margin-top: 16px; }
.card--flush { padding: 0; overflow: hidden; }
.card--inset { background: var(--surface-2); box-shadow: none; }
.card--accent { border-left: 3px solid var(--teal); }

.card__head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: 6px 16px;
  margin-bottom: 14px;
}
.card__title { margin: 0; font-size: 16px; font-weight: 700; }
.card__note { font-size: 12.5px; color: var(--muted); }

.auth {
  max-width: var(--shell-narrow);
  margin-inline: auto;
}
.auth__head { text-align: center; margin-bottom: 22px; }
.auth__head h1 { font-size: clamp(24px, 5vw, 30px); }
.auth__head p { color: var(--muted); font-size: 14.5px; margin: 0; }
.auth__alt {
  margin-top: 18px;
  text-align: center;
  font-size: 14px;
  color: var(--muted);
}

form { margin: 0; }

.field { margin-bottom: 18px; }
.field:last-of-type { margin-bottom: 0; }

.field > label,
.field-label {
  display: block;
  margin-bottom: 6px;
  font-size: 12px;
  font-weight: 700;
  letter-spacing: .09em;
  text-transform: uppercase;
  color: var(--muted);
}

/* Styled by element, not by class: the forms are written by another module and
   may or may not put a class on the widget. Element selectors always land. */
input:is([type="text"], [type="email"], [type="password"], [type="url"],
         [type="number"], [type="search"], [type="tel"], [type="date"]),
select,
textarea {
  display: block;
  width: 100%;
  padding: 11px 13px;
  border: 1px solid var(--line-2);
  border-radius: var(--radius-sm);
  background: var(--surface);
  color: var(--ink);
  font-family: inherit;
  /* 16px is a hard floor, not a taste decision: iOS Safari zooms the viewport
     on focus for any field below it, and the zoom does not reverse on blur. At
     15.5px every form in the product lurched sideways the moment it was tapped
     — including the URL paste, which is the single most important interaction
     in the app and is performed almost entirely on phones. */
  font-size: 16px;
  line-height: 1.4;
  transition: border-color .12s ease, box-shadow .12s ease;
}
textarea { min-height: 110px; resize: vertical; }

input:is([type="text"], [type="email"], [type="password"], [type="url"],
         [type="number"], [type="search"], [type="tel"], [type="date"]):focus,
select:focus,
textarea:focus {
  outline: none;
  border-color: var(--teal);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--teal) 22%, transparent);
}
@supports not (background: color-mix(in srgb, red 50%, blue)) {
  input:focus, select:focus, textarea:focus { box-shadow: 0 0 0 3px var(--teal-tint); }
}

input::placeholder, textarea::placeholder { color: var(--soft); }
input:disabled, select:disabled, textarea:disabled {
  background: var(--surface-2);
  color: var(--muted);
  cursor: not-allowed;
}

input[type="checkbox"], input[type="radio"] {
  accent-color: var(--teal);
  width: 16px;
  height: 16px;
  margin: 0 8px 0 0;
  vertical-align: -2px;
}

.field--error input, .field--error select, .field--error textarea {
  border-color: var(--danger);
}
.field--check > label {
  text-transform: none;
  letter-spacing: 0;
  font-size: 14.5px;
  font-weight: 500;
  color: var(--ink-2);
}

.req {
  color: var(--terra);
  margin-left: 3px;
  font-weight: 700;
}

.hint {
  margin: 6px 0 0;
  font-size: 13px;
  color: var(--muted);
}
/* Django renders help_text as a <ul> in some form styles; flatten it. */
.hint ul, .errorlist { margin: 0; padding: 0; list-style: none; }

.err, .errorlist li {
  margin: 6px 0 0;
  font-size: 13.5px;
  font-weight: 500;
  color: var(--danger);
}

.form-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 12px;
  margin-top: 24px;
}
.form-actions--split { justify-content: space-between; }


/* ------------------------------------------------------------ 6. buttons */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  padding: 11px 20px;
  border: 1px solid transparent;
  border-radius: var(--radius-sm);
  background: var(--teal);
  color: var(--btn-fg);
  font-family: inherit;
  font-size: 15px;
  font-weight: 600;
  line-height: 1.2;
  text-decoration: none;
  cursor: pointer;
  transition: background-color .12s ease, border-color .12s ease, color .12s ease;
}
.btn:hover { background: var(--teal-hover); color: var(--btn-fg); }
.btn:disabled, .btn[aria-disabled="true"] {
  background: var(--surface-2);
  color: var(--soft);
  border-color: var(--line);
  cursor: not-allowed;
}

.btn--accent { background: var(--terra); }
.btn--accent:hover { background: color-mix(in srgb, var(--terra) 84%, #000); }

.btn--ghost {
  background: transparent;
  border-color: var(--line-2);
  color: var(--ink-2);
}
.btn--ghost:hover { background: var(--surface-2); border-color: var(--soft); color: var(--ink); }

.btn--danger { background: transparent; border-color: var(--danger); color: var(--danger); }
.btn--danger:hover { background: var(--danger-tint); color: var(--danger); border-color: var(--danger); }

.btn--sm { padding: 7px 13px; font-size: 13.5px; }
.btn--block { width: 100%; }

.btn-link {
  border: 0;
  background: none;
  padding: 0;
  font: inherit;
  color: var(--teal);
  cursor: pointer;
  text-decoration: underline;
  text-underline-offset: 2px;
}
.btn-link--danger { color: var(--danger); }

.inline-form { display: inline; }


/* ------------------------------------ 7. badges, alerts, empty states */
.badge {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 3px 10px 3px 8px;
  border-radius: var(--radius-pill);
  border: 1px solid transparent;
  font-size: 12px;
  font-weight: 700;
  letter-spacing: .04em;
  white-space: nowrap;
  background: var(--surface-2);
  color: var(--ink-2);
}
.badge::before {
  content: "";
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: currentColor;
  flex: 0 0 auto;
}
.badge--pending, .badge--queued { background: var(--surface-2); color: var(--muted); }
.badge--running { background: var(--warn-tint); color: var(--warn); }
.badge--running::before { animation: pulse 1.6s ease-in-out infinite; }
.badge--done   { background: var(--ok-tint);     color: var(--ok); }
.badge--failed { background: var(--danger-tint); color: var(--danger); }
.badge--shared { background: var(--teal-tint);   color: var(--teal); }

@keyframes pulse { 0%, 100% { opacity: 1; } 50% { opacity: .28; } }

.alert {
  display: flex;
  gap: 12px;
  padding: 13px 16px;
  border: 1px solid var(--line);
  border-left-width: 3px;
  border-radius: var(--radius-sm);
  background: var(--surface);
  font-size: 14.5px;
  color: var(--ink-2);
}
.alert + .alert { margin-top: 10px; }
.alert p:last-child { margin-bottom: 0; }
.alert__icon { flex: 0 0 auto; font-size: 15px; line-height: 1.5; }
.alert--success { background: var(--ok-tint);     border-color: var(--ok);     color: var(--ink); }
.alert--error   { background: var(--danger-tint); border-color: var(--danger); color: var(--ink); }
.alert--warning { background: var(--warn-tint);   border-color: var(--warn);   color: var(--ink); }
.alert--info    { background: var(--teal-tint);   border-color: var(--teal);   color: var(--ink); }
.alert--debug   { background: var(--surface-2);   border-color: var(--soft); }

.messages { margin-bottom: var(--gap); }

.empty {
  text-align: center;
  padding: clamp(32px, 7vw, 64px) 24px;
  border: 1px dashed var(--line-2);
  border-radius: var(--radius);
  background: var(--surface);
}
.empty__mark { font-size: 28px; color: var(--soft); line-height: 1; margin-bottom: 12px; }
.empty h2 { font-size: 19px; margin-bottom: 8px; }
.empty p { color: var(--muted); max-width: 46ch; margin-inline: auto; }
.empty .btn { margin-top: 18px; }

.notice-page {
  max-width: 560px;
  margin-inline: auto;
  text-align: center;
  padding-block: clamp(30px, 8vw, 70px);
}
.notice-page__code {
  font-size: clamp(56px, 14vw, 96px);
  font-weight: 800;
  letter-spacing: -0.04em;
  line-height: 1;
  color: var(--terra);
  margin: 0 0 6px;
}
.notice-page h1 { font-size: clamp(21px, 4vw, 27px); }
.notice-page p { color: var(--ink-2); }
.notice-page .form-actions { justify-content: center; }


/* ------------------------------------------------------------ 8. reports */
.toolbar {
  display: flex;
  flex-wrap: wrap;
  gap: 10px 16px;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 16px;
}
.filters { display: flex; flex-wrap: wrap; gap: 6px; }
.filters a {
  padding: 5px 12px;
  border: 1px solid var(--line);
  border-radius: var(--radius-pill);
  font-size: 13.5px;
  text-decoration: none;
  color: var(--ink-2);
  background: var(--surface);
}
.filters a:hover { border-color: var(--line-2); color: var(--ink); }
.filters a[aria-current="true"] {
  background: var(--ink);
  border-color: var(--ink);
  color: var(--paper);
  font-weight: 600;
}

.report-list { list-style: none; margin: 0; padding: 0; display: grid; gap: 12px; }

.report-item {
  position: relative;
  display: grid;
  grid-template-columns: 1fr auto;
  gap: 6px 18px;
  align-items: start;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 16px 18px;
  box-shadow: var(--shadow-1);
  transition: border-color .12s ease, transform .12s ease, box-shadow .12s ease;
}
.report-item:hover {
  border-color: var(--line-2);
  transform: translateY(-1px);
  box-shadow: var(--shadow-2);
}
.report-item__title {
  margin: 0;
  font-size: 17px;
  font-weight: 700;
  letter-spacing: -0.01em;
}
.report-item__title a {
  color: var(--ink);
  text-decoration: none;
}
/* Stretched link: the whole card is the hit target, but the DOM keeps a single
   real <a> so keyboard and screen-reader navigation stay sane. */
.report-item__title a::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: var(--radius);
}
.report-item__title a:hover { color: var(--teal); }
/* The report's headline sentence. Spans both grid columns so it runs the full
   width of the card rather than being squeezed beside the status badges, and
   clamps to two lines so one long verdict cannot make a list row three times
   the height of its neighbours. */
.report-item__verdict {
  grid-column: 1 / -1;
  margin: 0;
  font-size: 14px;
  line-height: 1.45;
  color: var(--ink-2);
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.report-item__meta {
  grid-column: 1 / -1;
  display: flex;
  flex-wrap: wrap;
  gap: 3px 14px;
  font-size: 13px;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
}
.report-item__meta b { color: var(--ink-2); font-weight: 600; }
.report-item__side {
  display: flex;
  align-items: center;
  gap: 8px;
  justify-self: end;
}

.stat-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(158px, 1fr));
  gap: 12px;
}
.stat {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 15px 17px;
}
.stat--inset { background: var(--surface-2); border-color: transparent; }
.stat__label {
  display: block;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: .11em;
  text-transform: uppercase;
  color: var(--muted);
  margin-bottom: 7px;
}
.stat__value {
  display: block;
  font-size: clamp(24px, 3.4vw, 31px);
  font-weight: 800;
  letter-spacing: -0.025em;
  line-height: 1.05;
  font-variant-numeric: tabular-nums;
}
.stat__note { display: block; margin-top: 5px; font-size: 12.5px; color: var(--muted); }
.stat--accent .stat__value { color: var(--terra); }
.stat--teal   .stat__value { color: var(--teal); }

.detail-grid {
  display: grid;
  grid-template-columns: minmax(0, 1.55fr) minmax(0, 1fr);
  gap: var(--gap);
  align-items: start;
}

.preview {
  background: var(--surface-2);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 10px;
  overflow: hidden;
}
.preview img {
  width: 100%;
  border-radius: var(--radius-sm);
  box-shadow: var(--shadow-2);
  background: #fff;
}
.preview__cap {
  display: block;
  margin-top: 10px;
  font-size: 12.5px;
  color: var(--muted);
  text-align: center;
}

.kv { margin: 0; display: grid; grid-template-columns: auto 1fr; gap: 8px 16px; font-size: 14.5px; }
.kv dt { color: var(--muted); font-size: 13px; }
.kv dd { margin: 0; color: var(--ink); font-variant-numeric: tabular-nums; overflow-wrap: anywhere; }

/* -- job progress ------------------------------------------------------- */
.job { border-left: 3px solid var(--warn); }
.job__head {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
  margin-bottom: 14px;
}
.job__spinner {
  width: 18px;
  height: 18px;
  flex: 0 0 auto;
  border: 2px solid var(--line-2);
  border-top-color: var(--teal);
  border-radius: 50%;
  animation: spin 900ms linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }

.bar {
  height: 9px;
  background: var(--surface-2);
  border-radius: var(--radius-pill);
  overflow: hidden;
}
.bar__fill {
  height: 100%;
  width: 0;
  border-radius: var(--radius-pill);
  background: linear-gradient(90deg, var(--teal), var(--terra));
  transition: width .5s ease;
}
.bar--indeterminate .bar__fill {
  width: 34% !important;
  animation: slide 1.9s ease-in-out infinite;
}
@keyframes slide {
  0%   { transform: translateX(-110%); }
  100% { transform: translateX(330%); }
}

.steps { list-style: none; margin: 18px 0 0; padding: 0; display: grid; gap: 8px; }
.steps li {
  display: flex;
  align-items: center;
  gap: 10px;
  font-size: 14px;
  color: var(--muted);
}
.steps li::before {
  content: "○";
  font-size: 13px;
  color: var(--soft);
}
.steps li[data-state="active"] { color: var(--ink); font-weight: 600; }
.steps li[data-state="active"]::before { content: "◆"; color: var(--terra); }
.steps li[data-state="done"] { color: var(--ink-2); }
.steps li[data-state="done"]::before { content: "●"; color: var(--ok); }

.share-box {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
  align-items: center;
  margin-top: 12px;
}
.share-box input[type="text"] {
  flex: 1 1 220px;
  font-family: var(--mono);
  /* 16px for the same iOS reason as the base input rule above. The share link
     is monospace and long, so this reads tighter than the number suggests. */
  font-size: 16px;
  background: var(--surface-2);
}

.pagination {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  margin-top: var(--gap);
  font-size: 14px;
  color: var(--muted);
}
.pagination a {
  padding: 7px 14px;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  background: var(--surface);
  text-decoration: none;
  color: var(--ink-2);
}
.pagination a:hover { border-color: var(--line-2); color: var(--ink); }


/* ---------------------------------------------------------- 9. analytics */
.chart-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
  gap: 16px;
}
/* Categorical series colours for the inline SVG charts.
   analytics/charts.py emits every fill as `var(--chart-N, #hex)` precisely so
   the palette lives here and not in Python — the hex in the SVG is only the
   fallback. Redefining them under dark mode is the whole point: #1f7a71 on
   #1c1a17 is unreadable, and a chart that has to be legible in both schemes
   cannot have its colours baked into the markup. */
:root {
  --chart-1: #1f7a71;   /* teal       */
  --chart-2: #e4572e;   /* terracotta */
  --chart-3: #4f7cac;   /* slate blue */
  --chart-4: #b08900;   /* ochre      */
  --chart-5: #7d5ba6;   /* violet     */
  --chart-6: #8a8377;   /* stone      */
  --chart-fail: #c0392b;
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --chart-1: #4fb3a8;
    --chart-2: #f2845c;
    --chart-3: #7ea8d8;
    --chart-4: #d6ad3c;
    --chart-5: #a98cd0;
    --chart-6: #a29a8c;
    --chart-fail: #ef8674;
  }
}
:root[data-theme="dark"] {
  --chart-1: #4fb3a8;
  --chart-2: #f2845c;
  --chart-3: #7ea8d8;
  --chart-4: #d6ad3c;
  --chart-5: #a98cd0;
  --chart-6: #a29a8c;
  --chart-fail: #ef8674;
}
:root[data-theme="light"] {
  --chart-1: #1f7a71;
  --chart-2: #e4572e;
  --chart-3: #4f7cac;
  --chart-4: #b08900;
  --chart-5: #7d5ba6;
  --chart-6: #8a8377;
  --chart-fail: #c0392b;
}

/* Nothing here styles the chart *ink*. charts.py draws axes, gridlines and tick
   labels with `fill:currentColor` in a style attribute, which no stylesheet rule
   can outrank anyway, and which already follows the page's `color` in both
   schemes. The series colours above are the only thing the CSS owns. */

.chart-card { min-width: 0; }
/* A panel carrying a data table gets the full row: two ~500px columns is fine
   for a bar chart and cramped for a six-column table. */
.chart-card--wide { grid-column: 1 / -1; }
/* Wide charts scroll inside their own box; the page body never scrolls sideways. */
.chart-card__body { overflow-x: auto; }
.chart-card svg { display: block; width: 100%; height: auto; min-width: 280px; }
.chart-card__legend {
  display: flex;
  flex-wrap: wrap;
  gap: 6px 16px;
  margin-top: 12px;
  font-size: 13px;
  color: var(--muted);
}
.chart-card__legend span { display: inline-flex; align-items: center; gap: 6px; }
.swatch {
  width: 10px;
  height: 10px;
  border-radius: 3px;
  display: inline-block;
  background: var(--teal);
}

.table-wrap {
  overflow-x: auto;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
}
.table {
  width: 100%;
  min-width: 520px;
  border-collapse: collapse;
  font-size: 14.5px;
}
.table th, .table td {
  padding: 11px 15px;
  text-align: start;
  border-bottom: 1px solid var(--line);
  vertical-align: middle;
}
.table thead th {
  font-size: 11px;
  font-weight: 700;
  letter-spacing: .09em;
  text-transform: uppercase;
  color: var(--muted);
  background: var(--surface-2);
  white-space: nowrap;
}
.table tbody tr:last-child td { border-bottom: 0; }
.table tbody tr:hover td { background: var(--surface-2); }
.table .num { text-align: end; font-variant-numeric: tabular-nums; white-space: nowrap; }

.meter {
  display: block;
  height: 7px;
  border-radius: var(--radius-pill);
  background: var(--surface-2);
  overflow: hidden;
  min-width: 60px;
}
.meter > i {
  display: block;
  height: 100%;
  border-radius: var(--radius-pill);
  background: var(--teal);
}


/* --------------------------------------------- 9b. the on-screen report

   The analysis, rendered from Report.data by reports/_report.html.

   Ported from render.py's PAGE_TMPL so the page and the PDF read as the same
   publication — but expressed in tokens rather than the renderer's fixed
   palette, because this surface has to work in dark mode and on a 360px phone,
   and the PDF only ever has to work on white A4. Where the two disagree, that
   is the reason.

   Every colour that varies per report (bar fills, category dots, column rules)
   arrives as an inline style from the presenter, which is the only thing
   allowed to produce one. Nothing here may reintroduce a colour from the
   template — see the header of reports/_report.html.
   -------------------------------------------------------------------------- */
.rep {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--shadow-1);
  padding: clamp(18px, 4vw, 34px);
  /* The report is the page. Long Azerbaijani compounds and verbatim comments
     both overflow narrow columns, and a report that scrolls sideways on a phone
     is unreadable in a way a PDF at least is not. */
  overflow-wrap: anywhere;
}

/* -- masthead -- */
.rep__masthead { border-bottom: 2px solid var(--ink); padding-bottom: 14px; }
.rep__kicker {
  font-size: 11px; font-weight: 800; letter-spacing: .2em;
  text-transform: uppercase; color: var(--terra); margin: 0 0 10px;
}
.rep__title {
  /* 44px on A4 in the PDF; fluid here so it never wraps to five lines on a
     phone or look lost on a 1080px shell. */
  font-size: clamp(26px, 5.2vw, 42px);
  line-height: 1.05; font-weight: 800; letter-spacing: -.02em; margin: 0 0 10px;
}
.rep__subtitle {
  font-size: clamp(14px, 1.6vw, 16px); line-height: 1.45;
  color: var(--ink-2); margin: 0 0 12px; max-width: 62ch;
}
.rep__source { font-size: 12.5px; color: var(--muted); margin: 0 0 8px; }
.rep__source b { color: var(--ink-2); font-weight: 700; }
.rep__metrics {
  display: flex; flex-wrap: wrap; gap: 4px 16px;
  font-size: 13px; color: var(--muted); margin: 0;
}
.rep__metric b { color: var(--ink); font-weight: 700; }
.rep__legend { display: flex; flex-wrap: wrap; gap: 6px 18px; margin: 12px 0 0; }
.rep__legend-item {
  display: inline-flex; align-items: center; gap: 7px;
  font-size: 12.5px; font-weight: 600; color: var(--ink-2);
}
.rep__swatch { width: 11px; height: 11px; border-radius: 3px; flex: none; }

/* -- hero: the VOICE / SUPPORT axes -- */
.rep__hero { margin-top: 24px; }
.rep__axis {
  background: var(--surface-2); border-radius: var(--radius);
  padding: 16px 18px; margin-bottom: 14px;
}
.rep__axis-head {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 10px; margin-bottom: 12px;
}
.rep__axis-title { font-size: 15.5px; font-weight: 700; }
.rep__axis-note { font-size: 12px; color: var(--muted); }
.rep__bar-row {
  display: grid; grid-template-columns: minmax(70px, 130px) 1fr auto;
  align-items: center; gap: 12px; margin: 9px 0;
}
.rep__bar-label {
  font-size: 12px; font-weight: 700; letter-spacing: .03em;
  color: var(--ink-2); text-align: right;
}
.rep__bar-track {
  height: 16px; background: var(--paper); border-radius: 8px; overflow: hidden;
}
.rep__bar-fill { height: 100%; border-radius: 8px; min-width: 3px; }
.rep__bar-value {
  font-size: clamp(22px, 4vw, 30px); font-weight: 800; letter-spacing: -.02em;
  font-variant-numeric: tabular-nums; text-align: right; white-space: nowrap;
}
.rep__bar-tag {
  font-size: 10px; font-weight: 800; letter-spacing: .02em; margin-left: 7px;
  border: 1.5px solid currentColor; border-radius: var(--radius-pill);
  padding: 1px 7px; vertical-align: middle;
}
.rep__verdict {
  font-size: clamp(16px, 2.4vw, 19px); font-weight: 700; line-height: 1.35;
  text-align: center; letter-spacing: -.01em;
  margin: 18px 0 0; padding: 14px 16px;
  background: var(--teal-tint); border-radius: var(--radius); color: var(--ink);
}

/* -- generic block -- */
.rep__block { margin-top: 30px; }
.rep__sec-title {
  font-size: clamp(16px, 2.2vw, 19px); font-weight: 800; letter-spacing: -.01em;
  margin: 0 0 14px; padding-bottom: 8px; border-bottom: 1px solid var(--line);
}
.rep__lead { font-size: 14px; line-height: 1.5; color: var(--ink-2); margin: 0 0 14px; max-width: 70ch; }
.rep__footnote {
  font-size: 12.5px; line-height: 1.45; color: var(--muted);
  font-style: italic; margin: 14px 0 0;
}

/* -- categories -- */
.rep__cats { display: flex; flex-direction: column; }
.rep__cat-row:last-child { border-bottom: 0; }
.rep__cat-row {
  display: grid; grid-template-columns: auto minmax(0, 1fr) 34% auto;
  align-items: center; gap: 10px;
  padding: 7px 0; border-bottom: 1px solid var(--line);
}
.rep__cat-dot { width: 9px; height: 9px; border-radius: 50%; flex: none; }
.rep__cat-label { font-size: 13.5px; font-weight: 600; }
.rep__cat-bar { height: 7px; background: var(--surface-2); border-radius: 4px; overflow: hidden; }
.rep__cat-fill { display: block; height: 100%; border-radius: 4px; opacity: .85; min-width: 2px; }
.rep__cat-count { font-size: 16px; font-weight: 800; min-width: 2ch; text-align: right; }

/* -- drivers / weaknesses -- */
.rep__cols {
  /* auto-fit, not `1fr 1fr`: the schema allows 3+ entities and single mode has
     exactly one, and a hardcoded two-column grid rendered the first as a
     squeeze and the second as a half-width orphan. */
  display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: 22px;
}
.rep__col-head {
  display: flex; align-items: center; gap: 8px;
  font-size: 14.5px; font-weight: 800;
  padding-bottom: 8px; border-bottom: 2px solid; margin-bottom: 10px;
}
.rep__col-chip { width: 11px; height: 11px; border-radius: 3px; flex: none; }
.rep__col-list { list-style: none; margin: 0; padding: 0; }
.rep__col-list li {
  position: relative; font-size: 13.5px; line-height: 1.45;
  padding: 5px 0 5px 20px; color: var(--ink-2);
}
.rep__mk { position: absolute; left: 0; font-weight: 800; }

/* -- top comments -- */
.rep__tc { display: flex; flex-direction: column; gap: 9px; }
.rep__tc-row {
  display: grid; grid-template-columns: 62px minmax(0, 1fr);
  gap: 14px; align-items: center;
  background: var(--surface-2); border-radius: var(--radius);
  padding: 12px 15px;
}
.rep__tc-likes { text-align: center; }
.rep__heart { display: block; color: var(--terra); font-size: 13px; line-height: 1; }
.rep__tc-n { font-size: 24px; font-weight: 800; letter-spacing: -.02em; }
.rep__quote {
  margin: 0; font-size: 13.5px; line-height: 1.45; font-weight: 600; color: var(--ink);
}
.rep__quote::before { content: "\201C"; }
.rep__quote::after  { content: "\201D"; }
.rep__tags { margin: 7px 0 0; display: flex; flex-wrap: wrap; gap: 5px; }
.rep__chip {
  font-size: 9.5px; font-weight: 800; letter-spacing: .08em; text-transform: uppercase;
  color: var(--muted); background: var(--paper);
  border-radius: var(--radius-pill); padding: 3px 9px;
}

/* -- market -- */
.rep__brands { display: flex; flex-wrap: wrap; gap: 8px; margin: 0; }
.rep__brand {
  font-size: 13px; font-weight: 600; color: var(--ink-2);
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--radius-pill); padding: 6px 13px;
}

/* -- conclusions -- */
.rep__conc { display: flex; flex-direction: column; }
.rep__conc-row {
  display: grid; grid-template-columns: auto minmax(0, 1fr); gap: 14px;
  padding: 12px 0; border-top: 1px solid var(--line);
}
.rep__conc-row:first-child { border-top: 0; padding-top: 0; }
.rep__conc-n {
  font-size: 15px; font-weight: 800; color: var(--soft); letter-spacing: -.02em;
}
.rep__conc-head { font-size: 14.5px; font-weight: 800; margin: 0 0 5px; line-height: 1.3; }
.rep__conc-body { font-size: 13.5px; line-height: 1.5; color: var(--ink-2); margin: 0; }

.rep__method {
  font-size: 12px; line-height: 1.5; color: var(--muted);
  margin: 26px 0 0; padding-top: 14px; border-top: 1px solid var(--line);
}

/* ---------------------------------- 10. responsive, print, a11y prefs */
/* Screen-reader-only text. Used for the like counts in the report, where the
   number sits next to a decorative ♥ that conveys nothing to a screen reader. */
.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;
}

@media (max-width: 860px) {
  .detail-grid { grid-template-columns: minmax(0, 1fr); }
}

@media (max-width: 640px) {
  body { font-size: 15.5px; }
  .brand__tag { display: none; }
  .site-head__inner { min-height: 56px; }
  .nav { order: 3; width: 100%; overflow-x: auto; padding-bottom: 4px; }
  .nav a { padding: 6px 10px; font-size: 14px; }
  .report-item { grid-template-columns: minmax(0, 1fr); }
  .report-item__side { justify-self: start; }
  .page-head { align-items: flex-start; }
  .page-head__actions { width: 100%; }
  .page-head__actions .btn { flex: 1 1 auto; }
  .form-actions .btn { flex: 1 1 auto; }
  .kv { grid-template-columns: minmax(0, 1fr); gap: 2px 0; }
  .kv dd { margin-bottom: 10px; }

  /* Touch targets. Both platforms ask for ~44px and every one of these was
     around 31px, sitting in rows with 6px gaps — the status filters are the
     primary navigation on the reports list, so the smallest targets in the
     product were also the most used. Scoped to the mobile block so desktop
     density is untouched. */
  .filters a,
  .nav a,
  .btn--sm { min-height: 44px; display: inline-flex; align-items: center; }
  .theme-toggle { width: 44px; height: 44px; }

  /* The report's three-column bar row does not survive 360px: the label column
     alone would take half the width and the value is the largest type on the
     page. Give the label its own line and let the track keep the width. */
  .rep__bar-row { grid-template-columns: minmax(0, 1fr) auto; }
  .rep__bar-label { grid-column: 1 / -1; text-align: left; }

  /* Same idea for categories: dot + label + count read as one line, the bar
     becomes a full-width rule under them rather than a 34% sliver. */
  .rep__cat-row { grid-template-columns: auto minmax(0, 1fr) auto; }
  .rep__cat-bar { grid-column: 1 / -1; }
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
  }
  .report-item:hover { transform: none; }
}

@media (prefers-contrast: more) {
  :root { --line: var(--ink-2); --line-2: var(--ink-2); --muted: var(--ink-2); }
}

@media print {
  .site-head, .site-foot, .page-head__actions, .job, .form-actions, .skip-link { display: none !important; }
  body { background: #fff; color: #000; }
  .card, .report-item { box-shadow: none; border-color: #ccc; break-inside: avoid; }
  a[href^="http"]::after { content: " (" attr(href) ")"; font-size: 11px; color: #555; }

  /* Ctrl-P on the report page is now a real path to paper, so it should not
     produce something worse than the PDF we already generate. Same
     break-inside rules render.py uses; the download button stays the better
     artifact and this is the fallback. */
  .rep { border: 0; box-shadow: none; padding: 0; }
  .rep__axis, .rep__cat-row, .rep__tc-row, .rep__conc-row, .rep__col { break-inside: avoid; }
  .rep__sec-title { break-after: avoid; }
  .rep__verdict { background: #f2f0eb; }
}
