/* Shared design tokens across every customer-facing surface (app, PDF, landing page) --
   ported from src/constants.py's BRAND dict + the user-picked "Field Survey" mockup
   (docs/design_mockups_2026-07-03/1-cartographic.html) and landing/index.html.
   Keeping one token set here means all three surfaces can't drift out of sync. */
:root {
  --canopy-deep: #003049;
  --canopy: #0d4a68;
  --canopy-line: rgba(245, 248, 251, 0.18);
  --paper: #f5f8fb;
  --paper-card: #e8eef4;
  --gold: #fcbf49;
  --gold-dark: #d9a032;
  --clearing: #f77f00;
  --clearing-dark: #d66b00;
  --mist: #5f7182;
  --ink: #062330;
  --red: #d62828;
  --amber: #946419; /* darkened from #c08a2c 2026-08-24 (queue item 70, WCAG AA check): the
    original value read 3.04:1 against both white and --paper, failing the 4.5:1 normal-text
    threshold for every real usage found (.case-flag--amber's 9.5px white-on-fill label,
    .tile.amber's 11px label, .tag.context's amber-on-paper text) -- only the large 26px
    .tile .n number and small UI-boundary swatches were ever safe at the old value. This
    passes 4.5:1+ against both white and --paper while staying recognizably amber/gold, not
    drifting toward brown or red -- same hue identity, no flag-semantics change. */
  --green: #3f7a53;
  --slate: #7a6a96;
  --rule: rgba(6, 35, 48, 0.14);
  --serif: Helvetica, "Helvetica Neue", Arial, sans-serif;
  --sans: Helvetica, "Helvetica Neue", Arial, sans-serif;
  --mono: Helvetica, "Helvetica Neue", Arial, sans-serif;
}

/* ---------- Deforestation-screening mode token variant (D170/D167, Item 73
   Session B; body-text tokens redone D180) ----------
   Same token set, dark forest-green in place of dark navy blue. --canopy-deep/
   --canopy/--mist/--ink were originally the existing, already-reviewed
   BRAND_LEGACY_FIELD_SURVEY palette from src/constants.py -- a genuinely
   different, independently hand-picked green palette, not derived from the
   navy tokens it replaces. That was fine on its own, but once the hero/raster
   fix (D179) settled on a precise, consistent rule -- rotate each navy color's
   hue by -50deg, leave saturation and value completely untouched -- the two
   didn't match: BRAND_LEGACY's hue shift varied 41-80deg token to token and
   desaturated everything by roughly a third to a half, so body text/headings
   read as a muted grayish-green next to the hero's vivid, precisely-rotated
   one ("doesn't match the green theme"). Recomputed all four using the exact
   same -50deg/S-unchanged/V-unchanged rule as the hero, from the same navy
   source values the base (non-deforestation) tokens below use: --ink from
   #062330, --canopy from #0d4a68, --canopy-deep from #003049, --mist from
   #5f7182. Now the whole deforestation palette -- hero, raster, footer, body
   headings, links, muted text -- is one internally consistent hue rotation,
   not two independently-chosen greens sitting next to each other. --paper/
   --paper-card (backgrounds, not text) and --clearing/--clearing-dark (the
   nearby-pressure alert color, semantically distinct from the navy/green
   structural swap) are intentionally left as-is, matching D167's rule that
   flag/alert semantics stay identical across both modes -- only the
   navy-derived structural tokens got recomputed. */
:root[data-mode="deforestation"] {
  --canopy-deep: #004925;
  --canopy: #0d683a;
  --canopy-line: rgba(243, 245, 239, 0.18);
  --paper: #f3f5ef;
  --paper-card: #e7ebe0;
  --clearing: #b8592b;
  --clearing-dark: #954a24;
  --mist: #5f8276;
  --ink: #06301a;
  --rule: rgba(6, 48, 26, 0.14);
}
/* The shared Toraja contour raster (toraja-contours.webp) carries its navy
   background wash baked into the image, with the tan contour lines baked in
   at a completely different hue (measured: background cluster ~190-230deg,
   line cluster ~15-90deg, no overlap). Recoloring it for deforestation mode
   needs a real asset, not a CSS filter -- confirmed by direct experiment,
   not assumption: any single filter (hue-rotate etc.) applies to the whole
   image at once, so it recolors the tan lines right along with the
   background (tried, made lines go blue-ish/pink depending on the angle --
   there's no filter that touches one hue cluster and not the other).
   Two earlier asset-level attempts both introduced a real, measured
   crispness loss (Laplacian-variance sharpness ~17-25% below the untouched
   original, confirmed objectively, not just eyeballed) by rescaling
   saturation/value on the background cluster and/or the line cluster --
   any V/S rescale forces every affected pixel through a float32 RGB<->HSV
   round-trip, and critically this was ALSO being applied to the
   anti-aliased transition pixels at line edges (not just flat background),
   which measurably softened exactly the edges a viewer would notice.
   toraja-contours-green.webp/@2x is now a *pure hue rotation only* --
   background-cluster pixels (hue 15-90deg excluded, everything else with
   real saturation included) get -50deg added to their hue and NOTHING
   else touched: saturation and value are copied through completely
   unchanged, so the background reads exactly as dark as the original navy
   backdrop (same V), not a separately-chosen darkness. Tan-line pixels are
   completely excluded from any computation -- direct copy, zero float
   round-trip, zero possible precision loss. Confirmed by measurement: this
   version's sharpness is within ~1.5% of the untouched original (previous
   attempts were 17-25% below). This also resolves the earlier "crazy
   contrast" complaint as a side effect, not a separate fix: the
   line-to-background brightness ratio is now numerically identical to the
   navy page's own (same V on both sides, only hue rotated), so it reads
   exactly as calm as the page it's copied from. Re-encoded at quality 95.
   Each raster-using selector below overrides only background-image,
   leaving its own position/size/repeat/opacity and its own
   grayscale/saturate/contrast toning filter completely alone. */
:root[data-mode="deforestation"] .site-main--contours::before,
:root[data-mode="deforestation"] .site-main--contours::after,
:root[data-mode="deforestation"] .homepage-atlas::before,
:root[data-mode="deforestation"] .homepage-atlas::after,
:root[data-mode="deforestation"] .homepage-atlas__flow::before,
:root[data-mode="deforestation"] footer.homepage-cta::before {
  background-image: url("/static/img/toraja-contours-green.fp-6a1ac30c3c.webp");
}
:root[data-mode="deforestation"] .world-map,
:root[data-mode="deforestation"] .homepage-atlas__hero-continuation {
  background-image: url("/static/img/toraja-contours-green.fp-6a1ac30c3c.webp");
  background-image: -webkit-image-set(
    url("/static/img/toraja-contours-green.fp-6a1ac30c3c.webp") 1x,
    url("/static/img/toraja-contours-green@2x.fp-603846c344.webp") 2x
  );
  background-image: image-set(
    url("/static/img/toraja-contours-green.fp-6a1ac30c3c.webp") 1x,
    url("/static/img/toraja-contours-green@2x.fp-603846c344.webp") 2x
  );
}
/* Solid fills behind/around the raster (.hero--full/.hero--compact's own
   background was previously left un-overridden entirely -- a real bug, the
   hero band was still literally navy #17273a underneath the recolored
   raster). footer's own dark band is likewise a hardcoded hex, not
   token-driven -- same override target as the hero so both dark bands read
   as one consistent color, exactly like navy #17273a is shared by both on
   the original page. #173a30 is #17273a's own hue rotated by the same
   -50deg used on the raster, saturation and value both left untouched --
   not a separately eyeballed or swatch-matched color, so there is
   zero drift between the solid fill and the raster's own background tone,
   and the fill is exactly as dark as the navy original, no darker. */
:root[data-mode="deforestation"] .hero--full,
:root[data-mode="deforestation"] .hero--compact,
:root[data-mode="deforestation"] footer.homepage-cta {
  background: #173a30;
}
:root[data-mode="deforestation"] .hero--contour::after {
  background: radial-gradient(ellipse 58% 78% at 19% 48%, rgba(10, 33, 28, 0.34), rgba(10, 33, 28, 0.17) 54%, transparent 82%);
}

* { box-sizing: border-box; }

html { scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
}

/* Progressive-enhancement scroll reveal (marketing pages only, app/static/js/reveal.js).
   No baseline opacity:0 anywhere here on purpose -- if JS never runs or
   IntersectionObserver is unsupported, sections simply render normally with zero
   flash-of-hidden-content risk. The animation only ever ADDS visible motion on top
   of an already-visible default. */
@keyframes reveal-up { from { opacity: 0; transform: translateY(14px); } to { opacity: 1; transform: translateY(0); } }
.reveal-in { animation: reveal-up 0.6s ease both; }
@media (prefers-reduced-motion: reduce) {
  .reveal-in { animation: none; }
}

/* Site-wide horizontal-overflow backstop (STATUS.md 9.0 item 7 -- "fix the
   pattern, not just one instance"): every wide table on the site is already
   wrapped in .table-scroll (its own overflow-x:auto below), so no page should
   ever need to scroll sideways as a whole. This is defense-in-depth, not the
   primary fix -- it guards against the NEXT wide element (a table added without
   its wrapper, a long unbroken string, a fixed-width widget) silently reopening
   this exact failure mode instead of being caught in review. Setting overflow-x
   on `body` clips the viewport itself per the CSS spec's html/body overflow
   propagation quirk; it does not affect a descendant .table-scroll's own
   independent scroll container, which still scrolls normally within itself. */
body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--sans);
  font-size: 17px;
  line-height: 1.6;
  overflow-x: hidden;
}

.wrap { max-width: 920px; margin: 0 auto; padding: 0 28px; }
/* Dashboard pages (results, demo) need real room for a wide data table + map side
   by side -- the site's usual 920px is a prose/reading-column width, tuned for
   marketing copy, not a 15-column table. Scoped to a modifier (not a change to
   .wrap itself) so every prose page keeps its narrower, more readable column. */
.wrap--wide { max-width: 1360px; }

a { color: var(--gold-dark); }
a:hover { color: var(--gold); }
a:focus-visible, button:focus-visible, input:focus-visible { outline: 2px solid var(--gold); outline-offset: 3px; }

h1, h2, h3 { font-family: var(--serif); font-weight: 400; text-wrap: balance; margin: 0; }

.eyebrow {
  font-family: var(--mono);
  font-size: 12.5px;
  letter-spacing: 0.06em;
  color: var(--mist);
  font-variant-numeric: tabular-nums;
}

.top-nav {
  border-bottom: 1px solid var(--rule);
  padding: 18px 0;
}
.top-nav .wrap { display: flex; align-items: center; justify-content: space-between; }
.top-nav .wordmark {
  font-family: var(--mono);
  font-size: 13px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--canopy);
}
/* Token-gated app-area nav (app/templates/_app_top_nav.html.j2, round 2 session 85) --
   deliberately independent of the public marketing site's .site-nav/.nav-links (which
   carry Alpine state for its mobile hamburger): this is a much simpler always-visible
   link row, scoped only to /app/* pages, that makes "New screening"/"Collect supplier
   data"/"Monitoring" first-class peers instead of one buried inline sentence. */
.top-nav-links { display: flex; gap: 22px; align-items: center; flex-wrap: wrap; }
.top-nav-links a {
  font-family: var(--sans);
  font-size: 13.5px;
  font-weight: 600;
  color: var(--mist);
  text-decoration: none;
}
.top-nav-links a:hover { color: var(--canopy); }

@media (max-width: 700px) {
  .top-nav--app .wrap { flex-direction: column; gap: 12px; }
  .top-nav--app .top-nav-links { justify-content: center; gap: 8px 16px; }
  .top-nav--app .top-nav-links a { font-size: 12.5px; }
}

footer.site-footer { padding: 44px 0 64px; }
.footer-notes { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 20px 42px; }
.disclaimer,
.attribution { font-size: 12.5px; color: var(--mist); line-height: 1.65; }
.disclaimer strong { color: var(--ink); }
.attribution strong { color: var(--ink); }
.disclaimer a,
.attribution a { white-space: nowrap; }
.legal-links { margin-top: 18px; display: flex; gap: 18px; flex-wrap: wrap; }
.legal-links a { font-size: 11.5px; color: var(--mist); text-decoration: none; border-bottom: 1px solid var(--rule); }
.legal-links a:hover { color: var(--canopy); border-color: var(--canopy); }
.site-footer__inner--home { width: min(100% - 80px, 1180px); max-width: none; padding: 0; }

@media (max-width: 700px) {
  .footer-notes { grid-template-columns: 1fr; gap: 10px; }
  .site-footer__inner--home { width: min(100% - 40px, 920px); }
}

/* ---------- Shared contour canvas ----------
   The settled homepage owns its bespoke Living Atlas composition and explicitly
   opts out of this layer. Every other full page inherits a quieter version of the
   same Toraja terrain and slow-meander movement. The base field prevents isolated
   decorative patches; the masked field adds a restrained path down the page.
   Functional surfaces remain opaque enough that tables, forms, maps, and legal
   text keep their existing information hierarchy. */
.site-main--contours {
  --site-contour-strength: 0.11;
  display: flow-root;
  position: relative;
  isolation: isolate;
  overflow: clip;
  min-height: 42vh;
  background: #f0f1ec;
}
.site-main--contours::before,
.site-main--contours::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  background: url("/static/img/toraja-contours.fp-8f3cd33197.webp") 50% 0 / 1180px auto repeat;
  mix-blend-mode: multiply;
  filter: grayscale(0.24) saturate(0.66);
}
.site-main--contours::before {
  opacity: calc(var(--site-contour-strength) * 0.24);
}
.site-main--contours::after {
  opacity: calc(var(--site-contour-strength) * 0.86);
  -webkit-mask-image:
    radial-gradient(ellipse 52% 16% at 78% 3%, #000 36%, transparent 76%),
    radial-gradient(ellipse 55% 17% at 67% 18%, #000 38%, transparent 77%),
    radial-gradient(ellipse 57% 18% at 48% 34%, #000 38%, transparent 78%),
    radial-gradient(ellipse 55% 18% at 34% 50%, #000 38%, transparent 78%),
    radial-gradient(ellipse 56% 18% at 45% 66%, #000 38%, transparent 78%),
    radial-gradient(ellipse 54% 17% at 64% 82%, #000 38%, transparent 77%),
    radial-gradient(ellipse 50% 15% at 73% 97%, #000 36%, transparent 76%);
  mask-image:
    radial-gradient(ellipse 52% 16% at 78% 3%, #000 36%, transparent 76%),
    radial-gradient(ellipse 55% 17% at 67% 18%, #000 38%, transparent 77%),
    radial-gradient(ellipse 57% 18% at 48% 34%, #000 38%, transparent 78%),
    radial-gradient(ellipse 55% 18% at 34% 50%, #000 38%, transparent 78%),
    radial-gradient(ellipse 56% 18% at 45% 66%, #000 38%, transparent 78%),
    radial-gradient(ellipse 54% 17% at 64% 82%, #000 38%, transparent 77%),
    radial-gradient(ellipse 50% 15% at 73% 97%, #000 36%, transparent 76%);
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;
}
.site-main--contours > * {
  position: relative;
  z-index: 1;
}
/* Data-dense surfaces sit on a calm reading plane while the terrain stays visible
   in the surrounding whitespace. This is intentionally scoped off the homepage. */
.site-main--contours table.results,
.site-main--contours table.mapping {
  background: rgba(245, 248, 251, 0.94);
}
.site-main--contours .results-split-table,
.site-main--contours .results-split-map {
  background: rgba(245, 248, 251, 0.84);
  border: 1px solid rgba(6, 35, 48, 0.08);
  border-radius: 8px;
  padding: 18px;
}
@media (max-width: 700px) {
  .site-main--contours { --site-contour-strength: 0.095; }
  .site-main--contours .results-split-table,
  .site-main--contours .results-split-map {
    padding: 12px;
  }
}
@media (prefers-contrast: more) {
  .site-main--contours {
    --site-contour-strength: 0.035;
    background: var(--paper);
  }
}

/* ---------- Alert / disclaimer boxes (app tool page) ---------- */
.notice {
  background: var(--paper-card);
  border-left: 3px solid var(--clearing);
  border-radius: 2px;
  padding: 14px 18px;
  margin-bottom: 12px;
  font-size: 14.5px;
}
.notice.info { border-left-color: var(--canopy); }
.notice strong { color: var(--ink); }

.collect-share-link-row { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin-top: 8px; }
.collect-share-link-row code { flex: 1 1 auto; min-width: 0; }
.collect-share-actions { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 10px; }
.collect-share-actions .btn-secondary { text-decoration: none; }
/* Same [hidden]-vs-.btn-secondary specificity fix as collect.css's
   #collect-walk-drop-btn -- .btn-secondary's own `display` otherwise wins over
   the browser's default [hidden]{display:none}. */
#collect-share-native-btn[hidden] { display: none; }
@media (max-width: 560px) { .collect-share-link-row { flex-direction: column; align-items: stretch; } }

/* ---------- Buttons / forms ---------- */
.btn-primary {
  display: inline-block;
  background: var(--gold);
  color: var(--canopy-deep);
  font-family: var(--sans);
  font-weight: 600;
  font-size: 15px;
  text-decoration: none;
  border: none;
  padding: 12px 22px;
  border-radius: 3px;
  cursor: pointer;
  transition: background 0.15s ease;
}
.btn-primary:hover { background: var(--gold-dark); color: var(--canopy-deep); }
.btn-primary:disabled { background: var(--mist); cursor: not-allowed; }

.btn-secondary {
  display: inline-block;
  background: var(--paper-card);
  color: var(--ink);
  font-family: var(--sans);
  font-size: 14px;
  text-decoration: none;
  border: 1px solid var(--rule);
  padding: 10px 18px;
  border-radius: 3px;
  cursor: pointer;
}
.btn-secondary:hover { border-color: var(--canopy); }

form.upload-form { background: var(--paper-card); border-radius: 4px; padding: 24px; margin-bottom: 24px; }
form.upload-form label { display: block; font-size: 14px; margin-bottom: 8px; color: var(--ink); }
form.upload-form input[type="file"], form.upload-form select, form.upload-form input[type="email"] {
  font-family: var(--sans); font-size: 14px; padding: 8px; width: 100%;
  border: 1px solid var(--rule); border-radius: 3px; background: #fff; margin-bottom: 16px;
}
.form-hint { font-size: 13px; color: var(--mist); margin: -10px 0 16px; }
form.upload-form .btn-primary { margin-bottom: 16px; }
.trn-form { max-width: 640px; }
.trn-form input[type="text"] { width: 100%; box-sizing: border-box; }

/* ---------- Persistent case workspace ---------- */
.case-page { padding-top: 48px; padding-bottom: 48px; }
.case-page-title {
  max-width: 22ch; margin-top: 8px; color: var(--canopy); font-size: clamp(30px, 4vw, 46px);
  line-height: 1.08;
}
.case-page .lede { max-width: 66ch; }
.case-page-heading, .case-detail-header {
  display: flex; align-items: flex-start; justify-content: space-between; gap: 32px; margin-bottom: 30px;
}
.case-page-heading > .btn-primary, .case-detail-header > .btn-primary { flex: 0 0 auto; margin-top: 8px; }
.case-view-toggle { display: flex; gap: 8px; margin: 28px 0 22px; }
.case-view-toggle a {
  padding: 7px 12px; border: 1px solid var(--rule); border-radius: 3px; color: var(--mist);
  font-family: var(--mono); font-size: 11px; text-decoration: none; text-transform: uppercase;
}
.case-view-toggle a[aria-current="page"] { border-color: var(--canopy); background: var(--canopy); color: #fff; }
.case-card-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 18px; }
.case-card {
  display: block; padding: 24px; border: 1px solid rgba(6, 35, 48, 0.16); border-top: 3px solid var(--canopy);
  border-radius: 3px; background: rgba(255, 255, 255, 0.76); color: var(--ink); text-decoration: none;
  box-shadow: 0 12px 30px rgba(23, 39, 58, 0.06); transition: transform 0.15s ease, border-color 0.15s ease;
}
.case-card:hover { transform: translateY(-2px); border-color: var(--canopy); color: var(--ink); }
.case-card--archived { opacity: 0.72; border-top-color: var(--mist); }
.case-card h2 { margin: 4px 0 10px; color: var(--canopy); font-size: 25px; }
.case-card-topline { display: flex; align-items: center; justify-content: space-between; gap: 14px; }
.case-card-badges { display: flex; flex-wrap: wrap; gap: 6px; margin: 0 0 14px; }
.pill {
  display: inline-block; padding: 3px 9px; border: 1px solid var(--rule); border-radius: 999px;
  background: rgba(255, 255, 255, 0.7); color: var(--canopy); font-size: 11px; font-weight: 600;
}
.case-readiness-pill--incomplete { border-color: var(--gold-dark); color: var(--gold-dark); }
.case-readiness-pill--review_required { border-color: var(--red); color: var(--red); }
.case-readiness-pill--ready_for_operator_review { border-color: var(--green); color: var(--green); }
.case-reference, .case-stage, .case-version, .case-module-kicker {
  color: var(--mist); font-family: var(--mono); font-size: 10.5px; letter-spacing: 0.06em; text-transform: uppercase;
}
.case-reference { display: inline-flex; align-items: center; gap: 5px; }
.case-reference .icon { opacity: 0.75; }
.case-stage { padding: 3px 7px; border: 1px solid var(--rule); border-radius: 2px; }
.case-card-facts { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px 20px; margin: 0; }
.case-card-facts div { min-width: 0; }
.case-card-facts dt { color: var(--mist); font-family: var(--mono); font-size: 10px; text-transform: uppercase; }
.case-card-facts dd { overflow: hidden; margin: 2px 0 0; font-size: 14px; text-overflow: ellipsis; white-space: nowrap; }
.case-empty {
  padding: 34px; border: 1px solid var(--rule); border-left: 4px solid var(--canopy);
  background: rgba(255, 255, 255, 0.72);
}
.case-empty h2 { margin: 8px 0 10px; color: var(--canopy); font-size: 27px; }
.case-empty--compact { padding: 20px 24px; }
.case-empty--compact p { margin: 0; }
.case-error { margin: 22px 0; border-left-color: var(--red); }
.case-success { margin: 22px 0; border-left-color: var(--green); }
.case-form { margin-top: 24px; padding: 28px; border-radius: 4px; background: rgba(232, 238, 244, 0.9); }
.case-form-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 18px 22px; }
.case-fieldset { min-width: 0; margin: 0; padding: 0; border: 0; }
.case-fieldset:disabled { opacity: 0.72; }
.case-field { display: flex; min-width: 0; flex-direction: column; gap: 7px; color: var(--ink); font-size: 13px; }
.case-field--wide { grid-column: 1 / -1; }
.case-field > span { font-weight: 650; }
.case-field input, .case-field select, .case-field textarea, .case-attach-form input, .case-attach-form select {
  width: 100%; padding: 10px 11px; border: 1px solid var(--rule); border-radius: 3px; background: #fff;
  color: var(--ink); font: inherit;
}
.case-field textarea { resize: vertical; }
.case-field small { color: var(--mist); font-size: 12px; }
.field-help { color: var(--mist); font-size: 12px; }
.field-help summary { width: fit-content; cursor: pointer; text-decoration: underline; text-underline-offset: 2px; }
.field-help small { display: block; margin-top: 7px; line-height: 1.45; }
.case-form-actions { display: flex; align-items: center; gap: 12px; margin-top: 24px; }
.case-workspace-grid {
  display: grid; grid-template-columns: minmax(0, 1.8fr) minmax(260px, 0.72fr);
  grid-template-areas: "main readiness" "main rail"; gap: 16px 24px; align-items: start;
}
.case-workspace-main { min-width: 0; grid-area: main; }
.case-workspace-main .case-form { margin-top: 12px; }
.case-section-heading { display: flex; align-items: end; justify-content: space-between; gap: 20px; }
.case-section-heading h2 { margin-top: 4px; color: var(--canopy); font-size: 25px; }
.case-workspace-rail { display: grid; grid-area: rail; gap: 16px; }
.case-module-card {
  padding: 22px; border-top: 3px solid var(--canopy); background: rgba(255, 255, 255, 0.76);
  box-shadow: 0 10px 28px rgba(23, 39, 58, 0.05);
}
.case-module-card h2 { margin: 6px 0 10px; color: var(--canopy); font-size: 23px; }
.case-module-card p, .case-module-card li { color: var(--mist); font-size: 13px; }
.case-module-card ul { margin: 10px 0 0; padding-left: 20px; }
.case-module-card--future { border-top-color: var(--gold-dark); }
.case-readiness-card { grid-area: readiness; border-top-width: 4px; }
.case-readiness-card--incomplete { border-top-color: var(--gold-dark); }
.case-readiness-card--review_required { border-top-color: var(--red); }
.case-readiness-card--ready_for_operator_review { border-top-color: var(--green); }
.case-readiness-heading { display: flex; align-items: start; justify-content: space-between; gap: 16px; }
.case-readiness-heading h2 { margin-bottom: 6px; }
.case-readiness-score {
  flex: 0 0 auto; border: 1px solid var(--rule); border-radius: 999px;
  padding: 5px 9px; color: var(--canopy); font-size: 12px; font-weight: 700;
}
.case-readiness-track { height: 8px; overflow: hidden; border-radius: 999px; background: rgba(13,74,104,.13); }
.case-readiness-track span { display: block; height: 100%; border-radius: inherit; background: var(--gold); }
.case-readiness-card--review_required .case-readiness-track span { background: var(--red); }
.case-readiness-card--ready_for_operator_review .case-readiness-track span { background: var(--green); }
.case-readiness-label { margin: 13px 0 0; color: var(--canopy) !important; }
.case-readiness-actions, .case-readiness-blockers { margin-top: 18px; padding-top: 15px; border-top: 1px solid var(--rule); }
.case-readiness-actions ol, .case-readiness-blockers ul { margin: 10px 0 0; padding-left: 18px; }
.case-readiness-actions li, .case-readiness-blockers li { margin-bottom: 10px; }
.case-readiness-actions a, .case-readiness-blockers a { display: block; width: fit-content; color: var(--canopy); font-weight: 700; }
.case-readiness-actions li span, .case-readiness-blockers li span { display: block; margin-top: 2px; color: var(--mist); line-height: 1.45; }
.case-retention-form { display: grid; gap: 10px; margin: 18px 0; padding-top: 16px; border-top: 1px solid var(--rule); }
.case-retention-form .btn-secondary { justify-content: center; width: 100%; }
.case-legality { margin-top: 56px; }
.case-section-intro { max-width: 82ch; margin: 12px 0 20px; color: var(--mist); font-size: 14px; }
.case-legality-warning { margin: 14px 0; border-left-color: var(--amber); }
.scope-verdict {
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 1px; margin-top: 22px;
  border: 1px solid var(--rule); background: var(--rule);
}
.scope-verdict > div { padding: 16px; background: rgba(255,255,255,.88); }
.scope-verdict span { display: block; color: var(--mist); font-family: var(--mono); font-size: 10px; text-transform: uppercase; }
.scope-verdict strong { display: block; margin-top: 5px; color: var(--canopy); font-family: var(--serif); font-size: 18px; }
.scope-verdict small { display: block; margin-top: 3px; color: var(--mist); font-size: 11px; }
.scope-verdict-detail { grid-column: 1 / -1; padding: 12px 16px; background: rgba(255,255,255,.88); }
.scope-verdict-detail summary { cursor: pointer; color: var(--canopy); font-size: 13px; font-weight: 700; }
.scope-verdict-detail p { max-width: 82ch; margin: 10px 0 0; color: var(--mist); font-size: 13px; }
.case-legality-summary {
  display: flex; flex-wrap: wrap; gap: 1px; margin: 18px 0; border: 1px solid var(--rule);
  background: var(--rule);
}
.case-legality-summary > div {
  display: flex; min-width: 120px; flex: 1 1 120px; align-items: baseline; gap: 8px;
  padding: 13px 16px; background: rgba(255, 255, 255, 0.84);
}
.case-legality-summary strong { color: var(--canopy); font-family: var(--serif); font-size: 23px; }
.case-legality-summary span { color: var(--mist); font-family: var(--mono); font-size: 10px; text-transform: uppercase; }
.case-legality-summary .case-legality-summary--stale { background: rgba(230, 154, 45, 0.11); }
.case-legality-list { display: grid; gap: 10px; }
.case-legality-item {
  border: 1px solid rgba(6, 35, 48, 0.16); border-radius: 3px; background: rgba(255, 255, 255, 0.78);
  box-shadow: 0 8px 22px rgba(23, 39, 58, 0.04);
}
.case-legality-item > summary {
  display: grid; grid-template-columns: 32px minmax(0, 1fr) auto; gap: 12px; align-items: center;
  padding: 17px 20px; cursor: pointer; list-style: none;
}
.case-legality-item > summary::-webkit-details-marker { display: none; }
.case-legality-item > summary::after {
  content: "+"; grid-column: 4; color: var(--mist); font-family: var(--mono); font-size: 18px;
}
.case-legality-item[open] > summary::after { content: "−"; }
.case-legality-number {
  display: grid; width: 27px; height: 27px; place-items: center; border-radius: 50%;
  background: var(--canopy); color: #fff; font-family: var(--mono); font-size: 11px;
}
.case-legality-title { min-width: 0; }
.case-legality-title strong { display: block; color: var(--canopy); font-family: var(--serif); font-size: 19px; }
.case-legality-title small { color: var(--mist); font-family: var(--mono); font-size: 9.5px; text-transform: uppercase; }
.case-legality-status {
  padding: 4px 7px; border: 1px solid var(--rule); border-radius: 2px; color: var(--mist);
  font-family: var(--mono); font-size: 9.5px; text-transform: uppercase; white-space: nowrap;
}
.case-legality-status--complete { border-color: var(--green); background: var(--green); color: #fff; }
.case-legality-status--progress { border-color: var(--slate); color: var(--slate); }
.case-legality-status--concern { border-color: var(--red); background: var(--red); color: #fff; }
.case-legality-status--stale { border-color: var(--amber); background: var(--amber); color: var(--ink); }
.case-legality-body { padding: 4px 20px 22px 64px; border-top: 1px solid var(--rule); }
.case-legality-body > p:first-of-type { margin: 18px 0 5px; color: var(--ink); }
.case-legality-evidence { margin: 18px 0; padding: 17px; border-left: 3px solid var(--canopy); background: rgba(232, 238, 244, 0.7); }
.case-legality-evidence-heading { display: flex; justify-content: space-between; gap: 16px; }
.case-legality-evidence-heading span { color: var(--mist); font-family: var(--mono); font-size: 10px; text-transform: uppercase; }
.case-legality-evidence ul { margin: 12px 0 0; padding-left: 20px; }
.case-legality-evidence li { margin-top: 7px; font-size: 13px; }
.case-legality-evidence li span { display: block; color: var(--mist); font-size: 11px; }
.case-evidence-upload { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 12px; align-items: end; margin-top: 15px; }
.case-evidence-upload input[type="file"] { padding: 8px; }
.case-legality-form { margin-top: 18px; padding-top: 18px; border-top: 1px solid var(--rule); }
.resolution-choices { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; margin: 0; padding: 0; border: 0; }
.resolution-choices legend { margin-bottom: 8px; font-size: 13px; font-weight: 650; }
.resolution-choices label { display: flex; gap: 10px; padding: 13px; border: 1px solid var(--rule); border-radius: 3px; background: #fff; cursor: pointer; }
.resolution-choices input { flex: none; margin-top: 3px; }
.resolution-choices strong, .resolution-choices small { display: block; }
.resolution-choices small { margin-top: 3px; color: var(--mist); font-size: 11.5px; }
.resolution-clarification { margin-top: 18px; }
.resolution-clarification > summary { width: fit-content; cursor: pointer; color: var(--canopy); font-size: 13px; font-weight: 700; }
.resolution-data-notice { margin: 26px 0 40px; padding-top: 16px; border-top: 1px solid var(--rule); color: var(--mist); font-size: 13px; }
.resolution-data-notice summary { cursor: pointer; color: var(--canopy); font-weight: 700; }
.resolution-data-notice p { margin: 9px 0 0; }
.case-attestation { display: flex; align-items: flex-start; gap: 10px; color: var(--ink); font-size: 13px; line-height: 1.45; }
.case-attestation input { width: auto; margin-top: 3px; }
.case-attestation-history { margin: 14px 0 0; color: var(--mist); font-size: 12px; }
.case-legality-footnote { max-width: 90ch; margin-top: 16px; }
.case-screenings { margin-top: 48px; }
.case-screenings .table-scroll { margin-top: 18px; }
.case-risk-overview { margin-top: 24px; padding: 22px; border-top: 4px solid var(--canopy); background: rgba(255,255,255,.82); }
.case-risk-counts { display: flex; flex-wrap: wrap; gap: 7px; margin-top: 18px; }
.case-risk-bar { display: flex; height: 9px; overflow: hidden; margin-top: 12px; border-radius: 999px; background: var(--rule); }
.case-risk-bar span { display: block; min-width: 0; }
.case-risk-bar .red { background: var(--red); }
.case-risk-bar .amber { background: var(--amber); }
.case-risk-bar .green { background: var(--green); }
.case-risk-bar .slate { background: var(--slate); }
.case-comment-list { display: grid; gap: 14px; margin: 18px 0; padding: 0; list-style: none; }
.case-comment {
  padding: 14px 18px; border: 1px solid var(--rule); border-radius: 3px; background: rgba(255, 255, 255, 0.76);
}
.case-comment-meta { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; }
.case-comment p { margin: 8px 0 0; white-space: pre-wrap; }
.case-comment-form { max-width: 70ch; margin-top: 18px; }
.case-comment-form textarea {
  width: 100%; padding: 10px 12px; border: 1px solid var(--rule); border-radius: 3px; font: inherit; resize: vertical;
}
.case-flag-summary { display: flex; flex-wrap: wrap; gap: 5px; }
.case-flag { padding: 2px 6px; border-radius: 2px; color: #fff; font-family: var(--mono); font-size: 9.5px; white-space: nowrap; }
.case-flag--red { background: var(--red); }
.case-flag--amber { background: var(--amber); }
.case-flag--green { background: var(--green); }
.case-flag--slate { background: var(--slate); }
.case-archive-control { margin-top: 32px; padding-top: 22px; border-top: 1px solid var(--rule); }
.case-result-panel { margin-top: 16px; }
.case-result-linked { display: flex; align-items: center; justify-content: space-between; gap: 18px; }
.case-result-linked strong { color: var(--canopy); font-family: var(--serif); font-size: 21px; }
.case-result-linked .row-caption { margin: 4px 0 0; }
.case-attach-form { display: grid; grid-template-columns: minmax(180px, 1fr) auto; gap: 10px 12px; align-items: end; }
.case-attach-form .quiet-label { grid-column: 1 / -1; }
.case-attach-form + .case-attach-form { margin-top: 18px; }
.case-launch-notice { margin-bottom: 20px; border-left-color: var(--green); }

/* ---------- Case hub stage cards (queue item 64, D142/D143) ---------- */
.case-stage-rail { display: grid; gap: 8px; margin: 20px 0 28px; padding: 0; list-style: none; }
.case-stage-rail .case-stage-card { padding: 0; border-top-width: 1px; border-left: 4px solid var(--mist); }
.case-stage-rail .case-stage-card--in_progress { border-left-color: var(--gold-dark); }
.case-stage-rail .case-stage-card--attention { border-left-color: var(--red); }
.case-stage-rail .case-stage-card--done { border-left-color: var(--green); }
.case-stage-rail .case-stage-card--continue { border-width: 1px 1px 1px 4px; }
.case-stage-rail .case-stage-card-link {
  display: grid; grid-template-columns: 34px minmax(0, 1fr) auto; gap: 14px; align-items: center; padding: 14px 16px;
}
.case-stage-rail-index {
  display: grid; width: 30px; height: 30px; place-items: center; border-radius: 50%;
  background: var(--paper); color: var(--canopy); font-family: var(--mono); font-size: 11px;
}
.case-stage-rail-copy { display: grid; min-width: 0; gap: 3px; }
.case-stage-rail .case-stage-card-kicker { justify-content: flex-start; }
.case-stage-rail-title { color: var(--canopy); font-family: var(--serif); font-size: 18px; }
.case-stage-rail-blocker { overflow: hidden; color: var(--mist); font-size: 12.5px; text-overflow: ellipsis; white-space: nowrap; }
.case-stage-rail-action { color: var(--canopy); font-size: 12px; font-weight: 700; white-space: nowrap; }
.case-stage-rail .case-stage-card-secondary { display: block; margin: 0 16px 12px 64px !important; padding: 0; border: 0; font-size: 12px; }
.case-stage-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(230px, 1fr)); gap: 16px; margin: 28px 0; }
.case-stage-card {
  display: block; padding: 20px; border: 1px solid rgba(6, 35, 48, 0.16); border-top: 3px solid var(--mist);
  border-radius: 3px; background: rgba(255, 255, 255, 0.76); color: var(--ink);
  box-shadow: 0 10px 26px rgba(23, 39, 58, 0.05); transition: transform 0.15s ease, border-color 0.15s ease;
}
.case-stage-card:hover { transform: translateY(-2px); }
.case-stage-card-link { display: block; color: inherit; text-decoration: none; }
.case-stage-card-secondary { margin-top: 12px !important; padding-top: 12px; border-top: 1px solid var(--rule); }
.case-stage-card--not_started { border-top-color: var(--mist); }
.case-stage-card--in_progress { border-top-color: var(--gold-dark); }
.case-stage-card--attention { border-top-color: var(--red); }
.case-stage-card--done { border-top-color: var(--green); }
.case-stage-card--not_tracked { border-top-color: var(--rule); }
.case-stage-card--continue { box-shadow: 0 14px 32px rgba(23, 39, 58, 0.12); border-width: 2px; }
.case-stage-card-kicker { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
.case-stage-card h3 { margin: 8px 0 6px; color: var(--canopy); font-family: var(--serif); font-size: 21px; }
.case-stage-card p { margin: 0; color: var(--mist); font-size: 13px; line-height: 1.4; }
.case-stage-card-status {
  padding: 3px 7px; border: 1px solid var(--rule); border-radius: 2px; color: var(--mist);
  font-family: var(--mono); font-size: 9.5px; text-transform: uppercase; white-space: nowrap;
}
.case-stage-card--attention .case-stage-card-status { border-color: var(--red); background: var(--red); color: #fff; }
.case-stage-card--done .case-stage-card-status { border-color: var(--green); background: var(--green); color: #fff; }
.case-stage-card--in_progress .case-stage-card-status { border-color: var(--gold-dark); color: var(--gold-dark); }
.case-tab-nav { display: flex; gap: 8px; margin: 28px 0 0; }
.case-tab-nav a {
  padding: 7px 12px; border: 1px solid var(--rule); border-radius: 3px; color: var(--mist);
  font-family: var(--mono); font-size: 11px; text-decoration: none; text-transform: uppercase;
}
.case-tab-nav a[aria-current="page"] { border-color: var(--canopy); background: var(--canopy); color: #fff; }

@media (max-width: 800px) {
  .case-page-heading, .case-detail-header { flex-direction: column; gap: 14px; }
  .case-page-heading > .btn-primary, .case-detail-header > .btn-primary { margin-top: 0; }
  .case-section-heading { flex-direction: column; align-items: flex-start; gap: 12px; }
  .case-card-grid { grid-template-columns: minmax(0, 1fr); }
  .case-workspace-grid {
    grid-template-columns: minmax(0, 1fr);
    grid-template-areas: "readiness" "main" "rail";
  }
}
@media (max-width: 600px) {
  .case-page { padding-top: 32px; }
  .case-card-grid, .case-form-grid { grid-template-columns: minmax(0, 1fr); }
  .case-field--wide { grid-column: auto; }
  .case-form { padding: 20px; }
  .case-stage-rail .case-stage-card-link { grid-template-columns: 30px minmax(0, 1fr); padding: 12px; }
  .case-stage-rail-action { display: none; }
  .case-stage-rail .case-stage-card-secondary { margin-left: 56px !important; }
  .case-stage-rail-blocker { white-space: normal; }
  .scope-verdict { grid-template-columns: 1fr; }
  .resolution-choices { grid-template-columns: 1fr; }
  .results-summary-heading, .demo-result-header { align-items: flex-start; flex-direction: column; }
  .case-card-facts { grid-template-columns: 1fr; }
  .case-attach-form { grid-template-columns: 1fr; }
  .case-attach-form .quiet-label { grid-column: auto; }
  .case-result-linked { align-items: flex-start; flex-direction: column; }
  .case-legality-item > summary { grid-template-columns: 28px minmax(0, 1fr) auto; padding: 15px; }
  .case-legality-item > summary::after { grid-column: 3; grid-row: 1; }
  .case-legality-status { grid-column: 2 / -1; justify-self: start; }
  .case-legality-body { padding: 2px 15px 18px; }
  .case-evidence-upload { grid-template-columns: 1fr; }
  .case-evidence-upload .btn-secondary { justify-content: center; }
}

/* ---------- Metric tiles (Field Survey mockup) ---------- */
.metric-row { display: grid; grid-template-columns: repeat(4, 1fr); gap: 12px; margin-bottom: 10px; }
.tile { border-radius: 4px; padding: 16px 18px; color: #fff; }
.tile .n { font-family: var(--serif); font-size: 26px; font-variant-numeric: tabular-nums; display: block; }
.tile .lbl { font-family: var(--mono); font-size: 11px; letter-spacing: 0.06em; opacity: 0.88; }
.tile.red { background: var(--red); }
.tile.amber { background: var(--amber); }
.tile.green { background: var(--green); }
.tile.slate { background: var(--slate); }
.row-caption { font-size: 13px; color: var(--mist); margin: 0 0 26px; }

.dd-row { display: flex; gap: 10px; margin-bottom: 12px; flex-wrap: wrap; }
.dd-chip { background: var(--paper-card); border-left: 3px solid var(--canopy); border-radius: 2px; padding: 10px 14px; font-size: 13px; flex: 1; min-width: 160px; }
.dd-chip b { display: block; font-family: var(--serif); font-size: 17px; color: var(--canopy); }

.lot-metric { background: var(--paper-card); border-left: 3px solid var(--canopy); border-radius: 2px; padding: 12px 16px; margin-bottom: 26px; font-size: 14px; }
.lot-metric b { font-family: var(--serif); font-size: 17px; color: var(--canopy); }

/* ---------- Results table ---------- */
table.results { width: 100%; border-collapse: collapse; margin-bottom: 30px; font-size: 13.5px; }
table.results th {
  text-align: left; font-family: var(--mono); font-size: 11px; letter-spacing: 0.05em;
  color: var(--mist); text-transform: uppercase; padding: 8px 10px; border-bottom: 2px solid var(--canopy);
  position: sticky; top: 0; background: var(--paper);
}
table.results th.sortable { cursor: pointer; user-select: none; }
table.results th.sortable:hover { color: var(--canopy); }
table.results th.sortable .sort-arrow { display: inline-block; width: 1em; opacity: 0.5; }
table.results td { padding: 9px 10px; border-bottom: 1px solid var(--rule); vertical-align: middle; }
table.results .results-reason-col { min-width: 280px; }
table.results .trn-select-col { width: 34px; min-width: 34px; text-align: center; }
table.results .trn-select-col input { width: auto; margin: 0; }
table.results tr.row-hidden { display: none; }
.table-scroll { overflow-x: auto; margin-bottom: 24px; }
/* Caps the results table to roughly 20 visible rows (STATUS.md 2026-07-14):
   at real scale (hundreds of plots) an uncapped table pushes the map -- a
   feature in its own right -- far down the page. max-height (not height) so a
   short list just fits with no scrollbar/empty space; `min(...)`'s vh term is
   a floor for short browser windows. th's existing `position: sticky; top: 0`
   picks up this element as its scrolling ancestor automatically once it has
   overflow-y set -- no JS involved. */
.results-table-scroll {
  max-height: min(1750px, 75vh); overflow-y: auto;
  border: 1px solid var(--rule); border-radius: 4px;
}
.results-table-scroll table.results { margin-bottom: 0; }
.results-table-scroll table.results th { top: -1px; } /* absorbs the 1px border above so the sticky header leaves no seam */

/* ---------- Results table toolbar (filter/search) ---------- */
.table-toolbar { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin-bottom: 14px; }
.results-column-help { margin: 0 0 12px; color: var(--mist); font-size: 12px; }
.results-column-help summary { width: fit-content; cursor: pointer; color: var(--canopy); font-weight: 700; }
.results-column-help .table-scroll { margin-top: 8px; }
.results-column-help table { margin-bottom: 0; }
.table-filter-btn {
  font-family: var(--mono); font-size: 12px; letter-spacing: 0.03em; padding: 6px 12px;
  border-radius: 3px; border: 1px solid var(--rule); background: var(--paper-card);
  color: var(--ink); cursor: pointer;
}
.table-filter-btn:hover { border-color: var(--canopy); }
.table-filter-btn.active { background: var(--canopy); border-color: var(--canopy); color: #fff; }
.table-select-filter {
  font-family: var(--sans); font-size: 13px; padding: 6px 10px; border-radius: 3px;
  border: 1px solid var(--rule); background: var(--paper-card); color: var(--ink);
}
/* Hidden by results_table.js when a job has only one distinct country/commodity
   -- filtering on a value every row already shares is dead weight in the toolbar. */
.table-select-filter[hidden] { display: none; }
.table-search-input {
  font-family: var(--sans); font-size: 13px; padding: 6px 10px; border-radius: 3px;
  border: 1px solid var(--rule); background: var(--paper-card); color: var(--ink);
  min-width: 200px; flex: 1 1 200px;
}
.table-row-count { font-family: var(--mono); font-size: 12px; color: var(--mist); white-space: nowrap; }
.coord { font-family: var(--mono); font-size: 12px; color: var(--mist); }
.row-locate-btn {
  font-size: 14px; line-height: 1; padding: 4px 6px; border-radius: 3px; border: 1px solid var(--rule);
  background: var(--paper-card); cursor: pointer;
}
.row-locate-btn:hover { border-color: var(--canopy); }
.flag-chip, .dd-badge, .data-quality-badge, .pressure-badge {
  display: inline-flex; align-items: center; gap: 6px; font-family: var(--mono);
  font-size: 10.5px; font-weight: 600; letter-spacing: 0.03em; padding: 3px 8px;
  border-radius: 3px; color: #fff; white-space: nowrap;
}

/* ---------- Nearby-pressure portfolio tile ---------- */
/* Same visual family as .dd-chip/.lot-metric (paper-card + left rule), but on the
   --clearing accent so it reads as its own signal, not a restated flag or DD tier. */
.pressure-metric { background: var(--paper-card); border-left: 3px solid var(--clearing); border-radius: 2px; padding: 12px 16px; margin-bottom: 26px; font-size: 14px; }
.pressure-metric b { font-family: var(--serif); font-size: 17px; color: var(--clearing-dark); }

/* ---------- Map ---------- */
#map-container { margin-bottom: 24px; border: 1px solid var(--rule); border-radius: 4px; overflow: hidden; }
#map-container iframe { display: block; width: 100%; height: 500px; border: none; }
.map-interaction-shell { position: relative; }
.map-interaction-gate {
  position: absolute; inset: 0; z-index: 20; width: 100%; border: 0;
  background: rgba(6, 35, 48, 0.12); color: #fff; cursor: pointer;
  font: 700 13px/1 var(--sans); letter-spacing: 0.01em;
  text-shadow: 0 1px 3px rgba(6, 35, 48, 0.8);
}
.map-interaction-gate span {
  display: inline-flex; align-items: center; justify-content: center; min-width: 230px; height: 42px;
  border-radius: 4px;
  background: rgba(6, 35, 48, 0.86); box-shadow: 0 5px 20px rgba(6, 35, 48, 0.2);
}
.map-interaction-gate:hover span, .map-interaction-gate:focus-visible span { background: var(--canopy); }
.map-interaction-done {
  position: absolute; z-index: 21; top: 10px; right: 10px; padding: 7px 11px;
  border: 1px solid rgba(255,255,255,.7); border-radius: 4px; background: rgba(6,35,48,.9);
  color: #fff; font: 700 12px/1 var(--sans); cursor: pointer;
}
.map-interaction-shell.is-active { outline: 2px solid rgba(35, 111, 82, 0.45); outline-offset: -2px; }

/* ---------- Downloads / status panels (screening progress, PDF report) ---------- */
.download-row { display: flex; gap: 12px; flex-wrap: wrap; margin-bottom: 24px; }
.status-panel { background: var(--paper-card); border-radius: 4px; padding: 20px 24px; margin-bottom: 24px; }
.pdf-panels-row { display: flex; gap: 16px; flex-wrap: wrap; }
.pdf-panels-row .status-panel { flex: 1 1 320px; }

/* Screening-in-progress bar (app/templates/tool/_screening_panel.html.j2). Determinate
   (real width) once progress_done/progress_total are known; otherwise an indeterminate
   sliding stripe so "something is happening" is visible from the first render, before
   any real progress numbers exist yet. */
.progress-bar { height: 6px; background: rgba(6, 35, 48, 0.08); border-radius: 3px; overflow: hidden; margin-top: 16px; }
.progress-bar-fill { height: 100%; background: var(--gold); border-radius: 3px; transition: width 0.4s ease; }
.progress-bar-fill--indeterminate { width: 35%; animation: progress-indeterminate 1.4s ease-in-out infinite; }
.pdf-generate-starting { display: none; }
.htmx-request .pdf-generate-label { display: none; }
.htmx-request .pdf-generate-starting { display: inline-flex; align-items: center; gap: 8px; }
.pdf-generate-starting::before {
  content: ""; width: 12px; height: 12px; border: 2px solid rgba(255,255,255,.45);
  border-top-color: #fff; border-radius: 50%; animation: pdf-button-spin .75s linear infinite;
}
.htmx-request-error { margin-top: 10px; color: var(--red); }
@keyframes pdf-button-spin { to { transform: rotate(360deg); } }
@keyframes progress-indeterminate {
  0% { margin-left: -35%; }
  100% { margin-left: 100%; }
}
@media (prefers-reduced-motion: reduce) {
  .progress-bar-fill--indeterminate { animation: none; margin-left: 0; width: 100%; opacity: 0.45; }
  .pdf-generate-starting::before { animation: none; }
}

/* ---------- Results page: information-hierarchy overhaul (session 75) ----------
   Regroups the previously flat top-to-bottom stack (tiles -> pressure -> dd-tiles ->
   2 PDF panels -> monitoring -> diff -> table -> map -> Canopy Watch -> downloads)
   into 4 zones: Portfolio Summary (this section's own white card), a paired
   Results/Map split view, one Export & Reports panel, and an Advanced/beta
   accordion (reusing .faq/.faq-item -- the exact same collapsible pattern
   already established on the homepage FAQ, not a new component). */
.results-toolbar {
  display: flex; align-items: center; justify-content: space-between; gap: 16px;
  margin-bottom: 24px; padding-bottom: 18px; border-bottom: 1px solid var(--rule);
  flex-wrap: wrap;
}
.results-toolbar-label {
  margin: 0; font-family: var(--mono); font-size: 12px; letter-spacing: 0.06em;
  text-transform: uppercase; color: var(--mist);
}

.summary-card, .export-panel {
  background: #fff; border: 1px solid var(--rule); border-radius: 8px;
  padding: 26px 28px 6px; margin-bottom: 28px;
}
.summary-card .tool-title, .export-panel .tool-title { margin-bottom: 16px; }
.results-summary-heading { display: flex; align-items: center; justify-content: space-between; gap: 14px; margin-bottom: 12px; }
.results-summary-heading .tool-title { margin: 0; }
.demo-result-header { display: flex; align-items: end; justify-content: space-between; gap: 20px; padding-top: 38px; padding-bottom: 22px; }
.demo-result-header h1 { margin: 5px 0 0; color: var(--canopy); font-size: clamp(28px, 4vw, 43px); }

.results-split { display: grid; grid-template-columns: minmax(0, 1.6fr) minmax(0, 1fr); gap: 28px; margin-bottom: 28px; align-items: start; }
@media (max-width: 1150px) {
  /* minmax(0, 1fr), not a bare 1fr: a grid item's default min-width is auto (its
     content's intrinsic width), so without the explicit 0 floor here the wide
     results table refused to shrink below its own content width and forced the
     entire page to scroll horizontally on mobile -- confirmed via a real 390px
     Playwright render showing a >1600px-wide page. minmax(0, ...) is what lets
     .table-scroll's own overflow-x:auto actually take over instead. */
  .results-split { grid-template-columns: minmax(0, 1fr); }
}

.advanced-features { margin-bottom: 40px; }
.advanced-features .faq-item p:last-child { margin-bottom: 18px; }
.compliance-checklist-summary { color: var(--ink); font-weight: 600; }
.compliance-checklist-list {
  list-style: none; margin: 0 0 18px; padding: 0; counter-reset: checklist;
}
.compliance-checklist-list li {
  counter-increment: checklist; position: relative; padding: 12px 0 12px 34px;
  border-top: 1px solid var(--rule); color: var(--mist);
}
.compliance-checklist-list li::before {
  content: counter(checklist); position: absolute; left: 0; top: 11px;
  width: 22px; height: 22px; border: 1px solid var(--canopy-line); border-radius: 50%;
  color: var(--canopy); font-family: var(--mono); font-size: 11px; font-weight: 700;
  line-height: 20px; text-align: center;
}
.compliance-checklist-list strong {
  display: block; margin-bottom: 4px; color: var(--canopy); font-family: var(--serif);
  font-size: 16px; font-weight: 600;
}
.faq-item .compliance-checklist-list p { margin: 0; font-size: 14px; }

/* ---------- Demo country filter ---------- */
.demo-country-filter { display: flex; align-items: center; gap: 10px; margin-bottom: 8px; flex-wrap: wrap; }
.demo-country-filter label { font-size: 14px; color: var(--ink); }
.demo-country-filter select {
  font-family: var(--sans); font-size: 14px; padding: 7px 10px;
  border: 1px solid var(--rule); border-radius: 3px; background: #fff; color: var(--ink);
}

/* ---------- Tool-page subheadings ---------- */
/* The h3-level heading every tool-page section (PDF panel, diff, results, map) was
   repeating as an identical raw inline style -- one shared class instead. */
.tool-title { font-size: 19px; color: var(--canopy); margin-bottom: 10px; }

/* ---------- Upload page hero ---------- */
/* Reuses the marketing .hero/.world-map dark band (Session 9.4) instead of the old
   light, orphaned eyebrow+h1+lede with no visual relationship to the rest of the
   product -- this is a repeat visitor's utility page, so the band is shorter
   (.hero--compact) than the marketing homepage's, but the same system.
   Selector is `.hero.hero--compact`, not `.hero--compact` alone: both classes
   carry an equal single-class specificity, and `.hero`'s own `padding: 64px 0
   80px` (defined later in this file, Section "Landing page") was silently
   winning on source order -- this page's hero was never actually shorter than
   the marketing homepage's, confirmed via computed-style inspection (padding-
   bottom read 80px, not 40px, on a real render). */
.hero.hero--compact { padding: 44px 0 40px; }
.hero--compact .headline { font-size: 32px; margin-bottom: 14px; }
.hero--compact .sub { font-size: 16.5px; margin-bottom: 0; max-width: 62ch; }

/* Compact counterpart to .headline--hero (base rule below, homepage-only): same
   sans/weight-750/tight-tracking voice, but a much smaller clamp since a compact
   hero's headline is a literal page title ("EUDR Deforestation Risk Screening
   Tool"), not a punchy marketing line -- 14ch's max-width would clip it awkwardly,
   so this variant drops the max-width/text-wrap:balance instead of shrinking words
   onto their own lines. Used by every non-homepage hero-bearing page (upload tool,
   demo, dds-traces) so the brand voice is one register site-wide, just toned down
   for functional density. */
h1.headline.headline--hero-compact {
  font-family: var(--sans);
  font-weight: 750;
  letter-spacing: -0.02em;
  line-height: 1.1;
  font-size: clamp(28px, 4.2vw, 42px);
}

.scope-badge {
  display: inline-flex; align-items: center; gap: 7px; font-family: var(--mono);
  font-size: 11px; letter-spacing: 0.06em; text-transform: uppercase;
  color: rgba(243, 245, 239, 0.82); background: rgba(243, 245, 239, 0.1);
  border: 1px solid rgba(243, 245, 239, 0.24); border-radius: 20px;
  padding: 5px 12px 5px 10px; margin-bottom: 18px;
}
.scope-badge::before { content: ""; width: 6px; height: 6px; border-radius: 50%; background: var(--gold); flex: none; }

/* Three-step "how it works" strip, sitting inside the hero so the whole flow is
   visible before the user has touched anything -- this is the "clear in one
   second" requirement, answered above the fold rather than inferred from the form. */
.mini-steps { display: flex; gap: 0; margin-top: 34px; flex-wrap: wrap; }
.mini-step {
  display: flex; align-items: flex-start; gap: 10px; flex: 1 1 200px;
  padding-right: 20px;
}
.mini-step .n {
  font-family: var(--serif); font-size: 15px; color: var(--canopy-deep); background: var(--gold);
  width: 26px; height: 26px; border-radius: 50%; display: flex; align-items: center;
  justify-content: center; flex: none; font-weight: 600;
}
.mini-step p { margin: 3px 0 0; font-size: 14px; line-height: 1.4; color: rgba(243, 245, 239, 0.86); }
.mini-step-arrow { display: flex; align-items: center; color: rgba(243, 245, 239, 0.3); flex: none; margin: 6px 10px 0 -6px; }
@media (max-width: 700px) { .mini-step-arrow { display: none; } }

/* Quiet in-hero link to the marketing /demo page, for anyone who lands on /app
   directly without ever seeing the homepage -- reuses the existing hero-scoped
   .btn-secondary treatment (underline, no fill), already defined for this exact
   "understated link on a dark hero" case. */
.hero-demo-link { margin-top: 22px; }
.hero-demo-link .btn-secondary { font-size: 14.5px; }

/* ---------- Upload dropzone ---------- */
form.upload-form { background: #fff; border: 1px solid var(--rule); border-radius: 8px; padding: 30px; position: relative; box-shadow: 0 12px 32px rgba(6, 35, 48, 0.08); }
/* form.upload-form label {display:block} (above) otherwise wins on specificity
   over a bare .dropzone rule since it targets form.upload-form + label by tag --
   the extra .dropzone class here is required, not decorative, to win the cascade. */
form.upload-form label.dropzone {
  position: relative; display: flex; align-items: center; gap: 18px;
  border: 1.5px dashed rgba(13, 74, 104, 0.32); border-radius: 6px;
  padding: 26px 24px; cursor: pointer; background: var(--paper);
  transition: border-color 0.15s ease, background 0.15s ease;
  margin-bottom: 16px;
}
.upload-columns { margin: 0 0 12px; }
.upload-columns table { margin-bottom: 0; }
.upload-help { margin: 10px 0 18px; color: var(--mist); font-size: 13px; }
.upload-help summary { width: fit-content; cursor: pointer; color: var(--canopy); font-weight: 700; }
.upload-help p { max-width: 82ch; margin: 8px 0 0; }
/* Same specificity note as the label.dropzone rule above: the base rule's `border`
   shorthand only loses to another rule that matches or beats form.upload-form
   label.dropzone -- a bare .dropzone:hover/.has-file would silently no-op. */
form.upload-form label.dropzone:hover, form.upload-form label.dropzone:focus-within { border-color: var(--canopy); background: var(--paper-card); }
form.upload-form label.dropzone.has-file { border-style: solid; border-color: var(--green); background: rgba(63, 122, 83, 0.06); }
/* Real drag-over state (app/static/js/upload.js) -- distinct from :hover so a
   file actually being dragged over the zone reads as a stronger, more certain
   affordance than just a mouse resting on it. */
form.upload-form label.dropzone.is-dragover { border-style: solid; border-color: var(--gold-dark); background: rgba(252, 191, 73, 0.1); }
/* form.upload-form input[type="file"] (existing rule above) sets width:100%/border/
   background -- form.upload-form .dropzone input[...] here needs to out-specificity
   that to reposition the same element as an invisible full-cover click target. */
form.upload-form .dropzone input[type="file"] {
  position: absolute; inset: 0; width: 100%; height: 100%; opacity: 0; cursor: pointer;
  margin: 0; padding: 0; border: none; background: transparent;
}
.dropzone-icon { flex: none; color: var(--canopy); }
.dropzone.has-file .dropzone-icon { color: var(--green); }
.dropzone-text strong { display: block; font-size: 15px; color: var(--ink); margin-bottom: 3px; }
.dropzone-filename { font-family: var(--mono); color: var(--green); }
.dropzone-hint { display: block; font-size: 13px; color: var(--mist); }

.field-divider { display: flex; align-items: center; gap: 14px; margin: 26px 0 20px; color: var(--mist); font-family: var(--mono); font-size: 11px; letter-spacing: 0.06em; text-transform: uppercase; }
.field-divider::before, .field-divider::after { content: ""; flex: 1; height: 1px; background: var(--rule); }

.quiet-label { display: block; font-size: 14px; margin-bottom: 8px; color: var(--ink); }

.scope-caption { font-size: 13px; color: var(--mist); margin: 14px 0 0; }
.scope-caption a { color: var(--mist); text-decoration: underline; text-underline-offset: 2px; }
.scope-caption a:hover { color: var(--canopy); }

/* ---------- How-to-read-your-results (replaces "important limitations" wall) ---------- */
/* Same facts as before, same pre-upload visibility requirement -- restyled from a
   stack of identical orange alert boxes (reads as "5 reasons this might be wrong")
   to a calm, confident methodology grid on the canopy/slate palette already used
   for informational content elsewhere (.dd-chip, .source). Nothing substantive
   removed or softened, only the tone and the un-differentiated alarm styling. */
/* .read-results now just carries the shared section.block rhythm (padding, eyebrow/
   section-title/lede) -- no bespoke spacing of its own left to override. */
.read-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); gap: 16px; margin-top: 20px; }
.read-card { background: var(--paper-card); border-left: 3px solid var(--canopy); border-radius: 2px; padding: 16px 18px; }
.read-card.accent-info { border-left-color: var(--slate); }
.read-card.accent-red { border-left-color: var(--red); }
.read-card.accent-gold { border-left-color: var(--gold-dark); }
.read-card.accent-clearing { border-left-color: var(--clearing); }
.read-card b, .read-card h3 { display: block; font-family: var(--sans); font-size: 14px; font-weight: 600; color: var(--ink); margin-bottom: 5px; }
.read-card p { margin: 0; font-size: 13.5px; color: var(--mist); line-height: 1.5; }

/* ---------- Diff mode ---------- */
.diff-worse td, .diff-better td { border-bottom-color: var(--rule); }
.diff-worse { background: rgba(214, 40, 40, 0.055); }
.diff-better { background: rgba(63, 122, 83, 0.06); }
.diff-indicator {
  display: inline-flex; align-items: center; gap: 5px; font-family: var(--mono);
  font-size: 10.5px; font-weight: 600; letter-spacing: 0.03em;
}
.diff-indicator.worse { color: var(--red); }
.diff-indicator.better { color: var(--green); }
.diff-indicator.same { color: var(--mist); font-weight: 400; }

/* ---------- Cannot-screen status badge ---------- */
/* Matches .dd-badge/.data-quality-badge sizing, filled with --slate -- the same color
   already used for the CANNOT_SCREEN summary tile -- so this list stops looking like
   a bare, unstyled afterthought next to the map and flag chips around it. */
.cannot-screen-badge {
  display: inline-flex; align-items: center; gap: 6px; font-family: var(--mono);
  font-size: 10.5px; font-weight: 600; letter-spacing: 0.03em; padding: 3px 8px;
  border-radius: 3px; color: #fff; white-space: nowrap; background: var(--slate);
}

/* ---------- Error pages ---------- */
/* Modeled on .sample-card (quiet, light) rather than .contact-card (dark) -- these
   are informational states, not a primary CTA. */
.error-card {
  background: var(--paper-card); border-radius: 4px; padding: 26px 28px;
  margin-top: 18px; max-width: 520px;
}
.error-card h1 { font-size: 19px; color: var(--canopy); margin-bottom: 10px; }
.error-card p { margin: 0 0 18px; color: var(--ink); }
.error-card p:last-child { margin-bottom: 0; }

/* ---------- Landing page (ported, Phase 5) ---------- */
/* Marketing-page prose (hero headline/sub, .lede, .callout) intentionally has no
   max-width of its own -- it fills the .wrap container exactly like .steps/.legend/
   .sources already do, so it grows and shrinks with the browser window the same
   way those grids do instead of sitting at a fixed column width that ignores it. */
section.block { padding: 56px 0; border-bottom: 1px solid var(--rule); }
section.block:last-of-type { border-bottom: none; }
section.block .eyebrow { margin-bottom: 14px; }
h2.section-title { font-size: 26px; margin-bottom: 18px; color: var(--canopy); }
.lede { font-size: 17px; color: var(--ink); }
.lede + .lede { margin-top: 14px; }

.hero {
  background: var(--canopy-deep);
  color: var(--paper); position: relative; overflow: hidden; padding: 64px 0 80px;
}
/* Marketing homepage only: the hero fills the (remaining) viewport height on load.
   The persistent .site-nav bar now sits ABOVE this hero, in normal page flow (it has
   to also work on hero-less pages, so it can't be layered inside the hero the way
   the old in-hero nav row was) -- min-height is calc(100vh - <nav height>), not a
   bare 100vh, so hero+nav together fill one viewport instead of overflowing it by
   the nav's own height. ~40px is the nav's real rendered height (9px+9px padding
   plus one line of its wordmark/links text, no button -- a CTA in the nav was
   tried and dropped, it made the bar tall enough to push the hero's own CTA below
   the fold) -- verify against a real render, adjust if it drifts. hero-inner's own
   padding-top is reduced from its old 168px by
   roughly the height the in-hero nav row used to occupy, so the headline lands at
   about the same absolute position as before, just measured from a different origin
   now that the nav is external. */
.hero--full { min-height: calc(100vh - 40px); display: flex; flex-direction: column; padding-top: 28px; padding-bottom: 32px; }
/* Overrides .wrap's own centering (margin:0 auto) so the text column starts at a
   fixed left inset instead of being centered within the viewport's extra space --
   aligns it with .site-nav's own 80px inset instead of the 920px .wrap sitting
   ~260px in on a wide desktop screen. */
.hero--full .hero-inner { flex: 1; display: flex; flex-direction: column; justify-content: center; margin: 0; padding-left: 80px; padding-right: 40px; max-width: 900px; }
.hero--full .hero-inner p.sub { margin-top: 28px; }
/* Extra room below the subhead before the button -- the block is vertically
   centered as a whole now (see justify-content above), so there's real space to
   give the CTA its own deliberate gap instead of hugging the paragraph above it. */
.hero--full .hero-inner .cta-row { margin-top: 30px; }
/* Not wrapped in the 920px .wrap (that put the wordmark on the same left edge as the
   headline below it), but not full-bleed to the browser edge either -- a wider,
   still-centered container so both ends sit at a comfortable inset. */
.jump-links { display: flex; gap: 16px 22px; flex-wrap: wrap; list-style: none; margin: 0; padding: 0; }
.jump-links a { font-family: var(--sans); font-size: 13px; font-weight: 500; color: #ffffff; text-decoration: none; }
.jump-links a:hover { color: var(--gold); }
/* On mobile the .nav-links row collapses behind .site-nav's own hamburger toggle
   (see the .site-nav mobile rules further down) rather than wrapping in place --
   reduced side padding on .jump-links here just gives its (now nav-bar-internal)
   items room when that panel is open.

   The hero itself also drops the old fixed 168px padding-top + margin-top:auto
   push-to-bottom trick here -- those were calibrated for a ~900px desktop viewport;
   forced onto a phone (worse, iOS Safari's dynamic toolbar makes 100vh taller than
   the actual visible area) they produced a huge gap between headline and sub-text
   and pushed the CTA button off the first screen entirely (confirmed via a real
   iPhone Safari screenshot). Mobile hero is just naturally content-sized instead,
   min-height only accounting for .site-nav's own (smaller, collapsed) mobile
   height -- verify against a real render, adjust if it drifts. */
@media (max-width: 700px) {
  .jump-links { gap: 10px 16px; }
  .jump-links a { font-size: 12.5px; }
  /* min-height (not a fixed padding-top + margin-top:auto push-to-bottom trick
     that caused the original mobile bug) so the hero band still fills the
     screen on load. 100dvh accounts for the mobile browser's collapsing toolbar
     (100vh doesn't); the plain vh line is a fallback for browsers that don't
     support dvh, immediately overridden by the dvh line in ones that do. */
  .hero--full { min-height: calc(100vh - 40px); min-height: calc(100dvh - 40px); padding-top: 6px; padding-bottom: 12px; }
  /* Nav sits close to the top; headline gets a bit more room below it (nudged down
     slightly); sub-text and the CTA are pushed toward the bottom via margin-top:auto
     on p.sub, same mechanism as desktop, now safe to reuse since min-height is a real
     100dvh instead of the old fixed-offset version that broke on mobile. Paddings here
     are deliberately tight: verified against Playwright's real "iPhone 13" profile
     (390x664, Safari's address bar + toolbar included, not the chrome-less 390x844
     used earlier) that the CTA button stays fully on-screen at this font size --
     the previous 56px + looser padding pushed the button below the fold on that
     shorter, more realistic viewport. */
  .hero--full .hero-inner { padding-left: 20px; padding-right: 20px; }
  /* Fixed gap instead of margin-top:auto -- the auto-margin had already consumed
     all available leftover space at this point (hero height was exactly matching
     the viewport, no slack left), so asking for more bottom room just grew the
     container past the viewport instead of moving content within it. An explicit
     value lets the gap be dialed in directly regardless of how much space is left. */
  /* margin-top:auto, not a fixed value -- a fixed px gap assumes one specific real
     viewport height, and real devices vary a lot (confirmed: a real device screenshot
     showed a large empty gap below the button that a 390x664 test viewport never
     revealed, meaning that device's actual usable height is taller than 664px).
     auto adapts to however much space genuinely exists on each device, pushing
     sub+button down to use it, instead of leaving it unclaimed. padding-top is a
     floor so the gap never collapses below a sane minimum even on the shortest
     real screens. */
  .hero--full .hero-inner p.sub { margin-top: 20px; margin-bottom: 20px; }
  .hero--full .hero-inner .cta-row { margin-top: 6px; }
  /* Base h1.headline sets a 22px margin-bottom tuned for a shorter (desktop/3-line)
     headline; on mobile's 4-line version that's dead space on top of an already
     tight budget. Reclaiming most of it here. */
  .hero--full h1.headline.headline--hero { margin-bottom: 18px; }
  /* .hero--full ancestor prefix is load-bearing, not decorative: the bare
     h1.headline.headline--hero selector used here previously tied on specificity
     with the base (non-media) rule below at line ~490, and since that rule comes
     LATER in the file, it was silently winning on every viewport including mobile
     -- confirmed live: computed font-size was 38px (the clamp()'s floor), not the
     52px this rule was supposed to set. The extra ancestor class guarantees this
     wins regardless of where either rule sits in the file. */
  .hero--full h1.headline.headline--hero { font-size: 48px; }
}
/* Approved contour theme (session 93): a crisp real-terrain crop from Toraja,
   Indonesia. These values are carried over exactly from exploration option C:
   86% raster opacity, the selected 15% crop, and the original focal point. The
   shared element is used by the homepage and every contour-backed compact hero. */
.world-map {
  position: absolute; inset: 0; z-index: 0; pointer-events: none;
  background: url("/static/img/toraja-contours.fp-8f3cd33197.webp") 52% 50% / cover no-repeat;
  /* The 1x source is the original 1600x1000 master; high-density displays get
     a fresh 3200x2000 render of the same contours instead of browser-upscaling
     the former 1200x750 mockup export. Keep the prefixed form for older Safari. */
  background-image: -webkit-image-set(
    url("/static/img/toraja-contours.fp-8f3cd33197.webp") 1x,
    url("/static/img/toraja-contours@2x.fp-c566d0b34d.webp") 2x
  );
  background-image: image-set(
    url("/static/img/toraja-contours.fp-8f3cd33197.webp") 1x,
    url("/static/img/toraja-contours@2x.fp-c566d0b34d.webp") 2x
  );
  opacity: 0.86;
  transform: translateX(-7%) scale(1.15);
  transform-origin: center;
}
.hero-inner { position: relative; z-index: 1; }
/* Option C's subtle copy shield: enough local contrast for the text without
   visibly veiling the terrain or creating a card-like edge. Scoped to marked
   contour heroes so hero bands without a map remain unchanged. */
.hero--contour::after {
  content: "";
  position: absolute; inset: 0; z-index: 1; pointer-events: none;
  background: radial-gradient(ellipse 58% 78% at 19% 48%, rgba(10, 22, 34, 0.34), rgba(10, 22, 34, 0.17) 54%, transparent 82%);
}
.hero--contour .hero-inner { z-index: 2; }
.hero .eyebrow { color: rgba(243, 245, 239, 0.6); margin-bottom: 18px; }
h1.headline { font-size: 42px; line-height: 1.14; letter-spacing: -0.01em; margin-bottom: 22px; color: var(--paper); text-wrap: wrap; }
/* Larger, bolder hero type scale for the marketing homepage only (ported from
   design exploration, docs/design_mockups_2026-07-18/8-recommended.html). Compound
   selector so it beats the base h1.headline rule above on specificity regardless
   of source order -- the other three h1.headline pages (demo, dds-traces, upload
   tool) don't carry this modifier class and keep the original serif scale. */
h1.headline.headline--hero {
  font-family: var(--sans);
  font-weight: 750;
  letter-spacing: -0.03em;
  line-height: 1.05;
  font-size: clamp(38px, 6.8vw, 74px);
  /* Helvetica's `ch` unit is narrower than the previous system-sans unit. The
     adjusted cap preserves the headline's original line count; font size and
     line-height stay unchanged. */
  max-width: 16.75ch;
  text-wrap: balance;
}
.hero p.sub { font-family: var(--sans); font-size: 18px; color: rgba(243, 245, 239, 0.86); margin-bottom: 34px; }
.cta-row { display: flex; gap: 14px; flex-wrap: wrap; align-items: center; }

/* Self-select chip inside the hero CTA row, routing a wrong-mode visitor to
   the other purpose profile (D172, item 73 follow-up; redesigned D176: the
   original version was a muted caption line below the CTA row and read as
   near-invisible -- a real pill sitting next to .btn-primary in the same row
   is far more visible while staying clearly secondary to it: same rounded-pill
   shape language as .mode-switcher's own pills, but outlined/quiet like
   .btn-outline rather than filled, and noticeably lighter than .btn-outline
   itself (thinner border, no bold weight) so it never competes with the one
   real CTA button beside it. D178: the first pass was too subtle over a busy
   contour background -- "glass look... almost invisible." A real frosted-glass
   treatment (backdrop-filter blur, so the busy terrain behind the pill itself
   goes soft and the pill's own edge/text stay crisp regardless of what's
   behind them) plus meaningfully higher background/border/text opacity reads
   as intentional and legible instead of accidentally transparent, while
   staying a pill rather than a filled button. */
.hero-mode-chip {
  display: inline-flex; align-items: center; gap: 6px;
  font-family: var(--sans); font-size: 13.5px; color: rgba(243, 245, 239, 0.92);
  text-decoration: none; background: rgba(243, 245, 239, 0.14);
  backdrop-filter: blur(8px); -webkit-backdrop-filter: blur(8px);
  border: 1px solid rgba(243, 245, 239, 0.5); border-radius: 999px;
  padding: 11px 20px; transition: background 0.15s ease, border-color 0.15s ease, color 0.15s ease;
}
.hero-mode-chip:hover { background: rgba(243, 245, 239, 0.24); border-color: var(--gold); color: var(--paper); }

/* ---------- Navy/beige palette (design exploration, 2026-07-19; extended to every
   hero-bearing page, session 75) ----------
   Originally scoped to .hero--full only (the homepage); .world-map itself now
   defaults to the warm SVG (see above) so only the flat navy background color and
   the white-text treatment need repeating here for .hero--compact. --canopy-deep/
   BRAND stay untouched everywhere else (PDF, non-hero surfaces). */
.hero--full,
.hero--compact {
  background: #17273a;
}
/* Full white (not the site's usual ~86-92% off-white) -- against the beige land the
   reduced opacity read as gray/washed out rather than crisp. */
.hero--full .wordmark,
.hero--full .jump-links a,
.hero--full p.sub,
.hero--compact .wordmark,
.hero--compact .jump-links a,
.hero--compact p.sub {
  color: #ffffff;
}
.hero--full .wordmark,
.hero--full .jump-links a,
.hero--full .headline--hero,
.hero--full p.sub,
.hero--compact .wordmark,
.hero--compact .jump-links a,
.hero--compact .headline--hero-compact,
.hero--compact p.sub {
  text-shadow: 0 1px 6px rgba(0, 0, 0, 0.55);
}
.hero .btn-secondary { background: none; border: none; color: rgba(243, 245, 239, 0.86); border-bottom: 1px solid var(--canopy-line); border-radius: 0; padding: 0 0 2px; }
.hero .btn-secondary:hover { color: var(--paper); border-color: rgba(243, 245, 239, 0.5); }

/* No card/tint behind this text (.hero--compact only -- upload tool, demo,
   about/pricing/guide/DDS-TRACES pages). Five earlier attempts were tried and
   dropped in turn: a full-width left-right gradient, a flat tint over the whole
   map, a per-line "highlighter" hugging each wrapped line of text, a
   frosted-glass blur, and finally a masked-tint card (kept for a while, but
   ultimately disliked as "this box" over the map). Settled instead on a strong,
   purely typographic multi-layer text-shadow with the map left at full visual
   strength underneath -- no box shape at all. Verified via real renders across
   several alternatives (a global map fade, repositioning the map to dodge the
   text, a hard sticker-style outline) before picking this one: it holds up
   legibly over both the light "land" and dark "ocean" regions of the SVG
   without muting the map or constraining its crop. max-width keeps the text
   column a readable line length now that it's no longer implicitly capped by a
   card's own width. */
.hero--compact .hero-card { max-width: 640px; }
.hero--compact .hero-card--single-line-title { max-width: 700px; }
.hero-card .eyebrow,
.hero-card h1.headline,
.hero-card p.sub,
.hero-card .back-link,
.hero-card .mini-step p,
.hero-card .hero-demo-link .btn-secondary {
  color: #ffffff;
  text-shadow: 0 2px 6px rgba(0, 0, 0, 0.9), 0 6px 28px rgba(0, 0, 0, 0.75), 0 0 3px rgba(0, 0, 0, 0.9);
}
/* The approved C treatment replaces the old heavy compact-hero shadow with the
   finer two-layer shadow used in the mockup. Buttons intentionally stay crisp. */
.hero--contour .hero-inner,
.hero--contour .hero-inner .eyebrow,
.hero--contour .hero-inner .headline,
.hero--contour .hero-inner .sub,
.hero--contour .hero-inner .back-link,
.hero--contour .hero-inner .mini-step p,
.hero--contour .hero-inner .hero-demo-link .btn-secondary {
  text-shadow: 0 2px 6px rgba(0, 0, 0, 0.64), 0 7px 24px rgba(0, 0, 0, 0.48);
}
.hero--contour .hero-inner .btn-primary { text-shadow: none; }

.callout { background: var(--paper-card); border-left: 3px solid var(--red); border-radius: 2px; padding: 22px 26px; margin-top: 26px; }
.callout .q { font-family: var(--serif); font-size: 19px; font-style: italic; color: var(--canopy); margin-bottom: 10px; }
.callout p { margin: 0; font-size: 15.5px; color: var(--ink); }

/* ---------- "Is this you?" qualifier (marketing homepage, replaces "What EUDR requires") ---------- */
.check-list { list-style: none; margin: 26px 0 0; padding: 0; display: flex; flex-direction: column; gap: 14px; max-width: 62ch; }
.check-list li { display: flex; gap: 12px; align-items: flex-start; font-size: 16px; color: var(--ink); }
.check-list li::before {
  content: "\2713"; flex: none; width: 22px; height: 22px; border-radius: 50%;
  background: var(--green); color: #fff; font-size: 12px; font-weight: 700;
  display: flex; align-items: center; justify-content: center; margin-top: 1px;
}

/* Fine/deadlines/exemption as a scannable fact list, not a stat grid of bare numbers
   (meaningless without reading the fine print) and not a prose paragraph (accurate,
   but too much reading for a fact people mostly want to look up, not read). Each row
   pairs a short label with its value directly, so every row is self-explanatory on
   its own -- a compact "spec sheet" read in seconds, not a paragraph or a puzzle. */
.stakes-card { background: var(--paper-card); border-left: 3px solid var(--red); border-radius: 2px; margin-top: 26px; padding: 4px 22px; }
.fact-row { display: grid; grid-template-columns: 190px 1fr; gap: 16px; padding: 13px 0; border-bottom: 1px solid var(--rule); align-items: baseline; }
.fact-row:last-child { border-bottom: none; }
.fact-label { font-family: var(--mono); font-size: 11.5px; letter-spacing: 0.04em; text-transform: uppercase; color: var(--mist); }
.fact-value { font-size: 15px; font-weight: 600; color: var(--canopy); }
@media (max-width: 560px) { .fact-row { grid-template-columns: 1fr; gap: 3px; } }

/* Glanceable summary of the 3 trust points as pill badges, not a caption line --
   normal reading size (matches .chip's scale elsewhere on the page), compact because
   each badge is short, not because the text itself is shrunk down. */
/* Label and description are separate stacked lines (not inline text wrapping next
   to a bold label) so a wrapped description always lines up under the label's own
   left edge -- inline wrapping put the wrapped line back at the badge's outer edge,
   under the bullet dot instead of under the text it continued. */
.trust-badges { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 20px; }
.trust-badge { display: flex; align-items: flex-start; gap: 10px; background: var(--paper-card); border-radius: 14px; padding: 12px 16px; flex: 1 1 230px; max-width: 280px; }
.trust-badge::before { content: ""; width: 7px; height: 7px; border-radius: 50%; background: var(--green); flex: none; margin-top: 6px; }
.trust-badge-body { display: flex; flex-direction: column; gap: 3px; }
.trust-badge-label { font-size: 14px; font-weight: 700; color: var(--canopy); }
.trust-badge-text { font-size: 13px; color: var(--ink); line-height: 1.4; }

.steps { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 28px; margin-top: 30px; }
.step .n { font-family: var(--mono); font-size: 13px; color: var(--clearing-dark); margin-bottom: 8px; }
.step h3 { font-size: 17px; font-weight: 600; font-family: var(--sans); color: var(--canopy); margin-bottom: 6px; }
.step p { margin: 0; font-size: 14.5px; color: var(--mist); }

/* Sub-grouping label inside a section (e.g. "What you get" splitting per-supplier
   flags from report deliverables) -- same visual register as .step .n, but sits
   directly on a section instead of inside a grid cell. */
.group-label { font-family: var(--mono); font-size: 12.5px; letter-spacing: 0.05em; text-transform: uppercase; color: var(--mist); margin: 34px 0 14px; }
.group-label:first-of-type { margin-top: 30px; }
.group-label + .legend, .group-label + .steps, .group-label + .sources { margin-top: 0; }

.legend { display: flex; flex-wrap: wrap; gap: 12px; margin-top: 28px; }
.chip { display: flex; align-items: center; gap: 9px; background: var(--paper-card); border-radius: 3px; padding: 10px 14px; font-size: 14px; }
.swatch { width: 10px; height: 10px; border-radius: 50%; flex: none; }
.chip .label { font-weight: 600; font-family: var(--mono); font-size: 12.5px; letter-spacing: 0.03em; }
.chip .meaning { color: var(--mist); }

.sources { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: 22px; margin-top: 28px; }
.source dt { font-family: var(--sans); font-size: 17px; font-weight: 600; color: var(--canopy); margin-bottom: 6px; }
.source dd { margin: 0; font-size: 14.5px; color: var(--mist); }

/* Tighter variant for a longer, denser list (e.g. "What you get"'s 5-item deliverables
   list) where the full .sources scale would take up more room than the content needs.
   Forced to exactly 5 columns (not auto-fit) so all 5 sit on one row on desktop;
   collapses at the same breakpoints the rest of the page already uses. */
.sources.compact { grid-template-columns: repeat(5, 1fr); gap: 18px; margin-top: 20px; }
.sources.compact .source dt { font-size: 15.5px; margin-bottom: 5px; }
.sources.compact .source dd { font-size: 13.5px; }
@media (max-width: 700px) { .sources.compact { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 560px) { .sources.compact { grid-template-columns: 1fr; } }

.screenshot-badge {
  display: inline-block; margin-top: 22px; background: var(--canopy-deep); color: var(--paper);
  font-family: var(--mono); font-size: 10.5px; letter-spacing: 0.05em; text-transform: uppercase;
  padding: 5px 10px; border-radius: 3px;
}
.screenshot-frame {
  /* No border/box-shadow/radius: the screenshot's own background is the same
     --paper as the page, so a flat, frameless insert reads as part of the page
     rather than a separate card sitting on top of it. */
  margin-top: 12px;
}
.screenshot-frame img { display: block; width: 100%; height: auto; }
.screenshot-caption { margin-top: 12px; font-size: 14px; color: var(--mist); }

.faq { margin-top: 28px; display: flex; flex-direction: column; gap: 10px; }
.faq-item { background: var(--paper-card); border-radius: 4px; padding: 2px 22px; }
.faq-item summary {
  cursor: pointer; font-family: var(--sans); font-weight: 600; font-size: 15.5px;
  color: var(--canopy); padding: 16px 0; list-style: none; display: flex;
  justify-content: space-between; align-items: center; gap: 16px;
}
.faq-item summary::-webkit-details-marker { display: none; }
.faq-item summary::after { content: "+"; font-family: var(--serif); font-size: 21px; color: var(--mist); flex: none; }
.faq-item[open] summary::after { content: "\2212"; }
.faq-item[open] summary { padding-bottom: 4px; }
.faq-item p { margin: 0 0 18px; font-size: 14.5px; color: var(--mist); }
.faq-item p a { color: var(--gold-dark); }
.faq-more { margin-top: 20px; font-size: 14.5px; color: var(--mist); }

.price-card {
  background: var(--canopy); color: var(--paper); border-radius: 4px; padding: 32px 30px;
  margin-top: 28px; display: flex; justify-content: space-between; align-items: flex-end; flex-wrap: wrap; gap: 20px;
}

.price-figure { font-family: var(--serif); font-size: 38px; font-variant-numeric: tabular-nums; color: var(--gold); }
.price-figure small { font-family: var(--sans); font-size: 14px; color: rgba(245, 248, 251, 0.7); display: block; margin-top: 4px; }

/* Still used by demo.html.j2's own closing CTA (marketing homepage's own contact
   card was replaced by footer.cta-final below). */
.contact-card {
  background: var(--canopy); color: var(--paper); border-radius: 4px; padding: 32px 30px;
  margin-top: 22px; display: flex; justify-content: space-between; align-items: center; flex-wrap: wrap; gap: 24px;
}
.contact-card p { margin: 0; font-size: 15.5px; color: rgba(245, 248, 251, 0.86); flex: 1 1 320px; }
.contact-card .btn-primary { flex: none; }

/* ---------- Closing CTA band (marketing homepage, ported from design exploration) ----------
   Full-bleed navy band bookending the hero, same pattern (.hero-style outer element +
   inner .wrap), replacing the old two-tier contact-card/sample-card layout nested inside
   the page's single .wrap. */
footer.cta-final {
  background: var(--canopy-deep); color: var(--paper); padding: 72px 0;
}
footer.cta-final .eyebrow { color: rgba(243, 245, 239, 0.6); margin-bottom: 18px; }
footer.cta-final h2.section-title { color: var(--paper); font-size: clamp(26px, 3.6vw, 38px); margin-bottom: 18px; max-width: 24ch; }
footer.cta-final .lede { color: rgba(243, 245, 249, 0.86); max-width: 54ch; }
footer.cta-final .cta-row { margin-top: 28px; }

/* Secondary CTA on a dark band: a real bordered button (not a bare underlined link),
   quieter than .btn-primary's solid gold fill but still clearly a button. */
.btn-outline {
  display: inline-block; background: rgba(243, 245, 249, 0.08); color: var(--paper);
  font-family: var(--sans); font-weight: 600; font-size: 15px; text-decoration: none;
  border: 1px solid rgba(243, 245, 249, 0.34); padding: 12px 22px; border-radius: 3px;
  cursor: pointer; transition: background 0.15s ease, border-color 0.15s ease;
}
.btn-outline:hover { background: rgba(243, 245, 249, 0.16); border-color: rgba(243, 245, 249, 0.55); }

table.mapping { width: 100%; border-collapse: collapse; margin: 20px 0; font-size: 14px; }
table.mapping th { text-align: left; font-family: var(--mono); font-size: 11.5px; letter-spacing: 0.04em; color: var(--mist); font-weight: 600; padding: 8px 12px; border-bottom: 2px solid var(--rule); }
table.mapping td { padding: 10px 12px; border-bottom: 1px solid var(--rule); vertical-align: top; }
table.mapping tr:last-child td { border-bottom: none; }
table.mapping td.field { font-family: var(--mono); font-size: 12.5px; color: var(--canopy); white-space: nowrap; }
/* Prose columns (dds_traces.html.j2's "Maps to"/"Notes") need a real minimum width --
   without it, table.mapping's width:100% crushes them down to whatever's left after
   the widest nowrap .field cell, wrapping full sentences into unreadable 2-3-word
   lines on mobile. Same fix already proven for table.results' 5th column above;
   .table-scroll's overflow-x:auto (this table's own wrapper) is what makes giving
   these a floor safe -- the table scrolls sideways at a readable width instead of
   squeezing to fit. */
table.mapping td.notes { color: var(--mist); font-size: 13.5px; min-width: 260px; }

.tag { display: inline-block; font-family: var(--mono); font-size: 10.5px; letter-spacing: 0.03em; padding: 2px 7px; border-radius: 3px; font-weight: 600; }
.tag.direct { background: rgba(63, 122, 83, 0.16); color: var(--green); }
.tag.context { background: rgba(192, 138, 44, 0.18); color: var(--amber); }
.tag.gap { background: rgba(184, 67, 58, 0.14); color: var(--red); }
.tag.partial { background: rgba(122, 106, 150, 0.16); color: var(--slate); }

header.top { background: var(--canopy-deep); color: var(--paper); padding: 40px 0 48px; }
header.top .wordmark { font-family: var(--mono); font-size: 13px; letter-spacing: 0.14em; text-transform: uppercase; color: rgba(243, 245, 239, 0.72); margin-bottom: 28px; }
header.top .eyebrow { color: rgba(243, 245, 239, 0.6); margin-bottom: 14px; }
header.top h1.headline { font-size: 32px; line-height: 1.2; margin-bottom: 16px; }
header.top p.sub { font-size: 17px; max-width: 60ch; color: rgba(243, 245, 239, 0.86); margin: 0; }
.back-link { color: rgba(243, 245, 239, 0.72); font-size: 14px; text-decoration: none; border-bottom: 1px solid var(--canopy-line); }
.back-link:hover { color: var(--paper); }
.callout strong { color: var(--canopy); }

/* Session 9.3 mobile/responsive pass: a single 560px breakpoint left a real gap
   in the 561-767px tablet range -- confirmed via a real screenshot at 650px
   width, the 4-column .metric-row squeezed "CANNOT SCREEN * 0%" onto two lines
   while its three siblings stayed on one, an inconsistent row height that a
   phone-only breakpoint never caught. Widened to 700px so the whole tablet
   range gets the same 2-column layout as phone, not just <=560px. */
@media (max-width: 700px) {
  .metric-row { grid-template-columns: repeat(2, 1fr); }

  /* Option C's dedicated phone crop and reading treatment. The linear layer is
     the mockup's mobile-only shade; the radial layer is its compact copy shield. */
  .world-map {
    background-position: 53% 50%;
    transform: translateX(-5%) scale(1.08);
  }
  .hero--contour::after {
    background:
      linear-gradient(180deg, rgba(18, 31, 46, 0.62), rgba(18, 31, 46, 0.23) 72%, transparent),
      radial-gradient(ellipse 96% 52% at 26% 34%, rgba(10, 22, 34, 0.34), rgba(10, 22, 34, 0.14) 64%, transparent 88%);
  }
}

@media (max-width: 560px) {
  h1.headline { font-size: 32px; }
  .price-card { flex-direction: column; align-items: flex-start; }
  .contact-card, .sample-card { flex-direction: column; align-items: flex-start; }
  /* .contact-card p / .sample-card p use `flex: 1 1 320px` to size themselves in
     the desktop row layout (320px width basis). Once flex-direction switches to
     column above, that same 320px basis is read as a *height* basis instead --
     flex-grow:1 then stretches the paragraph to fill the card's free vertical
     space, leaving a large empty gap above the button. Confirmed via a real
     iPhone-width screenshot: both cards showed ~150-200px of dead space. Reset to
     auto so the paragraph only takes the height its text actually needs. */
  .contact-card p, .sample-card p { flex: none; }
}

/* ---------- Legal documents (rendered directly from docs/*.md via app/legal_docs.py --
   the .md files stay the single source of truth, this only styles the output) ---------- */
.legal-doc { max-width: 760px; margin: 44px auto 64px; }
.legal-doc h1 { font-size: 28px; color: var(--canopy); margin-bottom: 20px; }
.legal-doc h2 { font-size: 20px; color: var(--canopy); margin: 34px 0 12px; }
.legal-doc h2:first-of-type { margin-top: 0; }
.legal-doc p { margin: 0 0 14px; font-size: 15px; line-height: 1.65; color: var(--ink); }
/* The first paragraph of every legal doc is its own "Status: ..." banner --
   styled like .notice/.callout so it reads as a status flag, not body prose. */
.legal-doc > p:first-of-type {
  background: var(--paper-card); border-left: 3px solid var(--gold-dark); border-radius: 2px;
  padding: 16px 20px; font-size: 13.5px;
}
.legal-doc ul, .legal-doc ol { margin: 0 0 14px; padding-left: 22px; }
.legal-doc li { margin-bottom: 6px; font-size: 15px; line-height: 1.6; color: var(--ink); }
.legal-doc hr { border: none; border-top: 1px solid var(--rule); margin: 32px 0; }
.legal-doc code { font-family: var(--mono); font-size: 0.88em; background: var(--paper-card); padding: 1px 5px; border-radius: 2px; }
.legal-doc strong { color: var(--ink); }
.legal-doc em { color: var(--mist); }
.legal-doc table.mapping { font-size: 13px; margin: 18px 0; }
/* The closing "*Drafted ... Sources: ...*" line renders as a single trailing
   <em> paragraph -- set it off visually as a footnote, not more body prose. */
.legal-doc > p:last-of-type em { display: block; font-size: 12px; color: var(--mist); }

/* ---------- Canopy Watch (STATUS.md Section 9.5) ----------
   Adapted from the original concept mockup (docs/forecasting_concept_mockup_2026-07-06.html)
   onto the current BRAND tokens -- the mockup still used the superseded
   BRAND_LEGACY_FIELD_SURVEY palette. Trajectory (Rising/Stable/Falling) is rendered via
   icon + label + ink-weight, deliberately not a new color hue -- every hue here is
   already claimed by another axis (flag/data-quality/due-diligence/nearby-pressure). */
.beta-badge {
  display: inline-flex; align-items: center; font-family: var(--mono); font-size: 10px;
  font-weight: 700; letter-spacing: 0.05em; text-transform: uppercase; color: var(--canopy);
  background: rgba(13, 74, 104, 0.1); border: 1px solid rgba(13, 74, 104, 0.25);
  border-radius: 3px; padding: 2px 7px; margin-left: 8px; vertical-align: middle;
}
.watchlist-kpi {
  background: var(--paper-card); border-left: 3px solid var(--canopy); border-radius: 2px;
  padding: 16px 20px; margin-bottom: 18px;
}
.watchlist-kpi b { font-family: var(--serif); font-size: 17px; color: var(--canopy); }
.watchlist-legend { display: flex; flex-wrap: wrap; gap: 10px; margin-bottom: 18px; }
.watchlist-legend .chip {
  display: flex; align-items: center; gap: 8px; background: var(--paper-card);
  border-radius: 3px; padding: 7px 12px; font-size: 12.5px; color: var(--mist);
}
.watchlist-legend .chip .label { font-family: var(--sans); font-weight: 700; }
.watchlist-legend .traj-rising { color: var(--ink); }
.watchlist-legend .traj-stable { color: var(--mist); }
.watchlist-legend .traj-falling { color: var(--mist); opacity: 0.85; }
.watchlist-toolbar { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin-bottom: 12px; }
.watchlist-list { border-top: 1px solid var(--rule); margin-bottom: 24px; }
details.watchlist-row { border-bottom: 1px solid var(--rule); }
details.watchlist-row[data-row-hidden="true"] { display: none; }
details.watchlist-row summary {
  display: flex; align-items: flex-start; gap: 10px; cursor: pointer; list-style: none; padding: 14px 4px;
}
details.watchlist-row summary::-webkit-details-marker { display: none; }
details.watchlist-row summary::before {
  content: "\25B8"; flex: none; width: 12px; margin-top: 3px; color: var(--mist);
  transition: transform 0.15s ease;
}
details.watchlist-row[open] summary::before { transform: rotate(90deg); }
.watchlist-row-grid {
  flex: 1; min-width: 0; display: grid; grid-template-columns: 1.4fr auto auto 90px 2fr;
  align-items: center; gap: 14px;
}
.watchlist-who .name { font-weight: 600; font-size: 14.5px; color: var(--ink); }
.watchlist-who .loc { font-size: 12.5px; color: var(--mist); }
.watchlist-traj { font-size: 13px; font-family: var(--sans); white-space: nowrap; }
.watchlist-traj.rising { color: var(--ink); font-weight: 700; }
.watchlist-traj.stable { color: var(--mist); font-weight: 600; }
.watchlist-traj.falling { color: var(--mist); font-weight: 500; opacity: 0.85; }
.watchlist-composite { display: flex; flex-direction: column; gap: 4px; }
.watchlist-composite-num { font-family: var(--mono); font-size: 13px; font-weight: 700; color: var(--ink); font-variant-numeric: tabular-nums; }
.watchlist-composite-bar { width: 74px; height: 5px; background: var(--paper-card); border-radius: 3px; overflow: hidden; }
.watchlist-composite-bar .fill { height: 100%; background: var(--canopy); border-radius: 3px; }
.watchlist-why { font-size: 13px; color: var(--mist); }
.watchlist-detail { padding: 6px 4px 20px 20px; }
.watchlist-drivers { display: grid; gap: 10px; max-width: 560px; }
.watchlist-driver { display: grid; grid-template-columns: 190px 1fr 130px; align-items: center; gap: 12px; }
.watchlist-driver-label { font-size: 12.5px; color: var(--ink); }
.watchlist-driver-bar { height: 6px; background: var(--paper-card); border-radius: 3px; overflow: hidden; }
.watchlist-driver-bar .fill { height: 100%; border-radius: 3px; background: rgba(6, 35, 48, 0.45); }
.watchlist-driver-value { font-size: 12.5px; font-family: var(--mono); color: var(--mist); text-align: right; white-space: nowrap; }
.watchlist-action {
  font-size: 13.5px; color: var(--ink); background: var(--paper-card); border-radius: 3px;
  padding: 12px 16px; max-width: 560px; margin-top: 14px;
}
.watchlist-action strong { color: var(--canopy); }

@media (max-width: 700px) {
  .watchlist-row-grid {
    grid-template-columns: 1fr auto;
    grid-template-areas: "who flag" "traj traj" "comp comp" "why why";
    row-gap: 6px;
  }
  .watchlist-row-grid .watchlist-who { grid-area: who; }
  .watchlist-row-grid .flag-chip { grid-area: flag; justify-self: end; }
  .watchlist-row-grid .watchlist-traj { grid-area: traj; }
  .watchlist-row-grid .watchlist-composite { grid-area: comp; flex-direction: row; align-items: center; }
  .watchlist-row-grid .watchlist-composite-bar { width: 100px; }
  .watchlist-row-grid .watchlist-why { grid-area: why; }
  .watchlist-driver { grid-template-columns: 1fr; gap: 3px; }
  .watchlist-driver-value { text-align: left; }
}

/* ---------- Persistent site-wide nav (marketing pages only, rendered via
   marketing/_marketing_base.html.j2's top_nav override -- the account-gated
   tool/app/monitoring pages still extend base.html.j2 directly and keep the
   plain .top-nav, untouched). Needs its own solid background (not an overlay
   on a hero) since it must render identically whether the page below has a
   hero (home/about/pricing/guide/demo) or not (legal pages) -- the old
   hero-only .hero-jump nav depended on the hero's own background and couldn't
   do that. ---------- */
/* #0f1419, a deliberate near-black -- not --canopy-deep and not an exact match to
   the hero's own #17273a. Both were tried (real rendered comparisons, not just
   swatches) alongside a brighter canopy-teal and a warm dark-brown option; a
   near-exact navy match read as a near-miss/inconsistency rather than a real
   choice, so this reads intentionally as its own distinct "toolbar" bar instead. */
.site-nav { background: #0f1419; position: relative; z-index: 20; }
/* A full-width inner rail puts the menu on the right side of the viewport while
   preserving a deliberate 80px safety inset. The mobile rule below restores the
   tighter 20px edge used by the hero and homepage body. */
.site-nav-inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 20px;
  width: 100%;
  max-width: none;
  margin: 0;
  padding: 9px 80px;
}
.site-nav .wordmark {
  font-family: var(--mono); font-size: 13px; letter-spacing: 0.14em; text-transform: uppercase;
  color: #ffffff; text-decoration: none;
}
.nav-links { display: flex; align-items: center; gap: 24px; }
.nav-links .jump-links { display: flex; gap: 16px 22px; }
.language-switcher {
  display: flex; align-items: center; gap: 0; margin: 0; padding: 0;
  list-style: none; border-left: 1px solid var(--canopy-line); padding-left: 18px;
}
.language-switcher li + li::before { content: "/"; color: #7f8994; margin: 0 6px; }
.language-switcher a {
  color: #b8c0c8; font-family: var(--mono); font-size: 11px; letter-spacing: 0.08em;
  text-decoration: none;
}
.language-switcher a:hover, .language-switcher a[aria-current="page"] { color: var(--gold); }
.nav-toggle { display: none; }

/* Persistent EUDR/Deforestation mode toggle (D170, Item 73 Session B). A
   segmented pill rather than .language-switcher's plain text links, since this
   is the primary, always-visible mode control, not a secondary utility. The
   D172 "I need:" prefix label was tried and dropped again (D176 follow-up) --
   the two pill labels read clearly enough on their own. */
.mode-switcher {
  display: flex; align-items: center; gap: 2px; margin: 0; padding: 3px;
  list-style: none; background: rgba(255, 255, 255, 0.06); border-radius: 20px;
}
.mode-switcher a {
  display: block; padding: 5px 12px; border-radius: 16px;
  font-family: var(--sans); font-size: 12.5px; font-weight: 500;
  color: #b8c0c8; text-decoration: none; white-space: nowrap;
}
.mode-switcher a:hover { color: #ffffff; }
.mode-switcher a.is-active { background: var(--gold); color: var(--ink); }

/* Commodity landing pages (Section 9.0 item 11): a native <details> dropdown
   needs no extra JS and degrades to a plain inline list if CSS fails to load --
   deliberately not an Alpine x-data addition, to keep this one small piece of nav
   content independent of the mobile hamburger's own open/close state. */
.nav-dropdown { position: relative; }
.nav-dropdown summary {
  list-style: none; cursor: pointer; font-family: var(--sans); font-size: 13px;
  font-weight: 500; color: #ffffff;
}
.nav-dropdown summary::-webkit-details-marker { display: none; }
.nav-dropdown summary:hover, .nav-dropdown[open] summary { color: var(--gold); }
.nav-dropdown-panel {
  display: flex; flex-direction: column; gap: 2px;
  position: absolute; top: calc(100% + 12px); left: 0; z-index: 30;
  background: #0f1419; border: 1px solid var(--canopy-line); border-radius: 4px;
  padding: 8px 0; min-width: 170px;
}
.nav-dropdown-panel a {
  padding: 8px 16px; font-family: var(--sans); font-size: 13px; color: #ffffff;
  text-decoration: none; white-space: nowrap;
}
.nav-dropdown-panel a:hover { color: var(--gold); background: rgba(243, 245, 249, 0.06); }

@media (max-width: 860px) {
  .site-nav-inner { padding-left: 20px; padding-right: 20px; }
  .nav-toggle {
    display: flex; flex-direction: column; justify-content: center; gap: 4px;
    background: none; border: none; cursor: pointer; padding: 8px; margin: -8px;
  }
  .nav-toggle span { width: 20px; height: 2px; background: #ffffff; display: block; }
  .nav-links {
    display: none; position: absolute; top: 100%; left: 0; right: 0; background: #0f1419;
    flex-direction: column; align-items: flex-start; gap: 16px;
    padding: 20px 20px 26px; border-top: 1px solid var(--canopy-line);
  }
  .nav-links--open { display: flex; }
  .nav-links .jump-links { flex-direction: column; gap: 14px; }
  .mode-switcher { align-self: flex-start; }
  .language-switcher { border-left: 0; padding-left: 0; }
  .nav-dropdown-panel {
    position: static; margin-top: 10px; padding: 0; border: none; background: none;
  }
  .nav-dropdown-panel a { padding: 6px 0; }
}

/* ---------- Homepage living atlas (approved body-design studio direction,
   2026-08-12) ----------
   A continuous, quiet Toraja contour field carries the approved hero's visual
   language through the whole homepage. Everything is scoped to the homepage
   wrapper so compact marketing pages and the product UI remain unchanged. */
.homepage-atlas {
  --homepage-contour-strength: 0.15;
  --homepage-hero-height: 0px;
  --homepage-hero-continuation-depth: 64px;
  position: relative;
  isolation: isolate;
  overflow: clip;
  background: #ebece6;
}
.homepage-atlas::before,
.homepage-atlas::after,
.homepage-atlas__hero-continuation,
.homepage-atlas__flow,
.homepage-atlas__flow::before {
  position: absolute;
  pointer-events: none;
}
/* A very faint full-height field prevents the terrain current from reading as
   disconnected decorative blobs. */
.homepage-atlas::before {
  content: "";
  inset: 0;
  z-index: 0;
  background: url("/static/img/toraja-contours.fp-8f3cd33197.webp") center top / 1180px auto repeat;
  opacity: calc(var(--homepage-contour-strength) * 0.22);
  mix-blend-mode: multiply;
  filter: grayscale(0.25) saturate(0.62);
  -webkit-mask-image: linear-gradient(180deg, transparent 0, #000 var(--homepage-hero-continuation-depth));
  mask-image: linear-gradient(180deg, transparent 0, #000 var(--homepage-hero-continuation-depth));
}
/* The hero and body intentionally use different color treatments, but their
   contour geometry should cross the boundary without a cut. This is an exact,
   low-opacity copy of the hero map box, positioned over its original coordinates.
   Only the part that the hero's scale carries below its own box is revealed; it
   then hands off softly to the established body field. */
.homepage-atlas__hero-continuation {
  top: calc(-1 * var(--homepage-hero-height));
  left: 0;
  z-index: 1;
  width: 100%;
  height: var(--homepage-hero-height);
  background: url("/static/img/toraja-contours.fp-8f3cd33197.webp") 52% 50% / cover no-repeat;
  background-image: -webkit-image-set(
    url("/static/img/toraja-contours.fp-8f3cd33197.webp") 1x,
    url("/static/img/toraja-contours@2x.fp-c566d0b34d.webp") 2x
  );
  background-image: image-set(
    url("/static/img/toraja-contours.fp-8f3cd33197.webp") 1x,
    url("/static/img/toraja-contours@2x.fp-c566d0b34d.webp") 2x
  );
  opacity: calc(var(--homepage-contour-strength) * 1.3);
  transform: translateX(-7%) scale(1.15);
  transform-origin: center;
  mix-blend-mode: multiply;
  filter: grayscale(0.2) saturate(0.68);
  -webkit-mask-image: linear-gradient(180deg, #000 0 94%, transparent 100%);
  mask-image: linear-gradient(180deg, #000 0 94%, transparent 100%);
}
/* A locally stronger opening wash makes the map feel continuous across the
   hero/body handoff. It uses the full-height field's exact scale, position, and
   repeat phase, and fades in only after the hero-aligned continuation. */
.homepage-atlas::after {
  content: "";
  top: 0;
  right: 0;
  left: 0;
  z-index: 1;
  height: 430px;
  background: url("/static/img/toraja-contours.fp-8f3cd33197.webp") center top / 1180px auto repeat;
  opacity: calc(var(--homepage-contour-strength) * 1.3);
  mix-blend-mode: multiply;
  filter: grayscale(0.2) saturate(0.68);
  -webkit-mask-image: linear-gradient(180deg, transparent 0, #000 var(--homepage-hero-continuation-depth), rgba(0, 0, 0, 0.72) 24%, transparent 100%);
  mask-image: linear-gradient(180deg, transparent 0, #000 var(--homepage-hero-continuation-depth), rgba(0, 0, 0, 0.72) 24%, transparent 100%);
}
.homepage-atlas__flow {
  inset: 0;
  z-index: 0;
  overflow: hidden;
  -webkit-mask-image: linear-gradient(180deg, transparent 0, #000 var(--homepage-hero-continuation-depth));
  mask-image: linear-gradient(180deg, transparent 0, #000 var(--homepage-hero-continuation-depth));
}
.homepage-atlas__flow::before {
  content: "";
  inset: 0;
  background: url("/static/img/toraja-contours.fp-8f3cd33197.webp") 50% 0 / 1180px auto repeat;
  opacity: calc(var(--homepage-contour-strength) * 0.92);
  mix-blend-mode: multiply;
  filter: grayscale(0.24) saturate(0.68);
  -webkit-mask-image:
    radial-gradient(ellipse 50% 15% at 78% 4%, #000 38%, transparent 76%),
    radial-gradient(ellipse 54% 16% at 68% 17%, #000 38%, transparent 76%),
    radial-gradient(ellipse 56% 17% at 52% 31%, #000 38%, transparent 77%),
    radial-gradient(ellipse 54% 17% at 35% 45%, #000 38%, transparent 77%),
    radial-gradient(ellipse 55% 17% at 44% 59%, #000 38%, transparent 77%),
    radial-gradient(ellipse 54% 17% at 62% 73%, #000 38%, transparent 77%),
    radial-gradient(ellipse 52% 16% at 76% 87%, #000 38%, transparent 76%),
    radial-gradient(ellipse 50% 14% at 66% 98%, #000 38%, transparent 76%);
  mask-image:
    radial-gradient(ellipse 50% 15% at 78% 4%, #000 38%, transparent 76%),
    radial-gradient(ellipse 54% 16% at 68% 17%, #000 38%, transparent 76%),
    radial-gradient(ellipse 56% 17% at 52% 31%, #000 38%, transparent 77%),
    radial-gradient(ellipse 54% 17% at 35% 45%, #000 38%, transparent 77%),
    radial-gradient(ellipse 55% 17% at 44% 59%, #000 38%, transparent 77%),
    radial-gradient(ellipse 54% 17% at 62% 73%, #000 38%, transparent 77%),
    radial-gradient(ellipse 52% 16% at 76% 87%, #000 38%, transparent 76%),
    radial-gradient(ellipse 50% 14% at 66% 98%, #000 38%, transparent 76%);
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;
}
.homepage-atlas > section.block {
  position: relative;
  z-index: 2;
  padding: 0;
  border-bottom: 0;
}
.homepage-atlas__inner {
  position: relative;
  width: min(100% - 80px, 1180px);
  margin-inline: auto;
  padding: 90px 0 86px;
  display: grid;
  grid-template-columns: minmax(300px, 0.86fr) minmax(0, 1.14fr);
  row-gap: 30px;
  column-gap: clamp(36px, 5vw, 72px);
}
.homepage-atlas__inner > * { grid-column: 1 / -1; }
.homepage-atlas__meta {
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 0 0 6px;
  padding-bottom: 9px;
  border: 0;
  color: rgba(95, 113, 130, 0.62);
  line-height: 1.25;
}
.homepage-atlas__rule {
  display: block;
  flex: 1;
  min-width: 28px;
  height: 1px;
  background: rgba(95, 113, 130, 0.18);
}
.homepage-atlas__coordinate {
  flex: none;
  color: rgba(95, 113, 130, 0.68);
  font: 400 9.5px var(--mono);
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.055em;
  white-space: nowrap;
}
.homepage-atlas .homepage-atlas__inner > .section-title {
  max-width: 21.5ch;
  margin: 0;
  color: var(--canopy);
  font-family: var(--sans);
  font-size: clamp(34px, 3.5vw, 48px);
  font-weight: 760;
  letter-spacing: -0.04em;
  line-height: 1.03;
}
.homepage-atlas .homepage-atlas__inner > .section-title + .lede {
  max-width: 66ch;
  margin: -4px 0 0;
  padding-top: 0;
}
.homepage-atlas #faq .section-title { max-width: 21.5ch; }
.homepage-atlas .check-list {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 14px 34px;
  max-width: none;
}
.homepage-atlas .stakes-card,
.homepage-atlas .trust-badge,
.homepage-atlas .chip,
.homepage-atlas .homepage-atlas__read-card,
.homepage-atlas .faq-item {
  background: rgba(255, 255, 255, 0.68);
  border-radius: 0;
  -webkit-backdrop-filter: blur(2px);
  backdrop-filter: blur(2px);
}
.homepage-atlas .stakes-card { margin-top: 28px; }
.homepage-atlas .trust-badges { margin-top: 22px; }
.homepage-atlas .trust-badge {
  border-top: 2px solid rgba(63, 122, 83, 0.54);
  max-width: 280px;
}
.homepage-atlas .steps {
  grid-template-columns: repeat(4, 1fr);
  gap: 22px;
  margin-top: 32px;
}
.homepage-atlas .step .n { display: none; }
.homepage-atlas .group-label {
  display: flex;
  align-items: center;
  gap: 12px;
  color: rgba(95, 113, 130, 0.82);
  font-size: 10.5px;
  font-weight: 500;
  letter-spacing: 0.09em;
}
.homepage-atlas .group-label::after {
  content: "";
  flex: 1;
  height: 1px;
  background: rgba(95, 113, 130, 0.18);
}
.homepage-atlas .legend { margin-top: 0; }
.homepage-atlas .sources {
  gap: 0;
  border-top: 0;
}
.homepage-atlas .source { padding: 22px 22px 0 0; }
.homepage-atlas .sources.compact { margin-top: 0; }
.homepage-atlas .read-grid {
  grid-template-columns: 1fr 1fr;
  gap: 14px;
  margin-top: 0;
}
.homepage-atlas__read-card {
  padding: 20px 22px;
  border-left: 3px solid rgba(13, 74, 104, 0.34);
}
.homepage-atlas__read-card h3 {
  margin: 0 0 7px;
  color: var(--canopy);
  font-family: var(--sans);
  font-size: 16px;
  font-weight: 700;
}
.homepage-atlas__read-card p { margin: 0 0 12px; font-size: 14px; }
.homepage-atlas__read-card p:last-child { margin-bottom: 0; }
.homepage-atlas section.block a:not(.btn-primary):not(.btn-secondary):not(.btn-outline) { color: var(--canopy); }
.homepage-atlas #preview .screenshot-badge { width: max-content; }
.homepage-atlas #preview .screenshot-frame {
  margin-top: 42px;
  padding: 16px;
  border: 1px solid rgba(6, 35, 48, 0.2);
  background: rgba(255, 255, 255, 0.58);
  box-shadow: 0 24px 60px rgba(23, 39, 58, 0.12);
}

/* The CTA repeats the same raster at the body field's exact vertical phase.
   homepage_atlas.js keeps --cta-contour-offset synchronized as responsive
   content changes height. */
footer.homepage-cta {
  --homepage-contour-strength: 0.15;
  position: relative;
  z-index: 5;
  overflow: hidden;
  padding: 82px 0;
  background: #17273a;
}
footer.homepage-cta::before {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: url("/static/img/toraja-contours.fp-8f3cd33197.webp") 50% var(--cta-contour-offset, 0px) / 1180px auto repeat;
  opacity: calc(var(--homepage-contour-strength) * 2.15);
  mix-blend-mode: screen;
  filter: grayscale(0.12) saturate(0.72) contrast(1.08);
  -webkit-mask-image:
    radial-gradient(ellipse 58% 55% at 66% -5%, #000 38%, transparent 78%),
    radial-gradient(ellipse 62% 62% at 78% 52%, #000 38%, transparent 78%),
    radial-gradient(ellipse 58% 55% at 62% 108%, #000 38%, transparent 78%);
  mask-image:
    radial-gradient(ellipse 58% 55% at 66% -5%, #000 38%, transparent 78%),
    radial-gradient(ellipse 62% 62% at 78% 52%, #000 38%, transparent 78%),
    radial-gradient(ellipse 58% 55% at 62% 108%, #000 38%, transparent 78%);
}
.homepage-cta__inner {
  position: relative;
  z-index: 1;
  width: min(100% - 80px, 1180px);
  margin-inline: auto;
}
footer.homepage-cta .homepage-atlas__meta {
  max-width: 780px;
  margin-bottom: 28px;
  padding-bottom: 9px;
}
footer.homepage-cta .homepage-atlas__rule { background: rgba(255, 255, 255, 0.17); }
footer.homepage-cta .homepage-atlas__coordinate { color: rgba(255, 255, 255, 0.46); }
footer.homepage-cta h2.section-title {
  max-width: 20ch;
  font-family: Georgia, "Iowan Old Style", "Times New Roman", serif;
  font-size: clamp(29px, 4vw, 44px);
}
footer.homepage-cta .lede { max-width: 56ch; }

@media (max-width: 700px) {
  .homepage-atlas__hero-continuation {
    background-position: 53% 50%;
    transform: translateX(-5%) scale(1.08);
    -webkit-mask-image: linear-gradient(180deg, #000 0 96.5%, transparent 100%);
    mask-image: linear-gradient(180deg, #000 0 96.5%, transparent 100%);
  }
  .homepage-atlas__inner {
    display: block;
    width: min(100% - 40px, 920px);
    padding: 70px 0 68px;
  }
  .homepage-atlas__meta { margin-bottom: 24px; }
  .homepage-atlas__coordinate { font-size: 9px; }
  .homepage-atlas .homepage-atlas__inner > .section-title {
    max-width: 14.35ch;
    margin-bottom: 24px;
    font-size: clamp(34px, 10vw, 44px);
  }
  .homepage-atlas .homepage-atlas__inner > .section-title + .lede {
    margin-top: 24px;
    padding-top: 0;
  }
  .homepage-atlas .check-list,
  .homepage-atlas .steps,
  .homepage-atlas .sources,
  .homepage-atlas .sources.compact,
  .homepage-atlas .read-grid { grid-template-columns: 1fr; }
  .homepage-atlas .trust-badge { max-width: none; }
  .homepage-atlas #preview .screenshot-frame { margin-top: 28px; padding: 8px; }
  footer.homepage-cta { padding: 68px 0; }
  .homepage-cta__inner { width: min(100% - 40px, 920px); }
}

/* ---------- Inline terminology explainer (STATUS.md queue item 70, Phase 2):
   CSS-only <details>/<summary> disclosure -- no JS dependency, works via tap or
   click identically. Deliberately not a :hover tooltip (unusable on touch).
   Lives in base.css, not app_shell.css, because the macro is used from
   tool/_flag_tiles.html.j2, which is shared by both /app/results (app shell) and
   the public /demo page (marketing base, no app_shell.css loaded). */
/* <details> (used below) does not reliably participate as true inline content
   in every engine even with display:inline forced -- so info() is only ever
   used inside a flex item (case-flag-legend-item below, or an existing span/th/h2
   that already has no competing inline siblings), never embedded directly in a
   flowing multi-sentence <p>. See cases/resolutions.html.j2 for the pattern. */
.info-disclosure { display: inline-flex; align-items: center; position: relative; margin-left: 3px; }
.info-disclosure summary {
  list-style: none;
  cursor: pointer;
  display: inline-block;
  vertical-align: middle;
  color: var(--mist);
  opacity: 0.8;
}
.info-disclosure summary svg { display: block; }
.info-disclosure summary::-webkit-details-marker { display: none; }
.info-disclosure summary::marker { content: ""; }
.info-disclosure summary:hover,
.info-disclosure[open] summary { color: var(--canopy); opacity: 1; }
.info-disclosure-body {
  display: block;
  position: absolute;
  z-index: 20;
  top: calc(100% + 6px);
  left: 0;
  width: max-content;
  max-width: 260px;
  background: var(--canopy-deep);
  color: #fff;
  font-family: var(--sans);
  font-size: 12.5px;
  font-weight: 400;
  line-height: 1.45;
  letter-spacing: normal;
  text-transform: none;
  padding: 10px 12px;
  border-radius: 6px;
  box-shadow: 0 12px 28px rgba(6, 35, 48, 0.22);
}
@media (max-width: 480px) {
  .info-disclosure-body { left: auto; right: -8px; max-width: 220px; }
}
.case-flag-legend { display: flex; flex-wrap: wrap; gap: 18px; margin: -6px 0 20px; }
.case-flag-legend-item { display: inline-flex; align-items: center; }

/* ==========================================================================
   Compact component library (STATUS.md queue item 71, session A --
   docs/de_verbosity_strategy_2026-08-24.md). Formalizes the vocabulary
   sessions B-F reuse instead of each inventing its own "compact" pattern.
   Added here, unused by any template yet -- no visible change from this
   commit. Existing components already cover part of the vocabulary and are
   NOT duplicated below -- reuse these instead of adding new ones:
     - Status chip/badge  -> .flag-chip / .dd-badge / .data-quality-badge /
       .pressure-badge (line ~619), .chip (line ~1158), .tile (line ~545).
     - Fact list (short)  -> .stakes-card + .fact-row/.fact-label/.fact-value
       (line ~1124), or .dd-chip/.lot-metric/.pressure-metric for a single
       highlighted figure.
     - Definition grid     -> .sources/.source dt/dd (line ~1163), and its
       .compact modifier for a denser 5-up row.
     - Icon-led step list  -> .steps/.step (line ~1145). Trimming step body
       copy to ~15 words is a content task for B-F, not a CSS change.
     - Disclosure           -> .info-disclosure (line ~1850, the info() macro).
   Genuinely new below: a table-based fact list for longer/tabular content
   than .fact-row suits, a comparison table (no existing equivalent), and a
   generalized meter/proportion-bar (ported from the PDF's proven
   src/templates/report.css .proportion-bar, and generalized from the
   one-off .case-readiness-track above) so both single-value and
   multi-segment proportions share one primitive across every app page. */

/* ---------- Fact table: table-based key/value list ----------
   Same shaded-key-column look as the PDF's .fact-table (report.css), for app
   content that's genuinely tabular (more rows than .stakes-card's .fact-row
   comfortably stacks, or several columns) rather than a short highlighted
   list. Wrap in .table-scroll (existing) on narrow content. */
table.fact-table { width: 100%; border-collapse: collapse; font-size: 14.5px; }
table.fact-table td, table.fact-table th { padding: 10px 14px; border-bottom: 1px solid var(--rule); text-align: left; vertical-align: top; }
table.fact-table tr:last-child td, table.fact-table tr:last-child th { border-bottom: none; }
table.fact-table th {
  font-family: var(--mono); font-size: 11px; letter-spacing: 0.04em; text-transform: uppercase;
  color: var(--mist); font-weight: 600; background: var(--paper-card);
}
table.fact-table td:first-child, table.fact-table th:first-child { font-weight: 600; color: var(--canopy); width: 38%; background: var(--paper-card); }
@media (max-width: 560px) {
  table.fact-table, table.fact-table tbody, table.fact-table tr, table.fact-table td, table.fact-table th { display: block; width: auto; }
  table.fact-table tr { padding: 10px 0; border-bottom: 1px solid var(--rule); }
  table.fact-table td:first-child, table.fact-table th:first-child { background: none; padding: 0 0 3px; font-size: 12px; }
  table.fact-table td:last-child { padding-top: 0; }
}

/* ---------- Comparison table ----------
   Operator-vs-downstream, commodity coverage, pricing tiers -- replaces a
   paragraph contrast with a scannable grid. .comparison-table--highlight on
   a <td>/<th> calls out the recommended column/row (pricing tier, the
   reader's own applicable case) without a second color vocabulary. */
table.comparison-table { width: 100%; border-collapse: collapse; font-size: 14.5px; }
table.comparison-table th, table.comparison-table td { padding: 11px 14px; border-bottom: 1px solid var(--rule); text-align: left; vertical-align: top; }
table.comparison-table thead th {
  font-family: var(--mono); font-size: 11px; letter-spacing: 0.04em; text-transform: uppercase;
  color: var(--mist); font-weight: 600; border-bottom: 2px solid var(--canopy);
}
table.comparison-table tbody th { font-weight: 600; color: var(--canopy); text-align: left; }
table.comparison-table tbody tr:nth-child(even) td, table.comparison-table tbody tr:nth-child(even) th { background: rgba(13, 74, 104, 0.035); }
table.comparison-table .comparison-table--highlight { background: var(--paper-card); border-left: 2px solid var(--gold-dark); border-right: 2px solid var(--gold-dark); }
table.comparison-table thead .comparison-table--highlight { border-top: 2px solid var(--gold-dark); }

/* ---------- Meter: single-value proportion ----------
   Generalizes .case-readiness-track (line ~385, kept as-is so its existing
   colored-by-status modifiers don't need a template change) into a reusable
   primitive for any other single percentage -- e.g. a portfolio-level DD
   completion figure in session D/E. Color the fill with an inline
   custom property (style="--meter-fill: var(--green)") or a modifier class
   rather than a new color keyword per use site. */
.meter-track { height: 8px; overflow: hidden; border-radius: 999px; background: rgba(13, 74, 104, 0.13); }
.meter-track > span { display: block; height: 100%; border-radius: inherit; background: var(--meter-fill, var(--gold)); }
.meter-track.green > span { background: var(--green); }
.meter-track.amber > span { background: var(--amber); }
.meter-track.red > span { background: var(--red); }

/* ---------- Proportion bar: multi-segment ----------
   Direct port of the PDF's proven .proportion-bar/.proportion-segment
   (src/templates/report.css) onto app tokens -- same shape (flex-basis per
   segment, no chart library), so a RED/AMBER/GREEN/CANNOT_SCREEN portfolio
   split reads as one bar instead of four separate numbers on the app case
   hub, same as it already does in the PDF. */
.proportion-bar { display: flex; height: 10px; border-radius: 5px; overflow: hidden; }
.proportion-segment { flex-grow: 0; flex-shrink: 0; }
.proportion-segment.red { background: var(--red); }
.proportion-segment.amber { background: var(--amber); }
.proportion-segment.green { background: var(--green); }
.proportion-segment.slate { background: var(--slate); }

/* ---------- Demo note ----------
   /demo/* reuses the real app templates verbatim (app/templating.py's
   app_base_path global); this is the one net-new class those templates need,
   shown in place of a write action (upload, invite, subscribe, ...) that a
   public unauthenticated demo visitor can't actually perform. */
.demo-note { margin: 8px 0 0; padding: 8px 12px; border-left: 3px solid var(--slate); background: var(--paper-card); color: var(--mist); font-size: 13px; }

/* ---------- Public-site decision visuals (de-verbosity reset session 1) ---------- */
.decision-matrix td, .decision-matrix th { vertical-align: middle; }
.deadline-strip {
  display: grid; grid-template-columns: 1fr 1fr; gap: 1px; margin-top: 18px;
  border: 1px solid var(--rule); background: var(--rule);
}
.deadline-strip span { padding: 14px 16px; background: rgba(255,255,255,.72); color: var(--mist); font-size: 13.5px; }
.deadline-strip b { display: block; color: var(--canopy); font: 700 15px var(--mono); }

.process-flow, .method-flow, .phone-journey, .buying-steps {
  display: grid; grid-template-columns: repeat(4, 1fr); gap: 0; margin: 24px 0; padding: 0;
  list-style: none; counter-reset: none;
}
.process-flow li, .phone-journey li, .buying-steps li {
  position: relative; min-width: 0; padding: 18px 22px; border: 1px solid var(--rule);
  background: rgba(255,255,255,.72);
}
.process-flow li + li, .phone-journey li + li, .buying-steps li + li { border-left: 0; }
.process-flow li:not(:last-child)::after, .phone-journey li:not(:last-child)::after {
  content: ""; position: absolute; z-index: 2; top: 50%; right: -6px; width: 10px; height: 10px;
  border-top: 1px solid var(--canopy); border-right: 1px solid var(--canopy); background: var(--paper); transform: translateY(-50%) rotate(45deg);
}
.process-flow li > span, .phone-journey li > span {
  display: inline-grid; width: 24px; height: 24px; place-items: center; margin-bottom: 12px;
  border-radius: 50%; background: var(--canopy); color: #fff; font: 700 11px var(--mono);
}
.process-flow b, .process-flow small, .phone-journey b, .phone-journey small { display: block; }
.process-flow b, .phone-journey b { color: var(--canopy); font-size: 15px; }
.process-flow small, .phone-journey small { margin-top: 4px; color: var(--mist); font-size: 12.5px; line-height: 1.35; }
.process-flow--five { grid-template-columns: repeat(5, 1fr); }
.process-flow--three { grid-template-columns: repeat(3, 1fr); }
.boundary-line { margin: 18px 0 0; padding: 11px 14px; border-left: 3px solid var(--gold-dark); background: var(--paper-card); color: var(--mist); font-size: 13.5px; }
.boundary-line strong { color: var(--canopy); }

.output-preview { display: grid; grid-template-columns: minmax(230px,.65fr) minmax(0,1.35fr); gap: 28px; align-items: center; }
.legend--vertical { display: grid; margin: 0; }
.legend--vertical .chip { justify-content: flex-start; }
.trust-strip { display: flex; flex-wrap: wrap; gap: 7px; margin-top: 16px; }
.trust-strip span { padding: 5px 8px; border: 1px solid var(--rule); color: var(--mist); font: 600 10px var(--mono); text-transform: uppercase; }
.output-preview .screenshot-frame { margin: 0; }
.output-preview figcaption { margin-top: 8px; color: var(--mist); font-size: 12px; }

.decision-path { display: grid; grid-template-columns: repeat(3,1fr); gap: 20px; margin-top: 22px; }
.decision-path > div { position: relative; padding: 20px; border-top: 3px solid var(--canopy); background: var(--paper-card); }
.decision-path b, .decision-path small { display: block; }
.decision-path small { margin-top: 7px; color: var(--mist); }
.decision-branch { position: absolute; top: 50%; right: -16px; z-index: 2; padding: 2px 5px; background: var(--gold); color: var(--canopy-deep); font: 700 9px var(--mono); text-transform: uppercase; }
.decision-path > div:last-child .decision-branch { display: none; }
.compact-disclosure { margin-top: 16px; border-top: 1px solid var(--rule); border-bottom: 1px solid var(--rule); }
.compact-disclosure summary { cursor: pointer; padding: 11px 0; color: var(--canopy); font-size: 13.5px; font-weight: 600; }
.compact-disclosure p { margin: 0 0 13px; color: var(--mist); font-size: 13.5px; }

.deadline-timeline { display: grid; grid-template-columns: 1fr 1fr; gap: 22px; margin: 24px 0; padding: 0; list-style: none; }
.deadline-timeline li { padding: 18px 20px; border-left: 4px solid var(--gold-dark); background: var(--paper-card); }
.deadline-timeline time, .deadline-timeline span { display: block; }
.deadline-timeline time { color: var(--canopy); font: 700 18px var(--mono); }
.deadline-timeline span { margin-top: 7px; color: var(--mist); font-size: 13.5px; }
.mass-balance-diagram { display: flex; align-items: center; justify-content: center; gap: 20px; margin: 26px 0; }
.mass-balance-diagram > div:first-child { display: grid; grid-template-columns: repeat(3,18px); gap: 7px; text-align: center; }
.mass-balance-diagram > div:first-child small { grid-column: 1/-1; color: var(--mist); }
.plot-dot { width: 18px; height: 18px; border-radius: 50%; }
.plot-dot.green { background: var(--green); }
.plot-dot.red { background: var(--red); }
.diagram-arrow { color: var(--mist); font-size: 22px; }
.shipment-box { padding: 15px 18px; border: 2px solid var(--canopy); color: var(--canopy); font-weight: 700; }

.method-flow { grid-template-columns: repeat(4,1fr); }
.method-flow li { position: relative; padding: 18px 20px; background: var(--canopy); color: #fff; }
.method-flow li + li { border-left: 1px solid rgba(255,255,255,.2); }
.method-flow b, .method-flow small { display: block; }
.method-flow small { margin-top: 5px; color: rgba(255,255,255,.72); }
.methodology-matrix td:last-child { font-family: var(--mono); font-size: 12px; color: var(--canopy); }
.flag-rule-grid { display: grid; grid-template-columns: repeat(4,1fr); gap: 12px; margin-top: 22px; }
.flag-rule-grid > div { padding: 16px; background: var(--paper-card); }
.flag-rule-grid b, .flag-rule-grid small { display: block; }
.flag-rule-grid b { margin-top: 12px; color: var(--canopy); }
.flag-rule-grid small { margin-top: 4px; color: var(--mist); }
.validation-scorecard { display: grid; grid-template-columns: repeat(3,1fr); gap: 14px; }
.validation-scorecard > div { padding: 22px; border-top: 3px solid var(--green); background: var(--paper-card); }
.validation-scorecard strong, .validation-scorecard span { display: block; }
.validation-scorecard strong { color: var(--canopy); font: 700 24px var(--mono); }
.validation-scorecard span { margin-top: 6px; color: var(--mist); font-size: 13px; }
.limitations-matrix { display: grid; grid-template-columns: repeat(2,1fr); border-top: 1px solid var(--rule); border-left: 1px solid var(--rule); }
.limitations-matrix > div { padding: 15px 17px; border-right: 1px solid var(--rule); border-bottom: 1px solid var(--rule); background: rgba(255,255,255,.55); }
.limitations-matrix b, .limitations-matrix span { display: block; }
.limitations-matrix b { color: var(--canopy); }
.limitations-matrix span { margin-top: 4px; color: var(--mist); font-size: 13px; }

.action-split, .caveat-split { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; margin: 20px 0; }
.action-split > div, .caveat-split > div { padding: 18px; border-left: 3px solid var(--canopy); background: var(--paper-card); }
.action-split b, .action-split span, .caveat-split b, .caveat-split span { display: block; }
.action-split span, .caveat-split span { margin-top: 5px; color: var(--mist); font-size: 13.5px; }

.commodity-brief section.block { padding: 42px 0; }
.commodity-facts { display: grid; grid-template-columns: repeat(3,1fr); gap: 1px; border: 1px solid var(--rule); background: var(--rule); }
.commodity-facts > div { padding: 17px; background: rgba(255,255,255,.72); }
.commodity-facts b, .commodity-facts span { display: block; }
.commodity-facts b { color: var(--canopy); font: 700 11px var(--mono); text-transform: uppercase; }
.commodity-facts span { margin-top: 7px; color: var(--mist); font-size: 13.5px; }
.supply-chain-flow { display: flex; align-items: stretch; gap: 14px; margin: 24px 0; }
.supply-chain-flow > div:not(.diagram-arrow) { flex: 1; padding: 17px; border-top: 3px solid var(--canopy); background: var(--paper-card); }
.supply-chain-flow > .diagram-arrow { align-self: center; flex: none; }
.supply-chain-flow span, .supply-chain-flow b, .supply-chain-flow small { display: block; }
.supply-chain-flow span { color: var(--gold-dark); font: 700 11px var(--mono); }
.supply-chain-flow b { margin-top: 8px; color: var(--canopy); }
.supply-chain-flow small { margin-top: 5px; color: var(--mist); line-height: 1.35; }
.supply-chain-flow .supply-chain-risk { border-top-color: var(--red); }
.risk-stat { margin: 0; color: var(--mist); font-size: 14px; }
.commodity-action { display: grid; grid-template-columns: auto 1fr; gap: 10px 12px; align-items: center; }
.commodity-action .cta-row, .commodity-action .boundary-line { grid-column: 1/-1; }

.buying-steps li { display: flex; align-items: center; gap: 10px; padding: 12px 14px; }
.buying-steps b { display: grid; flex: none; width: 22px; height: 22px; place-items: center; border-radius: 50%; background: var(--canopy); color: #fff; font: 700 10px var(--mono); }
.buying-steps span { color: var(--ink); font-size: 13px; }
.inclusion-checklist { display: grid; grid-template-columns: repeat(4,1fr); gap: 1px; margin-top: 20px; border: 1px solid var(--rule); background: var(--rule); }
.inclusion-checklist span { padding: 13px 14px 13px 32px; background: var(--paper-card); color: var(--mist); font-size: 12.5px; position: relative; }
.inclusion-checklist span::before { content: "✓"; position: absolute; left: 13px; color: var(--green); font-weight: 700; }

.founder-note { display: grid; grid-template-columns: minmax(0,1fr) 220px; gap: 34px; align-items: start; }
.founder-note img { width: 100%; height: auto; }
.founder-purpose { margin-top: 16px; padding-left: 14px; border-left: 3px solid var(--gold-dark); color: var(--mist); font-size: 15px; }

@media (max-width: 700px) {
  .deadline-strip, .deadline-timeline, .action-split, .caveat-split, .limitations-matrix,
  .commodity-facts, .validation-scorecard, .flag-rule-grid, .founder-note { grid-template-columns: 1fr; }
  .process-flow, .process-flow--five, .process-flow--three, .method-flow, .phone-journey, .buying-steps { grid-template-columns: 1fr 1fr; }
  .process-flow li + li, .phone-journey li + li, .buying-steps li + li { border-left: 1px solid var(--rule); }
  .process-flow li:not(:last-child)::after, .phone-journey li:not(:last-child)::after { display: none; }
  .output-preview { grid-template-columns: 1fr; }
  .decision-path { grid-template-columns: 1fr; }
  .decision-branch { top: auto; right: 14px; bottom: -11px; }
  .mass-balance-diagram, .supply-chain-flow { flex-direction: column; align-items: stretch; }
  .mass-balance-diagram .diagram-arrow, .supply-chain-flow .diagram-arrow { transform: rotate(90deg); align-self: center; }
  .mass-balance-diagram > div:first-child { align-self: center; }
  .inclusion-checklist { grid-template-columns: 1fr 1fr; }
  .founder-note img { width: min(220px,100%); grid-row: 1; }
}

@media (max-width: 480px) {
  .process-flow, .process-flow--five, .process-flow--three, .method-flow, .phone-journey, .buying-steps, .inclusion-checklist { grid-template-columns: 1fr; }
  .commodity-action { grid-template-columns: 1fr; }
  .commodity-action .cta-row, .commodity-action .boundary-line { grid-column: 1; }
}
