/* ==========================================================================
   OLIVE LIQUID — COMPATIBILITY LAYER
   --------------------------------------------------------------------------
   olive-liquid.css defines the design language as new `.lq*` components. That
   is right for a page built from scratch (report-library.html, olive-liquid.html)
   and useless for the other 111 pages, which are already built from the site's
   own vocabulary — .card, .panel, .btn, .badge, .stat, .tool-card.

   Rewriting 111 pages onto .lq* markup would be a rewrite, and a rewrite passes
   the spec rather than reality. So this file goes the other way: it maps the
   EXISTING classes onto the liquid tokens. A page adopts the look by adding two
   lines — this stylesheet and `class="lq-page"` on <body> — and keeps its markup,
   its JS hooks and its tests.

   EVERYTHING here is scoped under body.lq-page. A page that has not opted in is
   not touched, even though the file is loaded.

   WHAT THIS DELIBERATELY DOES NOT TOUCH
   -------------------------------------
   Richard's constraint: do not overwrite the timeline graphics, and keep the
   process-flow animations working. Those are not incidental — they are drawn by
   their own stylesheets and driven by JS that measures real geometry, so a
   background, a border-radius or a transform applied from here can move a node
   off its connector or restart an animation on every repaint.

   Protected, by explicit :not() rather than by hoping the selectors miss:

     [class*="flow-"]      process-flow canvases, panels, nodes, connectors
     [class*="phase-"]     phase cards, dots, connectors, the delivery timeline
     [class*="timeline"]   every timeline variant
     [class*="gantt"]      gantt rows and bars
     .chart-body, svg, canvas   anything a chart library owns and re-measures

   The rule of thumb applied throughout: a CONTAINER may take glass; its
   CONTENTS are left alone. So .chart-panel gets the panel treatment and
   .chart-body — the element d3 measures and draws into — does not.

   No `animation` or `transition` property is set on any protected selector, and
   nothing here sets `overflow`, `transform` or `position` on a chart or flow
   container, because all three change what a measuring script reads back.
   ========================================================================== */


/* ── Page ground ─────────────────────────────────────────────────────────── */
/* The site's own pages paint their own background; body.lq-page in
   olive-liquid.css already sets the void + the ambient field, so this only has
   to stop the older stylesheets painting over it. */
body.lq-page {
  color: var(--lq-text);
}

/* The ambient drifting field sits behind everything. Pages that set an opaque
   background on their top-level wrapper would hide it, so those are made
   transparent — the wrapper keeps its layout job and gives up its paint job. */
body.lq-page .page-wrap,
body.lq-page .app-shell,
body.lq-page main,
body.lq-page .content-area {
  background: transparent;
}


/* ── Ambient field, without asking the page for markup ───────────────────── */
/* olive-liquid.css draws the drifting field from a real element, <div class="lq-field">.
   A purpose-built page can include that; 111 existing pages will not, and the
   whole point of this layer is that a page opts in with two lines. So the field
   is painted from a pseudo-element instead -- and only when the page has NOT
   supplied its own, so report-library.html and olive-liquid.html do not get two.
   :has() is doing that test; where it is unsupported the rule is dropped and the
   page simply has no ambient field, which is decorative and safe to lose. */
/* The base colour moves UP to <html>, and body goes transparent. That is what
   makes the -1 field visible: a pseudo-element at z-index -1 paints above its
   own element's background but below its content, so leaving the base colour on
   body would bury the field under it -- measured, the glow disappeared entirely.
   Painting the ground on <html> puts it below body's whole stacking context,
   and the field then sits between the ground and the content, where it belongs. */
html:has(body.lq-page) {
  background: var(--lq-base);
}
body.lq-page {
  background: transparent;
  /* Stacking context WITHOUT taking a z-index of its own, so the field can sit
     at -1 beneath every piece of page content and no rule is needed on the
     children at all. The first attempt did it the other way round -- field at 0,
     children forced to position:relative -- and that broke a fixed panel. */
  isolation: isolate;
}
body.lq-page:not(:has(.lq-field))::before {
  content: '';
  position: fixed;
  inset: -20% -20% -20% -20%;
  /* -1, not 0. At z-index 0 this fixed element painted OVER the page's
     non-positioned content, which is why the first attempt also carried a
     `body.lq-page > * { position: relative; z-index: 1 }` rule to push content
     back on top. That rule was a real defect: process-universe.html's
     .flow-detail-panel is a FIXED full-height panel and a direct child of body,
     so forcing position:relative dropped it into normal flow and moved it from
     y=0 to y=1133. Measured, not theorised. Negative z-index inside body's own
     stacking context gets the same result and touches nothing. */
  z-index: -1;
  pointer-events: none;
  background:
    radial-gradient(46% 38% at 18% 12%, color-mix(in srgb, var(--lq-indigo) 17%, transparent), transparent 62%),
    radial-gradient(42% 34% at 82% 78%, color-mix(in srgb, var(--lq-lime) 13%, transparent), transparent 62%),
    radial-gradient(38% 30% at 62% 22%, rgba(0, 212, 255, .07), transparent 62%);
  filter: blur(48px) saturate(130%);
  animation: lq-drift 34s ease-in-out infinite alternate;
}
/* ── Cards and panels → glass ────────────────────────────────────────────── */
/* Matches .lq in olive-liquid.css: tinted translucency, a blur that lifts and
   saturates what is behind it, a bright inner top edge and a deep soft drop. */
/* The site does NOT have one card class. A survey of public/*.html found 30+
   families -- card (110), tool-card (57), stat-card (42), template-card (37),
   panel (32), glass-panel (26), kpi-card (20), sysadmin-panel (16),
   integration-card, summary-card, option-card, rm-card, ps-card, mw-card ...
   Enumerating them would go stale the first time somebody adds a page, so match
   the SHAPE of the name instead and exclude what must not be touched.
   Learned the hard way: the first version of this file listed .card/.tool-card
   only, and library.html -- 37 template-cards -- came out with glass buttons and
   flat cards.

   tools-panel* is excluded because the substring match catches all three of
   .tools-panel (a layout container), .tools-panel-head (a heading row) and
   .tools-panel-sub (a paragraph -- "tools-panel-sub" contains "-panel"), so
   tools.html rendered a glass slab inside a glass slab inside a third one and
   the tool description overlapped its own title. None of the three is a card;
   the tools themselves bring their own. */
body.lq-page [class~="card"],
body.lq-page [class~="panel"],
/* csync (2026-09-28, Richard: "text touching the borders ... boxes inside boxes"):
   the three rules below used to be bare substring matches ([class*="-card"]),
   which also caught every PART of a card -- settings-card-header, settings-card-body,
   role-card-actions, crim-card-* (247 such class names across the site) -- and gave
   each part its own glass border and radius with no padding, so text sat on the
   inner border. They now match only a class TOKEN that ENDS in -card/-panel/-tile
   ([class$=] for the last token, [class*="-card "] for any earlier one).
   To switch this whole mapping off, delete these selectors, or drop "lq-page" from <body>. */
body.lq-page [class$="-card"]:not([class*="phase-card"]):not([class*="flow-"]):not([class*="timeline"]),
body.lq-page [class*="-card "]:not([class*="phase-card"]):not([class*="flow-"]):not([class*="timeline"]),
body.lq-page [class$="-panel"]:not([class*="flow-"]):not([class*="timeline"]):not([class*="chart-body"]):not([class*="tools-panel"]),
body.lq-page [class*="-panel "]:not([class*="flow-"]):not([class*="timeline"]):not([class*="chart-body"]):not([class*="tools-panel"]),
body.lq-page [class$="-tile"]:not([class*="lq-"]),
body.lq-page [class*="-tile "]:not([class*="lq-"]),
body.lq-page .glass,
body.lq-page .stat {
  background: var(--lq-tint);
  -webkit-backdrop-filter: blur(var(--lq-blur-thin)) var(--lq-lift);
  backdrop-filter: blur(var(--lq-blur-thin)) var(--lq-lift);
  border: 1px solid var(--lq-edge, rgba(255, 255, 255, .10));
  border-radius: var(--lq-r);
  box-shadow: var(--lq-inner), var(--lq-drop);
}

/* Nested-box fix 2026-09-28 (Richard): ONE box level per group. A mapped
   card/panel/tile inside another one (or inside a page's own .card) was a
   second full glass box, usually with the renderer's zero padding -- a box
   inside a box, text on the border. The inner one goes flat (no fill, blur,
   shadow or border); stacked flat siblings get a hairline + space between. */
body.lq-page :is([class$="-card"], [class*="-card "], [class$="-panel"], [class*="-panel "], [class$="-tile"], [class*="-tile "], .glass, .card)
  :is([class$="-card"], [class*="-card "], [class$="-panel"], [class*="-panel "], [class$="-tile"], [class*="-tile "], .glass, .stat):not([class*="lq-"]):not([class*="flow-"]):not([class*="timeline"]):not([class*="phase-card"]):not([class*="chart-body"]):not([class*="tools-panel"]) {
  background: transparent;
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
  box-shadow: none;
  border: 0;
  border-radius: 0;
}
body.lq-page :is([class$="-card"], [class*="-card "], [class$="-panel"], [class*="-panel "], [class$="-tile"], [class*="-tile "], .glass, .card)
  :is([class$="-card"], [class*="-card "], [class$="-panel"], [class*="-panel "], [class$="-tile"], [class*="-tile "], .glass, .stat):not([class*="lq-"]):not([class*="flow-"]):not([class*="timeline"]):not([class*="phase-card"]):not([class*="chart-body"]):not([class*="tools-panel"]) + :is([class$="-card"], [class*="-card "], [class$="-panel"], [class*="-panel "], [class$="-tile"], [class*="-tile "], .glass, .stat):not([class*="lq-"]):not([class*="flow-"]):not([class*="timeline"]):not([class*="phase-card"]):not([class*="chart-body"]):not([class*="tools-panel"]) {
  border-top: 1px solid var(--lq-rule-2, rgba(255, 255, 255, .08));
  margin-top: 14px;
  padding-top: 14px;
}

/* Chart panels: the frame is glass, the plotting surface is not. d3 reads
   offsetWidth/offsetHeight off .chart-body — leave its box arithmetic alone. */
body.lq-page .chart-body,
body.lq-page .chart-body * {
  background: transparent;
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
  box-shadow: none;
}

/* Panel chrome keeps its structure; only the fill changes. */
body.lq-page .panel-head {
  background: var(--lq-tint-2);
  border-bottom-color: rgba(255, 255, 255, .09);
}
body.lq-page .panel-body {
  background: transparent;
}

/* Interactive cards get the lift, not a new layout. Transform is on the CARD,
   which owns nothing another script measures. */
body.lq-page .card-interactive:not([class*="flow-"]):not([class*="phase-"]),
body.lq-page a[class*="-card"]:not([class*="phase-card"]):not([class*="flow-"]),
body.lq-page .tool-card {
  transition: transform var(--lq-mid) var(--lq-ease),
              box-shadow var(--lq-mid) var(--lq-ease),
              background var(--lq-mid) var(--lq-ease);
}
body.lq-page .card-interactive:not([class*="flow-"]):not([class*="phase-"]):hover,
body.lq-page a[class*="-card"]:not([class*="phase-card"]):not([class*="flow-"]):hover,
body.lq-page .tool-card:hover {
  background: var(--lq-tint-2);
  border-color: color-mix(in srgb, var(--lq-lime) 34%, transparent);
  transform: translateY(-3px);
  box-shadow: var(--lq-inner), var(--lq-drop-lg), var(--lq-glow-lime);
}


/* ── Buttons ─────────────────────────────────────────────────────────────── */
/* Height, padding and font stay exactly as ask-olive.css sets them, so nothing
   reflows. Only the surface changes. */
body.lq-page .btn {
  border-radius: var(--lq-r-pill);
  transition: transform var(--lq-fast) var(--lq-ease),
              background var(--lq-fast) var(--lq-ease),
              box-shadow var(--lq-fast) var(--lq-ease),
              border-color var(--lq-fast) var(--lq-ease);
}
body.lq-page .btn-primary {
  background: var(--lq-grad-brand);
  color: var(--lq-ground, #0f1005);
  border-color: transparent;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .40), var(--lq-glow-lime);
}
body.lq-page .btn-primary:hover {
  background: var(--lq-grad-brand);
  filter: brightness(1.06);
  transform: translateY(-1px);
}
body.lq-page .btn-secondary,
body.lq-page .btn-ghost {
  background: var(--lq-tint);
  -webkit-backdrop-filter: blur(var(--lq-blur-thin));
  backdrop-filter: blur(var(--lq-blur-thin));
  color: var(--lq-text);
  border-color: rgba(255, 255, 255, .14);
}
body.lq-page .btn-secondary:hover,
body.lq-page .btn-ghost:hover {
  background: var(--lq-tint-2);
  border-color: rgba(255, 255, 255, .26);
  transform: translateY(-1px);
}


/* ── Badges, pills, chips ────────────────────────────────────────────────── */
/* Status colour is INFORMATION, not decoration: .badge-ok / -warn / -danger and
   their variants keep whatever hue their own stylesheet gives them. Only the
   neutral badge and the generic pill are reskinned, so a green "passed" badge
   stays green. */
body.lq-page .badge-neutral,
body.lq-page .pill:not([class*="status-"]) {
  background: var(--lq-tint-2);
  border-color: rgba(255, 255, 255, .12);
  color: var(--lq-text-2);
  border-radius: var(--lq-r-pill);
}


/* ── Form controls ───────────────────────────────────────────────────────── */
body.lq-page .form-input,
body.lq-page .input,
body.lq-page select.form-input,
body.lq-page textarea.form-input {
  background: var(--lq-tint);
  -webkit-backdrop-filter: blur(var(--lq-blur-thin));
  backdrop-filter: blur(var(--lq-blur-thin));
  border: 1px solid rgba(255, 255, 255, .13);
  border-radius: var(--lq-r-sm);
  color: var(--lq-text);
}
body.lq-page .form-input:focus,
body.lq-page .input:focus {
  border-color: color-mix(in srgb, var(--lq-indigo) 55%, transparent);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--lq-indigo) 16%, transparent);
  outline: none;
}
body.lq-page .form-label {
  color: var(--lq-text-2);
}


/* ── Tables ──────────────────────────────────────────────────────────────── */
/* Row striping goes; a hairline and a hover tint read better on glass and,
   unlike a striped fill, does not fight the ambient field showing through. */
body.lq-page table:not([class*="flow-"]):not([class*="gantt"]) {
  background: transparent;
}
body.lq-page table:not([class*="flow-"]):not([class*="gantt"]) thead th {
  background: var(--lq-tint-2);
  color: var(--lq-text-2);
  border-bottom-color: rgba(255, 255, 255, .12);
}
body.lq-page table:not([class*="flow-"]):not([class*="gantt"]) tbody tr {
  background: transparent;
  transition: background var(--lq-fast) var(--lq-ease);
}
body.lq-page table:not([class*="flow-"]):not([class*="gantt"]) tbody tr:hover {
  background: var(--lq-tint);
}
body.lq-page table:not([class*="flow-"]):not([class*="gantt"]) td {
  border-bottom-color: rgba(255, 255, 255, .07);
}


/* ── Navigation ──────────────────────────────────────────────────────────── */
/* .topnav is `position: sticky; top: 0` and the sign-in banner offsets itself by
   the measured header height (csync #2955). Height is therefore load-bearing and
   is NOT changed here — only the fill. */
body.lq-page .topnav {
  background: rgba(13, 13, 18, .72);
  -webkit-backdrop-filter: blur(var(--lq-blur)) var(--lq-lift);
  backdrop-filter: blur(var(--lq-blur)) var(--lq-lift);
  border-bottom: 1px solid rgba(255, 255, 255, .08);
}
/* csync #3841/#3842 (2026-09-18): the rule above is a pre-Heartwood navy literal,
   left untouched (dark render must stay byte-identical). It has no light-mode
   variant, so it wins on every theme via body.lq-page's specificity and the nav
   stayed dark in light mode — root cause, measured live via computed-style read:
   olive-nav.css's own --nv-bg/--bg-raised chain already resolves correctly
   (#FFFFFF), it's this bare rule that was never theme-aware. Additive override,
   scoped to [data-theme="light"] only, so dark is untouched either way. */
[data-theme="light"] body.lq-page .topnav {
  background: var(--nv-bg, #FFFFFF);
  background: color-mix(in srgb, var(--nv-bg, #FFFFFF) 88%, transparent);
  border-bottom-color: var(--nv-line, #E5E3E3);
}
body.lq-page .nav-links a:hover {
  background: rgba(255, 255, 255, .07);
  border-radius: var(--lq-r-pill);
}


/* ── Typography helpers already in the markup ────────────────────────────── */
body.lq-page .eyebrow {
  color: var(--lq-lime);
  letter-spacing: .2em;
  text-transform: uppercase;
}
body.lq-page .muted,
body.lq-page .text-muted { color: var(--lq-text-2); }
body.lq-page .mono { font-variant-numeric: tabular-nums; }


/* ── Backdrop-filter fallback ────────────────────────────────────────────── */
/* Same bargain as olive-liquid.css: without backdrop-filter the translucent
   fills read as muddy grey, so they become opaque instead. */
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  body.lq-page [class~="card"],
  body.lq-page [class~="panel"],
  body.lq-page [class*="-card"],
  body.lq-page [class*="-panel"]:not([class*="tools-panel"]),
  body.lq-page .glass,
  body.lq-page .chart-panel,
  body.lq-page .stat,
  body.lq-page .btn-secondary,
  body.lq-page .form-input,
  body.lq-page .topnav {
    background: rgba(22, 22, 32, .94);
  }
}


/* ── Reduced motion ──────────────────────────────────────────────────────── */
/* Only the hover lifts introduced by THIS file are dropped. The blanket
   animation kill lives in olive-liquid.css and is itself scoped to
   body.lq-page, so a page's own flow animations are that page's business. */
@media (prefers-reduced-motion: reduce) {
  body.lq-page .card-interactive:hover,
  body.lq-page .tool-card:hover,
  body.lq-page .btn:hover {
    transform: none;
  }
}
