/* ============================================================
   css/liquid.css -- the "liquid" layer on top of css/glass.css's
   material tiers. NEW FILE. Never edits glass.css, global.css,
   alert.css, or anything TKT-000443/554/455/467 own.

   WHAT THIS ADDS that glass.css's blur-based tiers do not have:
   refraction/displacement (an SVG filter, injected and driven by
   js/liquid.js), a specular top rim + dark bottom rim, a soft
   depth shadow, and an optional pointer-reactive highlight on the
   login card. See DESIGN.md sections 2 and 5 for the full spec
   and the accessibility floors this file honours.

   TIER: refraction and every rule below are gated on
   `html.glass-hd` -- js/glassLite.js's own HD device tier (TKT-000452).
   `glass` and `glass-lite` are UNTOUCHED: no selector in this file
   ever matches without `.glass-hd` on <html>, so those two tiers
   look exactly as they did before this file existed.

   SPECIFICITY, ON PURPOSE: css/glass.css is an override layer that
   must stay the LAST stylesheet on the page (scripts/check-
   stylesheet-order.py). This file is a new stylesheet too, so it
   links BEFORE glass.css in <head> to keep that gate green -- which
   means every rule here needs to OUT-SPECIFY glass.css's own
   `html body .selector` idiom on the same property, or glass.css
   would win by source order on a tie. Every selector below is
   `html.glass-hd body :is(...).liquid` (and `.liquid-refract` for
   the backdrop-filter rule), which is always at least one class
   heavier than glass.css's plain `html body .foo` and its
   `html.glass-hd body .foo .bar` HD-tier rules -- verified against
   the current file, not assumed.

   ATTRIBUTION (MIT, confirmed in each repo's own LICENSE before
   anything here was written -- see docs/design/SOURCES.md for the
   full breakdown of copied-vs-re-implemented):
     - dpawlikowski/liquid-glass (MIT, 2026) -- the feTurbulence ->
       feDisplacementMap filter graph shape and the SCALE_MIN/MAX
       clamp reasoning that js/liquid.js's injected <filter> follows.
       No source text pasted; the graph itself is a standard SVG
       primitive combination, credited anyway per MIT's notice
       requirement for substantial reuse of the design.
     - rdev/liquid-glass-react (Max Rovensky, MIT, 2025) -- the
       pointer-follow idiom (custom properties updated on the
       element, not per-frame layout reads) behind --liquid-mx/-my.
     - LeonardSEO/liquid-glass-react (MIT, 2026) and
       nikdelvin/liquid-glass (Nikita Stadnik, MIT, 2025) -- cross-
       checked to confirm the displacement-map approach is a shared,
       non-original technique before it was re-implemented here.
   ============================================================ */

/* ------------------------------------------------------------
   1. TOKENS. New tokens, owned by this file, not glass.css's.
      Colour tokens get an explicit dark declaration each
      (scripts/check-dark-parity.py: any --custom-property whose
      value is a literal colour must have one). Everything else
      (durations, the displacement scale) is not a colour and
      needs no dark pair.
   ------------------------------------------------------------ */
:root {
  --liquid-rim-hi: rgba(255, 255, 255, .55);   /* the specular top edge */
  --liquid-rim-lo: rgba(8, 20, 24, .20);        /* the faint dark bottom rim */
  --liquid-specular: rgba(255, 255, 255, .30);  /* the pointer-reactive glare */
  --liquid-depth-shadow: rgba(11, 79, 84, .18); /* the extra "floats above the page" shadow */
}
html[data-theme="dark"] {
  --liquid-rim-hi: rgba(255, 255, 255, .28);
  --liquid-rim-lo: rgba(0, 0, 0, .42);
  --liquid-specular: rgba(255, 255, 255, .14);
  --liquid-depth-shadow: rgba(0, 0, 0, .38);
}

/* ------------------------------------------------------------
   2. THE SURFACES. Opt-in only: js/liquid.js is the only thing
      that ever writes the `.liquid` class, onto exactly the
      surfaces DESIGN.md section 5 allows (chrome and transient
      overlays) -- never a table, a chart, a canvas or running
      text. scripts/check-liquid.py fails the build if the
      selector list in js/liquid.js ever grows to match those
      words, so the allow-list lives in one place.
   ------------------------------------------------------------ */

/* 2a. Rim + depth: the safe, always-on-HD layer. Pure box-shadow,
   no positioning requirement, so it is safe on elements this file
   does not control the `position` of (the sidebar and header are
   already `sticky`/`fixed` from their own component sheets; this
   never touches `position`). Composed alongside the existing
   var(--mat-shadow-2) rest shadow rather than replacing it, so a
   surface keeps its resting elevation and gains the liquid rim on
   top of it, not instead of it. */
html.glass-hd body :is(.edash-header, .edash-sidebar, .hd-profile-menu,
                        .login-form-panel, .st-tabs, .ap-modal,
                        .pd-report-modal, .pd-env-settings-modal,
                        .lg-modal, .eb-sheet).liquid,
html.glass-hd body [id$="Toast"].liquid {
  box-shadow:
    inset 0 1px 0 var(--liquid-rim-hi),
    inset 0 -1px 0 var(--liquid-rim-lo),
    var(--mat-shadow-2),
    0 14px 32px -10px var(--liquid-depth-shadow);
  isolation: isolate; /* keeps the pointer-glow pseudo-element (2c) from
                          blending with anything outside this surface */
}

/* 2b. Refraction: ONLY when js/liquid.js both (1) confirmed the
   browser can actually resolve `backdrop-filter: url(#id)` and (2)
   found no reduced-motion/reduced-transparency/forced-colors/
   prefers-contrast signal -- see js/liquid.js's detect(). It marks
   <html> with `.liquid-refract` only then; this selector cannot
   match otherwise, which is the CSS half of the fallback (the JS
   half is that `.liquid` alone, from 2a, already looks complete on
   its own -- there is no bare, unstyled state to flash).

   scripts/check-glass-tiers.py also requires every html.glass-hd blur
   to sit inside a `min-width: 768px` block -- hd is already a desktop-
   class device tier by js/glassLite.js's own detection (>=8 cores and
   8GB/fine-pointer), but the check asks for the structural guarantee
   too, so the rule below carries it explicitly rather than relying on
   the tier class alone. */
@media (min-width: 768px) {
  html.glass-hd.liquid-refract body :is(.edash-header, .edash-sidebar,
                          .hd-profile-menu, .login-form-panel, .st-tabs,
                          .ap-modal, .pd-report-modal,
                          .pd-env-settings-modal, .lg-modal, .eb-sheet).liquid,
  html.glass-hd.liquid-refract body [id$="Toast"].liquid {
    /* var(--mat-filter-thick) is glass.css's own HD blur+saturate pair
       (24px, 1.4) -- reused rather than reinvented so the lite tier's
       existing `--mat-filter-thick: none` reset (css/glass.css, the
       lite gate) already turns this off structurally, on top of the
       tier-class gate this selector already carries. url(#id) adds
       the displacement; the material's own blur/saturate do the rest. */
    backdrop-filter: url(#edash-liquid-filter) var(--mat-filter-thick);
    -webkit-backdrop-filter: var(--mat-filter-thick);
  }
}

/* The lite-tier fallback the same check requires for any selector that
   ever carries a real blur: html.glass-lite resets it to none. Runtime
   belt-and-suspenders only -- js/liquid.js's tag()/apply() never add
   `.liquid` or `.liquid-refract` outside the html.glass-hd tier in the
   first place (see js/liquid.js section 4), so this can never actually
   fire; it exists so the guarantee is readable in the stylesheet, not
   only in the script that happens to be well-behaved today. */
html.glass-lite body :is(.edash-header, .edash-sidebar, .hd-profile-menu,
                        .login-form-panel, .st-tabs, .ap-modal,
                        .pd-report-modal, .pd-env-settings-modal,
                        .lg-modal, .eb-sheet).liquid,
html.glass-lite body [id$="Toast"].liquid {
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
}

/* 2c. The optional pointer-reactive highlight. Scoped to the login
   card only (DESIGN.md section 5): it is the one surface in this
   list whose `position` this file can safely touch (a flex child
   with no `position` of its own -- `position: relative` on a flex
   item changes nothing about flex layout, it only creates the
   positioning context the glare needs; every other surface in 2a
   is already positioned by its own component sheet and this file
   does not risk moving it). js/liquid.js only adds `.liquid-glow`
   on a fine-pointer, non-reduced-motion desktop and only updates
   --liquid-mx/--liquid-my, which this rule reads -- no JS ever
   writes a rect or a layout property. */
html.glass-hd.liquid-refract body .login-form-panel.liquid.liquid-glow {
  position: relative;
  overflow: hidden;
}
html.glass-hd.liquid-refract body .login-form-panel.liquid.liquid-glow::before {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: radial-gradient(220px circle at var(--liquid-mx, 50%) var(--liquid-my, 20%),
              var(--liquid-specular), transparent 65%);
  opacity: 0;
  transition: opacity .25s ease;
}
html.glass-hd.liquid-refract body .login-form-panel.liquid.liquid-glow.liquid-glow-active::before {
  opacity: 1;
}

/* ------------------------------------------------------------
   3. THE MOTION. feTurbulence's <animate> (js/liquid.js) is the
      only thing that moves on its own; this is its opt-out at the
      element level, matching glass.css's own accessibility gates
      one-for-one so a surface never contradicts the tier it is
      layered on top of.
   ------------------------------------------------------------ */
@media (prefers-reduced-motion: reduce) {
  html.glass-hd.liquid-refract body .login-form-panel.liquid.liquid-glow::before {
    transition: none;
  }
}

/* ------------------------------------------------------------
   4. THE ESCAPE HATCH. js/liquid.js already refuses to add
      `.liquid-refract` under any of these signals (belt), and
      glass.css's own device-tier detection (js/glassLite.js)
      already drops `.glass-hd` to `.glass-lite` the moment
      `prefers-reduced-transparency: reduce` fires, live, via its
      own matchMedia listener -- so 2b/2c already stop applying
      through the tier class alone. This block is the suspenders:
      if a stale `.liquid-refract` class ever survives a tier
      change (a listener that did not fire yet, a manual class
      edit in devtools), the surface still folds back to the safe
      2a look rather than trusting the class was kept in sync.
   ------------------------------------------------------------ */
@media (prefers-reduced-transparency: reduce), (prefers-contrast: more), (forced-colors: active) {
  html body :is(.edash-header, .edash-sidebar, .hd-profile-menu,
                .login-form-panel, .st-tabs, .ap-modal, .pd-report-modal,
                .pd-env-settings-modal, .lg-modal, .eb-sheet).liquid,
  html body [id$="Toast"].liquid {
    backdrop-filter: none !important;
    -webkit-backdrop-filter: none !important;
  }
  html body .login-form-panel.liquid.liquid-glow::before {
    display: none;
  }
}
