/* The portal's cascade layer contract, and nothing else - no rules live here.
 *
 * THIS FILE IS LINKED NOWHERE. It is the canonical source of the two statements below and the place
 * their rationale is written down, but what actually reaches the browser is the copy in
 * Views/Shared/_LayerContract.cshtml, rendered INLINE and first in <head> by all four entry points.
 * Keep the two in sync (see _Docs/css-layers.md, which lists all five copies).
 *
 * WHY INLINE RATHER THAN A <link> ON THIS FILE. Layer order is decided by where a name is first
 * mentioned, so the contract has to be parsed before anything else that names a layer. An external
 * <link>, even render-blocking and first in the markup, CAN LOSE that race to an inline <style>
 * BELOW it that declares layers of its own: the inline sheet parses synchronously, the external one
 * does not, and which one wins tracks how fast the sheet arrives (measured: cold or no-store, the
 * inline block wins; warm cache, the link does). Since all 147 of the views' inline blocks now
 * declare `project`, that race was real, and an external contract would lose it on every cold load.
 * An inline <style> cannot lose it at all - that is the whole reason for the partial.
 *
 * THE VIEWS' INLINE BLOCKS NOW DECLARE A LAYER. All 147 of them carry @layer project, because
 * leaving them unlayered made every one of them outrank the whole of wwwroot/css (measured: 219
 * changed winners on one page). So the precondition this file used to rely on - "no inline block
 * declares layers" - is gone, deliberately.
 *
 * What keeps the order right anyway: those blocks name exactly one layer, `project`, which this
 * file already declares seventh. A layer named a second time is not reordered - order is fixed by
 * where a name is FIRST declared - so an inline block winning the race can only re-declare a name
 * this contract already placed. It cannot move `project`, and it cannot introduce a name that
 * would sort ahead of `vendor`. The guard in check-css-links.ps1 is what keeps that true: it
 * rejects any other layer name in a block, `@layer modes` included.
 *
 * Details and the measurement are in _Docs/app-css-bundle.md and _Docs/css-important-audit.md.
 *
 * For normal declarations the LAST layer wins; for !important the FIRST one does, and layer order is
 * consulted before specificity. Unlayered CSS is the implicit final layer - strongest for normal,
 * weakest for important. Our own CSS is no longer there: both the stylesheets (through
 * `@import ... layer(...)` in the three entries) and the views' inline <style> blocks sit in layers.
 *
 * WHAT IS IN EACH LAYER TODAY:
 *   root    - eRoot/eRoot.css, eCSSCore/profile/eunify.tokens.css. Nothing but token declarations:
 *             387 declarations of 164 distinct custom properties, over `:root`, 16
 *             [data-accent="…"] selectors and `:root, [data-accent]` in the first file and
 *             `.eCSSCore` in the second, plus `color-scheme` and one `transition`. Nothing else of
 *             ours declares any of those 164 names - not one of the other stylesheets, not one of
 *             the 147 inline blocks - and the only !important here (--surface-secondary) is the
 *             sole declaration of that property in the codebase. The one redeclaration anywhere is
 *             bootstrap's own --bs-secondary-color, and bootstrap sits in `vendor`, which precedes
 *             `root` and `project` alike, so the move cannot change that relationship either.
 *             Nothing for the layer boundary to reorder. That, not import position, is why this one
 *             is safe.
 *   core      - eCSSCore/core/*: eLayout.css, eGrid.css, eForm.css - the kernel, synced 1:1 from
 *               upstream css_core; edits belong in extensions/, see eCSSCore/SYNC.md. Plus site.css,
 *               which is largely bare-tag base styling (html, body, h1..h6) and belongs under the
 *               components rather than over them.
 *   overrides - eCSSCore/extensions/*: eForm.eunify.css, eGrid.eunify.css. Our additions on top of
 *               the kernel, so they must sort AFTER it - which is why the two names are adjacent and
 *               why the split cannot be done by halves.
 *   project   - eUI, eIcon, eFilter, eModal, Global/*, Pages/*, AND the views' 147 inline blocks, in
 *               one layer so that specificity still decides between them.
 *   controls  - eControls/*: 41 files in the authorized zone, 10 in the anonymous one, 31 in Pages.
 *               Declared AFTER `project`, so for normal declarations a control beats both the other
 *               stylesheets and the views' inline blocks regardless of specificity; for !important
 *               the order inverts and `project` wins.
 *
 * THREE NAMES CARRY NO RULES. `reset` is empty because eCSSCore/core/eBaseReset.css is not linked -
 * the portal already ships the Bootstrap reboot. `modes` is empty BY DECISION: it was meant to hold
 * the views' inline blocks, and being declared last it outranks `project` for normal declarations
 * unconditionally - exactly as being unlayered does - so every inline block would have beaten every
 * stylesheet of ours regardless of specificity. Measured: `modes` 219 changed winners on one page,
 * `project` zero. See _Docs/css-important-audit.md. (`escape` holds no rules either, but that is a
 * file kept deliberately empty, not an unfilled name - see below.)
 *
 * WHAT THE SPLIT CHANGED IN PRACTICE, measured in a browser against the pre-split rendering. Two
 * examples worth knowing, because they show the mechanics better than any description:
 *   1. Views/PortalMenu/_PortalMenu3.cshtml:1162
 *      `.eBar .menu-item--active .k-menu-link-text i {display:block}` (0,3,1) and
 *      eControls/eBar.css:86 `.eControls .eBar .k-menu-link-text i {display:none}` (0,3,1) carry the
 *      same specificity. The inline block used to win on document order; the control wins now,
 *      because `controls` is declared after `project`.
 *   2. Global/eFontTitle.css:1 `h1..h6 {font-weight: var(--font-weight-bold)}` (900) sits in
 *      `project` and outranks eCSSCore/core/eForm.css `.eCSSCore .--eTitle > h4` and
 *      extensions/eForm.eunify.css `.priority__title` (600) in `core`/`overrides` - a bare-tag
 *      selector beating a class, purely on layer order.
 *
 * The rule to carry away: inside `controls` a control outranks both the other stylesheets and the
 * views' inline blocks at any specificity, and the only way to override it from a view is
 * !important (which inverts the layer order and hands `project` the win). A bare-tag rule in a later
 * layer outranks the component layers just as unconditionally.
 *
 * WHAT SPLITTING COSTS IN GENERAL, because the next person will want to move something too. Layer
 * order is consulted BEFORE specificity, so splitting CANCELS SPECIFICITY between the pieces: a rule
 * that won by being more specific loses the moment it and its opponent sit in different layers.
 *
 * THREE THINGS TO KNOW BEFORE MOVING ANYTHING ELSE, each learned by getting it wrong:
 *   1. Count !important per DECLARATION, not per file. For important declarations the layer order
 *      inverts, so a view's `!important` does still beat a later layer - but a block that contains
 *      some !important rules also contains normal ones, and those flip. Dismissing _PortalMenu3.cshtml
 *      as "all !important" is exactly how the vanishing menu icon above went unnoticed: the rule one
 *      line ABOVE it is !important, the broken one is not.
 *   2. Compare selectors where one side is a BARE TAG. A matcher keyed on the trailing class never
 *      generates the pair `.priority__title` vs `h4`, so a whole class of conflicts stays invisible -
 *      and `site.css` / `Global/*` are made of exactly those selectors.
 *   3. A clean getComputedStyle diff proves nothing on a page that lacks the disputed markup, and a
 *      changed winner whose two sides declare the SAME value is invisible to it entirely. Compare
 *      selectors first, then confirm in a browser, on markup copied from a real view.
 *
 * The split also exposed a real bug that had been masked: eControls.css declared
 * `margin-bottom: var(--eLabelMarginB, --spacing-md)`, a fallback written without an inner var(), so
 * with the variable unset the declaration was invalid at computed-value time and the label got 0.
 * While eControls and eForm.css shared a layer, the kernel's more specific rule won inside
 * `.--eProperty` and hid it; with eControls in `controls` it would have collapsed label spacing
 * across 181 views. Fixed to var(--spacing-sm), which is what the kernel's own chain resolves to.
 *
 * THE MEASUREMENT THAT DECIDES A SPLIT IS NOT "does a page still render". A changed winner whose two
 * candidates carry the same value is invisible to getComputedStyle, so a clean diff on a page that
 * does not contain the disputed markup proves nothing. The eForm/eControls case above was found by
 * comparing SELECTORS - same subject, different specificity, same property - and only then confirmed
 * in a browser. Do that before moving anything else out of `project`.
 *
 * The empty names above are a deliberate divergence from the appLegaWEB reference; the details
 * are in _Docs/app-css-bundle.md, which also explains why this file is kept out of the CSS bundle.
 */
@layer escape, reset, vendor, root, core, overrides, project, controls, modes;

/* Sub-layers of `vendor`, declared in the order the libraries load today: bootstrap and Kendo from
 * _StylesVendor.cshtml, the FontAwesome subset next, GridStack from the body of the dashboard views.
 * `vendor.fullcalendar` is the odd one out and is listed last DELIBERATELY: the library injects its
 * sheet from JS into the TOP of <head>, so it does not load in that position at all, and today it is
 * not in the layer either - the name is reserved for wwwroot/js/vendor/fullcalendar-layer.js, which
 * is written but not wired up (see _Docs/css-runtime-injections.md). Last is where it belongs if it
 * is ever switched on: weakest of the vendor sheets for normal declarations, strongest for important.
 * Keeping this identical to the current load order is what makes the file a no-op rather than a
 * reshuffle. Every sub-layer must be listed: an undeclared one sorts after the declared ones, which
 * for normal declarations puts it above the rest of the vendor CSS and for !important makes it the
 * weakest of them - either way not where it belongs. Names are set by -LayerName in
 * eUnifyPortal.csproj and by the default in build-fa-subsets.ps1; changing one without the other
 * silently reorders the cascade.
 */
@layer vendor.bootstrap, vendor.kendo, vendor.fontawesome, vendor.gridstack, vendor.fullcalendar;
