/* LifePilotOS Console -- token-binding CSS for the Elementor console template (FR-D131).
   Elementor core icon/atomic widgets bake color as a literal and strip var() (DECISION_LOG
   DCS-020/DCS-021). Plugin-native fix: re-bind the affected widgets to --lpos-* here, same
   pattern DCS-021 proved for the dashboard (BrandTokens::emit_active_state()). 100% token-
   referenced -- zero literal hex/rgb values in this file.
   Scoped to the console template wrappers (`.elementor-312` = New Console,
   `.elementor-821` = Operator Default Console blueprint), so it only affects the console
   surfaces -- never bleeds into other Elementor-built pages on the subsite. */

/* ---- Punch-list item A: CSS-only fallback token block ----
   BrandTokens::emit() only prints the tenant's resolved --lpos-* variables into <head> when
   a tenant AND an active brand pack both resolve for the request (BrandTokens::resolve_tenant_id()
   returns '' for an anonymous visitor with no pinned domain, for example) -- when it can't
   resolve either, it returns early and prints nothing. Every rule below this block depends on
   these variables being defined, so without this fallback the console would render completely
   unstyled on any page load where the emitter has nothing to print.
   Every value below is copied verbatim from the same default the corresponding
   ConsoleRenderer::brand_theme() `self::safe_*(..., $fallback)` call uses (includes the
   punch-list item C/G additions), so this block and brand_theme() can never silently drift
   out of the same defaults. `:root` tokens emitted by BrandTokens::emit() cascade at a higher
   specificity/later source order than this class selector, so a resolved tenant's real brand
   still overrides these -- this is a fallback floor, not a ceiling.
   NOTE: this fallback block is deliberately NOT scoped to .elementor-821. The tenant's real
   tokens are emitted on :root by BrandTokens::emit(); a wrapper-scoped fallback declaration
   here would win over that inherited :root value on the 821 subtree (a direct declaration on
   the element beats an inherited one), forcing 821 into the light fallback theme. 821 instead
   inherits the real :root tokens. (312 keeps its wrapper fallback because the emit also scopes
   real tokens to .elementor-312.) See DCS-043. */
/* App-default floor for EVERY surface (blueprint pages included): :where(:root) has zero
   specificity, so BrandTokens::emit()'s real :root block (tenant tier) always wins over it
   regardless of print order, while pages with no resolved tenant get full App defaults. */
/* ADVERSARIAL REVIEW 2026-08-01 fix: .elementor-312 was removed from this selector -- a direct
   declaration on the wrapper SHADOWS the tenant's inherited :root brand tokens for every
   descendant (custom-property resolution prefers the nearest declaration, specificity aside),
   so tenants saw App defaults instead of their brand on the flagship console. BrandTokens only
   ever emits :root, so the floor must live at zero-specificity :root scope ONLY. */
:where(:root) {
  /* ---- CYAN_HUD_APP_STYLE_TOKENS_2026-08-01: Transparent Cyan & Blue, App-default tier.
     Existing --lpos-* consumer names are kept (zero breakage); VALUES are remapped onto the
     sheet's App-tier palette. Net-new concepts (no prior name) are added as additive tokens
     below the legacy block. See DCS-bp / HUD_LAYOUT_METRICS_AND_AUDIT_2026-08-01 for the
     layout-token half of this same pass. ---- */
  --lpos-bg: #0A0E17;              /* sheet: bg-base */
  --lpos-panel: #0D111C;           /* sheet: bg-elevated */
  --lpos-panel-hover: color-mix(in srgb, var(--lpos-accent) 10%, transparent); /* JD 2026-08-04 TOKEN-DRIVEN: derive from --lpos-accent (was hardcoded cyan), so it follows the tenant accent */
  --lpos-overlay: #10151f;         /* deeper hover/overlay tier between bg-elevated and pure black; sheet has no explicit 3rd surface tier -- judgment call, stays in-family */
  --lpos-ink: #EAF2FB;             /* sheet: text-primary (headings + body -- cyan never on text) */
  --lpos-muted: #A8B2C7;           /* sheet: text-secondary */
  --lpos-ink-disabled: #6C7A93;    /* sheet: text-tertiary (deliberately sub-AA: disabled) */
  --lpos-ink-inverted: #0A0E17;    /* text-on-accent-fill: dark-on-cyan reads correctly at the sheet's 11:1 accent contrast */
  --lpos-accent: #00D4FF;          /* sheet: accent (11.0:1 on bg-base = AAA) */
  --lpos-accent-2: #4FC3F7;        /* sheet: accent-secondary */
  --lpos-accent-3: #3A6EA5;        /* sheet defines only 2 accents; #3A6EA5 synthesized in-family (muted azure) for legacy 3rd-accent consumers (e.g. chart-3) -- judgment call, not in the sheet verbatim */
  --lpos-border-tint: var(--lpos-accent-3, var(--lpos-accent)); /* JD 2026-08-06: ALL border color-mix bases run through this -- the LIGHTER brand accent (Biolimitless pack maps color.accent #AA81FF -> --lpos-accent-3), falling back to the primary accent */
  --lpos-good: #2ED573;            /* sheet reserves warn/danger only; success color kept but re-picked for AA legibility on the new dark navy base -- judgment call */
  --lpos-warn: #FFB020;            /* sheet: warning (reserved) */
  --lpos-bad: #FF5470;             /* sheet: danger (reserved) */
  --lpos-info: #4FC3F7;            /* mapped to accent-secondary */
  --lpos-font-ui: 'Inter', ui-sans-serif, system-ui, sans-serif;      /* sheet: font-body (UI chrome reads as body copy). Stack only -- no @font-face/enqueue added. */
  --lpos-font-display: 'Space Grotesk', ui-sans-serif, system-ui, sans-serif; /* sheet: font-display */
  --lpos-font-body: 'Inter', ui-sans-serif, system-ui, sans-serif;    /* sheet: font-body */
  --lpos-gap: 12px;                /* JD 2026-08-06: thinner global spacing */
  --lpos-pad: 20px;
  --lpos-panel-pad: 12px;          /* JD 2026-08-06: thinner global padding (was 16px) */
  --lpos-subpanel-pad: 6px;        /* JD 2026-08-06: thinner sub-panel pad (was 8px) */
  /* HUD audit: promote the magic number used by the top/bottom console rows to a named token.
     2026-08-01 THIRD retune (live-verified too tall every time so far, incl. the 70px "two layer
     -> one layer" pass): JD wants the row thinner still -- 46px control + 4px breathing above/below
     (--lpos-space-xs, not --lpos-subpanel-pad) = 54px, ONE inset layer, nothing else stacked on it.
     Every chrome-row cell's own vertical inset (below) drops from space-sm(8) to space-xs(4) to
     match; every top/bottom-row component that used to rely on a component-level sub-panel inset
     ALREADY renders that inset at 0 in this file (menu/logo/topright+botright clusters/botleft
     switcher/botcenter bar all override .lpos-c-subpanel's padding to 0 for chrome-row use, see the
     cell-padding block below), so dropping the cell's own inset is the only change needed -- no
     second layer to reconcile away this time. */
  --lpos-titlebar-h: calc(var(--lpos-control-size, 46px) + 2*var(--lpos-space-sm, 8px) + 2*var(--lpos-border-width, 1px)); /* = 64px: control + space-sm breathing + cell borders (JD: 56px read too tight; borders stay in the math per the earlier overflow fix) */
  /* logo image height (2026-08-01 SEVENTH retune, JD review loop): 62px full-interior read "way too
     big" once the padding-free lockup asset landed (the asset rework, not the box, was the real size
     lever all along) -- back to control-size 46px with the STANDARD space-sm cell inset restored
     (the zero-inset exception is gone). Marks now render ~43px tall, larger than any earlier pass
     because the asset no longer wastes 37% of its height on dead padding. */
  --lpos-logo-h: var(--lpos-control-size, 46px); /* = 46px */
  --lpos-space-xs: 4px;
  --lpos-space-sm: 8px;
  --lpos-space-md: 12px;
  /* RADIUS RECONCILIATION (2026-08-04, JD): reconciled against the canonical wireframe design
     library (C:/Users/front/CommandCenter/Console/_System/handoffs/CLAUDE_DESIGN_LIBRARY_
     WIREFRAMES_2026-07-22/DESIGN_HANDOFF/design-system-source/console-dashboard.css), the
     library's own scale: --console-radius:16px / --console-radius-inner:12px /
     --console-radius-control:8px / --console-radius-pill:999px. panel 10px->16px to match
     (--lpos-radius-lg already WAS 16px, defined-but-unused, below -- panel now equals it, by
     design: one canonical "outer panel" number, not two names for the same value); control(8px)
     and pill(999px) were ALREADY exact matches, unchanged. --lpos-radius-inner is NEW (added for
     parity with the library's 4-step scale) -- not yet migrated onto every "component inside
     panel" call site (a broader follow-up; radius-control still fills that role at most of
     today's call sites and is not being changed under this pass). */
  --lpos-radius-panel: 10px;       /* JD 2026-08-06: SHARPER global radius (was 16px) -- still rounded, tighter corner */
  --lpos-radius-control: 8px;
  --lpos-radius-sm: 4px;           /* sheet: radius-sm (already matched) */
  --lpos-radius-pill: 999px;       /* TOKEN-LAW fix 2026-08-03: pill/badge radius -- was referenced via fallback only (archive-card reward/chip), never declared */
  --lpos-glass-1: rgba(255,255,255,0.035);
  --lpos-glass-2: rgba(255,255,255,0.055);
  --lpos-glass-3: rgba(255,255,255,0.085);
  --lpos-glass-rule: rgba(255,255,255,0.10);
  --lpos-glass-spec: rgba(255,255,255,0.10);
  --lpos-glass-panel: linear-gradient(180deg, rgba(30,42,66,0.34), rgba(16,24,40,0.45)); /* JD 2026-08-06 FULL GLASSMORPHISM rev 2: lighter glass -- the bg video's motion reads through every panel layer */
  --lpos-asset-alpha: 0.9; /* JD 2026-08-06 LAYERED TRANSPARENCY: assets are the LEAST transparent layer but still let the ambient motion ghost through */
  /* TRANSLUCENCY RECONCILIATION (2026-08-04, JD: "none of the panels...have any degree of
     opacity"): the design library's own .console-panel is rgba(surface,0.238) over
     blur(10px) saturate(1.15) -- a genuinely see-through chrome tier, nowhere near this file's
     55-60%+ fill. Per-tenant brand packs (BrandPackRepository, data-fleet-owned, out of this
     file's edit scope) resolve their OWN --lpos-glass-panel at :root with real specificity and
     always win over this zero-specificity floor, so lowering --lpos-glass-panel's OWN value here
     would not actually change what a branded tenant (e.g. Biolimitless) renders. Instead this
     derives a NEW chrome-tier token as a fixed proportion of WHATEVER --lpos-glass-panel resolves
     to for the active tenant -- color-mix scales the alpha down uniformly, so App-default's 60%
     lands at ~24% (line up almost exactly with the library's 23.8%) and a branded tenant's own
     (typically similar 55-68%) value lands in the same ballpark -- without touching the per-tenant
     token itself. Applied to the general/chrome surfaces only (.lpos-cell, .lpos-c-subpanel);
     text-dense "focused content" surfaces (the midcenter editorial-copy cell, .lpos-search) keep
     consuming --lpos-glass-panel directly (unchanged, more opaque) so the DNA background video
     reads through the chrome without hurting legibility where it matters. */
  --lpos-glass-panel-chrome: color-mix(in srgb, var(--lpos-glass-panel) 40%, transparent);
  --lpos-glass-video: color-mix(in srgb, var(--lpos-bg) 22%, transparent);
  /* GLASSMORPHISM LAW (2026-08-04, JD): "no solid opaque fills anywhere -- this includes the
     active/featured/selected BUTTON state and the PROGRESS BAR fill". These three accent-tinted
     GLASS tokens replace every surface below that was rendering a flat var(--lpos-accent) fill
     (progress/meter bars, primary/featured buttons, pressed/active icon-button state). color-mix
     keeps them tenant-safe -- same technique --lpos-glass-panel-chrome above already uses, so
     each tracks whatever --lpos-accent resolves to per tenant (e.g. BioLimitless's violet)
     instead of a hardcoded hex. Three tiers because a translucent surface still needs to carry
     visual WEIGHT (a soft touch for a mere "selected" toggle vs. a stronger wash for the one
     PRIMARY button on a pane) -- same reasoning --lpos-glass-1/2/3 already tier the neutral-white
     glass above. */
  --lpos-accent-glass-soft: color-mix(in srgb, var(--lpos-accent) 18%, transparent);   /* selected/active TINT -- toggle .is-active, light highlights */
  --lpos-accent-glass: color-mix(in srgb, var(--lpos-accent) 32%, transparent);        /* brand-tint glass FILL -- progress/meter bars, replaces a flat accent fill */
  --lpos-accent-glass-strong: color-mix(in srgb, var(--lpos-accent) 46%, transparent); /* featured/PRIMARY button glass -- Buy Now, Next action, pressed icon-btn: carries the "primary" weight a solid fill used to, while staying translucent */
  /* FOUR LEFTOVER SETTINGS DELETED 2026-08-10 (JD's call). Each was a saved value with no
     consumer anywhere, left behind when the design that used it changed:
       --lpos-card-bg-alpha     card-photo dimming; readability comes from the scrim now
       --lpos-logo-accent-color a second colour for the logo mark; it only aliased --lpos-accent
       --lpos-sidecol-w         a width for a side column the layout no longer has (with its two
                                inputs --lpos-sidecol-chrome and --lpos-doc-aspect, dead with it)
       --lpos-shadow-1 / -glow  shadow strength and glow; the zero-shadow law means neither can
                                ever paint. Their Brand Styling fields went on 2026-08-10 and
                                ConsoleRenderer no longer emits them.
     --lpos-shadow-2 and --lpos-glass-spec are NOT dead (3 live consumers) and stay. */
  --lpos-shadow-2: 0 4px 20px rgba(0,0,0,.50), inset 0 1px 0 var(--lpos-glass-spec);
  --lpos-accent-soft: color-mix(in srgb, var(--lpos-accent) 10%, transparent);   /* JD 2026-08-04 TOKEN-DRIVEN: derive from --lpos-accent (was hardcoded cyan) */
  --lpos-accent-glow-sm: 0 0 12px color-mix(in srgb, var(--lpos-accent) 55%, transparent); /* TOKEN-DRIVEN glow-sm */
  --lpos-accent-glow-lg: 0 0 32px color-mix(in srgb, var(--lpos-accent) 35%, transparent); /* TOKEN-DRIVEN glow-lg */
  --lpos-focus-ring: 0 0 0 2px rgba(0,212,255,.9), 0 0 12px rgba(0,212,255,.6); /* sheet: focus-ring -- NEW */
  --lpos-grid-line: rgba(0,212,255,.035);     /* sheet: grid-overlay line color -- NEW, feeds .lpos-blueprint--console::before */
  --lpos-heading-color: var(--lpos-ink);      /* sheet: headings WHITE, never cyan -- alias for clarity, same value the h1/h2 rules already resolve to */
  --lpos-tracking-label: 0.08em;   /* sheet: eyebrow/label tracking -- defined for future use; no eyebrow/label class exists in this console yet */
  --lpos-tracking-heading: -0.01em;
  --lpos-logo-word-color: var(--lpos-ink);
  --lpos-blur-sm: blur(14px) saturate(140%);
  --lpos-blur-md: blur(16px) saturate(140%); /* JD 2026-08-06 FULL GLASSMORPHISM: back to the deep frosted tier (was reconciled down to 10px/115% when panels sat on a flat bg -- with the ambient DNA video behind, the stronger frost is what makes the glass read) */
  --lpos-blur-lg: blur(32px) saturate(160%);
  --lpos-control-size: 46px;
  /* RESPONSIVE CONTROL LADDER (2026-08-10). The small-screen tiers were shipped with raw pixels and
     three invented token names that had no definitions -- a token-law break. The ladder is DERIVED
     from the base control size so one edit still moves every tier, and the rail lane is derived
     from the control it must hold plus the panel's own inset. No standalone magic numbers. */
  --lpos-control-size-md: calc(var(--lpos-control-size, 46px) - 6px);  /* tablet control */
  --lpos-control-size-sm: calc(var(--lpos-control-size, 46px) - 10px); /* phone control */
  /* the ladder's missing BASE rung (added 2026-08-10): -md and -sm existed but the full-size rail
     width was only ever written out longhand at its call sites. */
  --lpos-rail-w: calc(var(--lpos-control-size, 46px) + 2*var(--lpos-subpanel-pad, 6px));
  --lpos-rail-w-md: calc(var(--lpos-control-size-md) + 2*var(--lpos-subpanel-pad, 6px));
  --lpos-rail-w-sm: calc(var(--lpos-control-size-sm) + 2*var(--lpos-subpanel-pad, 6px));
  --lpos-icon-size-md: calc(var(--lpos-icon-size, 26px) - 4px);
  --lpos-icon-size-phone: calc(var(--lpos-icon-size, 26px) - 8px);
  --lpos-media-floor-sm: calc(2.5 * var(--lpos-control-size, 46px)); /* stacked-lane media never collapses below this */
  --lpos-media-cap-sm: 26dvh;      /* stacked-lane media ceiling, viewport-relative by design */
  --lpos-icon-size: 26px;          /* HUD audit: 26/46 = 56.5%, in the 50-60% norm; kills the 30px/22px fallback drift */
  --lpos-icon-size-xs: 20px;       /* TOKEN-PURITY 2026-08-01: icon scale -- search svg, thumb svg */
  --lpos-icon-size-sm: 24px;       /* TOKEN-PURITY 2026-08-01: icon scale -- big-play glyph */
  --lpos-icon-size-lg: 32px;       /* TOKEN-PURITY 2026-08-01: icon scale -- spinner, big-play i */
  --lpos-card-ghost: 56px;         /* archive card ghost-icon zone (2026-08-03 card grid) */
  --lpos-archive-card-min-h: 240px; /* JD 2026-08-04 item 2: cards were too short (rows shared the panel's raw available height with no floor) -- each grid row now holds this minimum so image+text breathe */
  --lpos-tab-icon-size: 28px;
  --lpos-border-width: 1px;
  --lpos-border-width-active: 2px;
  --lpos-control-min-h: 2rem;
  /* TOKEN-PURITY 2026-08-01: border-alpha ladder -- collapses the color-mix(in srgb, var(--lpos-accent)
     NN%, transparent) hairline sites onto 4 named steps. Mapping: 30%->-1, 35%/40%/45%->-2 (40%),
     50%/55%->-3 (55%), 65%->-4. Visual deltas of <=5% are accepted per the consolidation intent. */
  --lpos-border-alpha-1: 30%;
  --lpos-border-alpha-2: 40%;
  --lpos-border-alpha-3: 55%;
  --lpos-border-alpha-4: 65%;
  --lpos-title-size: 1.5rem;             /* primary title (centerfeature -- the middle-center focal panel) */
  --lpos-title-size-secondary: 1.1rem;   /* JD: left/right title panels are secondary content, ~73% of primary */
  --lpos-subtitle-size: 1rem;            /* primary subtitle (centerfeature) */
  --lpos-subtitle-size-secondary: .75rem; /* secondary subtitle, scaled with the secondary title */
  --lpos-subtitle-margin: .15rem 0 0;    /* TOKEN-PURITY 2026-08-01: promoted from the 6 repeated inline margins */
  --lpos-text-2xs: 12px;                 /* TOKEN-PURITY 2026-08-01: text scale */
  --lpos-text-xs: 13px;
  --lpos-text-sm: 14px;
  --lpos-text-md: 17px;
  --lpos-text-lg: 20px;                  /* TOKEN-LAW fix 2026-08-03: text scale -- was referenced via fallback only (archive-grid__title h2), never declared */
  --lpos-chart-1: #166466;
  --lpos-chart-2: #2f4f66;
  --lpos-chart-3: #7c5f27;
  --lpos-chart-4: #236a35;
  --lpos-chart-5: #245f8f;
  --lpos-chart-6: #a06100;
  --lpos-chart-7: #9f1d1d;
  --lpos-chart-8: #5f6b7a;
  /* ---- off-canvas drawer engine (hamburger + top-icon drawers) -- NEW, additive ---- */
  --lpos-drawer-w: 360px;
  /* TOKEN-PURITY AUDIT 2026-08-01 (JD full-console consistency pass): named tokens for the last
     bare literals in the media stylesheet -- bespoke component sizes and non-interaction cadences
     that have no home on the spacing/duration ladders get their own names instead of literals. */
  --lpos-page-bg: #fff;                    /* flipbook page paper */
  --lpos-video-bg: #000;                   /* video letterbox stage */
  --lpos-scrim-heavy: rgba(0,0,0,.62);     /* in-player bar gradient top stop (heavier than scrim-bg) */
  --lpos-spin-track: rgba(255,255,255,.18);/* buffering spinner ring track */
  --lpos-duration-spin: .8s;               /* buffering spinner revolution */
  --lpos-duration-pulse: 2.8s;             /* paused big-play gentle pulse */
  --lpos-volslide-w: 82px;                 /* collapsible volume slider open width */
  --lpos-flipthumb-h: 84px;                /* flipbook thumbnail strip image height */
  --lpos-thumb-h: 56px;                    /* botleft/midleft switcher tile height cap (JD 2026-08-01: taller than a 46px control -- tiles read as media, not buttons) */
  /* FOCAL-POINT IMAGE SYSTEM (task #14, JD APPROVED 2026-08-05): every cover-cropped image
     component reads its crop anchor from these two tokens -- default dead center; a per-image
     inline `style="--lpos-focal-x:..%;--lpos-focal-y:..%"` (emitted from the asset's own slot
     config, never fabricated) re-anchors the crop for that one image. PANEL RATIO TOKENS: the
     two canonical image-panel ratios declared here explicitly (were fallback-only). */
  --lpos-focal-x: 50%;
  --lpos-focal-y: 50%;
  --lpos-thumb-ratio: 1/1;                 /* canonical SQUARE shop-thumb ratio (EXACT_SPEC section 7) */
  --lpos-media-switch-ratio: 16/9;         /* canonical LANDSCAPE media-panel ratio */
  /* (The LIQUID SIDE COLUMNS trio -- --lpos-sidecol-w, --lpos-sidecol-chrome, --lpos-doc-aspect --
     was deleted 2026-08-10 with the other leftover settings. It sized a side column whose width is
     no longer computed that way; nothing had read any of the three in some time.) */
  --lpos-play-btn-size: 80px;              /* big-play overlay circle (JD-tuned 78-80) */
  --lpos-duration-base: 220ms;
  --lpos-duration-fast: 120ms;    /* TOKEN-PURITY 2026-08-01: hover/press micro-interactions (.12s/.08s sites) */
  --lpos-duration-reveal: 180ms;  /* TOKEN-PURITY 2026-08-01: overlay reveal transitions (.18s/.2s/.22s sites) */
  --lpos-ease-tech: cubic-bezier(0.16, 1, 0.3, 1);
  --lpos-z-scrim: 8990;
  --lpos-z-drawer: 9000;
  /* the load screen must clear the console SHELL, not just the drawer tier: the shell is a
     position:fixed full-viewport layer, so an overlay at the drawer z-index paints underneath
     it and the loading state is invisible (caught in verify 2026-08-10). */
  --lpos-z-loadscreen: 100000;
  --lpos-scrim-bg: rgba(0, 0, 0, 0.45);
  /* TOKEN-LAW PASS 2026-08-10 (full-app law review): these seven were referenced through
     `var(--x, literal)` fallbacks at real call sites but were never declared anywhere, so the
     literal was what actually painted -- a hardcoded value wearing a token's name. Declared here
     at the value each call site was already using, so the canonical block is genuinely the single
     source of truth for them. `--lpos-radius-full` was NOT added: it was a name-drift duplicate of
     the already-canonical `--lpos-radius-pill` and its 3 call sites were migrated instead. */
  --lpos-radius-lg: 16px;          /* calendar day/agenda tiles (components/calendar-grid.css) */
  --lpos-radius-md: 8px;           /* dashboard listing controls (dashboard-layout.css) */
  --lpos-bgvideo-blur: 3px;        /* ambient background-video defocus */
  --lpos-card-media-ratio: 16/9;   /* archive-card media well */
  --lpos-cta-media-ratio: 4/3;     /* focus-panel (buy box) media well */
  --lpos-duration-loading: 1.4s;   /* skeleton/loading sweep cycle */
  --lpos-m8card-h: 44vh;           /* magick8 card preferred height (inside its clamp) */
  /* BRAND FLOOR (same pass): BrandTokens emits these two only when a tenant AND a brand pack both
     resolve. Every other structural token has an App default here; without one, anonymous/no-tenant
     pages silently fell back to PortalHomeRenderer's inline literals. These are the App defaults. */
  --lpos-color-primary: #7c5cf6;
  --lpos-color-void: #0a0612;
  /* FALLBACK-DRIFT PASS 2026-08-10. 400 `var(--x, literal)` fallbacks across 13 files disagreed with
     the declarations above and with each other -- `--lpos-gap` said 16px at 77 sites and 12px at 40
     (declared: 12px), `--lpos-radius-panel` said 16px at 27 and 10px at 21 (declared: 10px),
     `--lpos-accent-soft` fell back to a literal CYAN at 13 sites (declared: an accent color-mix, so
     the literal would have painted the wrong hue for every non-cyan tenant). None of it rendered:
     every one of those tokens IS declared here, so the fallback never fires. It made the files lie
     about their own values, which is how the 2026-08-06 "thinner spacing / sharper radius" retune
     ended up half-recorded. Every fallback now equals its declaration.
     TWO deliberate exceptions:
       - 8 sites inside PHP strings write `--lpos-font-ui, Inter, ...` UNQUOTED. CSS resolves an
         unquoted family identically; quoting it would terminate the surrounding PHP string.
       - `--lpos-glass-veil` is intentionally NOT declared here. It is emitted per tenant by
         ConsoleRenderer, and its two call sites want different no-tenant behaviour (one no veil,
         one a 22% scrim), so a floor here would silently change one of them. */
}

/* (CONSOLIDATION 2026-08-05, plan Phase 2: the ~459-line .elementor-312/.elementor-821-scoped copy
   of the console rules was DELETED here -- the plugin never emits those legacy Elementor wrappers;
   the .lpos-blueprint mirror below is the single live copy.) */
/* =====================================================================================
   BLUEPRINT-RENDERED CONSOLES (.lpos-blueprint): the same console styling applied under the
   [lpos_blueprint] wrapper, so a console composed on ANY page (e.g. /console-2) inherits the
   full treatment. Auto-mirrored from the .elementor-821/.elementor-312 rules above (the light
   fallback var block is intentionally NOT mirrored -- :root real tokens apply). DCS-bp.
   ===================================================================================== */
/* ---- base text ---- */
.lpos-blueprint,
.lpos-blueprint,
.lpos-blueprint :where(p, span, h1, h2, h3, h4, h5, h6, a, li, div),
.lpos-blueprint :where(p, span, h1, h2, h3, h4, h5, h6, a, li, div) {
  color: var(--lpos-ink);
}

/* ---- muted/secondary text ---- */
.lpos-blueprint .lpos-muted,
.lpos-blueprint .lpos-muted,
.lpos-blueprint :where(small, .elementor-icon-list-text small),
.lpos-blueprint :where(small, .elementor-icon-list-text small) {
  color: var(--lpos-muted);
}

/* ---- icon glyphs: Elementor bakes these as a literal and strips var(), so !important is
   required to win -- the documented DCS-021 mechanism, delivered plugin-native here.
   Muted per operator design; accent stays reserved for active/borders (not glyph fill). ---- */
.lpos-blueprint .elementor-icon,
.lpos-blueprint .elementor-icon i,
.lpos-blueprint .elementor-icon svg,
.lpos-blueprint .elementor-icon,
.lpos-blueprint .elementor-icon i,
.lpos-blueprint .elementor-icon svg {
  color: var(--lpos-muted) !important;
  fill: var(--lpos-muted) !important;
}

/* ---- frosted depth on the region panels (FR-D130 depth tokens). Restrained: translucent
   panel tint + blur-md + shadow-2 (whose inset carries the glass top-highlight). Keeps the
   existing accent hairline border. 100% token-referenced. ---- */
.lpos-blueprint .elementor-element-d39a85b,
.lpos-blueprint .elementor-element-3f4c388,
.lpos-blueprint .elementor-element-cba38cb,
.lpos-blueprint .elementor-element-e999a20,
.lpos-blueprint .elementor-element-bedfc71,
.lpos-blueprint .elementor-element-4ceb058,
.lpos-blueprint .elementor-element-2d45ce8,
.lpos-blueprint .elementor-element-ac086cb,
.lpos-blueprint .elementor-element-b9c1f8c {
  background: var(--lpos-glass-panel) !important; /* JD 2026-08-06: shorthand -- the glass token is a gradient now */
  -webkit-backdrop-filter: var(--lpos-blur-md);
  backdrop-filter: var(--lpos-blur-md);
  
}

/* ---- FR-D132: icon buttons -- top-right 6 + top-left menu -- bigger, dead-centered glyph.
   Size/center/radius only; background + accent hairline stay on the widgets' own atomic
   styles. 100% token-referenced. ---- */
.lpos-blueprint .elementor-element-0ba1f52,
.lpos-blueprint .elementor-element-62beecb,
.lpos-blueprint .elementor-element-eb7a024,
.lpos-blueprint .elementor-element-8d237a6,
.lpos-blueprint .elementor-element-e29315c,
.lpos-blueprint .elementor-element-f581e0c,
.lpos-blueprint .elementor-element-64667df {
  width: var(--lpos-control-size) !important;
  height: var(--lpos-control-size) !important;
  min-width: var(--lpos-control-size);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0 !important;
  border-radius: var(--lpos-radius-control);
}
.lpos-blueprint .elementor-element-0ba1f52 .elementor-icon,
.lpos-blueprint .elementor-element-62beecb .elementor-icon,
.lpos-blueprint .elementor-element-eb7a024 .elementor-icon,
.lpos-blueprint .elementor-element-8d237a6 .elementor-icon,
.lpos-blueprint .elementor-element-e29315c .elementor-icon,
.lpos-blueprint .elementor-element-f581e0c .elementor-icon,
.lpos-blueprint .elementor-element-64667df .elementor-icon {
  font-size: var(--lpos-icon-size) !important;
  line-height: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 100%;
}
.lpos-blueprint .elementor-element-0ba1f52 .elementor-icon i,
.lpos-blueprint .elementor-element-62beecb .elementor-icon i,
.lpos-blueprint .elementor-element-eb7a024 .elementor-icon i,
.lpos-blueprint .elementor-element-8d237a6 .elementor-icon i,
.lpos-blueprint .elementor-element-e29315c .elementor-icon i,
.lpos-blueprint .elementor-element-f581e0c .elementor-icon i,
.lpos-blueprint .elementor-element-64667df .elementor-icon i {
  line-height: 1;
}

/* ---- FR-D132: bottom-right JetTabs controls (b9c1f8c) -- square rounded inline icon
   buttons matching the icon-button treatment above. Token-referenced background + accent
   hairline (color-mix on --lpos-accent, no literal alpha value). ---- */
.lpos-blueprint .elementor-element-b9c1f8c .jet-tabs__control {
  width: var(--lpos-control-size) !important;
  min-width: var(--lpos-control-size);
  height: var(--lpos-control-size) !important;
  padding: 0 !important;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: var(--lpos-radius-control) !important;
  background: var(--lpos-panel) !important;
  border: var(--lpos-border-width) solid color-mix(in srgb, var(--lpos-border-tint,var(--lpos-accent)) var(--lpos-border-alpha-3, 55%), transparent) !important;
}
.lpos-blueprint .elementor-element-b9c1f8c .jet-tabs__control-wrapper {
  display: flex;
  flex-direction: row;
  gap: var(--lpos-gap);
  justify-content: flex-end;
  align-items: center;
  flex-wrap: nowrap;
}
.lpos-blueprint .elementor-element-b9c1f8c .jet-tabs__control i,
.lpos-blueprint .elementor-element-b9c1f8c .jet-tabs__control svg {
  font-size: var(--lpos-tab-icon-size);
  color: var(--lpos-muted) !important;
  fill: var(--lpos-muted) !important;
  line-height: 1;
}
.lpos-blueprint .elementor-element-b9c1f8c .jet-tabs__control.active-tab i,
.lpos-blueprint .elementor-element-b9c1f8c .jet-tabs__control.active-tab svg,
.lpos-blueprint .elementor-element-b9c1f8c .jet-tabs__control-active i,
.lpos-blueprint .elementor-element-b9c1f8c .jet-tabs__control-active svg {
  color: var(--lpos-accent) !important;
  fill: var(--lpos-accent) !important;
}

/* ---- FR-D132: center JetTabs (be630c3) -- labeled tab control + a visible glass
   sub-panel for the stacked content region below the video. ---- */
.lpos-blueprint .elementor-element-be630c3 .jet-tabs__control {
  color: var(--lpos-muted);
  border-radius: var(--lpos-radius-control);
  /* Punch-list item E: was a literal `6px 12px`; now reads the spacing_tokens.sm/md
     leaves (--lpos-space-sm/--lpos-space-md, emitted by brand_theme() per punch-list
     item C) instead of a hardcoded pixel pair. */
  padding: var(--lpos-space-sm) var(--lpos-space-md);
}
.lpos-blueprint .elementor-element-be630c3 .jet-tabs__control.active-tab,
.lpos-blueprint .elementor-element-be630c3 .jet-tabs__control-active {
  color: var(--lpos-ink);
  border-bottom: var(--lpos-border-width-active) solid var(--lpos-accent);
}
.lpos-blueprint .elementor-element-be630c3 .jet-tabs__content-box,
.lpos-blueprint .elementor-element-be630c3 .jet-tabs__content {
  background: var(--lpos-glass-1);
  border-radius: var(--lpos-radius-panel);
}
.lpos-blueprint .elementor-element-2bb9699 {
  color: var(--lpos-ink);
}
.lpos-blueprint .elementor-element-7d6d8cc {
  /* DCS-042: was left as a literal per punch-list item E / DCS-036 precedent (no px-based
     spacing token mapped cleanly to a rem value). Now reads depth_tokens.control.min_height
     via the new --lpos-control-min-h var -- it no longer needs a spacing_tokens leaf since
     it's a control-token sibling of control.size/icon_size/tab_icon_size. */
  min-height: var(--lpos-control-min-h);
}

/* ---- FR-D132: background video (a5d9d91) -- lighter frosted tint than the 48% region
   panels, sitting on Elementor's own background-overlay layer (over the video, under
   content). If a5d9d91 has no background-overlay div rendered, JD needs to enable
   "Background Overlay" on that container in Elementor -- this rule cannot create the
   layer, only style it. ---- */
.lpos-blueprint .elementor-element-a5d9d91 > .elementor-background-overlay {
  background: var(--lpos-glass-video) !important;
  -webkit-backdrop-filter: var(--lpos-blur-sm);
  backdrop-filter: var(--lpos-blur-sm);
}

/* ---- FR-D132 follow-up (punch-list item F): the rule above only frosts the video if
   Elementor's own "Background Overlay" toggle is enabled on a5d9d91 in the editor -- it
   cannot create that layer, only style it (documented gap, DECISION_LOG DCS-035). This
   self-contained ::after pseudo-element frosts the video unconditionally, with no editor
   toggle required: a5d9d91 becomes the positioning context, the pseudo-element sits over
   the video (z-index 1), and the container's direct content child (d131370) is raised
   above the frost (z-index 2) so console content stays legible. Token-driven, no literal
   color/size values. ---- */
.lpos-blueprint .elementor-element-a5d9d91 {
  position: relative;
}
.lpos-blueprint .elementor-element-a5d9d91::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  z-index: 1;
  background: var(--lpos-glass-video);
  -webkit-backdrop-filter: var(--lpos-blur-sm);
  backdrop-filter: var(--lpos-blur-sm);
}
.lpos-blueprint .elementor-element-a5d9d91 > .elementor-element-d131370 {
  position: relative;
  z-index: 2;
}

/* ============================================================================
   Operator Default Console (blueprint 821) -- same token-driven treatment as the
   New Console (312) above, mapped to 821's element IDs. 100% --lpos-* referenced;
   glassmorphism via the same depth tokens (--lpos-glass-panel / -blur-md / -shadow-2
   / -glass-video). Region IDs verified against the live 821 render (DCS-043). ---- */

/* region panels -- frosted glass */
.lpos-blueprint .elementor-element-c83beaa,
.lpos-blueprint .elementor-element-4b6dbb9,
.lpos-blueprint .elementor-element-daf2b68,
.lpos-blueprint .elementor-element-da44d26,
.lpos-blueprint .elementor-element-6639cae,
.lpos-blueprint .elementor-element-4f39396 {
  background: var(--lpos-glass-panel) !important; /* JD 2026-08-06: shorthand -- the glass token is a gradient now */
  -webkit-backdrop-filter: var(--lpos-blur-md);
  backdrop-filter: var(--lpos-blur-md);
  
}

/* icon buttons -- square box, dead-centered glyph */
.lpos-blueprint .elementor-element-16f9434,
.lpos-blueprint .elementor-element-f72569c,
.lpos-blueprint .elementor-element-cf2cad5,
.lpos-blueprint .elementor-element-1213239,
.lpos-blueprint .elementor-element-c5e39cf,
.lpos-blueprint .elementor-element-a7a881e {
  width: var(--lpos-control-size) !important;
  height: var(--lpos-control-size) !important;
  min-width: var(--lpos-control-size);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0 !important;
  border-radius: var(--lpos-radius-control);
}
.lpos-blueprint .elementor-element-16f9434 .elementor-icon,
.lpos-blueprint .elementor-element-f72569c .elementor-icon,
.lpos-blueprint .elementor-element-cf2cad5 .elementor-icon,
.lpos-blueprint .elementor-element-1213239 .elementor-icon,
.lpos-blueprint .elementor-element-c5e39cf .elementor-icon,
.lpos-blueprint .elementor-element-a7a881e .elementor-icon {
  font-size: var(--lpos-icon-size) !important;
  line-height: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 100%;
}

/* background video -- lighter frost than panels (self-contained ::after, mirrors 312 a5d9d91) */
.lpos-blueprint .elementor-element-17ff9be {
  position: relative;
}
.lpos-blueprint .elementor-element-17ff9be::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  z-index: 1;
  background: var(--lpos-glass-video);
  -webkit-backdrop-filter: var(--lpos-blur-sm);
  backdrop-filter: var(--lpos-blur-sm);
}
.lpos-blueprint .elementor-element-17ff9be > .elementor-element-445dbc8 {
  position: relative;
  z-index: 2;
}

/* ---- 821 refinements (DCS-044) ----
   #2 remove the hardcoded off-token bg strip behind the tab-nav controls (was #090e1b);
      the nav now sits on the panel glass. #1 the left tab-nav image thumbnails rendered
      tiny (25x17); size them to fill the control. #4 the top row used an asymmetric width
      split while the columns are a symmetric 24.1/50.1/24.1 grid, so the gridlines didn't
      stack -- align the top row to the column grid (desktop only, so the per-device liquid
      grid on tablet/mobile is left to the template). Token-driven; no literal colors. ---- */
.lpos-blueprint .jet-tabs__control-wrapper {
  background-color: transparent !important;
}
.lpos-blueprint .jet-tabs__control img {
  width: auto !important;
  height: 34px !important;
  max-width: none !important;
  object-fit: contain;
}
@media (min-width: 1025px) {
  .lpos-blueprint .elementor-element-c83beaa { width: 24.108% !important; }
  .lpos-blueprint .elementor-element-4b6dbb9 { width: 50.1% !important; }
  .lpos-blueprint .elementor-element-daf2b68 { width: 24.108% !important; }
}

/* center content tab (template 782): compact title + subtitle sharing one frosted-glass
   panel, and the video in its own frosted-glass panel (DCS-046). Token-driven glass. */
.lpos-blueprint .elementor-element-7d6d8cc h2,
.lpos-blueprint .elementor-element-7d6d8cc h2,
.lpos-blueprint .elementor-element-36a2f1c h2,
.lpos-blueprint .elementor-element-74668a5 h2 {
  font-size: var(--lpos-title-size, 1.5rem) !important;
  line-height: 1.2 !important;
  margin: 0 !important;
}
.lpos-blueprint .elementor-element-7d6d8cc h3,
.lpos-blueprint .elementor-element-7d6d8cc h3,
.lpos-blueprint .elementor-element-36a2f1c h3,
.lpos-blueprint .elementor-element-74668a5 h3 {
  font-size: var(--lpos-subtitle-size, 1rem) !important;
  line-height: 1.3 !important;
  margin: var(--lpos-subtitle-margin, .15rem 0 0) !important;
  color: var(--lpos-muted) !important;
  font-weight: 500 !important;
}
.lpos-blueprint .elementor-element-7d6d8cc,
.lpos-blueprint .elementor-element-7d6d8cc,
.lpos-blueprint .elementor-element-36a2f1c,
.lpos-blueprint .elementor-element-74668a5,
.lpos-blueprint .elementor-element-dbb1a45,
.lpos-blueprint .elementor-element-dbb1a45 {
  background: var(--lpos-glass-panel) !important;
  -webkit-backdrop-filter: var(--lpos-blur-md);
  backdrop-filter: var(--lpos-blur-md);
  
  border: var(--lpos-border-width) solid color-mix(in srgb, var(--lpos-border-tint,var(--lpos-accent)) var(--lpos-border-alpha-2, 40%), transparent) !important;
  border-radius: var(--lpos-radius-panel) !important;
}
.lpos-blueprint .elementor-element-7d6d8cc,
.lpos-blueprint .elementor-element-7d6d8cc,
.lpos-blueprint .elementor-element-36a2f1c,
.lpos-blueprint .elementor-element-74668a5 { padding: var(--lpos-space-md) var(--lpos-pad) !important; align-content: start !important; }
.lpos-blueprint .elementor-element-dbb1a45,
.lpos-blueprint .elementor-element-dbb1a45 { padding: var(--lpos-space-sm) !important; }


/* ---- DCS-047: "every element in its own panel" -- frosted-glass panel treatment on the
   individual icon buttons, tab buttons, thumbnails, and the flipbook/3D viewers (nested
   inside the region panels). 100% token/glass driven. ---- */
.lpos-blueprint .elementor-element-16f9434,
.lpos-blueprint .elementor-element-f72569c,
.lpos-blueprint .elementor-element-cf2cad5,
.lpos-blueprint .elementor-element-1213239,
.lpos-blueprint .elementor-element-c5e39cf,
.lpos-blueprint .elementor-element-a7a881e,
.lpos-blueprint .elementor-element-bb8e667 .jet-tabs__control,
.lpos-blueprint .elementor-element-75904c8 .jet-tabs__control {
  background: var(--lpos-glass-panel) !important;
  -webkit-backdrop-filter: var(--lpos-blur-sm);
  backdrop-filter: var(--lpos-blur-sm);
  
  border: var(--lpos-border-width) solid color-mix(in srgb, var(--lpos-border-tint,var(--lpos-accent)) var(--lpos-border-alpha-2, 40%), transparent) !important;
  border-radius: var(--lpos-radius-control) !important;
}
/* flipbook + 3D viewers framed as panels (larger radius) */
.lpos-blueprint .lpos-media {
  background: var(--lpos-glass-panel) !important;
  -webkit-backdrop-filter: var(--lpos-blur-sm);
  backdrop-filter: var(--lpos-blur-sm);
  
  border: var(--lpos-border-width) solid color-mix(in srgb, var(--lpos-border-tint,var(--lpos-accent)) var(--lpos-border-alpha-2, 40%), transparent) !important;
  border-radius: var(--lpos-radius-panel) !important;
}
/* bottom-left thumbnails: one row of equal glass pills, image fills (cut internal padding) */
.lpos-blueprint .elementor-element-75904c8 .jet-tabs__control-wrapper {
  flex-wrap: nowrap !important;
  gap: var(--lpos-gap) !important;
  align-items: stretch !important;
}
.lpos-blueprint .elementor-element-75904c8 .jet-tabs__control {
  flex: 1 1 0 !important;
  min-width: 0 !important;
  max-width: none !important;
  width: auto !important;
  height: 56px !important;
  padding: 4px !important;
  overflow: hidden !important;
}
.lpos-blueprint .elementor-element-75904c8 .jet-tabs__control img {
  height: 100% !important;
  width: 100% !important;
  object-fit: cover !important;
  border-radius: var(--lpos-radius-sm) !important;
}


/* ---- DCS-048: consistency fixes ----
   - top-right + menu icon buttons -> fixed 46x46 square (were squished to 39x46);
   - gap between the center title/subtitle panel and the video panel (were touching);
   - bottom-left media thumbnails: center the image in the pill + fill (was bottom-aligned
     with a big top gap because the control was display:block);
   - flipbook/3D toolbar glyphs -> muted to match every other console icon (were white/ink),
     active control keeps a light glyph on the accent fill. ---- */
.lpos-blueprint .elementor-element-16f9434,
.lpos-blueprint .elementor-element-f72569c,
.lpos-blueprint .elementor-element-cf2cad5,
.lpos-blueprint .elementor-element-1213239,
.lpos-blueprint .elementor-element-c5e39cf,
.lpos-blueprint .elementor-element-a7a881e {
  width: var(--lpos-control-size) !important;
  height: var(--lpos-control-size) !important;
  min-width: var(--lpos-control-size) !important;
  flex: 0 0 auto !important;
}
.lpos-blueprint .elementor-element-dbb1a45 { margin-top: var(--lpos-gap) !important; }
.lpos-blueprint .elementor-element-75904c8 .jet-tabs__control {
  display: flex !important;
  align-items: center !important;
  justify-content: center !important;
  padding: 3px !important;
}
.lpos-blueprint .elementor-element-75904c8 .jet-tabs__control img {
  height: 100% !important;
  width: 100% !important;
  object-fit: cover !important;
}
.lpos-blueprint .lpos-media__bar button,
.lpos-blueprint .lpos-media__bar a,
.lpos-blueprint .lpos-media__bar button,
.lpos-blueprint .lpos-media__bar a,
.lpos-blueprint .lpos-media__bar button svg,
.lpos-blueprint .lpos-media__bar a svg,
.lpos-blueprint .lpos-media__bar button svg,
.lpos-blueprint .lpos-media__bar a svg {
  color: var(--lpos-muted) !important;
  stroke: var(--lpos-muted) !important;
}
.lpos-blueprint .lpos-media__bar button.-on,
.lpos-blueprint .lpos-media__bar button.-on svg,
.lpos-blueprint .lpos-media__bar button.-on,
.lpos-blueprint .lpos-media__bar button.-on svg {
  color: var(--lpos-ink) !important;
  stroke: var(--lpos-ink) !important;
}


/* ---- Reusable title/subtitle box (class-based, NOT tied to any element ID) ----
   Add the class "lpos-title-panel" to ANY container in the console (left, right, center,
   anywhere) that holds an h2 (title) + h3 (subtitle). Fixes the hardcoded-ID limitation:
   works on every box you build, no plugin change per box. Token/glass driven. ---- */
/* ONE-PANEL LAW CONSOLIDATION (2026-08-04): chrome (background/blur/shadow/border/radius/padding)
   for .lpos-title-panel/.lpos-c-title-panel moved to the single LAW definition further down this
   file (search "ONE ATOMIC PANEL COMPONENT (authoritative, last-word)") -- this used to duplicate
   that chrome with a different padding value (space-md instead of the law's panel-pad/16px), which
   is exactly the "two sources of chrome" bug the law forbids. Only the typography sub-rules below
   (h1-h4 sizing) stay here; they are not chrome and the LAW block does not set them. */
.lpos-blueprint .lpos-title-panel h1, .lpos-blueprint .lpos-title-panel h2,
.lpos-blueprint .lpos-c-title-panel h1, .lpos-blueprint .lpos-c-title-panel h2 {
  font-size: var(--lpos-title-size, 1.5rem) !important; line-height: 1.2 !important; margin: 0 !important; color: var(--lpos-heading-color,var(--lpos-ink)) !important; letter-spacing: var(--lpos-tracking-heading,-0.01em);
}
.lpos-blueprint .lpos-title-panel h3, .lpos-blueprint .lpos-title-panel h4,
.lpos-blueprint .lpos-c-title-panel h3, .lpos-blueprint .lpos-c-title-panel h4 {
  font-size: var(--lpos-subtitle-size, 1rem) !important; line-height: 1.3 !important; margin: var(--lpos-subtitle-margin, .15rem 0 0) !important; color: var(--lpos-muted) !important; font-weight: 500 !important;
}
/* JD: left/right title panels are secondary content (middle-center is primary) -- smaller type
   scale, same panel chrome. Applied via a plain BEM modifier on the same .lpos-c-title-panel
   element (BlueprintRenderer::panel_left()/panel_right()), higher source order + equal specificity
   to the base rule above so it wins without an extra !important escalation. */
.lpos-blueprint .lpos-c-title-panel--secondary h1, .lpos-blueprint .lpos-c-title-panel--secondary h2 {
  font-size: var(--lpos-title-size-secondary, 1.1rem) !important;
}
.lpos-blueprint .lpos-c-title-panel--secondary h3, .lpos-blueprint .lpos-c-title-panel--secondary h4 {
  font-size: var(--lpos-subtitle-size-secondary, .75rem) !important;
}

/* JD 2026-08-06: midcenter TITLECAP typography pass -- the primary title/subtitle text (center
   focal panel, .lpos-feat__titlecap) read unfinished: no display font, loose 1.2 leading, and a
   near-invisible 2.4px title->subtitle gap, all made worse by the panel's own flex:1 1 auto height
   (see the titlecap layout rules further down) which lets it grow tall in -right-collapsed/
   -left-collapsed/both-collapsed and strands the two text lines looking sparse. Scoped to
   `.lpos-cell--midcenter .lpos-feat__titlecap` only (3-class specificity beats the shared
   .lpos-c-title-panel h1-h4 rule above without an extra !important escalation) so the left/right
   --secondary title panels and the view-peer title are untouched. Chrome (background/blur/border/
   radius/panel-pad) still comes 100% from the ONE-PANEL LAW block -- nothing here overrides it. */
.lpos-blueprint .lpos-cell--midcenter .lpos-feat__titlecap {
  display: flex !important; flex-direction: column !important;
  align-items: flex-start !important; justify-content: flex-start !important; /* top-left anchor, never vertically centered when the panel grows tall */
}
.lpos-blueprint .lpos-cell--midcenter .lpos-feat__titlecap h2 {
  font-family: var(--lpos-font-display, 'Space Grotesk', ui-sans-serif, system-ui, sans-serif) !important;
  /* fluid step anchored to the existing --lpos-title-size token (24px) so it never regresses below
     today's size, growing toward 30px as the viewport widens -- clamp() per JD's ask, all 4 collapse
     states read from the same rule (no per-state override needed, the panel width changes, this doesn't). */
  font-size: clamp(var(--lpos-title-size, 1.5rem), calc(var(--lpos-title-size, 1.5rem) + 1vw), 1.875rem) !important;
  line-height: 1.1 !important;
  font-weight: 600 !important;
  letter-spacing: var(--lpos-tracking-heading, -0.01em) !important;
}
.lpos-blueprint .lpos-cell--midcenter .lpos-feat__titlecap h3 {
  color: var(--lpos-muted) !important;
  font-weight: 400 !important;
  margin: var(--lpos-space-xs, 4px) 0 0 !important; /* was --lpos-subtitle-margin (2.4px) -- token-based 4px step reads as an intentional gap instead of a clipped-looking sliver */
}

/* side panels (left/right): stack title + media vertically instead of inline (DCS side-stack).
   6f86633 is the shared side-panel row container the console composes into each side column. */
.lpos-blueprint .elementor-element-6f86633{flex-direction:column!important;}
.lpos-blueprint .elementor-element-6f86633 > *{width:100%!important;}

/* ===== BLUEPRINT RESPONSIVE ============================================================
   Any [lpos_blueprint] composes a CSS grid whose columns come from the shape (inline style).
   Override per device so blueprints stack to whole rows on tablet/phone (never a cramped
   multi-col squeeze) -- makes every blueprint device-safe regardless of its shape. ===== */
/* These two only ever applied to NON-console blueprint shapes (the console shell is display:flex,
   so grid-template-columns on it is inert) -- kept for those shapes, scoped so the intent is
   explicit. The console's own responsive behaviour is the auto-collapse below, driven by
   lpos-drawers.js (matchMedia 1280px) reusing the proven collapsed-state layouts. */
@media (max-width:1024px){ .lpos-blueprint:not(.lpos-blueprint--console){grid-template-columns:1fr 1fr!important;} }
@media (max-width:767px){ .lpos-blueprint:not(.lpos-blueprint--console){grid-template-columns:1fr!important;} }

/* (CONSOLIDATION 2026-08-05, plan Phase 2: the .lpos-topbar/.lpos-bottombar container bars,
   .lpos-topbar__left/__search/__actions, .lpos-center/__video, and the first .lpos-col__media copy
   were DELETED -- no renderer emits those containers any more (only .lpos-topbar__brand and
   .lpos-topbar__logo-img survive as elements inside the portal switcher). The later
   .lpos-col__media rule (with overflow:hidden) is the single live copy.) */
.lpos-topbar__brand{font:700 1.25rem/1 var(--lpos-font-display,'Space Grotesk', ui-sans-serif, system-ui, sans-serif);color:var(--lpos-logo-word-color,var(--lpos-ink));letter-spacing:.02em;white-space:nowrap}
/* owned left/right columns: title stacked over media, media fills remaining height */
.lpos-col{display:flex;flex-direction:column;gap:var(--lpos-gap,12px);height:100%}

/* ================= 9-PANEL CONSOLE (owned Blueprint "console" shape) ==================
   Screen-fill 3x3 grid. Rows locked 9dvh / remainder / 9dvh (A10): the flex remainder on the
   middle row does the "calc(100vh - 18vh - gaps)" math for free once the top/bottom rows have
   a fixed flex-basis, so it never drifts out of sync with the gap token. overflow:hidden at
   every level below -- zero scrollbars, anywhere, ever (A10).
   Each layout cell is its own frosted padded Panel (--lpos-panel-pad -- the one token this
   file's cell padding reads everywhere, replacing the old mixed space-md/pad pair (A9)); every
   Component nested inside a cell gets its OWN smaller frosted sub-panel via the reusable
   .lpos-c-panel/.lpos-c-title-panel component classes (ComponentStyles.php: menu/logo tiles,
   flipbook title, icon clusters) so nesting composes from one shared vocabulary (A8/A9). ==== */
/* SCREEN-FILL FREEZE (moved here 2026-08-10, JD approved deleting dashboard-layout.css): that file
   carried an UNSCOPED `html,body{height:100%;overflow:hidden!important}` -- a site-wide page freeze
   shipped for a JetEngine dashboard (.bl-dashboard-root) this plugin never renders. The freeze
   itself is still load-bearing for the no-scrollbar law, so it moves here, scoped to pages that
   actually contain a console blueprint. Every other page on the site scrolls normally again. */
html:has(.lpos-blueprint),
body:has(.lpos-blueprint){height:100%;min-height:100%;overflow:hidden}

/* JD 2026-08-03 (screen-fill + dark-HUD law): the console OWNS its dark HUD backdrop and its dark
   STRUCTURAL tokens -- it must never render light. A stale light brand-pack default was overriding
   the dark :where(:root) canon at :root (zero specificity), turning the whole HUD white; re-declaring
   the structural surface/ink tokens ON the console subtree (normal specificity) restores dark while
   leaving per-tenant ACCENT tokens (--lpos-accent etc) free to theme. Values == console-tokens canon. */
.lpos-blueprint--console,.lpos-blueprint--gate,.lpos-blueprint--magick8{
  --lpos-bg:#0A0E17;--lpos-panel:#0D111C;--lpos-panel-hover:color-mix(in srgb,var(--lpos-accent) 10%,transparent);--lpos-overlay:#10151f; /* JD 2026-08-04 TOKEN-DRIVEN: panel-hover derives from the tenant --lpos-accent, not hardcoded cyan */
  --lpos-ink:#EAF2FB;--lpos-muted:#A8B2C7;--lpos-glass-panel:linear-gradient(180deg, rgba(30,42,66,0.52), rgba(16,24,40,0.62))} /* kept in lockstep with the root token (JD 2026-08-06) */
/* JD 2026-08-06: .lpos-blueprint--magick8 joins the screen-fill/dark-HUD rule below -- same tokens,
   no rows/grid (Magick8 has none), just the backdrop-hosting box the shared .lpos-blueprint__bgvideo
   layer (render_bg_video_layer(), unchanged) needs to fill the screen and paint behind nothing. */
.lpos-blueprint--magick8{--lpos-m8-w:min(92vw,860px);
  --lpos-m8-car-w:min(calc(100vw - 2*var(--lpos-gap,12px)),1600px)} /* JD 2026-08-06: near full-bleed carousel row -- the chevrons float INSIDE it over the edge-fade zones */ /* JD 2026-08-06: ONE width token for player/rows -- resize in one place */
.lpos-blueprint--console,.lpos-blueprint--magick8{display:flex;flex-direction:column;gap:var(--lpos-gap,12px);height:100dvh;padding:var(--lpos-gap,12px);box-sizing:border-box;overflow:hidden;
  background:radial-gradient(120% 90% at 50% -10%,color-mix(in srgb,var(--lpos-accent,#00D4FF) 7%,var(--lpos-bg,#0A0E17)) 0%,var(--lpos-bg,#0A0E17) 58%);color:var(--lpos-ink,#EAF2FB)}
.lpos-blueprint--console>.lpos-blueprint__row{min-height:0;overflow:hidden;align-items:stretch;background:transparent} /* JD 2026-08-04 CORRECTION: ROWS carry NO fill/tint/glass -- layout only, so the console bg (video/gradient) shows through the GAPS between panels. Glass/frosting lives ONLY on panels (.lpos-cell/.lpos-c-panel/.lpos-c-subpanel). The edge-glyph bleed-through fix moved to the bg-video LAYER ITSELF (a real blur filter on `.lpos-blueprint__bgvideo-media`, far below) instead of a row-level tint, so the gaps still show real ambient motion, just diffused enough that no error-page text ever reads as legible. */
/* Phase D 2026-08-09: legacy row sizing machinery deleted -- both console states are flat grids
   (BLUEPRINT SHIFT stage A/B below), rows are display:contents in every state, so properties set
   directly on .lpos-blueprint__row's own box (flex/height/grid-template-columns/position/z-index)
   never render. This tombstone marks the first of several such deletions in this file. */
/* each grid TRACK cell (.lpos-blueprint__region) must not grow past its track: min-width:0 stops
   intrinsic content (3D viewer, video, flipbook) from stretching a 1fr column wider than its
   siblings, and height:100% (resolved against the row's definite cross-size from CSS Grid's
   default stretch) is what lets the .lpos-cell panel inside it fill the row/column exactly --
   this is the mechanism that makes top-left/mid-left/bot-left (and the -right column) share the
   SAME width and the top-row/bottom-row panels share the SAME height as the search reference. */
.lpos-blueprint--console .lpos-blueprint__region{display:block;height:100%;min-width:0;min-height:0;overflow:hidden;box-sizing:border-box}
/* each cell = frosted padded Panel, stretched to fill its region (see above) so every panel in a
   row is exactly the same height, and every panel in a column is exactly the same width. */
/* JD 2026-08-01: Display Panel inset tightened panel-pad(16) -> subpanel-pad(8) to match the locked
   reference spec (the midright Tab Tool Bar: 8px inset, 16px between items). The 16px tier now only
   lives BETWEEN things (grid gaps, item gaps), never as a panel inset. */
/* JD 2026-08-04 LAW: ONE ATOMIC PANEL. Every blueprint cell/region panel renders from the SAME
   token-driven definition as the .lpos-c-panel atomic component (background/blur/shadow/border/radius),
   so editing the panel tokens changes every panel everywhere. Size + padding come from the Blueprint
   per instance; content comes from Components. No divergent chrome variant.
   ONE-PANEL LAW CONSOLIDATION (2026-08-04): chrome (background/blur/shadow/border/radius/padding) for
   .lpos-cell moved to the single LAW definition further down this file (search "ONE ATOMIC PANEL
   COMPONENT (authoritative, last-word)") so there is exactly one source of chrome. This rule now
   carries LAYOUT ONLY (display/flex/size/overflow) -- do not re-add background/border/radius/padding
   here, it would become a second, driftable chrome definition. */
.lpos-blueprint .lpos-cell{
  display:flex;flex-direction:column;gap:var(--lpos-gap,12px);height:100%;width:100%;min-height:0;min-width:0;box-sizing:border-box;overflow:hidden}
/* JD 2026-08-04 (translucency pass): the midcenter cell carries the "editorial copy" body text
   (the [lpos_video]/tab-content description block) -- kept at the FULLER --lpos-glass-panel
   opacity (not the new chrome-tier translucent default above) so paragraph copy stays legible
   over the moving DNA background. Same specificity as the base rule above (two classes each); the
   later source position wins the cascade, no !important needed. */
.lpos-blueprint .lpos-cell--midcenter{background:var(--lpos-glass-panel)}
/* top/bottom rows (2026-08-01 THIRD retune): row shrunk 70px -> 54px (--lpos-titlebar-h above), so
   the cell's own vertical inset drops space-sm(8) -> space-xs(4) to match -- STILL one padding
   layer only, every chrome-row component that sits inside a `.lpos-c-subpanel` wrapper already
   renders that wrapper's vertical padding at 0 for chrome-row use (menu/logo/topright+botright
   clusters/botleft row/botcenter bar all override it, see .lpos-c-subpanel below), so nothing
   stacks on top of this single 4px inset: 4 + 46 + 4 = 54, exactly, for every row. Horizontal
   panel-pad is unchanged throughout. align-items:center added to botleft/botright (JD: bottom-right
   icon buttons read closer to the panel's TOP than its bottom -- the cell's own cross-axis alignment
   was left at its column-flex default, which is fine for the vertical axis here since justify-content
   already centers that; align-items:center keeps the row's own content horizontally centered instead
   of stretching, matching the intent even though the visual symptom traced to the icon SVGs' default
   inline-baseline gap, fixed separately below). */
/* topleft (2026-08-01 SEVENTH logo retune): standard chrome-row inset restored -- space-sm vertical
   like every other chrome cell (8 + 46 + 8 + 2*1border = 64). The zero-inset exception from the
   sixth retune is retired along with the 62px logo. */
.lpos-blueprint .lpos-cell--topleft{flex-direction:row!important;align-items:center;gap:var(--lpos-gap,12px);padding:var(--lpos-space-sm,8px)} /* JD 2026-08-01: uniform 8px inset per the locked reference spec */
/* JD 2026-08-01 (final layout): topcenter carries ONLY the tab buttons -- centered as a group,
   fixed 46px boxes, same row recipe as the other chrome cells. The search moved to botcenter,
   which takes over the row-with-flexing-search treatment. */
.lpos-blueprint .lpos-cell--topcenter{flex-direction:row!important;align-items:center;justify-content:flex-start;gap:var(--lpos-gap,12px);padding:var(--lpos-space-sm,8px)} /* JD 2026-08-01: left-aligned controls; uniform 8px inset per the locked reference spec */
.lpos-blueprint .lpos-cell--topcenter .lpos-c-icon-btn{flex:0 0 auto}
/* twin of the top action icons, shown right-aligned here only while the right column is collapsed */
/* JD 2026-08-01 (rail unification): the .lpos-topcenter-icons twin is RETIRED -- the collapsed
   right column now surfaces the topright buttons in the vertical rail (.lpos-rail-topset below). */
/* (COLLAPSE REBUILD JD 2026-08-05: the hidden rail twins + display:contents promotion system is
   GONE -- the collapsed bars are real .lpos-rail elements now, see the COLLAPSE REBUILD block.) */
/* JD 2026-08-01: the midcenter's TAB BAR twin -- hidden in every normal view (the header owns the
   tab bar there); in the both-collapsed cinematic view the header row is gone, so it surfaces as a
   GHOST strip across the top INSIDE the main panel, above the video, on the same reveal contract
   as the rails. */
.lpos-blueprint--console .lpos-feat__tabbar{display:none!important}
/* JD 2026-08-02 (C7 + F5): one-active-pane switching. Every midleft asset and every midright view
   is rendered once; only the -active pane occupies the column, so each engine initialises once and
   keeps its state instead of being rebuilt on every switch. */
.lpos-blueprint--console [data-lpos-media-host] > .lpos-col__slot:not(.-active),
.lpos-blueprint--console [data-lpos-view-host] > [data-lpos-view]:not(.-active){display:none!important} /* matches the 3D slot wrapper AND the direct view panes, so a relocated title hides with its view */
/* ---- JD 2026-08-02: slide-out MENU tree. Console first (primary link), then collapsible
   sections. Every row is a control-height target on the standard panel recipe, so the drawer
   reads like the rest of the console rather than a bare list. ---- */
.lpos-menu{display:flex;flex-direction:column;gap:var(--lpos-space-sm,8px);min-width:0}
.lpos-menu__section{display:flex;flex-direction:column;gap:var(--lpos-space-sm,8px)}
.lpos-menu__toggle,.lpos-menu__link{
  all:unset;box-sizing:border-box;display:flex;align-items:center;gap:var(--lpos-space-sm,8px);
  min-height:var(--lpos-control-size,46px);padding:0 var(--lpos-space-md,12px);cursor:pointer;
  border-radius:var(--lpos-radius-control,8px);
  background:var(--lpos-glass-panel,linear-gradient(180deg, rgba(30,42,66,0.34), rgba(16,24,40,0.45)));
  border:var(--lpos-border-width,1px) solid color-mix(in srgb,var(--lpos-border-tint,var(--lpos-accent)) var(--lpos-border-alpha-1,30%),transparent);
  color:var(--lpos-ink,#EAF2FB);font:600 var(--lpos-text-sm,14px)/1.2 var(--lpos-font-ui,'Inter', ui-sans-serif, system-ui, sans-serif)}
.lpos-menu__link--primary{border-color:color-mix(in srgb,var(--lpos-border-tint,var(--lpos-accent)) var(--lpos-border-alpha-3,55%),transparent);background:var(--lpos-accent-soft,color-mix(in srgb, var(--lpos-accent) 10%, transparent))}
.lpos-menu__link:hover{border-color:var(--lpos-accent,#00D4FF);background:var(--lpos-accent-soft,color-mix(in srgb, var(--lpos-accent) 10%, transparent))}
.lpos-menu__link:focus-visible{outline:none;box-shadow:var(--lpos-focus-ring,0 0 0 2px rgba(0,212,255,.9),0 0 12px rgba(0,212,255,.6))}
.lpos-menu__chev{display:flex;transition:transform var(--lpos-duration-fast,120ms) var(--lpos-ease-tech,cubic-bezier(0.16, 1, 0.3, 1))}
.lpos-menu__chev svg{width:var(--lpos-icon-size-xs,20px);height:var(--lpos-icon-size-xs,20px);color:var(--lpos-muted,#A8B2C7);fill:none;stroke:currentColor}
.lpos-menu__panel[hidden]{display:none}
.lpos-menu__panel{padding-left:var(--lpos-space-md,12px)}
/* JD 2026-08-02 (sub-items landed): item rows step DOWN from the section headers -- one space-sm
   shorter than a control, token-derived. Hierarchy reads at a glance AND the tallest header+items
   run (Marketplace open, 6 items) stays inside the drawer height (the 46px rows overran by ~23px
   and the no-scrollbar rule clipped the Settings header). */
.lpos-menu__item .lpos-menu__link{min-height:calc(var(--lpos-control-size,46px) - var(--lpos-space-sm,8px));font-weight:500}
/* JD 2026-08-02 (FINAL menu): section headers are DIVIDER TEXT TOGGLES -- bare text over a
   hairline, no panel chrome; the chevron reuses the shared rotate-on-expanded behavior. */
.lpos-menu__divider{
  all:unset;box-sizing:border-box;display:flex;align-items:center;justify-content:space-between;
  gap:var(--lpos-space-sm,8px);width:100%;cursor:pointer;
  padding:var(--lpos-space-sm,8px) var(--lpos-space-md,12px);
  border-bottom:var(--lpos-border-width,1px) solid color-mix(in srgb,var(--lpos-border-tint,var(--lpos-accent)) var(--lpos-border-alpha-1,30%),transparent);
  color:var(--lpos-muted,#A8B2C7);font:600 var(--lpos-text-sm,14px)/1.2 var(--lpos-font-ui,'Inter', ui-sans-serif, system-ui, sans-serif)}
.lpos-menu__divider:hover{color:var(--lpos-ink,#EAF2FB)}
.lpos-menu__divider:focus-visible{outline:none;box-shadow:var(--lpos-focus-ring,0 0 0 2px rgba(0,212,255,.9),0 0 12px rgba(0,212,255,.6))}
.lpos-menu__divider[aria-expanded="true"]{color:var(--lpos-ink,#EAF2FB);border-bottom-color:color-mix(in srgb,var(--lpos-border-tint,var(--lpos-accent)) var(--lpos-border-alpha-3,55%),transparent)}
.lpos-menu__divider .lpos-menu__chev{transition:transform var(--lpos-duration-fast,120ms) var(--lpos-ease-tech,cubic-bezier(0.16, 1, 0.3, 1))}
.lpos-menu__divider[aria-expanded="true"] .lpos-menu__chev{transform:rotate(180deg)}
/* JD 2026-08-02: menu ITEM buttons carry the same chrome as the Logout button (accent hairline +
   accent-soft fill -- the --primary recipe), so every actionable row reads as a button. */
.lpos-menu__link--go{
  border-color:color-mix(in srgb,var(--lpos-border-tint,var(--lpos-accent)) var(--lpos-border-alpha-3,55%),transparent);
  background:var(--lpos-accent-soft,color-mix(in srgb, var(--lpos-accent) 10%, transparent))}
/* JD 2026-08-02: SECOND-STEP menu (the local-app drill-in pattern). Home list and step panels
   swap via [hidden]; a primary-with-children row is [item button, flex:1][chevron step-in]. */
.lpos-menu{display:flex;flex-direction:column;min-height:100%}
.lpos-menu__home{display:flex;flex-direction:column;gap:var(--lpos-space-sm,8px);flex:1 1 auto;min-height:0}
.lpos-menu__home[hidden],.lpos-menu__step[hidden]{display:none}
.lpos-menu__step{display:flex;flex-direction:column;gap:var(--lpos-space-sm,8px)}
.lpos-menu__item{display:flex;align-items:stretch;gap:var(--lpos-space-sm,8px)}
.lpos-menu__item .lpos-menu__link{flex:1 1 auto;min-width:0}
/* JD 2026-08-02: the step-in chevron sits INSIDE the menu button, not beside it -- for rows with
   children the ROW carries the single button chrome and both inner controls go chromeless (the
   label zone opens the Display, the chevron zone steps into the submenu). */
.lpos-menu__item--haskids{
  gap:0;min-height:calc(var(--lpos-control-size,46px) - var(--lpos-space-sm,8px));
  border-radius:var(--lpos-radius-control,8px);
  background:var(--lpos-accent-soft,color-mix(in srgb, var(--lpos-accent) 10%, transparent));
  border:var(--lpos-border-width,1px) solid color-mix(in srgb,var(--lpos-border-tint,var(--lpos-accent)) var(--lpos-border-alpha-3,55%),transparent)}
.lpos-menu__item--haskids .lpos-menu__link{background:transparent;border:0;min-height:0}
.lpos-menu__item--haskids:hover,.lpos-menu__item--haskids:focus-within{border-color:var(--lpos-accent,#00D4FF)} /* review fix: keyboard focus gets the same row highlight as hover */
.lpos-menu__stepin{
  all:unset;box-sizing:border-box;flex:0 0 auto;display:flex;align-items:center;justify-content:center;cursor:pointer;
  padding:0 var(--lpos-space-md,12px);
  color:var(--lpos-muted,#A8B2C7)}
.lpos-menu__stepin:hover{color:var(--lpos-accent,#00D4FF)}
.lpos-menu__stepin:focus-visible{outline:none;box-shadow:var(--lpos-focus-ring,0 0 0 2px rgba(0,212,255,.9),0 0 12px rgba(0,212,255,.6))}
.lpos-menu__stepin svg,.lpos-menu__back svg{width:var(--lpos-icon-size-xs,20px);height:var(--lpos-icon-size-xs,20px);fill:none;stroke:currentColor}
.lpos-menu__back{
  all:unset;box-sizing:border-box;display:flex;align-items:center;gap:var(--lpos-space-sm,8px);width:100%;cursor:pointer;
  padding:var(--lpos-space-sm,8px) var(--lpos-space-md,12px);
  border-bottom:var(--lpos-border-width,1px) solid color-mix(in srgb,var(--lpos-border-tint,var(--lpos-accent)) var(--lpos-border-alpha-3,55%),transparent);
  color:var(--lpos-ink,#EAF2FB);font:600 var(--lpos-text-sm,14px)/1.2 var(--lpos-font-ui,'Inter', ui-sans-serif, system-ui, sans-serif)}
.lpos-menu__back:hover{color:var(--lpos-accent,#00D4FF)}
.lpos-menu__back:focus-visible{outline:none;box-shadow:var(--lpos-focus-ring,0 0 0 2px rgba(0,212,255,.9),0 0 12px rgba(0,212,255,.6))}
/* the Logout button anchors to the BOTTOM of the off-canvas menu (JD) */
.lpos-menu__logout{margin-top:auto;justify-content:center}
.lpos-menu__list{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:var(--lpos-space-sm,8px)}
.lpos-menu__empty{margin:0;padding:var(--lpos-space-sm,8px) var(--lpos-space-md,12px);color:var(--lpos-muted,#A8B2C7);font:400 var(--lpos-text-sm,14px)/1.4 var(--lpos-font-ui,'Inter', ui-sans-serif, system-ui, sans-serif)}
/* a slot is the asset's whole group (tools bar + title panel + media), stacked like the column */
.lpos-col__slot{display:flex;flex-direction:column;gap:var(--lpos-gap,12px);min-height:0;flex:1 1 auto}
/* view panes (chat/bookmarks/calendar/notes): the standard column stack -- title panel, then an
   honest-empty body panel that fills the rest until its engine lands. */
.lpos-col__view{display:flex;flex-direction:column;gap:var(--lpos-gap,12px);min-height:0}
.lpos-view__body{flex:1 1 auto;min-height:0;display:flex;align-items:center;justify-content:center} /* DUP FIX: .lpos-c-subpanel{display:flex} appears later with equal specificity and was winning, so this twin rendered on top of the real header tab bar in EVERY state */
/* JD 2026-08-02: the cinematic tab bar is IN FLOW like the side rails' push behaviour -- it does
   not overlay the video. At rest it collapses to zero height (content takes the space); on reveal
   it grows to a control row and the content moves down, matching how the rails push the sides. */
/* JD 2026-08-04 (PDP shell law, item 7): the collapsed-state top bar is ALWAYS VISIBLE now -- no
   hover-to-reveal ghost. It used to render at height:0/opacity:0 until pointer activity or focus
   revealed it (see the removed -railshow/:hover/:focus-within reveal selectors this rule replaces);
   that entire "ghost" contract is gone -- the twin renders at full height/opacity unconditionally
   the instant both columns collapse, exactly like every other chrome bar below. */
/* (JD 2026-08-05 both-collapsed rework, items 3/4/9/11: the ghost tabbar twin reveal is DELETED --
   the REAL top row stays visible in both-collapsed now (full width, real panel outline, real
   pager), so the in-panel twin never shows anywhere. Base display:none above governs.) */
@media (prefers-reduced-motion: reduce){.lpos-feat__tabbar{transition:none!important}}
/* (COLLAPSE REBUILD JD 2026-08-05: display:contents twin-promotion rules deleted -- rail content
   lives in the real .lpos-rail elements.) */
/* JD 2026-08-01: chevron-only pager (moved up from the center title bar) pins to the RIGHT edge */
.lpos-blueprint .lpos-cell--topcenter .lpos-pagination--nav{margin-left:auto}
/* labeled icon button (icon + inline text, JD 2026-08-01: the Dashboard tab): grows to fit its
   text -- width:auto + side padding need !important to beat the ComponentStyles registry's fixed
   46px (same precedent as every other width override of that rule). Height/chrome unchanged. */
.lpos-blueprint .lpos-c-icon-btn.lpos-c-icon-btn--labeled{width:auto!important;min-width:0;padding:0 var(--lpos-space-md,12px)!important;gap:var(--lpos-space-sm,8px)!important}
.lpos-c-icon-btn__text{font:600 var(--lpos-text-sm,14px)/1 var(--lpos-font-ui,'Inter', ui-sans-serif, system-ui, sans-serif);color:var(--lpos-ink,#EAF2FB);white-space:nowrap}
.lpos-blueprint .lpos-cell--botcenter{flex-direction:row!important;gap:var(--lpos-gap,12px)} /* search host now: row so .lpos-search's flex:1 fills the panel */
.lpos-blueprint .lpos-cell--topright{flex-direction:row!important;align-items:center;justify-content:center;gap:var(--lpos-gap,12px);padding:var(--lpos-space-sm,8px)} /* JD 2026-08-01: uniform 8px inset */
.lpos-blueprint .lpos-cell--botleft,.lpos-blueprint .lpos-cell--botright{justify-content:center;align-items:center;padding:var(--lpos-space-sm,8px)} /* JD 2026-08-01: uniform 8px inset */
/* JD 2026-08-01 batch 17: botleft = [collapse toggle, LEFT-aligned] [profile-image button] [empty
   slot panel absorbing the rest]; botright = [switch cluster] [toggle LAST, far right]. The
   cluster/slot flex, the toggle + avatar keep their fixed squares (needs !important against the
   distributed-row width rule). */
.lpos-blueprint .lpos-cell--botleft{justify-content:flex-start}
.lpos-blueprint .lpos-cell--botleft,.lpos-blueprint .lpos-cell--botright{flex-direction:row!important;gap:var(--lpos-gap,12px)}
/* (Phase 3: dead .lpos-cell--botright .lpos-switch sizing rule deleted -- wrapper gone from markup.) */
.lpos-blueprint .lpos-cell--botleft>.lpos-c-icon-btn[data-lpos-collapse],
.lpos-blueprint .lpos-cell--botleft>.lpos-c-icon-btn--avatar,
/* DEAD BLOCK REMOVED 2026-08-10 (full-app law review): the XP progress bar / level badge /
   botleft slot panel. No PHP or JS emits .lpos-c-subpanel--slot, .lpos-progress* or .lpos-level
   any more (the botleft XP+level computation was deleted earlier this session), so ~50 lines of
   rules here painted nothing. They also held the only two references to `--lpos-xp`, a token
   that was never declared anywhere -- the "token-driven" width was permanently calc(0*1%). The
   live XP bar is .lpos-magick8__xpfill, whose width lpos-drawers.js sets directly. */
.lpos-topbar__brand{font:700 1.25rem/1 var(--lpos-font-display,'Space Grotesk', ui-sans-serif, system-ui, sans-serif);color:var(--lpos-logo-word-color,var(--lpos-ink));letter-spacing:.02em;white-space:nowrap}
/* brand logo image (A2): token-sized to the row's control height, never a hardcoded px */
/* JD 2026-08-01: logo asset is a wide lockup (icon+wordmark, ~2000x301) -- fills the titlebar row at
   near-full height. Reconciliation pass: the logo's own sub-panel wrapper (.lpos-c-subpanel--logo,
   below) is now zero-padding -- the topleft CELL's own var(--lpos-space-sm,8px) inset (above) is the
   ONLY layer around the image, so its available height is titlebar-h minus that one inset on both
   sides, not the generic panelled-component 4px figure; width scales naturally with the asset's own
   aspect ratio, no max-width clamp shrinking it back down. */
.lpos-topbar__logo-img{height:var(--lpos-logo-h,46px);width:auto;max-width:100%;object-fit:contain;object-position:left center;display:block;flex:0 1 auto;min-width:0;filter:none} /* 2026-08-01 SEVENTH retune: back to control-size (46px) -- the padding-free asset carries the visual size now; max-width + contain still guard against wordmark clipping */

/* ---- reusable sub-panel wrapper (A8): every top-bar Component (menu button, logo, search box,
   each icon-button cluster, the asset-switcher cluster) sits inside one of these -- one class +
   modifier pattern instead of a one-off rule per cell. ----
   ONE-PANEL LAW CONSOLIDATION (2026-08-04): this class used to carry its OWN divergent chrome
   recipe here (blur-sm/shadow-1/radius-control/border-alpha-3/4px+8px padding) that DUPLICATED and
   conflicted with the single LAW chrome definition further down this file (search "ONE ATOMIC
   PANEL COMPONENT (authoritative, last-word)"), which also matches .lpos-c-subpanel and forces the
   uniform blur-md/shadow-2/radius-panel/border-alpha-2/16px-padding recipe via !important -- two
   sources of chrome for the same class, exactly what the law forbids. Chrome removed from here;
   this rule now carries LAYOUT ONLY. Do not re-add background/border/radius/padding here. */
.lpos-c-subpanel{display:flex;align-items:center;gap:var(--lpos-space-sm,8px);min-width:0;min-height:0;box-sizing:border-box;overflow:hidden}
/* menu button already carries its own full icon-btn chrome -- the wrapper here is structural
   only (its own Component panel per A8), not a second visible box around an already-boxed button.
   ONE-PANEL LAW NOTE (2026-08-04): this element carries the base .lpos-c-subpanel class too (BEM
   base+modifier pair, BlueprintRenderer::topleft menu markup), which the LAW chrome block further
   down this file matches with !important -- these chrome-cancelling properties need !important to
   keep winning, or the hamburger button would render inside a second, redundant panel box. This is
   the one narrow, pre-existing "wrapper around an already-chromed Component" case in the file (kept
   out of the deleted ghost block on purpose); the real fix is dropping the .lpos-c-subpanel class
   from this element in the PHP markup so it never matches the panel-chrome selector at all. */
/* (Phase 3: the --menu chrome-cancel rule is deleted -- panel_topleft() no longer emits that wrapper.) */
/* logo: reconciliation pass -- zero padding of its own (was subpanel-pad 8px, which combined with
   the cell's new 8px inset overflowed the 70px row). The topleft cell's own space-sm inset is now
   the ONLY layer around the image (see .lpos-topbar__logo-img above); the panel border still frames
   the logo tightly (border/background/shadow inherited from the base rule, unchanged), it's just a
   snug frame with no additional inset -- the "larger, minimal padding" treatment. */
/* JD 2026-08-01: logo OUT of its component container -- image sits directly in the Display Panel
   (same unwrap as the icon clusters); small left margin separates it from the menu button. The
   icon-to-wordmark spacing is baked into the lockup asset itself. */
/* JD 2026-08-01 (final): logo CENTERED in the space between the menu button and the empty slot
   panel -- the wrapper claims that remaining width (flex:1 1 auto) and centers the intrinsically
   sized <img> inside it. */
.lpos-c-subpanel--cluster{flex:0 0 auto;gap:var(--lpos-gap,12px)}
/* JD 2026-08-01 (final): the topleft slot/logo/avatar were replaced by the WORKSPACE DROPDOWN --
   trigger wears the search-bar recipe (46px glass box, accent-40 hairline), closed state shows the
   MyLivingOS logo as the styled default selection; the popover menu wears the facebar tool-panel
   recipe. Behavior in lpos-drawers.js (toggle, outside-click + Esc close). */
.lpos-c-select{position:relative;flex:1 1 auto;min-width:0;height:var(--lpos-control-size,46px);display:flex;align-items:center;gap:calc(0.5*var(--lpos-space-sm,8px))} /* JD 2026-08-07: brand panel + its dropdown toggle read as ONE unit (gap halved); spacing to the Dashboard button is the cell gap, untouched */
/* TWO components (JD): the VALUE is its own glass sub-panel (inherits .lpos-c-subpanel chrome;
   sized + centered here), the toggle is the standard icon button beside it. */
.lpos-c-select__value{flex:1 1 auto;min-width:0;height:100%;display:flex;align-items:center;justify-content:center;overflow:hidden;padding:0 var(--lpos-space-sm,8px)} /* JD 2026-08-01 batch 17 (EIGHTH logo retune): vertical padding dropped -- the panel border is the only frame, so the logo renders at full control height again */
.lpos-c-select .lpos-topbar__logo-img{height:calc(var(--lpos-control-size,46px) + var(--lpos-space-sm,8px))} /* JD EXPLICIT 2026-08-04: BL wordmark too small at ~42px -> enlarged; SIZE FROZEN again at new value unless JD says otherwise. (~54px; supersedes the 2026-08-03 "up one step to ~42px" retune below it.) */
.lpos-c-select__menu{position:absolute;left:0;right:0;top:calc(100% + var(--lpos-space-xs,4px));z-index:var(--lpos-z-drawer,9000);
  display:flex;flex-direction:column;gap:var(--lpos-space-xs,4px);padding:var(--lpos-subpanel-pad,6px);
  /* NO-SCROLLBAR / REACHABILITY LAW (2026-08-10 review): the popover had no vertical bound at all.
     One workspace renders today, so nothing overflowed -- but the moment a second lands, an
     unbounded menu on a short viewport runs past the bottom edge with the document frozen
     (overflow:hidden everywhere), i.e. unreachable options and no scrollbar to reach them. Same
     clamp the rail-flyout variant already carries. lpos-drawers.js clamps the fixed-position
     `top` against the viewport to match. */
  max-height:min(calc(100dvh - 2*var(--lpos-panel-pad,12px)),80dvh);overflow:hidden;
  /* JD 2026-08-03: the menu was too see-through to read the logos over the panel behind it -- near
     opaque dark now (still frosted), so brand logos read clearly. Visual-QA follow-up (same day):
     94%/blur-md still let panel texture bleed through behind wide wordmarks -- bumped to 97% +
     blur-lg (canon blur(32px) saturate(160%)) so every logo reads clean regardless of what's behind it. */
  background:color-mix(in srgb,var(--lpos-bg,#0A0E17) 97%,transparent);-webkit-backdrop-filter:var(--lpos-blur-lg,blur(32px) saturate(160%));backdrop-filter:var(--lpos-blur-lg,blur(32px) saturate(160%));
  border:var(--lpos-border-width,1px) solid color-mix(in srgb,var(--lpos-border-tint,var(--lpos-accent)) var(--lpos-border-alpha-3,55%),transparent);
  border-radius:var(--lpos-radius-control,8px);
  }
.lpos-c-select__menu[hidden]{display:none}
/* JD 2026-08-06: tenant logo INSIDE the open dropdown panel (its first child) -- token-sized to
   the standard control height, width auto so it never distorts, centered as its own block. */
.lpos-c-select__panel-logo{display:block;margin:0 auto var(--lpos-gap,12px);height:var(--lpos-control-size,46px);width:auto;max-width:100%}
/* COLLAPSED-BUTTON REVEAL, Layer B (JD 2026-08-03, COLLAPSED_BUTTON_CONTENT_DISPLAY_SPEC §4.2) --
   the rail flyout IS a `.lpos-c-select__menu` (same class, inherits the frosted/positioned/[hidden]
   chrome above verbatim) plus this one sizing modifier, since its content is a relocated media/view
   PANE, not a short option list. lpos-drawers.js's positionSelectMenu() sets position:fixed +
   left/top/width inline exactly as it already does for the portal switcher -- no new JS positioning
   logic. */
.lpos-rail-flyout{width:min(360px,90vw);max-height:min(480px,80vh);overflow:hidden;padding:var(--lpos-panel-pad,12px)} /* JD no-scroll law: fit, never scroll */
.lpos-rail-flyout__target{display:flex;flex-direction:column;gap:var(--lpos-gap,12px);min-height:0}
/* JD 2026-08-03 (access gate): logged-out / no-access shows ONLY a centered panel, never the console. */
.lpos-blueprint--gate{min-height:100dvh;display:flex;align-items:center;justify-content:center;padding:var(--lpos-gap,12px);box-sizing:border-box;
  background:radial-gradient(120% 90% at 50% -10%,color-mix(in srgb,var(--lpos-accent,#00D4FF) 7%,var(--lpos-bg,#0A0E17)) 0%,var(--lpos-bg,#0A0E17) 58%);color:var(--lpos-ink,#EAF2FB)}
.lpos-blueprint__gate{display:flex;flex-direction:column;align-items:center;gap:var(--lpos-gap,12px);padding:calc(var(--lpos-panel-pad,12px)*1.5) calc(var(--lpos-panel-pad,12px)*2);text-align:center;max-width:420px}
.lpos-blueprint__gate-msg{margin:0;font-weight:600;font-size:var(--lpos-text-md,17px);line-height:1.4;color:var(--lpos-ink,#EAF2FB)}
/* Phase D 2026-08-09: the -select-open ROW-level position/z-index lift is deleted -- rows are
   display:contents in both console states now, so a row can't be a stacking context any more.
   The flat-grid stage A/B blocks below lift the CELL that hosts the open menu instead. */
/* JD 2026-08-03 (portal-twin, item 3): a hidden-by-default duplicate of the portal switcher rides
   inside the center tab bar (top-center header + both center-feature tabtwins) so it can surface
   there while the RIGHT column is collapsed -- BlueprintRenderer::portal_twin_html(). Hidden at
   rest; the .-right-collapsed console state covers BOTH the right-only rail (top-center header
   twin shows) and the both-collapsed cinematic view (row1's header is display:none there, so only
   the .lpos-feat__tabbar ghost twin -- itself gated on .-left-collapsed.-right-collapsed -- ever
   paints), so the same single selector is correct for every collapse combination. Sized to hug its
   content (the default flex:1 1 auto is right for the topleft cell's 2-child row, wrong here where
   it would shove the tab buttons off to the side). */
[data-lpos-portal-twin]{display:none}
/* JD 2026-08-05 FIX (dup switcher): the twin must show only when the REAL topleft switcher is
   hidden -- that is LEFT-collapsed (menu-only topleft) and both-collapsed (ghost tabbar strip),
   never right-collapsed, where the real one still renders and the twin duplicated it. */
.lpos-blueprint--console.-left-collapsed [data-lpos-portal-twin]{display:flex;align-items:center;flex:0 0 auto}
[data-lpos-portal-twin] .lpos-c-select{flex:0 0 auto}
[data-lpos-portal-twin] .lpos-c-select__value{flex:0 0 auto}
/* USABILITY FIX (review CRITICAL): the popover is absolutely positioned inside the topleft cell,
   and both the cell and its row carry overflow:hidden (the no-scrollbar law) -- so the menu was
   being clipped to zero and the dropdown "did nothing" on screen. While it is open the console
   marks itself -select-open and those two ancestors go overflow:visible for that moment only.
   The same clip-escape is needed for the portal TWIN's two extra homes (item 3): the top-center
   header cell/region (row 1, alongside topleft) and the center-feature tabtwin's cell/region
   (row 2) -- row 2 itself is not covered by the row-1-only rule below it, so it is added here too. */
.lpos-blueprint--console.-select-open .lpos-blueprint__region--topleft,
.lpos-blueprint--console.-select-open .lpos-cell--topleft,
.lpos-blueprint--console.-select-open .lpos-blueprint__region--topcenter,
.lpos-blueprint--console.-select-open .lpos-cell--topcenter,
.lpos-blueprint--console.-select-open .lpos-blueprint__region--midcenter,
.lpos-blueprint--console.-select-open .lpos-cell--midcenter,
.lpos-blueprint--console.-select-open .lpos-feat__tabbar{overflow:visible!important} /* JD 2026-08-02: the REGION between row and cell was a third clipper -- it swallowed the popover below the row band */
.lpos-c-select__option{all:unset;box-sizing:border-box;display:flex;align-items:center;width:100%;padding:var(--lpos-space-sm,8px) var(--lpos-space-md,12px);cursor:pointer;
  /* visual-QA fix (2026-08-03): min-height = tallest logo (brandimg max-height, control-size minus
     space-xs) plus its own top+bottom padding (2x space-sm) -- so a logo row and a text-only row sit
     at the same height instead of the list zig-zagging. */
  min-height:calc(var(--lpos-control-size,46px) + var(--lpos-space-md,12px));
  border-radius:var(--lpos-radius-sm,4px);color:var(--lpos-ink,#EAF2FB);font:500 var(--lpos-text-sm,14px)/1.2 var(--lpos-font-ui,'Inter', ui-sans-serif, system-ui, sans-serif)}
.lpos-c-select__option:hover{background:var(--lpos-accent-soft,color-mix(in srgb, var(--lpos-accent) 10%, transparent))}
/* JD 2026-08-03: real brand options -- a lockup image fills the option like the value logo does;
   an icon-only mark (Commerce Copilot) pairs with the brand name at the standard control scale. */
.lpos-c-select__option{gap:var(--lpos-space-sm,8px)}
/* JD 2026-08-03 (portal switcher): the SEARCH row sits above the first option -- the composer
   search recipe at menu scale; filtering is live in lpos-drawers.js. Explore Portals anchors the
   list with the compass glyph. */
.lpos-c-select__search{display:flex;align-items:center;gap:var(--lpos-space-sm,8px);
  padding:var(--lpos-space-sm,8px) var(--lpos-space-md,12px);
  border-bottom:var(--lpos-border-width,1px) solid color-mix(in srgb,var(--lpos-border-tint,var(--lpos-accent)) var(--lpos-border-alpha-1,30%),transparent)}
.lpos-c-select__search svg{width:var(--lpos-icon-size-xs,20px);height:var(--lpos-icon-size-xs,20px);flex:0 0 auto;color:var(--lpos-muted,#A8B2C7);fill:none;stroke:currentColor}
.lpos-c-select__search input{all:unset;box-sizing:border-box;flex:1 1 auto;min-width:0;
  font:400 var(--lpos-text-sm,14px)/1.2 var(--lpos-font-ui,'Inter', ui-sans-serif, system-ui, sans-serif);color:var(--lpos-ink,#EAF2FB)}
.lpos-c-select__search input::placeholder{color:var(--lpos-muted,#A8B2C7)} /* native input ::placeholder css */
.lpos-c-select__explore svg{width:var(--lpos-icon-size-xs,20px);height:var(--lpos-icon-size-xs,20px);flex:0 0 auto;color:var(--lpos-accent,#00D4FF);fill:none;stroke:currentColor}
.lpos-c-select__explore{border-top:var(--lpos-border-width,1px) solid color-mix(in srgb,var(--lpos-border-tint,var(--lpos-accent)) var(--lpos-border-alpha-1,30%),transparent)}
.lpos-c-select__option[hidden]{display:none} /* the option's own display:flex outranks the UA [hidden] rule -- filtered-out portals must actually disappear */
/* visual-QA fix (2026-08-03): capped BOTH axes -- a wide wordmark (e.g. "The Triad Mind") was
   scaling off the height cap alone and rendering huge/overflowing sideways. max-height keeps the
   existing ~42px cap, max-width:140px stops wide lockups from blowing out the option row, and
   width/height:auto (with object-fit:contain) let the smaller of the two constraints win per image. */
.lpos-c-select__brandimg{max-height:calc(var(--lpos-control-size,46px) - var(--lpos-space-xs,4px));max-width:140px;width:auto;height:auto;object-fit:contain;display:block}
/* JD EXPLICIT 2026-08-04: the SELECTED-portal wordmark (esp. Biolimitless's wide "BIOLIMITLESS"
   lockup) read too small at the base rule's ~42px/140px cap -- overrides ONLY the live
   `.lpos-c-select__value` display (the value pill actually rendered in the topbar switcher; the
   base rule above still governs every OTHER row -- the closed dropdown's option list -- so this
   does not touch the "default"/non-selected sizing per JD's instruction). NOTE: the pre-existing
   `.lpos-c-select .lpos-topbar__logo-img` rule elsewhere in this file targets a DIFFERENT class
   that the current markup's selected-value <img> does not actually carry (only one legacy dropdown
   option row does) -- this is the rule that actually controls what renders in the switcher pill.
   max-width bumped 140px -> 220px (the wide-lockup blowout guard from the base rule's own 2026-08-03
   comment, raised rather than removed) alongside max-height 42px -> ~54px so a wide wordmark like
   Biolimitless's clears the height step instead of being width-clamped back down under it; the
   value pill's own `overflow:hidden` (`.lpos-c-select__value` rule above) remains the hard backstop
   against any lockup wider than the available pill width. SIZE FROZEN again at these values unless
   JD says otherwise. */
.lpos-c-select__value .lpos-c-select__brandimg{max-height:calc(var(--lpos-control-size,46px) + var(--lpos-space-sm,8px));max-width:220px}
.lpos-c-select__brandmark{width:var(--lpos-icon-size,26px);height:var(--lpos-icon-size,26px);flex:0 0 auto}
.lpos-c-select__brandname{font:600 var(--lpos-text-sm,14px)/1.2 var(--lpos-font-ui,'Inter', ui-sans-serif, system-ui, sans-serif);color:var(--lpos-ink,#EAF2FB);white-space:nowrap}
.lpos-c-select__option:focus-visible{outline:none;box-shadow:var(--lpos-focus-ring,0 0 0 2px rgba(0,212,255,.9),0 0 12px rgba(0,212,255,.6))} /* review fix: all:unset stripped the UA outline, leaving dropdown options with NO visible focus (WCAG 2.4.7) */
.lpos-c-select__option.-selected{background:var(--lpos-glass-2,rgba(255,255,255,0.055))}
/* centerfeature Tab Tool Bar (restored): content-sized and pinned to the left edge of the column
   cell it's the first child of -- without align-self it would stretch to the cell's full width
   like the title panel below it does, which reads as a second title bar, not a compact tool cluster.
   Middle-row exception (item 3): reverts the base .lpos-c-subpanel's chrome-row 4px/8px padding
   back to a uniform var(--lpos-subpanel-pad,6px) -- this is the one middle-row (midcenter) user of
   the shared .lpos-c-subpanel class, and middle-row sub-panels keep the symmetric inset. */
.lpos-c-subpanel--tabbar{align-self:stretch;width:100%;padding:var(--lpos-subpanel-pad,6px)} /* JD: tab toolbar spans full width like the title panel below it */
/* JD 2026-08-01 (midright parity): the flip glue relocates the tools bar + pagination OUT of the
   document panel to be the midleft cell's own panels. The .lpos-media scope no longer matches them,
   so their styling lives here: the tools bar re-declares the --lpm-* chain its buttons consume
   (same IACVT guard as the extbar-wrap precedent), neutralizes the shared __bar order:2/overlay
   leftovers, and distributes its buttons; the pagination becomes a full-width panel keeping JD's
   locked 2.6/4.8/2.6 shares + edge-aligned glyphs. */
.lpos-blueprint .lpos-cell--midleft .lpos-media__bar--above{
  --lpm-btn: var(--lpos-panel-hover, rgba(0,212,255,.10));
  --lpm-txt: var(--lpos-ink, #EAF2FB);
  --lpm-accent: var(--lpos-accent, #00D4FF);
  --lpm-ctl: var(--lpos-radius-control, 8px);
  position:static;order:0;z-index:auto;flex-wrap:wrap;justify-content:center}
.lpos-blueprint .lpos-cell--midleft .lpos-media__bar--above button,
.lpos-blueprint .lpos-cell--midleft .lpos-media__bar--above a{flex:1 1 0;width:auto;min-width:0}
/* (JD follow-up: the flip pagination stays INSIDE the document panel -- the outside-pagination
   rules that lived here were removed same day; the .lpos-media.-flip scoped rules govern it.) */

/* search (A3: ONE bar, ONE inline SVG magnifier, inside its own token-styled box). HUD audit
   deviation #3: the inset was doubled (cell pad 14 + component pad 14 = 28) vs the hamburger's
   single 14 -- horizontal padding now reads --lpos-subpanel-pad instead of stacking panel-pad. */
/* JD 2026-08-01 review loop: the input itself was a bare text line (~22px) floating inside the 46px
   bar -- it now FILLS the bar. The bar's inset is a uniform var(--lpos-subpanel-pad,6px) on all four
   sides -- the same breathing the tabbar's icon buttons get inside their sub-panel -- and the input
   stretches to the full remaining height/width. Idle it stays chrome-less (one box, not box-in-box);
   on focus it lights up as its own glass control inside the bar. */
.lpos-search{flex:1 1 auto;display:flex;align-items:stretch;gap:var(--lpos-space-sm,8px);height:var(--lpos-control-size,46px);padding:var(--lpos-subpanel-pad,6px);
  background:var(--lpos-glass-panel);-webkit-backdrop-filter:var(--lpos-blur-sm);backdrop-filter:var(--lpos-blur-sm);
  border:var(--lpos-border-width,1px) solid color-mix(in srgb,var(--lpos-border-tint,var(--lpos-accent)) var(--lpos-border-alpha-2,40%),transparent);border-radius:var(--lpos-radius-control,8px);box-sizing:border-box;overflow:hidden}
.lpos-search input{flex:1;min-width:0;box-sizing:border-box;background:transparent;outline:0;color:var(--lpos-ink);font:500 .95rem/1 var(--lpos-font-ui,'Inter', ui-sans-serif, system-ui, sans-serif);
  padding:0 var(--lpos-space-sm,8px);border-radius:var(--lpos-radius-sm,4px);border:var(--lpos-border-width,1px) solid transparent;
  transition:background-color var(--lpos-duration-fast,120ms) var(--lpos-ease-tech,cubic-bezier(0.16, 1, 0.3, 1)),border-color var(--lpos-duration-fast,120ms) var(--lpos-ease-tech,cubic-bezier(0.16, 1, 0.3, 1))}
.lpos-search input:focus{background:var(--lpos-glass-2,rgba(255,255,255,0.055));border-color:color-mix(in srgb,var(--lpos-border-tint,var(--lpos-accent)) var(--lpos-border-alpha-2,40%),transparent)}
.lpos-search svg{width:var(--lpos-icon-size-xs,20px);height:var(--lpos-icon-size-xs,20px);flex:0 0 auto;align-self:center;color:var(--lpos-muted);fill:none!important;stroke:currentColor}

/* media fill (flipbook/3D): title stacked over media, media fills the remaining height */
.lpos-col{display:flex;flex-direction:column;gap:var(--lpos-gap,12px);height:100%;min-height:0;overflow:hidden}
.lpos-col__media{flex:1 1 auto;min-height:0;display:flex;overflow:hidden}
.lpos-col__media>.lpos-media{width:100%;height:100%!important}
/* middle-center featured: title panel (back + titles + pager) over the video */
.lpos-feat__titles h2{font-size:var(--lpos-title-size,1.5rem)!important;line-height:1.2!important;margin:0!important;color:var(--lpos-ink)!important;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis} /* JD 2026-08-01: the 4-digit pager reserves real width -- the title stays ONE line and ellipsizes instead of wrapping past the title-bar budget */
/* JD 2026-08-01 review loop: the video is a REAL 16:9 now, not a fill-the-column stretch -- the
   body hugs the video's aspect height and the new empty .lpos-feat__spare panel below absorbs
   whatever the column has left (flex:1). max-height guard keeps the pair inside the column on
   short viewports (video shrinks first, spare can hit 0 without violating the no-clip law). */
/* JD 2026-08-01 (slim-columns pass): the video keeps a TRUE ratio in every width -- when the
   column's height is the binding constraint the media goes HEIGHT-driven and centres, instead of
   stretching to the column width (which produced a 1.97 box). The text panel below never loses
   its content height (flex:0 0 auto there), so copy can't clip; the video absorbs the change. */
/* SPACING AUDIT (JD 2026-08-04, video-top-gap fix): align-items:center here was the root cause of
   the "video-top-gap inconsistency" the finalization team could not pin down -- centering the
   video vertically inside this flex box means the visible gap ABOVE the video is HALF of whatever
   slack exists between the rendered video height and the body's own available height, which
   varies with viewport/aspect/panel state (measured 46px in one render, ~9px in another, same
   markup). flex-start makes the gap a CONSTANT (this panel's own padding-top, --lpos-space-sm
   below), never centering slack -- any leftover vertical room now falls below the video instead
   of splitting unevenly above and below it. */
/* JD 2026-08-05 (alignment law): ZERO padding on this chromeless wrapper -- its 8px top pad pushed
   the video panel below the midleft/midright panel tops. The cell's token pad is the ONE inset. */
.lpos-feat__body{flex:1 1 auto;min-height:0;display:flex;align-items:flex-start;justify-content:center;overflow:hidden}
/* GLASS LOADING BAR (2026-08-04, JD): replaces a plain top-aligned "Loading..." text line with a
   futuristic, token-driven, translucent brand-tint glass bar CENTERED on both axes within whatever
   panel is loading -- lpos-drawers.js's setCenterMessage() emits this markup for the loading state
   only (honest-empty "Nothing here yet"/error text is untouched, different law). The `-loading`
   modifier overrides the base rule's flex-start (real video content wants a fixed top offset; the
   loader wants to sit dead-center in the panel it's loading into) without touching the base rule
   used by every other .lpos-feat__body consumer. Reusable per the panel-component-system law --
   `.lpos-c-loading` is a bare, unscoped component class so any loading region (mid-right/mid-left
   swap, archive grid, media host) can drop it in identically. */
.lpos-feat__body.-loading{align-items:center}
.lpos-c-loading{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:var(--lpos-space-sm,8px);width:100%;height:100%;min-height:0}
.lpos-c-loading__bar{position:relative;width:min(220px,70%);height:10px;border-radius:var(--lpos-radius-control,8px);overflow:hidden;
  background:var(--lpos-glass-panel,linear-gradient(180deg, rgba(30,42,66,0.34), rgba(16,24,40,0.45)));-webkit-backdrop-filter:var(--lpos-blur-md,blur(16px) saturate(140%));backdrop-filter:var(--lpos-blur-md,blur(16px) saturate(140%));
  border:var(--lpos-border-width,1px) solid color-mix(in srgb,var(--lpos-border-tint,var(--lpos-accent)) var(--lpos-border-alpha-2,40%),transparent);
  }
.lpos-c-loading__fill{position:absolute;inset:0;width:40%;border-radius:inherit;
  background:var(--lpos-accent-glass-strong,color-mix(in srgb,var(--lpos-accent) 46%,transparent));
  animation:lpos-c-loading-sweep var(--lpos-duration-loading,1.4s) ease-in-out infinite}
@keyframes lpos-c-loading-sweep{0%{transform:translateX(-100%)}100%{transform:translateX(350%)}}
.lpos-c-loading__label{margin:0;font:600 var(--lpos-text-sm,14px)/1 var(--lpos-font-ui,'Inter', ui-sans-serif, system-ui, sans-serif);color:var(--lpos-muted,#A8B2C7);letter-spacing:.03em}
@media (prefers-reduced-motion:reduce){.lpos-c-loading__fill{animation:none;width:46%;left:27%}}
/* JD 2026-08-01: the video panel is always FULL WIDTH of its container (width-driven 16:9); when
   the column is too short for that height the panel caps and the STAGE inside keeps the true
   ratio (letterboxing internally) -- liquid at every width, never a stretched video. */
.lpos-feat__body>.lpos-media{width:100%!important;height:auto!important;aspect-ratio:var(--lpm-aspect,16/9);max-height:100%}
.lpos-feat__body>.lpos-media .lpos-media__stagev{width:auto;max-width:100%;max-height:100%;margin-inline:auto} /* width:auto lets the stage's own aspect-ratio hold when the height caps (base rule pins width:100%, which broke the ratio) */
/* JD 2026-08-01 (final): the text panel below the video = TITLE (primary scale) + subtitle +
   content copy in one sub-panel (the standalone title bar is gone) -- column layout on the shared
   sub-panel chrome; typography mirrors the old feat__titles scales on the shared tokens. */
/* Spacing pattern (JD 2026-08-01 consistency pass): TEXT panels carry the title-panel component
   inset (space-md 12px, same as every .lpos-c-title-panel instance), one space-sm (8px) rhythm
   step between blocks, and the title/subtitle pair pulled one step tighter (net space-xs 4px) --
   the same two-tier rhythm the rest of the console uses. */
/* JD 2026-08-01 (second pass): airier vertical rhythm -- space-md (12px) between blocks, lead
   paragraph emphasized in ink (rest stay muted), roomier 1.6 copy line-height. */
/* (task #9, 2026-08-05: ALL .lpos-feat__spare/.lpos-feat__titlerow rules DELETED -- the renderer
   deleted those elements in the 2026-08-04 ONE-PANEL pass; the rules were pure dead weight, and
   the spare block's reserved padding was part of the "dead pager gap" the spec section 2 flags.
   The description copy now lives in .lpos-feat__copy (a real .lpos-c-panel, law-styled). */
/* (2026-08-01, superseded same day: the transport moved into the video's in-player hover bar --
   the .lpos-feat__controls panel is gone and the spare panel below reclaims its height.) */
/* pagination component (right of the title).
   JD 2026-08-01 review loop: the page-count is now ONE chromed component -- the editable current-page
   input plus a muted "/ total" together inside a single control-height glass box (the old treatment
   floated "/ total" as bare text beside a chromed input, which read out of place). This base is
   SHARED verbatim by the flipbook's pagination bar (media.php only adds its wide flex shares and
   pill-edge alignment on top -- same component, different width budget, per JD's one-component law). */
/* CENTER dynamic action button (JD 2026-08-04, relocation item 2) -- fills the title-row slot the
   chevron pager used to occupy. FIXED SIZE regardless of label length: min-width (not width), so a
   longer future label ("Add to Cart") never resizes the control, only its own text may ellipsis.
   Same control-radius-rectangle/no-pills family as .lpos-c-cta__buy. */
/* GLASSMORPHISM LAW (2026-08-04, JD): this is a featured/primary button -- flat accent fill ->
   --lpos-accent-glass-strong. Text moves from --lpos-bg (which only worked as dark-on-bright-SOLID)
   to --lpos-ink: the glass fill resolves to roughly #321F70 over the app bg for this tenant, where
   ink measures 11.9:1 but the accent itself measures under 2:1 (unreadable). Light-on-dark-glass is
   the only pairing that satisfies BOTH the glass law and legibility. */
.lpos-c-next-action{all:unset;box-sizing:border-box;cursor:pointer;flex:0 0 auto;
  min-width:calc(var(--lpos-control-size,46px)*2.2);min-height:var(--lpos-control-size,46px);
  display:flex;align-items:center;justify-content:center;
  padding:0 var(--lpos-space-md,12px);
  background:var(--lpos-accent-glass-strong,color-mix(in srgb,var(--lpos-accent) 46%,transparent));color:var(--lpos-ink,#EAF2FB);
  font:700 var(--lpos-text-sm,14px)/1 var(--lpos-font-ui,'Inter', ui-sans-serif, system-ui, sans-serif);
  border-radius:var(--lpos-radius-control,8px);border:var(--lpos-border-width,1px) solid var(--lpos-accent);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
  transition:box-shadow var(--lpos-duration-fast,120ms) var(--lpos-ease-tech,cubic-bezier(0.16, 1, 0.3, 1)),transform var(--lpos-duration-fast,120ms) var(--lpos-ease-tech,cubic-bezier(0.16, 1, 0.3, 1))}
.lpos-pagination{flex:0 0 auto;display:flex;align-items:center;gap:var(--lpos-space-sm,8px)}
.lpos-pagination__count{display:inline-flex;align-items:center;justify-content:center;gap:var(--lpos-space-sm,8px);box-sizing:border-box;white-space:nowrap;
  height:var(--lpos-control-size,46px);padding:0 var(--lpos-space-sm,8px);
  background:var(--lpos-glass-2,rgba(255,255,255,0.055));
  border:var(--lpos-border-width,1px) solid color-mix(in srgb,var(--lpos-border-tint,var(--lpos-accent)) var(--lpos-border-alpha-2,40%),transparent);
  border-radius:var(--lpos-radius-control,8px);
  color:var(--lpos-muted);font:600 var(--lpos-text-md,17px)/1 var(--lpos-font-ui,'Inter', ui-sans-serif, system-ui, sans-serif)}
/* JD 2026-08-01: the editable current-page half carries its OWN hairline box inside the count pill
   (says "editable" at a glance) -- same inset-control recipe as the search input inside its bar:
   control-size minus 2*space-sm tall (30px), radius-sm, accent hairline. Gap between input, "/" and
   total is one even space-sm step. */
/* JD 2026-08-01: BOTH number slots sized to hold up to 4 digits -- the input's border-box width
   reserves exactly 4ch of content (padding + border added on top), and the total reserves a 4ch
   minimum so the box never jumps as counts grow. */
.lpos-pagination__jump{all:unset;box-sizing:border-box;display:inline-flex;align-items:center;justify-content:center;
  width:calc(4ch + 2*var(--lpos-space-xs,4px) + 2*var(--lpos-border-width,1px));text-align:center;padding:0 var(--lpos-space-xs,4px);
  height:calc(var(--lpos-control-size,46px) - 2*var(--lpos-space-sm,8px));
  border:var(--lpos-border-width,1px) solid color-mix(in srgb,var(--lpos-border-tint,var(--lpos-accent)) var(--lpos-border-alpha-2,40%),transparent);
  border-radius:var(--lpos-radius-sm,4px);
  color:var(--lpos-ink,#EAF2FB);font:700 var(--lpos-text-md,17px)/1 var(--lpos-font-ui,'Inter', ui-sans-serif, system-ui, sans-serif);cursor:text}
.lpos-pagination__jump:focus-visible{outline:none;box-shadow:var(--lpos-focus-ring,0 0 0 2px rgba(0,212,255,.9),0 0 12px rgba(0,212,255,.6))}
.lpos-pagination__sep{color:var(--lpos-muted,#A8B2C7)}
.lpos-pagination__tot{color:var(--lpos-muted,#A8B2C7);font:600 var(--lpos-text-md,17px)/1 var(--lpos-font-ui,'Inter', ui-sans-serif, system-ui, sans-serif);
  display:inline-flex;align-items:center;justify-content:center;min-width:4ch} /* JD 2026-08-01: reserves 4-digit capacity, centered */
/* JD 2026-08-01: the CENTER pager's number holder gets extra width -- panel-pad side padding instead
   of the shared space-sm (flipbook keeps the compact base; its width comes from the flex share). */
/* flipbook pagination bar (media.php lpos_dm_flip_glue_js(), `.lpos-pagination.lpos-c-subpanel
   .lpos-media__bar--below`) is a KEPT panel (item 2) sitting in a middle-row cell (midleft) --
   reverts the base .lpos-c-subpanel's chrome-row 4px/8px padding back to a uniform
   var(--lpos-subpanel-pad,6px), same middle-row exception as .lpos-c-subpanel--tabbar above. The
   centerfeature pager (bare .lpos-pagination, no .lpos-c-subpanel class) is untouched by this rule. */
.lpos-pagination.lpos-c-subpanel{padding:var(--lpos-subpanel-pad,6px)}
/* switchers (bottom-left assets / bottom-right views): one cluster sub-panel (A8) around real
   image thumbnails sized as thumbnails, not icon tiles (A7) -- neutral glass background, not
   the accent-tinted --lpos-panel-hover surface color the old grid-icon buttons used. */
.lpos-switch{display:flex;align-items:stretch;justify-content:space-between;gap:var(--lpos-space-sm,8px);flex-wrap:nowrap;width:100%;min-width:0} /* JD 2026-08-01: fixed-ratio thumbs DISTRIBUTE across the panel; the tighter 8px step between TILES (they are one strip, not separate panels) buys each tile more width -> taller at 16:9 */
/* bottom-right view switcher (#5): even gaps (uniform --lpos-gap above), grouped/centered as a
   unit rather than pinned to the edge -- matches the uniform icon-btn sizing from #3. */
/* JD 2026-08-01 review loop: the top-right, bottom-right and mid-right button rows DISTRIBUTE their
   width like the botleft thumbnails -- the buttons themselves widen to share the full row, glyphs
   stay centered (the registry's own justify-content:center). The ComponentStyles registry emits
   .lpos-c-icon-btn width:46px with !important, so width:auto!important + higher specificity is
   required here (same precedent as the flipbook's navwide pills). Height is untouched (46px). */
/* (Phase 3: dead topright-cluster sizing rule deleted -- wrapper gone from markup.) */
/* batch 18 fix: the botright selector is scoped to the CLUSTER's buttons -- the bare POWER cell
   child must keep its fixed 46px square (it was being stretched by the cell-wide selector). */
/* RESPONSIVE AUDIT FIX (CRITICAL): distributed buttons may GROW to share the row but must never
   shrink below the control size -- without a floor they degraded to 2-20px (unclickable, under
   the WCAG 2.5.8 24px target minimum) on tablet/phone widths in the default open state. */
.lpos-blueprint .lpos-cell--topright .lpos-c-icon-btn,
.lpos-blueprint .lpos-cell--botright .lpos-c-icon-btn:not([data-lpos-collapse]),
.lpos-blueprint .lpos-cell--midright .lpos-c-subpanel--tabbar .lpos-c-icon-btn{flex:1 1 auto!important;width:auto!important;min-width:var(--lpos-control-size,46px)!important} /* Phase 3: botright selector re-scoped -- the .lpos-switch wrapper is gone from the markup; :not([data-lpos-collapse]) keeps the corner toggle at its fixed square (the old batch-18 exclusion) */
/* JD 2026-08-01: each thumbnail is its OWN Component Panel (glass + border + subpanel pad), nested
   directly in the botleft Display Panel -- the group wrapper carries no chrome (cluster unwrap). */
/* task #11 (JD APPROVED 2026-08-05, EXACT_SPEC section 7): the SHOP thumbnail (.lpos-c-thumb) is
   canonical -- the media-switcher tiles now carry the EXACT same constants (square thumb-ratio,
   same flex sizing, same pad/chrome/radius/transition). One thumbnail style everywhere; only the
   collapsed-rail 46px icon-square override (rail context law) remains distinct. */
.lpos-switch__thumb{all:unset;box-sizing:border-box;position:relative;cursor:pointer;overflow:hidden;
  flex:1 1 calc(20% - var(--lpos-space-sm,8px));min-width:64px;max-width:calc(var(--lpos-thumb-h,56px)*1.6);
  aspect-ratio:var(--lpos-thumb-ratio,1/1);align-self:center;
  display:flex;align-items:center;justify-content:center;
  padding:var(--lpos-space-xs,4px);
  background:var(--lpos-glass-panel,linear-gradient(180deg, rgba(30,42,66,0.34), rgba(16,24,40,0.45)));-webkit-backdrop-filter:var(--lpos-blur-sm);backdrop-filter:var(--lpos-blur-sm);
  border:var(--lpos-border-width,1px) solid color-mix(in srgb,var(--lpos-border-tint,var(--lpos-accent)) var(--lpos-border-alpha-2,40%),transparent);border-radius:var(--lpos-radius-control,8px);
  color:var(--lpos-muted);
  transition:border-color var(--lpos-duration-fast,120ms) var(--lpos-ease-tech,cubic-bezier(0.16, 1, 0.3, 1)),box-shadow var(--lpos-duration-fast,120ms) var(--lpos-ease-tech,cubic-bezier(0.16, 1, 0.3, 1))}
/* JD: the botleft GROUP wrapper carries no chrome -- each thumbnail is the Component Panel now */
/* JD 2026-08-01 batch 17: the botleft cluster-unchrome rule is retired -- the thumbnails moved to
   the MIDLEFT column where their .lpos-c-subpanel--cluster wrapper keeps full panel chrome (JD:
   "their own panel", same treatment as the tools bar above the document). */
.lpos-switch__thumb:hover{border-color:var(--lpos-accent);color:var(--lpos-ink);} /* task #11: same hover as the canonical .lpos-c-thumb */
/* JD 2026-08-04: the SELECTED thumb gets the SAME accent ring as the canonical shop thumbnail
   (.lpos-c-thumb.is-active) -- lpos-drawers.js sets aria-pressed=true on the active thumb. */
.lpos-switch__thumb[aria-pressed="true"]{border-color:var(--lpos-accent);box-shadow:0 0 0 2px var(--lpos-accent),var(--lpos-accent-glow-sm,0 0 12px rgba(0,212,255,.55))}
/* JD 2026-08-03: the ADD (plus) square rides the right end of the thumb strip at its fixed
   control size -- it never joins the thumbs' flexible 16:9 distribution. */
.lpos-switch [data-lpos-switch-add]{flex:0 0 auto;align-self:center}
.lpos-switch__thumb{position:relative} /* anchors the fill below */
.lpos-switch__thumb img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;display:block; /* JD 2026-08-01 BUG FIX: percentage height cannot resolve against an aspect-ratio-sized box (the rail thumbs rendered a 16px image inside a 26px tile -- "collapsed improperly"); absolute inset fills reliably in every state */
  border-radius:calc(var(--lpos-radius-control,8px) - var(--lpos-space-xs,4px))} /* JD: image corners match the thumb panel's inner radius */
.lpos-switch__thumb svg{width:28%;height:28%;max-width:var(--lpos-icon-size-sm,24px);max-height:var(--lpos-icon-size-sm,24px);fill:none!important;stroke:currentColor}
/* JD 2026-08-06 THUMB STRIP STRETCH + TYPE BADGE: thumbs distribute the strip width evenly, the
   SAME adaptive-stretch law as .lpos-drawer__tabs .lpos-c-icon-btn and .lpos-feat__toolbar
   .lpos-c-icon-btn -- height keeps coming from the base rule's aspect-ratio above, untouched here. */
.lpos-blueprint .lpos-switch .lpos-switch__thumb{
  /* JD 2026-08-06: the canonical thumb's 1/1 ratio AND its 1.6x max-width cap held 3 thumbs at
     90px in a 380px strip -- in the STRIP the thumbs distribute the full width (rail squares
     keep their ratio via their own re-assert). Height keeps the control-derived scale. */
  aspect-ratio:auto!important;max-width:none!important;
  height:calc(2*var(--lpos-control-size,46px) - 2*var(--lpos-border-width,1px));
  flex:1 1 0!important;width:auto!important;min-width:var(--lpos-control-size,46px);
  position:relative}
/* rail-scoped re-assert: the collapsed rail keeps its fixed 46px square, never joins the stretch */
.lpos-blueprint .lpos-rail .lpos-switch__thumb{
  flex:0 0 auto!important;width:var(--lpos-control-size,46px)!important;
  min-width:var(--lpos-control-size,46px)!important}
/* the type badge (PHP-rendered <span class="lpos-switch__thumb-badge"> after the optional preview
   img): ONE-PANEL chrome, centered over the thumb, clicks pass through to the button beneath. */
.lpos-blueprint .lpos-switch__thumb-badge{
  position:absolute;inset:0;margin:auto;pointer-events:none;
  /* JD 2026-08-06: FULL control-size chip -- at 30px the 16px radius token read as a circle,
     off-system; at 46px it is the standard rounded-square icon-button silhouette. */
  width:var(--lpos-control-size,46px);
  height:var(--lpos-control-size,46px);
  display:inline-flex;align-items:center;justify-content:center;
  background:var(--lpos-glass-panel);-webkit-backdrop-filter:var(--lpos-blur-md);backdrop-filter:var(--lpos-blur-md);
  border:var(--lpos-border-width,1px) solid color-mix(in srgb,var(--lpos-border-tint,var(--lpos-accent)) var(--lpos-border-alpha-2,40%),transparent);
  border-radius:var(--lpos-radius-panel,10px);color:var(--lpos-muted)}
.lpos-blueprint .lpos-switch__thumb-badge svg{
  width:var(--lpos-icon-size-sm,24px);height:var(--lpos-icon-size-sm,24px);fill:none!important;stroke:currentColor}
/* bottom-center detached controls: [lpos_video_controls] (media.php, not editable here) renders a
   bare `.lpos-media__bar[data-extbar]` with no panel chrome of its own (its base rule in media.php
   is transparent/borderless by design, since it normally lives INSIDE an already-panelled player).
   Reconciliation pass (item 1): JD wants this rendered WITHOUT a glass-box group wrapper -- the
   detached control buttons (their own chrome comes from media.php's `.lpos-media__bar button/a`
   rule, including the extbar --lpm-* token-bridge fix, both untouched) sit directly in the botcenter
   Display Panel. No panel box added here any more; the cell's own var(--lpos-space-sm,8px) vertical
   inset (see the cell padding block above) is this bar's only inset -- nothing of its own stacked
   on top, so it never touches the cell's border either. */
.lpos-blueprint .lpos-cell--botcenter .lpos-media__bar{
  background:transparent!important;-webkit-backdrop-filter:none;backdrop-filter:none;
  box-shadow:none;border:0!important;border-radius:0!important;padding:0!important;
}
.lpos-media__extbar-wrap{width:100%;display:flex;justify-content:center}
.lpos-media__extbar{width:100%;justify-content:center} /* sweep fix: transport group CENTERED in the botcenter panel (flex-start left it hugging the edge) */
/* (JD 2026-08-01 final: the detached-extbar distributed-transport rules that lived here are
   RETIRED with the wide-pill styling -- transport renders as standard 46px icon buttons inside
   the video facebar now; any legacy [lpos_video_controls] falls back to standard buttons.) */
/* top-right action cluster + bottom-right view switcher (item 1): JD wants both rendered WITHOUT a
   glass-box group wrapper -- the individual 46px .lpos-c-icon-btn / .lpos-switch__thumb chrome
   (ComponentStyles.php icon-btn key, and .lpos-switch__thumb above) is untouched; only the
   .lpos-c-subpanel--cluster box these two specific clusters sit inside goes transparent. Scoped by
   cell so the identical `.lpos-c-subpanel--cluster` class used by the (unaffected, still-panelled)
   midleft thumbnail switcher (batch 17 home) and the midcenter tabbar keeps its normal chrome. Cell padding (space-sm, above)
   is this cluster's only inset -- 0 of its own, matching the botcenter bar treatment above. */
/* 2026-08-01: JD wants both clusters DISTRIBUTED across the panel's full width, not a centered
   fixed-gap group -- width:100% (topright's cluster was flex:0 0 auto/content-sized via the base
   .lpos-c-subpanel--cluster rule; botright's is already 100% via .lpos-switch, re-declared here so
   both read identically) + justify-content:space-evenly (equal space at both edges AND between every
   button, reading as "spread across the panel" rather than "space-between" pinning the end buttons
   flush to the cell's padding edge). Specificity here (3 classes) beats both the base
   .lpos-c-subpanel--cluster flex:0 0 auto/center-via-parent and botright's own .lpos-switch--icons
   center, so one rule governs the distribution for both panels identically. */
/* (Phase 3: the topright/botright cluster ghost+distribution block is deleted -- those wrapper divs
   no longer exist in the markup; the buttons sit directly in their bar cells and the grow rule above
   distributes them.) */
/* icon buttons inside any cell/sub-panel: fixed square + outline svg (guard global svg{fill}).
   `.lpos-media` is included alongside `.lpos-cell` so the flipbook's Pagination component (media.php
   DCS-flip2, emits the exact same .lpos-c-icon-btn class) is governed by this ONE rule too -- no
   second copy of the icon-button recipe anywhere else, per the atomic-component law. */
/* The four Component roots get the SAME button, one rule, further down -- see COMPONENT ICON
   BUTTON at the end of this file (JD 2026-08-10: "make all four match"). */
.lpos-cell .lpos-c-icon-btn,.lpos-media .lpos-c-icon-btn{cursor:pointer;color:var(--lpos-muted);width:var(--lpos-control-size,46px)!important;height:var(--lpos-control-size,46px)!important;flex:0 0 auto!important;padding:0!important;transition:color var(--lpos-duration-fast,120ms),background var(--lpos-duration-fast,120ms),border-color var(--lpos-duration-fast,120ms),box-shadow var(--lpos-duration-fast,120ms)}
/* JD bug-batch 2026-08-01 (bottom-right icon buttons, uneven vertical centering): display:block on
   the glyph -- an SVG's UA-default display is inline, which reserves a few px of baseline
   "phantom whitespace" below it inside any non-flex ancestor; that asymmetric slack is a common
   cause of "more space below than above" for an icon that otherwise looks centered. Belt-and-braces
   alongside the cell's own align-items:center (above). */
.lpos-cell .lpos-c-icon-btn svg,.lpos-media .lpos-c-icon-btn svg{width:var(--lpos-icon-size,26px)!important;height:var(--lpos-icon-size,26px)!important;flex:0 0 auto!important;display:block;color:inherit;fill:none!important;stroke:currentColor}
.lpos-cell .lpos-c-icon-btn:hover,.lpos-media .lpos-c-icon-btn:hover{color:var(--lpos-ink);border-color:var(--lpos-accent);background:var(--lpos-accent-soft,color-mix(in srgb, var(--lpos-accent) 10%, transparent))}
.lpos-cell .lpos-c-icon-btn:active,.lpos-media .lpos-c-icon-btn:active{}
.lpos-cell .lpos-c-icon-btn:focus-visible,.lpos-media .lpos-c-icon-btn:focus-visible,.lpos-blueprint .lpos-search input:focus-visible,.lpos-blueprint .lpos-switch__thumb:focus-visible{outline:none;box-shadow:var(--lpos-focus-ring,0 0 0 2px rgba(0,212,255,.9),0 0 12px rgba(0,212,255,.6))}
/* COLLAPSED-BUTTON REVEAL, Layer A (JD 2026-08-03, COLLAPSED_BUTTON_CONTENT_DISPLAY_SPEC §4.1) --
   ports the proven dashboard-layout.css:239-262 tooltip idea into THIS stylesheet (the console
   blueprint never loaded that file) and closes its keyboard gap by also firing on :focus-visible,
   not just :hover. Reads the SAME string icon_btn()/tabbar_buttons() already put in aria-label --
   zero new PHP data, just the new `title="..."` attribute those two builders now also emit.
   Every var() fallback below is that token's canon :where(:root) value (token law). */
.lpos-c-icon-btn[title]{position:relative}
.lpos-c-icon-btn[title]:hover::after,
.lpos-c-icon-btn[title]:focus-visible::after{
  content:attr(title);position:absolute;top:50%;transform:translateY(-50%);left:calc(100% + var(--lpos-space-sm,8px));
  padding:var(--lpos-space-xs,4px) var(--lpos-space-sm,8px);
  font:600 11px/1.2 var(--lpos-font-ui,'Inter', ui-sans-serif, system-ui, sans-serif);white-space:nowrap;color:var(--lpos-ink,#EAF2FB);
  background:color-mix(in srgb,var(--lpos-bg,#0A0E17) 97%,transparent);
  -webkit-backdrop-filter:var(--lpos-blur-md,blur(16px) saturate(140%));backdrop-filter:var(--lpos-blur-md,blur(16px) saturate(140%));
  border:var(--lpos-border-width,1px) solid color-mix(in srgb,var(--lpos-accent,#00D4FF) var(--lpos-border-alpha-3,55%),transparent);
  border-radius:var(--lpos-radius-sm,4px);
  z-index:var(--lpos-z-drawer,9000);pointer-events:none}
/* Right-side rail clusters (botright + its collapsed twins) flip the tooltip to the LEFT of the
   icon so it never runs off the right edge of the viewport. */
.lpos-cell--botright .lpos-c-icon-btn[title]:hover::after,
.lpos-cell--botright .lpos-c-icon-btn[title]:focus-visible::after,
.lpos-rail-topset .lpos-c-icon-btn[title]:hover::after,.lpos-rail-topset .lpos-c-icon-btn[title]:focus-visible::after,
.lpos-rail-botset .lpos-c-icon-btn[title]:hover::after,.lpos-rail-botset .lpos-c-icon-btn[title]:focus-visible::after{
  left:auto;right:calc(100% + var(--lpos-space-sm,8px))}
@media (prefers-reduced-motion:reduce){.lpos-c-icon-btn[title]::after{transition:none}}
/* account button (A4): the real avatar photo fills the same square icon-btn shape; the
   person-glyph SVG fallback is plain markup from PHP when logged out / no avatar, so no CSS
   branch is needed here -- just size+round whichever child (img or svg) is actually present. */
.lpos-c-icon-btn--avatar{padding:0!important;overflow:hidden!important}
/* JD 2026-08-01: the profile image COVERS the whole button like the botleft thumbnails cover their
   tiles -- full-bleed inside the button chrome, corners matched to the button's inner radius
   (same recipe as .lpos-switch__thumb img).
   JD 2026-08-05 FIX: img radius = inherit (was a smaller control-radius, so the square corners poked
   past the button's 16px panel radius) + overflow:hidden on the button clips it cleanly in every state. */
.lpos-c-icon-btn--avatar .lpos-c-avatar{width:100%!important;height:100%!important;object-fit:cover;display:block;
  border-radius:inherit}
/* near-subliminal grid overlay (sheet: grid-overlay) -- behind the row content, never intercepts clicks */
.lpos-blueprint--console,.lpos-blueprint--magick8{position:relative;isolation:isolate} /* JD 2026-08-03: stacking context so the z-index:-1 bg-video + grid layers paint ABOVE the console's own background instead of behind it; magick8 joined 2026-08-06 (same requirement, no rows to stack above) */
/* ---- JD 2026-08-01: RIGHT-COLUMN COLLAPSE (crosshair toggle, lpos-drawers.js) ----
   Closed: the whole layout reflows to TWO content columns + a narrow 64px rail. The midright panel
   hides; left + center absorb the freed width (1:2.08 keeps the open-state column ratio); the
   top-right buttons become a VERTICAL list pinned down the viewport's right edge (absolute rail
   anchored to the console root's padding box), vertically inline with the crosshair, which stays
   alone in the bottom-right corner as the reopen toggle. */
/* JD 2026-08-01: the TOP row is the exception -- the topleft panel HOLDS its open width (the
   row-emitted --lpos-leftcol-w, derived from the shape's fr ratio) and only the tab bar (center)
   absorbs the freed space; mirrored for the right when the LEFT collapses. Both-collapsed row1
   overrides both sides to rails (declared after, higher specificity). */
/* JD 2026-08-01 (gap fix): with the right rail living only in the MIDDLE band, the top + bottom
   rows drop the 64px third track entirely -- the top-center (and bottom search row) run to the
   right edge with no orphan gap. The topright region display:nones (last region, placement-safe);
   the botright region can NOT display:none (it hosts the rail cluster) so it leaves the flow as a
   full-size transparent anchor instead (rail offsets unchanged, clicks pass through elsewhere). */
/* JD 2026-08-01 (rail-to-top): row1 KEEPS its 64px right track -- the topcenter bar must NOT run
   to the right edge; the rail (absolutely positioned, top:gap below) rises through that track so
   the collapsed right column reads top-to-bottom like the left one. */
/* JD 2026-08-05 (right-collapsed batch item 1): the HEADER stretches all the way across -- row1
   drops its empty 64px third track; the right rail starts below the header, mirroring the left. */
/* batch 19 + nav-to-rail: left-collapsed row1 = [64px menu][TAB BAR to the edge]; the row rule and the topright hide live in the nav-to-rail block below. */
/* JD 2026-08-01 (nav-to-rail law): whenever EITHER side collapses, the right column's action
   icons leave the header and join the right icon stack (the rail twins already carry them); the
   topright cell hides, and the TAB BAR (back/dashboard/add) stays in the header in every view.
   Left-collapsed reads: [64px menu][TAB BAR to the rail][64px right rail from the top]; the whole
   right side becomes ONE vertical stack, and the composer row owns the full bottom between the
   two corner toggles. */
/* JD 2026-08-09 rev 5 (CORNER SHUFFLE 2): the topright region is BACK -- it is the top-right
   64px corner box and holds ONLY the profile image button (guest: the lock). Placement lives in
   the stage-A grid block below. */
/* (COLLAPSE REBUILD JD 2026-08-05: the absolute botright overlay rail + the midright padding hack
   are deleted -- the collapsed bar is a real .lpos-rail grid child in its own 64px lane, so content
   never underlaps it and needs no compensating padding.) */
/* (COLLAPSE REBUILD JD 2026-08-05: dead topright-cluster rules deleted -- the region is
   display:none in this state, so they never painted.) */
/* the hidden midleft column's in-flow controls (flip tools bar + pager) must not linger as
   crushed slivers behind the rail -- the region is visibility:hidden, this makes it explicit. */
.lpos-blueprint--console.-left-collapsed .lpos-cell--midleft .lpos-media__bar--above,
.lpos-blueprint--console.-left-collapsed .lpos-cell--midleft .lpos-media__bar--below,
.lpos-blueprint--console.-left-collapsed .lpos-cell--midleft .lpos-media__title{display:none}
/* Phase D 2026-08-09: the both-collapsed row templates and the whole right-collapsed:not(.-left-
   collapsed) rail/midleft block are deleted -- .-right-collapsed can never be applied by any code
   path (verified), so every rule requiring it (alone or combined with .-left-collapsed) was dead.
   The full-height rails now live in the BLUEPRINT SHIFT stage A/B blocks further down. */
/* pressed/ACTIVE state -- accent-tint GLASS like every other .-on control. Generalized: collapse
   toggles when engaged AND view-switch buttons marked as the current view (JD: the crosshair
   lights while the 3D viewer is what's showing).
   GLASSMORPHISM LAW (2026-08-04, JD): was a flat accent fill with dark ink-inverted text (that
   pairing only works on a bright SOLID fill); swapped to --lpos-accent-glass-strong with regular
   --lpos-ink text/icon color, since the surface now reads as a dark-tinted glass over the app bg,
   not a bright solid block. */
/* ONE PANEL, zero exceptions (JD 2026-08-04): the active tab is the SAME identical panel -- only its
   icon/text Asset color changes to show active, never the panel chrome. */
.lpos-blueprint .lpos-c-icon-btn[aria-pressed="true"]{color:var(--lpos-ink,#EAF2FB)!important}
.lpos-blueprint .lpos-c-icon-btn[aria-pressed="true"] svg{color:var(--lpos-ink,#EAF2FB)}
.lpos-blueprint .lpos-c-icon-btn[aria-pressed="true"] .lpos-c-icon-btn__text{color:var(--lpos-ink,#EAF2FB)} /* JD 2026-08-02: active tab TEXT matches the icon's active color */
/* ---- JD 2026-08-01: LEFT-COLUMN COLLAPSE (chevrons toggle by the thumbnails) ----
   Mirror of the right collapse with two differences: the THUMBNAILS become the vertical stack,
   and their rail aligns with the CENTER MIDDLE CONTENT (anchored to the middle row's band, not
   the full viewport); the top-left reduces to just the menu button. Center + right absorb the
   freed width (2.08:1 keeps the open-state ratio). */
/* visibility (NOT display): the region must keep occupying grid column 1, or auto-placement
   shifts midcenter into the 64px rail track (the bug the first pass shipped). */
.lpos-blueprint--console.-left-collapsed .lpos-blueprint__region--midleft{visibility:hidden}
.lpos-blueprint--console.-left-collapsed .lpos-cell--topleft .lpos-c-select{display:none}
/* JD 2026-08-01 batch 17 (+ follow-up): the thumbnails moved into the MIDLEFT column, but on
   left-collapse they STILL become the vertical rail beside the middle band (JD). The midleft
   region stays visibility:hidden; the thumbs panel alone overrides back to visible and pulls out
   as the absolute rail (same facebar-recipe box the old botleft rail used, anchored to the
   console root -- the cell's backdrop-filter must drop, or it becomes the containing block). The
   botleft cell mirrors the right side's CORNER BOX: only the reopen toggle stays visible in the
   64px track; the avatar + empty slot panel hide (display -- the row is flex, placement-safe). */
/* ==== COLLAPSE REBUILD (JD 2026-08-05) ====
   The collapsed side bars are REAL grid children of the middle row (BlueprintRenderer::
   console_rails_html) -- standalone vertical Display bars in their own 64px lane, OUTSIDE the
   content panels. No position:absolute, no overlays, no hidden twins, no display:contents.
   Visibility per state: left bar in -left-collapsed, right bar in -right-collapsed, BOTH bars
   in both-collapsed (JD law: both bars stay visible with their icons).
   Chrome comes from the ONE-PANEL law block (the .lpos-rail selector is in that list) -- byte-
   identical to every other panel; this block owns layout only. */
/* placement law: the rails carry DEFINITE grid positions, and the CSS grid placement algorithm
   seats definite items before auto-flow -- so the three content regions must ALSO be pinned to
   their columns or they shift one lane right the moment a rail displays (verified live bug). */
.lpos-blueprint--console>.lpos-blueprint__row:nth-child(2)>.lpos-blueprint__region:nth-child(1){grid-column:1;grid-row:1}
.lpos-blueprint--console>.lpos-blueprint__row:nth-child(2)>.lpos-blueprint__region:nth-child(2){grid-column:2;grid-row:1}
.lpos-blueprint--console>.lpos-blueprint__row:nth-child(2)>.lpos-blueprint__region:nth-child(3){grid-column:3;grid-row:1}
.lpos-rail{display:none;min-height:0;grid-row:1;
  flex-direction:column;align-items:center;justify-content:flex-start;flex-wrap:nowrap;
  gap:var(--lpos-gap,12px);
  padding:var(--lpos-subpanel-pad,6px)!important;
  padding-top:var(--lpos-gap,12px)!important} /* first tile sits one inter-item gap from the top (JD 2026-08-03 rhythm rule) */
.lpos-rail--left{grid-column:1} /* foot group (compass + avatar) lives IN the rail -- no reserved zone needed */
.lpos-rail--right{grid-column:3}
.lpos-blueprint--console.-left-collapsed .lpos-rail--left{display:flex}
/* nav-to-rail law (kept, deliberate JD asymmetry): LEFT-collapse also surfaces the right icon bar
   (the topright header set hides) -- row2 gains a 4th 64px lane for it so it still sits OUTSIDE
   the open midright content, never over it. */
/* JD 2026-08-05 ratio law: LEFT collapsed -> center (primary) 2/3, right column 1/3; bars untouched. */
.lpos-blueprint--console.-left-collapsed:not(.-right-collapsed) .lpos-rail--right{display:flex;grid-column:4}
/* rail controls: every item is the standard 46px component square; thumbs drop the 16:9 open-strip
   ratio inside the rail (JD 2026-08-01 law). */
.lpos-rail .lpos-c-icon-btn{flex:0 0 auto!important;width:var(--lpos-control-size,46px)!important;height:var(--lpos-control-size,46px)!important;padding:0!important;cursor:pointer;color:var(--lpos-muted)}
.lpos-rail .lpos-c-icon-btn svg{width:var(--lpos-icon-size,26px)!important;height:var(--lpos-icon-size,26px)!important;flex:0 0 auto!important;display:block;color:inherit;fill:none!important;stroke:currentColor}
.lpos-rail .lpos-c-icon-btn:hover{color:var(--lpos-ink)}
.lpos-rail .lpos-switch__thumb{flex:0 0 auto;width:var(--lpos-control-size,46px);height:var(--lpos-control-size,46px);min-width:0;max-width:none;aspect-ratio:auto} /* JD 2026-08-05 fix: min-width:0 -- the canonical thumb's 64px floor was overriding the 46px rail square, bleeding the tile into the bar's token padding */
/* the rail hamburger shows ONLY in both-collapsed (the top row -- which owns the menu button --
   is display:none there); every other state keeps the single top-bar copy. */
.lpos-rail .lpos-c-icon-btn[data-lpos-railmenu]{display:none!important}
/* (JD 2026-08-05 both-collapsed rework: the rail hamburger reveal is deleted -- the top row's own
   menu box is back in both-collapsed, so the single header copy is the only one everywhere.) */
/* ==== /COLLAPSE REBUILD ==== */
.lpos-blueprint--console.-left-collapsed .lpos-cell--botleft{justify-content:center}
.lpos-blueprint--console.-left-collapsed .lpos-cell--botleft .lpos-c-icon-btn[data-lpos-collapse]{flex:0 0 auto!important;width:var(--lpos-control-size,46px)!important}
/* JD 2026-08-01 follow-up: in the collapsed rail the botleft AVATAR and the (button-look) BLANK
   slot pull out of the row and pin to the BOTTOM of the middle band, directly above the corner-box
   toggle -- visual column bottom-up: toggle (row3 box), profile, blank. Both anchor to the console
   root (the cell's backdrop-filter drops -- containing-block law); left offset centers the 46px
   squares on the 64px rail track. display + width need !important vs the registry emissions. */
/* COLLAPSE REBUILD (JD 2026-08-05): while the left column is collapsed the botleft cell keeps ONLY
   the corner reopen toggle -- the avatar/XP-slot/compass copies hide here (display, row is flex,
   placement-safe); the LEFT RAIL's own foot group (compass + avatar, margin-top:auto) is the visible
   pair, directly above the corner box. No absolute pulls, no overlay anchors. */
/* ONE-STATE 2026-08-09: the old collapsed-state hides are retired -- the corner box IS the
   avatar's (or guest lock's) permanent home now; compass and the XP slot are deleted. */
.lpos-blueprint--console .lpos-cell--botleft{justify-content:center!important;align-items:center!important}
/* GUEST RAIL SIGN-IN retired (JD 2026-08-09 ONE-STATE: the corner LOCK routes to the Login display) */
/* ==== BLUEPRINT SHIFT stage A (JD 2026-08-07, boot/-left-collapsed state ONLY) ====
   The resting console becomes ONE grid: side lanes run FULL viewport height (left rail from the
   very top, right content column + right rail top to bottom), the header tab bar and the composer
   SHORTEN to exactly the content column (shared grid tracks -- the fr mismatch between row grids
   is gone), the pager chevrons stay right-aligned inside the shortened tab bar, and the botright
   switch cluster becomes the right lane's bottom box. Both-open keeps the legacy row layout until
   stage B. Rows go display:contents here, so the old row-level flex/nth-child sizing is inert in
   this state!important; regions stay REAL boxes (JS walks to .lpos-blueprint__region). */
.lpos-blueprint--console.-left-collapsed{display:grid!important;
  grid-template-columns:var(--lpos-titlebar-h,64px) minmax(0,2fr) minmax(0,1fr) var(--lpos-titlebar-h,64px)!important; /* JD 2026-08-09 RATIO LAW rev 2: right column narrower (2:1) -- the 3:2 render still FELT too wide (his sketch), and 2:1 is the proportion he originally approved */
  grid-template-rows:var(--lpos-titlebar-h,64px) minmax(0,1fr) var(--lpos-titlebar-h,64px)!important}
.lpos-blueprint--console.-left-collapsed>.lpos-blueprint__row{display:contents!important}
.lpos-blueprint--console.-left-collapsed>.lpos-blueprint__row>.lpos-blueprint__region--topleft{grid-column:1!important;grid-row:1!important} /* JD rev 4: the MENU button box stays in the top-left corner, collapsed or open */
.lpos-blueprint--console.-left-collapsed .lpos-rail--left [data-lpos-railmenu]{display:none!important} /* topleft box owns the menu again -- no duplicate on the rail */
.lpos-blueprint--console.-left-collapsed>.lpos-blueprint__row>.lpos-blueprint__region--topcenter{grid-column:2/4!important;grid-row:1!important} /* JD 2026-08-09 rev 5: the TAB BAR runs ALL the way across (over the right content column) to the top-right corner box */
.lpos-blueprint--console.-left-collapsed>.lpos-blueprint__row>.lpos-blueprint__region--topright{grid-column:4!important;grid-row:1!important;display:flex!important} /* JD rev 5: the top-right corner box = the PROFILE image button (guest: lock) */
.lpos-blueprint--console.-left-collapsed .lpos-cell--topright{justify-content:center!important;align-items:center!important}
.lpos-blueprint--console.-left-collapsed>.lpos-blueprint__row>.lpos-blueprint__region--midcenter{grid-column:2!important;grid-row:2!important}
.lpos-blueprint--console.-left-collapsed>.lpos-blueprint__row>.lpos-blueprint__region--midleft{display:none!important} /* the rail owns the left lane; the hidden-box track trick is dead in the flat grid */
.lpos-blueprint--console.-left-collapsed>.lpos-blueprint__row>.lpos-blueprint__region--midright{grid-column:3!important;grid-row:2/4!important} /* JD 2026-08-09 rev 5: right CONTENT moves DOWN -- starts below the full-width tab bar, still runs to the very bottom */
.lpos-blueprint--console.-left-collapsed>.lpos-blueprint__row>.lpos-blueprint__region--botleft{grid-column:1!important;grid-row:3!important} /* corner reopen toggle stays the lane's bottom box */
.lpos-blueprint--console.-left-collapsed>.lpos-blueprint__row>.lpos-blueprint__region--botcenter{grid-column:2!important;grid-row:3!important} /* composer = content width; mic/send land at its right edge */
.lpos-blueprint--console.-left-collapsed>.lpos-blueprint__row>.lpos-blueprint__region--botright{grid-column:4!important;grid-row:3!important} /* JD rev 2: the PLUS rides the corner box under the right rail -- the exact mirror of botleft's collapse-toggle box (switches stay hidden here in boot; they live on the rail) */
.lpos-blueprint--console.-left-collapsed .lpos-cell--botright{justify-content:center!important;align-items:center!important} /* corner box centers its lone plus, same look as the botleft toggle box */
.lpos-blueprint--console.-left-collapsed .lpos-rail--left{grid-column:1!important;grid-row:2/4!important} /* JD rev 4: the LEFT lane does NOT get the top extension -- rail starts below the header row. JD 2026-08-10: it now runs to the very BOTTOM, the corner chevron box that used to hold row 3 is deleted. */
.lpos-blueprint--console.-left-collapsed .lpos-rail--right{grid-column:4!important;grid-row:2/4!important;display:flex!important;
  justify-content:space-between!important} /* JD rev 5: rail starts BELOW the header (the profile corner sits above it). JD 2026-08-10: runs to the very BOTTOM now -- the corner chevron box that held row 3 is deleted. */
/* select-popover lift, flat-grid edition: the row stacking-context trick (rows lifted with
   z-index) is inert under display:contents -- lift the CELL that hosts the open menu instead
   (cells are stacking contexts already via backdrop-filter!important; z beats z:auto siblings). */
.lpos-blueprint--console.-left-collapsed.-select-open .lpos-cell--topcenter,
.lpos-blueprint--console.-left-collapsed.-select-open .lpos-cell--midcenter{position:relative;z-index:31}
/* ==== /BLUEPRINT SHIFT stage A ==== */
/* BLUEPRINT SHIFT stage B DELETED (JD 2026-08-09 ONE-STATE CONSOLE: the left column never opens, the collapse machine is retired). Dock-exclusivity + 3D-toolbar-above rules relocated below. */
.lpos-cell--midleft .lpos-col:has(.lpos-col__slot.-active .lpos-media.-model)>.lpos-col__tools{order:0} /* JD 2026-08-09: 3D Object Viewer toolbars sit ABOVE the viewer (documents/images keep tools below) */
.lpos-blueprint .lpos-media.-model>.lpos-media__bar{order:-1}
.lpos-cell--midright .lpos-media.-model>.lpos-media__bar,
.lpos-cell--midright .lpos-media>.lpos-media__bar--above{order:99}
.lpos-cell--midright .lpos-c-title-panel.-tools{order:98}
.lpos-cell--midright .lpos-c-title-panel:not(.-tools):not(.lpos-c-title-panel--display),
.lpos-cell--midright .lpos-media__title{display:none!important} /* the DISPLAY title panel (JD 2026-08-10 move: title + caption lead this column now) is exempt from the no-titles-in-the-right-column law -- it IS the Display's title, not a component's */
/* DISPLAY TITLE PANEL (JD 2026-08-10): first panel of the right column, above the secondary
   content; never grows, so the Focus keeps its space. */
.lpos-blueprint .lpos-cell--midright .lpos-c-title-panel--display{flex:0 0 auto;width:100%;box-sizing:border-box;margin-bottom:var(--lpos-gap,12px)}
.lpos-blueprint .lpos-cell--midright .lpos-c-title-panel--display h2{margin:0;font:600 var(--lpos-text-lg,20px)/1.2 var(--lpos-font-display,'Space Grotesk', ui-sans-serif, system-ui, sans-serif);color:var(--lpos-ink,#EAF2FB)}
.lpos-blueprint .lpos-cell--midright .lpos-c-title-panel--display h3{margin:calc(0.25*var(--lpos-gap,12px)) 0 0;font:400 var(--lpos-text-sm,14px)/1.3 var(--lpos-font-ui,'Inter', ui-sans-serif, system-ui, sans-serif);letter-spacing:var(--lpos-tracking-label,0.08em);text-transform:uppercase;color:var(--lpos-muted,#A8B2C7)}
.lpos-cell--midright .lpos-c-subpanel--tabbar{display:none!important} /* JD 2026-08-09: the four Focus tabs moved to the LEFT rail; the right column top bar is gone */
/* FEATURED IMAGE RATIO LAW (JD 2026-08-09): every featured-image panel holds a PROPER ratio,
   16:9 for landscape art, 3:4 for portrait (data-lpos-orient is stamped by a tiny onload tagger
   in lpos-drawers.js; untagged defaults to landscape). Cover-crop, never squash. */
/* cta media (JD rev 4): TRUE 16:9 landscape frame, WIDTH-driven (width is definite, so no
   percent-of-auto collapse); the grid's flexible row moved to the TEXT panel, which absorbs
   the freed height above the buttons. */
.lpos-blueprint .lpos-c-cta__media{aspect-ratio:16/9;height:auto;min-height:0;overflow:hidden}
.lpos-blueprint .lpos-c-cta__media img{width:100%;height:100%;object-fit:cover}
/* FULL-PANE right-column viewers (JD: no toolbar under the 3D object / PDF viewer): same
   deterministic treatment as the buy pane -- pane anchors, bar pinned visible at the foot. */
.lpos-cell--midright .lpos-col__media .lpos-media{position:relative}
.lpos-cell--midright .lpos-col__media .lpos-media .lpos-media__bar{position:absolute!important;left:0!important;right:0!important;bottom:0!important;top:auto!important;height:auto!important;min-height:0!important;flex-direction:row!important;z-index:2;display:flex!important;
  opacity:1!important;transform:none!important;pointer-events:auto!important} /* 2026-08-10 (G2 verify): the engine's auto-hide (.-barin.-idle => opacity:0) left the FULL-PANE viewer's toolbar invisible until hover -- JD's reference shots show it permanently visible under the document/model in this column, so the idle fade is overridden here only. */
.lpos-cell--midright .lpos-col__media .lpos-media.-barin.-idle{cursor:auto} /* and the cursor never disappears over a pane whose controls are always showing */
.lpos-cell--midright .lpos-col__media .lpos-media .lpos-media__stage{display:flex!important;align-items:center!important;justify-content:center!important;width:100%!important} /* the page/model mount CENTERS in the pane -- kills the dead band to the right of the PDF (JD) */
/* engines FILL the cta media panel (JD FIX rev 2): viewer stretches, its toolbar rides the
   bottom edge (order:99 rules), chrome sheds so the media panel is the ONE panel */
.lpos-blueprint .lpos-c-cta__media .lpos-media{width:100%!important;height:100%!important;display:flex;flex-direction:column;background:transparent!important;border:0!important;padding:0!important}
.lpos-blueprint .lpos-c-cta__media .lpos-media{position:relative}
.lpos-blueprint .lpos-c-cta__media .lpos-media .lpos-media__mv{position:absolute;inset:0;width:100%!important;height:100%!important} /* deterministic fill: flex siblings cannot shrink the viewer */
.lpos-blueprint .lpos-c-cta__media .lpos-media .lpos-media__bar{position:absolute!important;left:0!important;right:0!important;bottom:0!important;top:auto!important;height:auto!important;min-height:0!important;flex-direction:row!important;z-index:2} /* toolbar pinned to the viewer bottom (JD law), full weight: the engine's own bar layout rules were floating it mid-pane */
.lpos-blueprint .lpos-media-image-wrap[data-lpos-orient="portrait"] .lpos-media__stage{aspect-ratio:3/4}
/* ==== MEDIA ORIENTATION LAW (JD 2026-08-09) ==== EVERY media display component (video, 3D
   model, PDF, image) has BOTH a landscape and a portrait view; the panel carries the canonical
   ratio for its column: PRIMARY/CENTER = landscape (16:9, two-page spreads); RIGHT column =
   portrait (3:4 docs/images/3D, 9:16 video). Engines adapt inside the frame -- the flipbook's
   own shape rule flips to single-page in portrait; featured IMAGES keep per-image orientation
   via data-lpos-orient. */
.lpos-cell--midright .lpos-col__media .lpos-media{aspect-ratio:3/4;max-height:100%;width:auto;max-width:100%;min-height:0;margin-inline:auto;overflow:hidden} /* portrait frame capped by its track, never starves sibling rows */
.lpos-cell--midright .lpos-col__media .lpos-media.-video{aspect-ratio:9/16} /* JD 2026-08-09: NO title/text panels in the right column, ever -- components render bare (the buy info block is commerce data, not a title panel, and stays) */ /* JD 2026-08-09: ANY right-column component toolbar (incl. the docked pane's toolified title strip) sits at the BOTTOM of its viewer */ /* JD 2026-08-09: in the RIGHT column the media toolbar sits BELOW the secondary content panel; only the LEFT primary keeps 3D tools above */
/* DOCK EXCLUSIVITY (JD 2026-08-09, "notifications opens broken"): while a drawer pane is
   docked into the midright column, the column's own view slots and panes HIDE -- the docked
   panel replaces the content instead of stacking on top of the always-visible full-height
   column. returnRailBoxPane() lifts the class and the previous view comes back. */
.lpos-blueprint--console .lpos-col.-docked>.lpos-col__slot,
.lpos-blueprint--console .lpos-col.-docked>[data-lpos-view]{display:none!important}

.lpos-cell--botleft .lpos-c-icon-btn[hidden]{display:none!important} /* the icon-btn chrome's display:flex!important beats the [hidden] UA rule -- the step-2 submit button leaked visible (caught in v558 verify) */
.lpos-blueprint--console::before{
  content:"";position:absolute;inset:0;z-index:-1;pointer-events:none;
  background-image:linear-gradient(var(--lpos-grid-line,rgba(0,212,255,.035)) 1px,transparent 1px),
    linear-gradient(90deg,var(--lpos-grid-line,rgba(0,212,255,.035)) 1px,transparent 1px);
  background-size:42px 42px;
}
/* TENANT BACKGROUND VIDEO LAYER (2026-08-03, parallel theming-fleet contract): PHP
   (BlueprintRenderer::render_bg_video_layer()) emits `.lpos-blueprint__bgvideo` as the console
   shell's first child when a tenant has a video configured; this plugin owns ONLY the layer's
   position/z-index -- same -1 tier as the grid-line ::before above so it paints behind every
   normal-flow panel row without needing z-index on the rows themselves (proven pattern, same
   file). The actual video/veil VISUAL treatment (grid-line blend, reduced-motion static swap,
   --lpos-glass-veil's real tint) is tenant-theme.css's call; the transparent fallback here is a
   neutral no-op, not a color decision, so a tenant with no video yet renders identically to
   before this change (the existing radial-gradient background on .lpos-blueprint--console itself
   just shows through the empty wrapper). */
/* positioning context: .lpos-blueprint--console{position:relative;isolation:isolate} (JD 2026-08-03:
   stacking context so the z-index:-1 bg-video + grid layers paint ABOVE the console's own background
   instead of behind it) already declared elsewhere in this file -- not redeclared here to avoid a
   duplicate-rule smell.
   FIX (2026-08-04, Fleet F QA): the comment above used to open a SECOND comment-start token inside this
   one, which CSS does not allow -- comments do not nest. The parser closed this whole comment at the
   FIRST comment-end token it hit (the one that used to sit mid-sentence above) and then tried to parse
   everything after it, up to the trailing comment-end token that used to follow, as a selector. That
   garbage selector's error recovery consumed tokens up to the NEXT curly-brace block -- which was the
   `.lpos-blueprint__bgvideo` rule below -- silently discarding that entire rule from the parsed
   stylesheet (confirmed via a fresh CSSOM parse: the sibling `-media` and `-veil` rules right after it
   parsed fine; the bare wrapper rule was simply absent from `document.styleSheets`). Losing that rule
   meant the wrapper never got `position:absolute;z-index:-1`; it stayed `position:static` (the CSS
   default) with a collapsed 0-height box, and its child `<video>` (`position:absolute` from its own,
   unaffected rule) positioned itself against the next real positioned ancestor -- `.lpos-blueprint--
   console` itself -- filling the ENTIRE console at `z-index:auto` instead of the intended `-1` tier,
   painting OVER every panel instead of behind them. Fix: keep this whole note inside ONE comment, no
   inner comment-start/end tokens anywhere in the body (this paragraph included). */
.lpos-blueprint__bgvideo{position:absolute;inset:0;z-index:-1;overflow:hidden;pointer-events:none}
/* EDGE-GLYPH FIX (2026-08-04, corrected placement; BLUR REDUCED same day, coordinator relay): the
   blur lives on the bg LAYER itself, not on the rows above it (rows are transparent, JD's law --
   see .lpos-blueprint__row) and not as an opaque row-level tint. Root cause: the grid `gap`
   gutters between panels have no panel over them, so whatever this -1 layer paints there shows
   completely raw/sharp -- normally just soft ambient motion, but while the DNA Vimeo embed stays
   domain-restricted (known separate blocker, needs a Vimeo privacy-setting change) it instead
   renders VIMEO'S OWN blocked-embed error page, whose bold logo mark + text read as legible stray
   glyphs right at the seam ("V" / "))" artifacts). The FIRST pass over-corrected to an 18px blur,
   which also smeared the real DNA-loop footage into an unreadable wash once JD's own environment
   had the video actually playing (JD 2026-08-04: "very blurred... should be clearly visible"). The
   fix is two LIGHT layers instead of one heavy one: (1) a tasteful blur (3px, JD's own suggested
   2-4px range) that keeps the DNA loop readable but still softens any stray text past legibility,
   plus (2) `.lpos-blueprint__bgvideo-veil` (already present below, previously transparent-by-
   default) now carries a subtle token-derived dark scrim as its OWN fallback -- a second,
   independent contrast-reduction pass on top of the light blur, so a still-blocked environment
   (this wp-test install, per the HANDOFF's own note) doesn't regress to legible glyphs. A tenant
   theme can still override `--lpos-glass-veil` to any value; this only changes what an UNSET tenant
   gets. `blur` (not backdrop-filter) keeps blurring the layer's OWN pixels, not what's behind it --
   the "ambient bg shows through every gap" law stays intact, still real motion/color, only less
   smeared. 110% scale offsets the blur's edge softening so it doesn't reveal a hairline of the
   unblurred outer edge. */
.lpos-blueprint__bgvideo-media{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;
  filter:blur(var(--lpos-bgvideo-blur,3px));transform:scale(1.1)}
/* 2026-08-04: Vimeo BACKGROUND-embed iframe variant (BlueprintRenderer::render_bg_video_layer()'s
   Vimeo branch). `object-fit` on an <iframe> is not reliably honoured cross-browser, so this uses
   Vimeo's own documented background-embed technique instead: oversize the iframe to a fixed 16:9
   box (177.78vh wide == 16/9*100vh, 56.25vw tall == 9/16*100vw, whichever clamps larger via the
   min-width/min-height 100% floor), center it, and let the wrapper's own overflow:hidden (rule
   above) crop it to "cover". `inset:auto` cancels the base rule's `inset:0` so top/left below are
   free to position from center instead of the corner. pointer-events:none repeated explicitly
   (belt-and-suspenders alongside the wrapper's own pointer-events:none) so the chrome-free iframe
   never intercepts a click meant for the panels stacked above it.  */
.lpos-blueprint__bgvideo-media--vimeo{inset:auto;top:50%;left:50%;width:177.78vh;height:56.25vw;min-width:100%;min-height:100%;transform:translate(-50%,-50%) scale(1.1);object-fit:cover;border:0;pointer-events:none} /* scale(1.1) chained onto the existing center transform -- see the blur-edge note on the base .lpos-blueprint__bgvideo-media rule above */
/* Light second-pass scrim (see the blur-reduction note above) -- a per-tenant `--lpos-glass-veil`
   still wins when set; an UNSET tenant now gets a subtle token-derived dark wash (22% of the base
   ink color) instead of fully transparent, so a still-blocked/legible-glyph environment keeps a
   defensive contrast-reduction pass even at the new light 3px blur. */
.lpos-blueprint__bgvideo-veil{position:absolute;inset:0;background:var(--lpos-glass-veil,color-mix(in srgb,var(--lpos-bg,#0A0E17) 22%,transparent))}
/* (task #11: divergent accent-soft hover deleted -- the canonical .lpos-c-thumb hover above owns it.) */

/* archive-mode CENTER: the card grid fills the primary panel (video body's flex slot). */
.lpos-cell--midcenter.lpos-cell--archive{display:flex;flex-direction:column;gap:var(--lpos-gap,12px);min-height:0}
.lpos-feat__body--archive{flex:1 1 auto;min-height:0;display:flex}
.lpos-feat__body--archive .lpos-c-archive-grid{flex:1 1 auto;min-width:0}
/* EMPTY COLLECTION carousel (JD 2026-08-09): the home-blueprint featured carousel variant for a
   zero-card archive -- fills the center band, slides host real media engines full-bleed. */
.lpos-feat__body--coming{flex:1 1 0;min-height:0;display:flex;align-items:center}
.lpos-feat__body--coming .lpos-c-carousel{width:100%;min-width:0}
.lpos-feat__body--coming .lpos-c-carousel__slide .lpos-media{height:100%!important;width:100%!important}
/* EMPTY-PRIMARY DEFAULT (JD 2026-08-10): the Coming Soon slide -- slide 1 of every Display whose
   primary area has nothing bound yet. Chrome comes from the carousel slide it sits in (one panel);
   this is just the centred glyph/title/subtext stack inside it. All spacing/type/colour tokenized. */
.lpos-c-coming{display:flex;flex-direction:column;align-items:center;justify-content:center;
  gap:var(--lpos-space-sm,8px);width:100%;height:100%;min-height:0;text-align:center;
  padding:var(--lpos-panel-pad,12px);box-sizing:border-box}
.lpos-c-coming__glyph{display:flex;align-items:center;justify-content:center;
  width:var(--lpos-play-btn-size,80px);height:var(--lpos-play-btn-size,80px);color:var(--lpos-muted,#A8B2C7)}
.lpos-c-coming__glyph svg{width:var(--lpos-icon-size-lg,32px);height:var(--lpos-icon-size-lg,32px)}
.lpos-c-coming__title{font:700 var(--lpos-text-lg,20px)/1.2 var(--lpos-font-display,'Space Grotesk', ui-sans-serif, system-ui, sans-serif);color:var(--lpos-ink,#EAF2FB);
  letter-spacing:var(--lpos-tracking-label,0.08em);text-transform:uppercase}
.lpos-c-coming__sub{font:400 var(--lpos-text-sm,14px)/1.4 var(--lpos-font-ui,'Inter', ui-sans-serif, system-ui, sans-serif);color:var(--lpos-muted,#A8B2C7)}

/* dashboard-mode CENTER (JD 2026-08-03 RECOMPOSE #2, dashboard panel-distribution fix -- supersedes
   the RECOMPOSE #1 comment this replaces): the CENTER is now CHART-ONLY, given the full panel. The
   KPI row that used to sit on top of the chart here has MOVED OUT to the midleft Secondary panel
   (BlueprintRenderer::panel_left_dashboard(), see `.lpos-dashboard__kpis--midleft` below) so each
   component gets its own panel instead of three things stacked into one
   (LAYOUT_ARCHITECTURE_2026-08-03.md: "midcenter Primary = the main visual... given full room --
   readable, not tiny"). The activity feed lives in the Focus panel (midright,
   BlueprintRenderer::panel_right_dashboard_focus()) -- "center=Primary charts, Focus=related/
   activity" per LAYOUT_ARCHITECTURE §4-5. Mirrors the archive-mode recipe immediately above (same
   .lpos-cell--midcenter flex-column wrapper, same gap token) so both special center modes share one
   containment pattern. NO-SCROLLBAR LAW: every level down to the component's own root class
   (.lpos-c-chart, already `height:100%;flex:1 1 auto;overflow:hidden` in its own component CSS) is
   a flex parent with min-height:0, so its height:100% resolves against a real, definite height
   instead of an auto one -- nothing here ever needs its own overflow rule because the component
   already owns theirs. */
.lpos-cell--midcenter.lpos-cell--dashboard{display:flex;flex-direction:column;gap:var(--lpos-gap,12px);min-height:0}
.lpos-feat__body--dashboard{flex:1 1 auto;min-height:0;display:flex;flex-direction:column;gap:var(--lpos-gap,12px);overflow:hidden}
/* the chart is now the body's ONLY child -- flex:1 1 auto fills 100% of the panel's remaining
   height/width, the "given full room" requirement, instead of sharing the row with a KPI block. */
.lpos-dashboard__chart--full{flex:1 1 auto;min-width:0;min-height:0;display:flex}

/* Dashboard FOCUS panel, midright (JD 2026-08-03 RECOMPOSE): the activity feed now lives here
   instead of the center -- reuses the SAME .lpos-cell--midright/.lpos-col/.lpos-col__slot/
   .lpos-col__media chrome the 3D-viewer branch already uses (BlueprintRenderer::panel_right()), so
   no new sizing rules are needed; [lpos_timeline]'s own component CSS (height:100%;flex:1 1
   auto;overflow:hidden) resolves against .lpos-col__media's definite flex height exactly like the
   3D model does today. */

/* Dashboard midleft (Secondary, JD 2026-08-03 RECOMPOSE #2, dashboard panel-distribution fix):
   compact quick-nav pillars (unchanged, own chrome row) ABOVE the role-aware KPI tiles / quick
   stats -- BlueprintRenderer::panel_left_dashboard(). The KPI markup/classes below
   (.lpos-dashboard__kpis / __kpis-role) are the SAME ones the midcenter dashboard branch used to
   own before RECOMPOSE #2; only the `--midleft` sizing variant is new (flex:1 1 auto instead of
   flex:0 0 auto, since this panel has no chart beside it competing for the fill space -- the KPI
   tiles get the full remaining column height here, their own "given full room" per
   LAYOUT_ARCHITECTURE §4-5's midleft/Secondary assignment). Quicknav reuses the
   .lpos-c-subpanel/.lpos-c-title-panel components, just re-flowed as a wrapping button row instead
   of the default horizontal cluster row. */
.lpos-dashboard-quicknav{flex-wrap:wrap;align-items:stretch}
.lpos-dashboard-quicknav__item{all:unset;box-sizing:border-box;display:flex;align-items:center;justify-content:center;gap:var(--lpos-space-xs,4px);padding:var(--lpos-space-xs,4px) var(--lpos-space-sm,8px);border-radius:var(--lpos-radius-control,8px);color:var(--lpos-muted);cursor:pointer;flex:1 1 auto;min-width:0}
.lpos-dashboard-quicknav__item svg{width:var(--lpos-icon-size-sm,24px);height:var(--lpos-icon-size-sm,24px);flex:0 0 auto;fill:none!important;stroke:currentColor}
.lpos-dashboard-quicknav__item span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.lpos-dashboard-quicknav__item:hover{color:var(--lpos-ink);background:var(--lpos-accent-soft,color-mix(in srgb, var(--lpos-accent) 10%, transparent))}
.lpos-dashboard__kpis{flex:0 0 auto;min-width:0;display:flex;flex-direction:column;gap:var(--lpos-gap,12px)}
/* midleft variant: fills whatever column height the quicknav row left behind, and scrolls never --
   .lpos-c-stat-group (stat-tile.css, not owned by this file) already reflows its own grid columns
   to fit any definite height/width it's handed, same no-scale-to-fit/no-scrollbar contract every
   other component in this console follows. */
.lpos-dashboard__kpis--midleft{flex:1 1 auto;min-height:0;overflow:hidden}
/* ROLE-AWARE KPI sections (JD 2026-08-03, item 2): the optional staff/business group and the
   always-present customer group are each their own labeled block, stacked (never side-by-side, so
   neither visually competes for the "primary" read) -- the gap above already comes from
   .lpos-dashboard__kpis' own flex `gap`, this rule just keeps each role block from stretching taller
   than its own content. */
.lpos-dashboard__kpis-role{flex:0 0 auto;min-width:0}
/* ===== ARCHIVE CARD + GRID (flagship, 2026-08-03) -- 1:1 port of ConsoleCard/ConsoleCardGrid.
   Fixed 3x2 paginated grid (JD 2026-08-03), token-driven, no-scale-to-fit, no scrollbars. ===== */
.lpos-c-archive-grid{display:flex;flex-direction:column;gap:var(--lpos-gap,12px);min-height:0;height:100%;flex:1 1 auto;box-sizing:border-box}
/* HEAD ROW -- title left, pager cluster panel pinned TOP-RIGHT above the cards (JD 2026-08-03). */
.lpos-c-archive-grid__head{flex:0 0 auto;display:flex;align-items:center;justify-content:space-between;gap:var(--lpos-gap,12px);min-height:var(--lpos-titlebar-h,64px)}
/* JD 2026-08-04: the head row's only job was the (now top-bar) pager; when it carries just an empty
   aria-hidden title placeholder it is dead space -> collapse it so the cards sit at the panel top. A
   real title panel (div.lpos-c-title-panel with an h2) is NOT an empty span, so titled archives keep their head. */
.lpos-c-archive-grid__head:has(> span.lpos-c-archive-grid__title:empty:only-child){display:none}
.lpos-c-archive-grid__title{flex:1 1 auto;min-width:0;margin:0}
.lpos-c-archive-grid__title h2{margin:0;font:700 var(--lpos-text-lg,20px)/1.2 var(--lpos-font-ui,'Inter', ui-sans-serif, system-ui, sans-serif);color:var(--lpos-ink,#EAF2FB);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.lpos-c-archive-grid__empty{margin:0;padding:var(--lpos-space-sm,8px) var(--lpos-space-md,12px);color:var(--lpos-muted,#A8B2C7);font:400 var(--lpos-text-sm,14px)/1.4 var(--lpos-font-ui,'Inter', ui-sans-serif, system-ui, sans-serif)}
/* JD 2026-08-06 (task #15, VAULT = "MY STUFF"): the COLLECTIONS tab row -- chromeless flow, layout
   only (each tab is already its own .lpos-c-panel Component per the cloned .lpos-c-cta__tab pattern,
   NO grouping chrome wrapper here, tokens only). */
.lpos-vault__tabs{display:flex;gap:var(--lpos-gap,12px)}
/* the grid area below the tabs fills the rest of the cell, same fill rule the archive branch's own
   .lpos-c-archive-grid already gets ({@see .lpos-feat__body--archive .lpos-c-archive-grid} above) --
   Vault's grid sits as a direct cell sibling instead (ONE-PANEL LAW, no wrapping .lpos-feat__body),
   so it needs the same rule scoped to its own modifier class. */
.lpos-vault__grid{flex:1 1 auto;min-width:0}
/* only the active collection shows -- same -active/display:none idiom as .lpos-gallery__panel below;
   the tabs are inert wireframe today (no click JS yet), so Saved is the only one ever visible. */
.lpos-vault__collection{display:none}
.lpos-vault__collection.-active{display:block}
/* the 3x2 grid: 3 columns, 2 rows; only the current page's 6 tiles are visible ([hidden] removes the rest). */
.lpos-c-archive-grid__list{list-style:none;margin:0;padding:0;flex:1 1 auto;min-height:0;
  display:grid;grid-template-columns:repeat(var(--lpos-archive-cols,3),minmax(0,1fr));
  /* JD 2026-08-04 item 2: rows used to be minmax(0,1fr) -- purely whatever slice of the panel's
     available height fell out of the division, which read as squashed/too-short cards on a short
     panel. Each row now floors at --lpos-archive-card-min-h so a card always has real room for its
     image + text to breathe, growing past that floor when the panel has more room to give. */
  grid-template-rows:repeat(2,minmax(var(--lpos-archive-card-min-h,320px),1fr));gap:var(--lpos-gap,12px)} /* JD 2026-08-04 redesign item 1: taller floor (240->320px) for a proper portrait-ish card */
.lpos-c-archive-card{min-width:0;min-height:0;--lpos-card-accent:var(--lpos-accent,#00D4FF)}
.lpos-c-archive-card[hidden]{display:none}
/* TOMBSTONE (JD 2026-08-09, ONE-CARD UNIFICATION law 8): CardGrid.php's "standard" cards now render
   BlueprintRenderer::m8_product_card()'s OWN `.lpos-m8card.-product` markup instead of a card-specific
   body -- the outer `.lpos-c-archive-card` <li> above stays a GHOST positioning wrapper only (pager/
   [hidden] contract unchanged). Grepped 2026-08-09: everything below down to the `--create` rules
   (~line 2044) that targets `__media/__bg/--has-bg/__price/__body/__meta/__ghost-img/__eyebrow/
   __summary/__foot/__reward/__chip/__actions/__btn*` is now ORPHANED -- no PHP in the plugin renders
   those classes any more. `.lpos-c-archive-card` (bare, above), `__hit`, `__hit::before`, `__ghost`
   (+svg), `__title` stay LIVE: CardGrid's "create new" tile still uses that exact shell. Left in place
   (not deleted) for a dedicated cleanup pass; safe to delete then.
   PRE-EXISTING (unrelated to this pass): `__media`/`__body`/`__meta` were already orphaned before
   today -- the "ONE-PANEL LAW" pass (2026-08-04/05) had already dropped those wrapper <div>s from the
   PHP without a matching CSS cleanup; folded into this same tombstone since the grep surfaced them. */
/* CARD REDESIGN (JD 2026-08-04): the card is no longer one giant <button> -- three real click
   targets now share the same visual shell (item 5): the outer `.lpos-c-archive-card__hit` is a
   plain group container (the card-BODY click target, wired in JS), image on top / content below,
   with the two action buttons at the foot as their OWN focusable controls. Glass panel with a soft
   accent wash + hairline, same recipe as before. */
/* JD 2026-08-06 LAW PASS: the card panel is the ONE PANEL chrome, byte-identical -- glass token,
   blur-md, border-tint recipe, panel radius, NO shadows. The old per-card accent wash, blur-sm
   and shadow-1 are deleted (JD: "those are not our law panel token driven archive cards"). */
.lpos-c-archive-card__hit{box-sizing:border-box;cursor:pointer;width:100%;height:100%;position:relative;
  display:flex;flex-direction:column;gap:0;
  background:var(--lpos-glass-panel,linear-gradient(180deg, rgba(30,42,66,0.34), rgba(16,24,40,0.45)));
  -webkit-backdrop-filter:var(--lpos-blur-md,blur(16px) saturate(140%));backdrop-filter:var(--lpos-blur-md,blur(16px) saturate(140%));
  border:var(--lpos-border-width,1px) solid color-mix(in srgb,var(--lpos-border-tint,var(--lpos-accent)) var(--lpos-border-alpha-2,40%),transparent);
  border-radius:var(--lpos-radius-panel,10px);
  transition:border-color var(--lpos-duration-fast,120ms) var(--lpos-ease-tech,cubic-bezier(0.16, 1, 0.3, 1)),transform var(--lpos-duration-fast,120ms) var(--lpos-ease-tech,cubic-bezier(0.16, 1, 0.3, 1));overflow:hidden}
.lpos-c-archive-card__hit:hover{border-color:var(--lpos-border-tint,var(--lpos-accent));transform:translateY(-2px)} /* JD 2026-08-06 law pass: glow shadow removed (NO shadows) */
.lpos-c-archive-card__hit:focus-visible{outline:none;box-shadow:var(--lpos-focus-ring,0 0 0 2px rgba(0,212,255,.9),0 0 12px rgba(0,212,255,.6))}
/* MEDIA (image on top, item 1): a real fixed-ratio band, not a full-card background wash any more --
   the taller card gives the image genuine room to read as a proper cover shot. */
.lpos-c-archive-card__media{position:relative;flex:0 0 auto;width:100%;aspect-ratio:var(--lpos-card-media-ratio,16/9);overflow:hidden;
  background:var(--lpos-glass-1,rgba(255,255,255,0.035));border-bottom:var(--lpos-border-width,1px) solid color-mix(in srgb,var(--lpos-card-accent) var(--lpos-border-alpha-1,30%),transparent)}
/* PRICE BADGE (item 2, JD 2026-08-06 REDESIGN): its own SUBPANEL pinned top-right over the image
   area -- a nested Component-within-a-Component (the established subpanel idiom, same as the
   pager/logo/cluster subpanels elsewhere), exact chrome per JD's spec: glass-panel background,
   border-tint border (border-alpha-2), CONTROL radius (a badge, not the card's own panel radius),
   blur-md, NO shadow (the global `.lpos-blueprint *{box-shadow:none!important}` reset already
   covers this). `!important` on position/z-index only -- the two properties that would otherwise
   lose to the generic "every __hit child gets position:relative" flatten-safe rule below (that
   rule carries no !important of its own, so this one still wins on normal cascade rules; the
   !important is defensive insurance, not fighting real contention). */
.lpos-c-archive-card__price{position:absolute!important;z-index:3!important;top:var(--lpos-space-sm,8px);right:var(--lpos-space-sm,8px);
  display:flex;align-items:center;justify-content:center;width:auto;
  padding:var(--lpos-space-xs,4px) var(--lpos-space-sm,8px);margin:0;
  font:700 var(--lpos-text-sm,14px)/1 var(--lpos-font-ui,'Inter', ui-sans-serif, system-ui, sans-serif);color:var(--lpos-ink,#EAF2FB);
  background:var(--lpos-glass-panel);
  border:var(--lpos-border-width,1px) solid color-mix(in srgb,var(--lpos-border-tint,var(--lpos-accent)) var(--lpos-border-alpha-2,40%),transparent);
  border-radius:var(--lpos-radius-control,8px);
  -webkit-backdrop-filter:var(--lpos-blur-md);backdrop-filter:var(--lpos-blur-md);box-shadow:none}
/* card without an image still keeps the media band as a plain glass panel (no broken empty gap). */
/* JD 2026-08-04 (CORRECTION -- supersedes the "image on top" band above; matches SINGLE_AND_FOCUS_CTA_LAYOUT):
   a card WITH a featured image renders that image as a FULL-CARD BACKGROUND behind ALL content, with a
   little alpha so content stays readable. Content sits above (z-index); a bottom scrim keeps the
   title/summary/buttons legible over bright shots. */
.lpos-c-archive-card--has-bg .lpos-c-archive-card__media::after{content:"";position:absolute;inset:0;z-index:1;pointer-events:none;
  background:linear-gradient(to bottom,color-mix(in srgb,var(--lpos-bg,#0A0E17) 90%,transparent) 0%,color-mix(in srgb,var(--lpos-bg,#0A0E17) 74%,transparent) 55%,color-mix(in srgb,var(--lpos-bg,#0A0E17) 58%,transparent) 100%)} /* JD 2026-08-04: darkest at TOP where the icon/eyebrow/title live (title must never be sacrificed), lighter at the bottom where buttons carry their own bg + the image can read */
.lpos-c-archive-card--has-bg .lpos-c-archive-card__body,
.lpos-c-archive-card--has-bg .lpos-c-archive-card__actions{position:relative;z-index:2}
/* FLATTEN-SAFE readability scrim (JD 2026-08-05): the one-panel flatten removed __media/__body, so the
   has-bg scrim above no longer matches. This dims the card's bg image and lays a gradient directly on the
   single __hit panel, keeping every content Asset above it so title/price/buttons always read. */
.lpos-blueprint .lpos-c-archive-card__hit{position:relative;isolation:isolate;overflow:hidden}
.lpos-blueprint .lpos-c-archive-card__hit .lpos-c-archive-card__bg,
.lpos-blueprint .lpos-c-archive-card__hit > img{position:absolute!important;inset:0;width:100%!important;height:100%!important;object-fit:cover;z-index:0;opacity:.7}
.lpos-blueprint .lpos-c-archive-card__hit::before{content:"";position:absolute;inset:0;z-index:1;pointer-events:none;border-radius:inherit;
  background:linear-gradient(180deg,color-mix(in srgb,var(--lpos-bg,#0A0E17) 78%,transparent) 0%,color-mix(in srgb,var(--lpos-bg,#0A0E17) 58%,transparent) 45%,color-mix(in srgb,var(--lpos-bg,#0A0E17) 84%,transparent) 100%)}
/* BODY (below the image): meta row (icon + eyebrow) + title + summary, flexes to fill remaining
   height. DEFECT 0d (2026-08-04): `overflow` was left at its default `visible`, so when the body was
   squeezed below its content height its children did NOT clip -- they bled downward and rendered
   straight over the action buttons (measured: 150px of content in an 85px box; title and summary
   collapsed to 0px while the icon and foot chip drew across the buttons). The meta row + shorter
   media band above reclaim enough height to actually FIT (JD's no-scrollbars/fit law, so this
   clips rather than scrolls); `overflow:hidden` is the defensive backstop that guarantees content
   can never again overlap the controls on an unusually long value. */
/* META ROW (item 0d): category icon box and eyebrow share ONE row instead of stacking. */
/* the icon box is the single biggest consumer of the body's height (--lpos-card-ghost is 56px). Now
   that it shares a row with the eyebrow it only needs to match that row, not stand alone. */
/* the eyebrow's own `align-self:flex-start` is for the COLUMN body it used to sit in; inside the
   meta row that would top-align it against the icon box, so re-center it here. */
/* CATEGORY ICON BOX (item 7): the pre-existing "ghost" icon slot, now category/type-driven. */
.lpos-c-archive-card__ghost{flex:0 0 auto;display:flex;align-items:center;justify-content:center;
  width:var(--lpos-card-ghost,40px);height:var(--lpos-card-ghost,40px);border-radius:var(--lpos-radius-control,8px);
  background:color-mix(in srgb,var(--lpos-card-accent) var(--lpos-border-alpha-2,40%),transparent);
  border:var(--lpos-border-width,1px) solid color-mix(in srgb,var(--lpos-card-accent) 55%,transparent)}
.lpos-c-archive-card__ghost svg{width:var(--lpos-icon-size-sm,24px);height:var(--lpos-icon-size-sm,24px);color:var(--lpos-card-accent);fill:none;stroke:currentColor}
/* COLLECTION ICON IMAGE (JD 2026-08-06): a real per-collection icon captured off the live shop
   page, rendered inside the SAME ghost slot instead of the generic glyph -- fills the square,
   inherits the ghost's own radius (never a second shape), SVG glyph stays the fallback when a
   category has no real icon image (Bio Basics, honest-empty). */
.lpos-c-archive-card__ghost-img{width:100%;height:100%;object-fit:contain;border-radius:inherit;display:block}
/* TITLE must never be the thing that gets sacrificed: with the default `flex:0 1 auto` a squeezed
   body shrank it to 0px height, so cards rendered with NO name at all (measured 2026-08-04). It is
   the one field every card must show, so it never shrinks -- the summary below absorbs the squeeze
   instead. */
.lpos-c-archive-card__title{flex:0 0 auto;font:700 var(--lpos-text-md,17px)/1.25 var(--lpos-font-ui,'Inter', ui-sans-serif, system-ui, sans-serif);color:var(--lpos-ink,#EAF2FB);
  overflow:hidden;text-overflow:ellipsis;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical}
.lpos-c-archive-card__summary{margin:0;flex:0 0 auto;min-height:0;font:400 var(--lpos-text-sm,14px)/1.55 var(--lpos-font-ui,'Inter', ui-sans-serif, system-ui, sans-serif);color:var(--lpos-muted,#A8B2C7);
  overflow:hidden;text-overflow:ellipsis;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical} /* JD 2026-08-04: cards show a SHORT 2-line excerpt, not the full description */
/* JD no-pills law: reward reads as a small PANEL (control radius), not a pill; brand accent only.
   item 3: this chip alone (never a border-top divider -- REMOVED, see the redesign note above). */
/* JD 2026-08-06: margin-top:auto moved OFF the foot chip and ONTO `__actions` below -- the reward
   chip is optional (most cards carry a price, not a reward), so the actions row (always present)
   is the one that reliably needs to be the thing pinned to the card's bottom edge. */
.lpos-c-archive-card__reward{display:inline-block;font:700 var(--lpos-text-xs,13px)/1 var(--lpos-font-ui,'Inter', ui-sans-serif, system-ui, sans-serif);color:var(--lpos-card-accent);
  padding:var(--lpos-space-xs,4px) var(--lpos-space-sm,8px);border-radius:var(--lpos-radius-control,8px);background:color-mix(in srgb,var(--lpos-card-accent) var(--lpos-border-alpha-2,40%),transparent)}
.lpos-c-archive-card__chip{display:inline-flex;align-items:center;gap:var(--lpos-space-xs,4px);font:600 var(--lpos-text-xs,13px)/1 var(--lpos-font-ui,'Inter', ui-sans-serif, system-ui, sans-serif);color:var(--lpos-card-accent);
  padding:var(--lpos-space-xs,4px) var(--lpos-space-sm,8px);border-radius:var(--lpos-radius-control,8px);
  border:var(--lpos-border-width,1px) solid color-mix(in srgb,var(--lpos-card-accent) var(--lpos-border-alpha-2,40%),transparent)}
/* ACTIONS (item 4, JD 2026-08-06 CORRECTION): two INLINE canonical buttons in one row, no divider
   above them, no-pills family (matches .lpos-c-cta__buy). "Learn More" = outline/secondary; the
   adaptive action = primary (glass, not solid -- see --btn--primary below). `__actions` is the
   chromeless flex-ROW wrapper CardGrid.php nests the two buttons in so they sit side by side
   instead of stacking as separate rows of the card's own column-flex `__hit` -- pure layout flow,
   zero background/border/shadow of its own (the "wrapper carries ZERO chrome" law), so the card
   stays ONE visible panel. `__hit` already supplies the 16px panel padding on every side (the
   byte-identical panel law), so this wrapper adds none of its own -- only the inline gap between
   the two buttons, pinned to the bottom of the card via margin-top:auto. */
.lpos-c-archive-card__btn{all:unset;box-sizing:border-box;cursor:pointer;flex:1 1 0;min-width:0;text-align:center;
  min-height:var(--lpos-control-size,46px);display:flex;align-items:center;justify-content:center;
  padding:0 var(--lpos-space-sm,8px);font:700 var(--lpos-text-sm,14px)/1 var(--lpos-font-ui,'Inter', ui-sans-serif, system-ui, sans-serif);
  border-radius:var(--lpos-radius-control,8px);border:var(--lpos-border-width,1px) solid var(--lpos-card-accent);
  color:var(--lpos-card-accent);background:transparent;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
  transition:box-shadow var(--lpos-duration-fast,120ms) var(--lpos-ease-tech,cubic-bezier(0.16, 1, 0.3, 1)),transform var(--lpos-duration-fast,120ms) var(--lpos-ease-tech,cubic-bezier(0.16, 1, 0.3, 1))}
/* GLASSMORPHISM LAW (2026-08-04, JD): was a solid --lpos-card-accent fill; swapped for a 46%
   color-mix of the SAME per-card token (card categories can override --lpos-card-accent, so the
   glass tint must derive from it, not the global --lpos-accent-glass-strong) so it stays the
   featured/primary read while remaining translucent. Text is --lpos-ink, NOT --lpos-card-accent:
   accent-on-its-own-46%-glass measures under 2:1 for this tenant's violet, while ink measures
   about 11.9:1 on the same surface. Tint the SURFACE, never the text. */
.lpos-c-archive-card__btn--primary{background:color-mix(in srgb,var(--lpos-card-accent) 46%,transparent);color:var(--lpos-ink,#EAF2FB)}
/* the CREATE ("+") tile -- dashed, centered, the universal-editor entry (unchanged, still one button) */
.lpos-c-archive-card--create .lpos-c-archive-card__hit{align-items:center;justify-content:center;text-align:center;gap:var(--lpos-space-sm,8px);
  padding:var(--lpos-panel-pad,12px);border-style:dashed;background:transparent;box-shadow:none}
.lpos-c-archive-card--create .lpos-c-archive-card__title{color:var(--lpos-muted,#A8B2C7);-webkit-line-clamp:1}
/* pager -- a real cluster subpanel, sits in the head row top-right; inherits .lpos-c-subpanel--cluster chrome. */

/* ================= OFF-CANVAS DRAWER ENGINE (hamburger + top-icon drawers) =================
   One data-driven engine (assets/js/lpos-drawers.js) drives every `[data-lpos-drawer]` panel
   BlueprintRenderer::render_drawers() emits -- left for the hamburger menu, right for each
   top-icon drawer (command/notifications/security/billing/cart/account), swap-with-slide
   between right-side drawers (both panels transition their own transform at the same tick, so
   the old one visibly slides out while the new one slides in -- no extra JS state needed).
   Full-viewport-height overlay, same glass-panel/blur-md depth tier every `.lpos-cell` uses, 1px
   accent hairline on the INNER edge only, panel radius on the INNER corners only. No scrollbars
   (A10): body is overflow:hidden -- the stand-in heading + sample content stay short by design;
   real content (Phase C, via the `lpos_drawer_content` filter) owns its own pagination per the
   no-scrollbar law. prefers-reduced-motion collapses the slide to instant. ================= */
.lpos-drawer-scrim{
  position:fixed;inset:0;z-index:var(--lpos-z-scrim,8990);
  background:var(--lpos-scrim-bg,rgba(0,0,0,.45));-webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px);
  opacity:0;pointer-events:none;
  transition:opacity var(--lpos-duration-base,220ms) var(--lpos-ease-tech,cubic-bezier(0.16, 1, 0.3, 1));
}
.lpos-drawer-scrim.is-open{opacity:1;pointer-events:auto}
.lpos-drawer{
  position:fixed;top:0;bottom:0;width:var(--lpos-drawer-w,360px);max-width:92vw;z-index:var(--lpos-z-drawer,9000);
  display:flex;flex-direction:column;overflow:hidden;box-sizing:border-box;
  background:var(--lpos-glass-panel);-webkit-backdrop-filter:var(--lpos-blur-md);backdrop-filter:var(--lpos-blur-md);
  
  transition:transform var(--lpos-duration-base,220ms) var(--lpos-ease-tech,cubic-bezier(0.16, 1, 0.3, 1));
}
/* left drawer (menu): hairline + radius live on the RIGHT edge -- the inner edge facing content */
.lpos-drawer--left{
  left:0;transform:translateX(-100%);
  border-right:var(--lpos-border-width,1px) solid color-mix(in srgb,var(--lpos-border-tint,var(--lpos-accent)) var(--lpos-border-alpha-3,55%),transparent);
  border-radius:0 var(--lpos-radius-panel,10px) var(--lpos-radius-panel,10px) 0;
}
/* right drawers (command/notifications/security/billing/cart/account): hairline + radius on the LEFT edge */
.lpos-drawer--right{
  right:0;transform:translateX(100%);
  border-left:var(--lpos-border-width,1px) solid color-mix(in srgb,var(--lpos-border-tint,var(--lpos-accent)) var(--lpos-border-alpha-3,55%),transparent);
  border-radius:var(--lpos-radius-panel,10px) 0 0 var(--lpos-radius-panel,10px);
}
.lpos-drawer.is-open{transform:translateX(0)}
/* JD 2026-08-06 (audit CRITICAL): opening one drawer shifts every sibling's fixed containing
   block (content-push ancestor transform), which dragged CLOSED drawers into view stacked on
   the open one (the leaked "Account" panel). Closed drawers are simply invisible now. */
.lpos-drawer:not(.is-open){visibility:hidden;pointer-events:none}
.lpos-drawer__header{
  flex:0 0 auto;display:flex;align-items:center;justify-content:space-between;gap:var(--lpos-space-sm,8px);
  padding:var(--lpos-space-sm,8px) var(--lpos-panel-pad,12px);
  border-bottom:var(--lpos-border-width,1px) solid color-mix(in srgb,var(--lpos-border-tint,var(--lpos-accent)) var(--lpos-border-alpha-2,40%),transparent);
}
.lpos-drawer__title{font-size:var(--lpos-title-size-secondary,1.1rem)!important;line-height:1.2!important;margin:0!important;color:var(--lpos-ink)!important}
/* 2026-08-10 review D2: `overflow:hidden` here silently CLIPPED any drawer whose open section
   plus header exceeded a short viewport (the file documents a past incident where the Settings
   header was cut). The no-scrollbar law is about visible scrollbar CHROME, not about making
   content unreachable -- so the body scrolls when it must, with the bars hidden the same way the
   oracle chat panel already does it (the one established precedent in this file). */
.lpos-drawer__body{flex:1 1 auto;min-height:0;overflow-y:auto;overflow-x:hidden;box-sizing:border-box;padding:var(--lpos-panel-pad,12px);display:flex;flex-direction:column;gap:var(--lpos-gap,12px);
  scrollbar-width:none;-ms-overflow-style:none;overscroll-behavior:contain}
.lpos-drawer__body::-webkit-scrollbar{width:0;height:0}
.lpos-drawer__heading{margin:0!important;font-size:var(--lpos-subtitle-size-secondary,.75rem)!important;text-transform:uppercase;letter-spacing:var(--lpos-tracking-label,0.08em);color:var(--lpos-muted)!important;font-weight:600!important}
/* JD 2026-08-03 (item 2): the MENU drawer swaps its duplicate second "Menu" heading (the header
   already carries one) for an icon-button tab strip -- same .lpos-c-subpanel--cluster icon-tab-bar
   look used elsewhere in the console. Tab 1 (menu) is the only live tab; tabs 2-4 are honest,
   disabled placeholders (dimmed + not-allowed cursor, no fake interactivity). */
.lpos-drawer__tabs{flex:0 0 auto}
/* pointer-events:none means :hover/:focus-visible can never fire on a disabled button -- opacity
   + cursor alone communicate the inert state, no redundant hover override needed. */
.lpos-drawer .lpos-c-icon-btn:disabled{opacity:.4;cursor:not-allowed;pointer-events:none;color:var(--lpos-ink-disabled,#6C7A93)}
.lpos-drawer__content{flex:1 1 auto;min-height:0;overflow:hidden;color:var(--lpos-muted)}
/* close button + any content-hook icon buttons: same 46px square chrome as every other icon-btn
   in the console, scoped to `.lpos-drawer` since the drawer sits outside `.lpos-cell`/`.lpos-media`. */
.lpos-drawer .lpos-c-icon-btn{cursor:pointer;color:var(--lpos-muted);width:var(--lpos-control-size,46px)!important;height:var(--lpos-control-size,46px)!important;flex:0 0 auto!important;padding:0!important;transition:color var(--lpos-duration-fast,120ms),background var(--lpos-duration-fast,120ms),border-color var(--lpos-duration-fast,120ms),box-shadow var(--lpos-duration-fast,120ms)}
.lpos-drawer .lpos-c-icon-btn svg{width:var(--lpos-icon-size,26px)!important;height:var(--lpos-icon-size,26px)!important;flex:0 0 auto!important;display:block;color:inherit;fill:none!important;stroke:currentColor}
.lpos-drawer .lpos-c-icon-btn:hover{color:var(--lpos-ink);border-color:var(--lpos-accent);background:var(--lpos-accent-soft,color-mix(in srgb, var(--lpos-accent) 10%, transparent))}
.lpos-drawer .lpos-c-icon-btn:active{}
.lpos-drawer .lpos-c-icon-btn:focus-visible{outline:none;box-shadow:var(--lpos-focus-ring,0 0 0 2px rgba(0,212,255,.9),0 0 12px rgba(0,212,255,.6))}
@media (prefers-reduced-motion: reduce){
  .lpos-drawer,.lpos-drawer-scrim{transition-duration:0ms!important}
}

/* ================= ORACLE CHAT WIDGET -- DARK-HUD RETHEME (2026-08-04 defect fix) =================
   `mylivingos-oracle` is a SIBLING plugin (not this one) that injects `#mylivingos-oracle-chat-widget`
   into <body> via its own assets/js/chat.js on $(document).ready, for logged-in users only
   (MLOS_Oracle_Access::can_user_access_chat() gates it to is_user_logged_in()). Its own
   assets/css/chat.css only styles the outer container (#fff background, fixed size/position) and
   never themes the header/messages/input/buttons at all -- those render in raw browser-default
   white/black, which is the reported "white box floating on the dark console" defect.
   Builder-B scope fence: edit only files under mylivingos-for-wp/assets/. Rather than touch the
   sibling plugin's own files, this block re-themes its DOM with the same --lpos-* glass/frosted
   tokens every other panel in this console uses (see `.lpos-c-subpanel`/`.lpos-drawer` above) and
   is paired with the "force-closed-on-load" click in lpos-drawers.js (own IIFE at the end of that
   file) so the widget never auto-opens over content. `!important` throughout: load order between
   two independent plugins' enqueued stylesheets is not guaranteed, so specificity alone can't be
   trusted to win. ================= */
#mylivingos-oracle-chat-widget{
  background:var(--lpos-glass-panel)!important;
  -webkit-backdrop-filter:var(--lpos-blur-md)!important;backdrop-filter:var(--lpos-blur-md)!important;
  border:var(--lpos-border-width,1px) solid color-mix(in srgb,var(--lpos-border-tint,var(--lpos-accent)) var(--lpos-border-alpha-2,40%),transparent)!important;
  border-radius:var(--lpos-radius-panel,10px)!important;
  box-shadow:var(--lpos-shadow-2)!important;
  color:var(--lpos-ink)!important;
  font-family:var(--lpos-font-ui)!important;
}
#mylivingos-oracle-chat-widget.drag-over{
  border:var(--lpos-border-width-active,2px) dashed var(--lpos-accent)!important;
  background:var(--lpos-accent-soft,color-mix(in srgb, var(--lpos-accent) 10%, transparent))!important;
}
/* header */
#mylivingos-oracle-chat-widget .mylivingos-oracle-chat-header{
  display:flex;align-items:center;justify-content:space-between;gap:var(--lpos-space-sm,8px);
  padding:var(--lpos-space-sm,8px) var(--lpos-panel-pad,12px);
  border-bottom:var(--lpos-border-width,1px) solid color-mix(in srgb,var(--lpos-border-tint,var(--lpos-accent)) var(--lpos-border-alpha-2,40%),transparent)!important;
  background:transparent!important;
}
#mylivingos-oracle-chat-widget .mylivingos-oracle-chat-header h3{
  margin:0!important;font-size:var(--lpos-subtitle-size-secondary,.75rem)!important;text-transform:uppercase;
  letter-spacing:var(--lpos-tracking-label,0.08em);color:var(--lpos-muted)!important;font-weight:600!important;
}
#mylivingos-oracle-chat-widget .mylivingos-oracle-chat-actions{display:flex;align-items:center;gap:var(--lpos-space-xs,4px)}
#mylivingos-oracle-chat-widget .mylivingos-oracle-voice-toggle,
#mylivingos-oracle-chat-widget .mylivingos-oracle-chat-toggle,
#mylivingos-oracle-chat-widget .mylivingos-oracle-file-button,
#mylivingos-oracle-chat-widget .mylivingos-oracle-send-button{
  cursor:pointer;color:var(--lpos-muted)!important;background:transparent!important;
  border:none!important;width:32px!important;height:32px!important;min-width:32px!important;
  display:flex!important;align-items:center;justify-content:center;padding:0!important;
  border-radius:var(--lpos-radius-control,8px);
  transition:color var(--lpos-duration-fast,120ms),background var(--lpos-duration-fast,120ms);
}
#mylivingos-oracle-chat-widget .mylivingos-oracle-voice-toggle:hover,
#mylivingos-oracle-chat-widget .mylivingos-oracle-chat-toggle:hover,
#mylivingos-oracle-chat-widget .mylivingos-oracle-file-button:hover,
#mylivingos-oracle-chat-widget .mylivingos-oracle-send-button:hover{
  color:var(--lpos-ink)!important;background:var(--lpos-accent-soft,color-mix(in srgb, var(--lpos-accent) 10%, transparent))!important;
}
/* body / messages -- overflow-y:auto is an INTERNAL scroll region only (never the document), and
   the webkit/Firefox rules below hide the visible scrollbar chrome per the console's no-scrollbar
   law while keeping the region wheel/touch-scrollable. */
#mylivingos-oracle-chat-widget .mylivingos-oracle-chat-body{
  background:transparent!important;color:var(--lpos-ink)!important;
  flex:1 1 auto;min-height:0;display:flex;flex-direction:column;
}
#mylivingos-oracle-chat-widget .mylivingos-oracle-messages{
  flex:1 1 auto;min-height:0;overflow-y:auto;scrollbar-width:none;
  padding:var(--lpos-panel-pad,12px);display:flex;flex-direction:column;gap:var(--lpos-space-sm,8px);
}
#mylivingos-oracle-chat-widget .mylivingos-oracle-messages::-webkit-scrollbar{width:0;height:0}
#mylivingos-oracle-chat-widget .mylivingos-oracle-message{display:flex;gap:var(--lpos-space-sm,8px);align-items:flex-start}
#mylivingos-oracle-chat-widget .mylivingos-oracle-message-avatar{
  flex:0 0 auto;width:28px;height:28px;border-radius:50%;display:flex;align-items:center;justify-content:center;
  font-size:var(--lpos-text-2xs,12px);font-weight:600;background:var(--lpos-accent-soft,color-mix(in srgb, var(--lpos-accent) 10%, transparent));color:var(--lpos-accent)!important;
}
#mylivingos-oracle-chat-widget .mylivingos-oracle-message-content{
  flex:1 1 auto;min-width:0;background:var(--lpos-panel)!important;color:var(--lpos-ink)!important;
  border-radius:var(--lpos-radius-control,8px);padding:var(--lpos-space-sm,8px) var(--lpos-space-md,12px);
  font-size:var(--lpos-text-sm,14px);line-height:1.4;
}
#mylivingos-oracle-chat-widget .mylivingos-oracle-message.user .mylivingos-oracle-message-content{
  background:var(--lpos-accent-soft,color-mix(in srgb, var(--lpos-accent) 10%, transparent))!important;
}
#mylivingos-oracle-chat-widget .mylivingos-oracle-loading{color:var(--lpos-muted)!important}
#mylivingos-oracle-chat-widget .mylivingos-oracle-quick-actions{
  background:transparent!important;border-bottom:var(--lpos-border-width,1px) solid color-mix(in srgb,var(--lpos-border-tint,var(--lpos-accent)) var(--lpos-border-alpha-1,30%),transparent)!important;
}
#mylivingos-oracle-chat-widget .mylivingos-oracle-quick-action{
  background:var(--lpos-glass-1)!important;color:var(--lpos-ink)!important;
  border:var(--lpos-border-width,1px) solid color-mix(in srgb,var(--lpos-border-tint,var(--lpos-accent)) var(--lpos-border-alpha-1,30%),transparent)!important;
  border-radius:var(--lpos-radius-control,8px);
}
/* input row */
#mylivingos-oracle-chat-widget .mylivingos-oracle-chat-input{
  background:transparent!important;border-top:var(--lpos-border-width,1px) solid color-mix(in srgb,var(--lpos-border-tint,var(--lpos-accent)) var(--lpos-border-alpha-2,40%),transparent)!important;
  padding:var(--lpos-space-sm,8px) var(--lpos-panel-pad,12px);
}
#mylivingos-oracle-chat-widget .mylivingos-oracle-input-wrapper{display:flex;align-items:flex-end;gap:var(--lpos-space-xs,4px)}
#mylivingos-oracle-chat-widget .mylivingos-oracle-input-field{
  background:var(--lpos-glass-1)!important;color:var(--lpos-ink)!important;
  border:var(--lpos-border-width,1px) solid color-mix(in srgb,var(--lpos-border-tint,var(--lpos-accent)) var(--lpos-border-alpha-2,40%),transparent)!important;
  border-radius:var(--lpos-radius-control,8px);padding:var(--lpos-space-xs,4px) var(--lpos-space-sm,8px);
  font-family:var(--lpos-font-ui)!important;font-size:var(--lpos-text-sm,14px);resize:none;
}
#mylivingos-oracle-chat-widget .mylivingos-oracle-input-field::placeholder{color:var(--lpos-muted)!important}
#mylivingos-oracle-chat-widget .mylivingos-oracle-input-field:focus{
  outline:none!important;border-color:var(--lpos-accent)!important;box-shadow:var(--lpos-focus-ring,0 0 0 2px rgba(0,212,255,.9),0 0 12px rgba(0,212,255,.6))!important;
}
#mylivingos-oracle-chat-widget .mylivingos-oracle-file-preview{
  background:var(--lpos-glass-1)!important;border-top:var(--lpos-border-width,1px) solid color-mix(in srgb,var(--lpos-border-tint,var(--lpos-accent)) var(--lpos-border-alpha-1,30%),transparent)!important;
  color:var(--lpos-muted)!important;
}
#mylivingos-oracle-chat-widget .mylivingos-oracle-file-remove{color:var(--lpos-bad)!important}
#mylivingos-oracle-chat-widget .mylivingos-oracle-upload-progress{background:var(--lpos-glass-1)!important}
/* GLASSMORPHISM LAW (2026-08-04, JD): flat accent fill -> brand-tint glass. */
#mylivingos-oracle-chat-widget .mylivingos-oracle-upload-progress-bar{background:var(--lpos-accent-glass,color-mix(in srgb,var(--lpos-accent) 32%,transparent))!important}
/* closed-by-default state -- lpos-drawers.js clicks .mylivingos-oracle-chat-toggle once on load
   (through the widget's own OracleChat.toggleChat(), so its internal isMinimized flag stays in
   sync for any later real user click) which adds this class; mirrors the collapse rule the
   sibling plugin already ships for its wp-admin chat (assets/css/admin-chat.css .minimized). The
   frontend chat.css never shipped the matching rule, so nothing collapsed it there -- this is
   that missing rule, plus it also hides the input row (the original .minimized never did). */
#mylivingos-oracle-chat-widget.minimized{height:auto!important}
#mylivingos-oracle-chat-widget.minimized .mylivingos-oracle-chat-body,
#mylivingos-oracle-chat-widget.minimized .mylivingos-oracle-chat-input{display:none!important}

/* ================= BL HOME HERO RAIL + CTA COMMERCE PANE (2026-08-04) =================
   CSS-agent pass per the shared contract (PHP/JS agents own the markup + swap behavior; this
   file owns 100% of the visual treatment, --lpos-* tokens only, zero raw hex/px-literal-as-value).
   Two new components, same visual vocabulary the rest of the console already uses:
     (a) .lpos-c-thumb -- the 10-item hero thumbnail rail (real product photos, not the existing
         .lpos-switch__thumb media-switcher -- a DIFFERENT rail, deliberately not reusing that
         class so the home hero rail and the left-column asset switcher can evolve independently,
         but the recipe below is intentionally the SAME family: glass tile, control-radius-minus-
         inset image corner, accent hover/active -- "copy the existing pattern" per the brief.
     (b) .lpos-c-cta -- the midright commerce pane (product image + name/price/sku + Add to Cart),
         styled like `.lpos-c-archive-card` (glass panel, accent wash, no-pills law) since that is
         this file's closest existing "media + text + action" card recipe.
   Per-tenant: --lpos-accent already resolves to BioLimitless's violet (#AA81FF, BrandPackRepository)
   on this tenant, so "brand-violet ring" below is just var(--lpos-accent) -- no tenant selector,
   no hardcoded violet hex, the token IS the brand. ========================================== */

/* ---- (a) thumbnail rail ----
   Optional wrapper class in case the PHP/JS rail markup groups the 10 buttons in their own strip
   (harmless no-op if the tiles instead sit directly in an existing `.lpos-cell`/`.lpos-c-subpanel
   --cluster` flex row, both of which are already flex containers per the base registry above).
   "Whole rows only, no scroll" is a JS/count concern (liquid-grid item-count law); this wrapper
   only supplies the wrap/gap so an even integer count of tiles lays out cleanly once JS picks it. */
.lpos-c-thumb-rail{display:flex;flex-wrap:wrap;align-content:flex-start;gap:var(--lpos-space-sm,8px);width:100%;min-width:0;overflow:hidden}
/* each thumb is its own Component Panel (glass + border + inset image), same family as
   .lpos-switch__thumb above but SQUARE (product bottle/box shots read better 1:1 than 16:9 video
   frames) and sized to flex evenly across whatever row it's dropped into. `all:unset` first so a
   real <button> loses UA chrome before the panel recipe applies (same pattern as switch__thumb). */
.lpos-c-thumb{all:unset;box-sizing:border-box;position:relative;cursor:pointer;overflow:hidden;
  flex:1 1 calc(20% - var(--lpos-space-sm,8px));min-width:64px;max-width:calc(var(--lpos-thumb-h,56px)*1.6);
  aspect-ratio:var(--lpos-thumb-ratio,1/1); /* RATIO-CONSISTENCY AUDIT 2026-08-04: bare 1/1 literal -> token, fallback identical */
  padding:var(--lpos-space-xs,4px);
  background:var(--lpos-glass-panel,linear-gradient(180deg, rgba(30,42,66,0.34), rgba(16,24,40,0.45)));-webkit-backdrop-filter:var(--lpos-blur-sm);backdrop-filter:var(--lpos-blur-sm);
  border:var(--lpos-border-width,1px) solid color-mix(in srgb,var(--lpos-border-tint,var(--lpos-accent)) var(--lpos-border-alpha-2,40%),transparent);
  border-radius:var(--lpos-radius-control,8px);
  color:var(--lpos-muted);
  transition:border-color var(--lpos-duration-fast,120ms) var(--lpos-ease-tech,cubic-bezier(0.16, 1, 0.3, 1)),box-shadow var(--lpos-duration-fast,120ms) var(--lpos-ease-tech,cubic-bezier(0.16, 1, 0.3, 1))}
.lpos-c-thumb img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;display:block;
  border-radius:calc(var(--lpos-radius-control,8px) - var(--lpos-space-xs,4px))}
.lpos-c-thumb:hover{border-color:var(--lpos-accent);}
.lpos-c-thumb:focus-visible{outline:none;box-shadow:var(--lpos-focus-ring,0 0 0 2px rgba(0,212,255,.9),0 0 12px rgba(0,212,255,.6))}
/* active state: the brand-violet (per-tenant --lpos-accent) ring the brief calls for -- a real
   2px ring drawn via box-shadow (never outline, which the focus-visible rule above already owns)
   so it composes cleanly if a tile is both active AND focused. */
.lpos-c-thumb.is-active{border-color:var(--lpos-accent);box-shadow:0 0 0 2px var(--lpos-accent),var(--lpos-accent-glow-sm,0 0 12px rgba(0,212,255,.55))}

/* ---- (b) commerce / CTA pane ----
   Layout wrapper for the buy box: image up top, name/price/sku stacked, Add to Cart pinned to the
   bottom via margin-top:auto so the pane fills its cell however tall the midright slot renders at.
   ONE-PANEL LAW (2026-08-04): this used to carry its OWN full glass-panel chrome here (a THIRD,
   independent chrome definition for .lpos-c-cta alongside the LAW "extend" grant list and the old
   force-ghost block, all three disagreeing) -- .lpos-c-cta is a grouping wrapper that houses other
   already-panelled Components (.lpos-c-cta__body, .lpos-c-cta__trust below), so per the law it must
   NOT be a panel itself (a Component may only house Assets, never other Components). Chrome removed
   here; only layout (flex/size/gap/padding-as-spacing/overflow) remains. See the LAW "extend" block
   (search "ONE-PANEL LAW: .lpos-c-cta and .lpos-c-buytoggle were REMOVED") for the full rationale. */
.lpos-c-cta{min-width:0;min-height:0;display:flex;flex-direction:column;gap:var(--lpos-space-md,12px);
  width:100%;height:100%;box-sizing:border-box;
  /* JD 2026-08-05: padding REMOVED -- a chromeless wrapper carries ZERO padding (it inset the
     media/Focus panels 16px narrower than the sibling tab row; the cell's own token pad is the
     one inset). */
  overflow:hidden}
/* product shot: contained (not cropped, unlike the archive-card background treatment) -- a
   commerce image must show the whole bottle/box, never crop the label. Class-named element AND a
   bare `img` fallback (scoped to the pane) so this renders correctly whichever the PHP/JS agents
   land on. */
.lpos-c-cta__media,.lpos-c-cta>img{flex:0 0 auto;width:100%;max-height:40%;aspect-ratio:var(--lpos-cta-media-ratio,4/3); /* RATIO-CONSISTENCY AUDIT 2026-08-04: bare 4/3 literal -> token, fallback identical */
  border-radius:var(--lpos-radius-control,8px);overflow:hidden;
  background:var(--lpos-glass-1,rgba(255,255,255,0.035));
  border:var(--lpos-border-width,1px) solid color-mix(in srgb,var(--lpos-border-tint,var(--lpos-accent)) var(--lpos-border-alpha-1,30%),transparent);
  box-shadow:inset 0 1px 0 rgba(255,255,255,0.08)} /* JD 2026-08-04 item 8: glass/translucent frame -- inner highlight, same recipe as .lpos-c-archive-card__hit's own inset sheen */
/* SPEC REVERT (2026-08-04, JD via BL_CONSOLE_EXACT_SPEC section 2 -- "Product image in a
   token-styled image component (contained, not covering)" -- restated live: "the image is
   ZOOMED IN / cutting off products, change fit so the WHOLE image is always VISIBLE"): the item-8
   pass above briefly swapped this to object-fit:cover ("DESIGN_LIBRARY image-component spec"),
   which directly contradicts the exact spec's own explicit buy-box wording AND the ORIGINAL intent
   documented right above this rule ("a commerce image must show the whole bottle/box, never crop
   the label"). Reverted to contain + centered so any product photo (portrait or landscape) shows
   in full inside the token-sized frame with balanced letterbox, never cropped. */
.lpos-c-cta__media img,.lpos-c-cta>img{width:100%;height:100%;object-fit:contain;object-position:center;display:block;border-radius:inherit}
/* JD 2026-08-04 buy-box refinement: the BODY (name/excerpt/price/toggle) sizes to its own content
   now -- flex:0 0 auto, not flex:1 -- so it no longer swallows the dead space between the toggle and
   the action-button row. The TRUST panel below is what flexes to fill that gap instead (see its own
   rule). */
.lpos-c-cta__body{flex:0 0 auto;min-height:0;display:flex;flex-direction:column;gap:var(--lpos-space-sm,8px)}
.lpos-c-cta__name{margin:0;font:700 var(--lpos-text-md,17px)/1.25 var(--lpos-font-ui,'Inter', ui-sans-serif, system-ui, sans-serif);color:var(--lpos-ink,#EAF2FB);
  overflow:hidden;text-overflow:ellipsis;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical}
.lpos-c-cta__price,[data-lpos-price]{font:700 var(--lpos-text-lg,20px)/1 var(--lpos-font-ui,'Inter', ui-sans-serif, system-ui, sans-serif);color:var(--lpos-accent)}
[data-lpos-sku]{font:500 var(--lpos-text-xs,13px)/1 var(--lpos-font-ui,'Inter', ui-sans-serif, system-ui, sans-serif);color:var(--lpos-muted,#A8B2C7);letter-spacing:.03em}
/* BUY BOX FINALIZATION item a: the EXCERPT that now sits where the SKU line used to. */
.lpos-c-cta__excerpt{margin:0;font:400 var(--lpos-text-sm,14px)/1.5 var(--lpos-font-ui,'Inter', ui-sans-serif, system-ui, sans-serif);color:var(--lpos-muted,#A8B2C7);
  overflow:hidden;text-overflow:ellipsis;display:-webkit-box;-webkit-line-clamp:3;-webkit-box-orient:vertical}
/* BUY BOX FINALIZATION item c, refined 2026-08-04: the trust/reassurance line is a real
   `.lpos-c-subpanel` (panel-component system law) that now FLEXES to fill the vertical gap between
   the One-Time/Subscribe&Save toggle (above) and the Add-to-Cart/Buy-Now row (below) -- flex:1 1 auto
   on the CTA's own column axis, own content vertically centered so a short line reads centered in a
   tall panel instead of leaving dead space above/below it. */
.lpos-c-cta__trust.lpos-c-subpanel{flex:1 1 auto;min-height:var(--lpos-control-size,46px);margin:0;width:auto;
  display:flex;align-items:center;justify-content:center;
  padding:var(--lpos-space-sm,8px) var(--lpos-space-md,12px);
  font:600 var(--lpos-text-xs,13px)/1.3 var(--lpos-font-ui,'Inter', ui-sans-serif, system-ui, sans-serif);color:var(--lpos-muted,#A8B2C7);text-align:center}
/* JD no-pills law (matches .lpos-c-archive-card__reward/__chip precedent): the button is a real
   control-radius rectangle, never a pill. Height matches every other console control
   (--lpos-control-size) so it reads as part of the same control system, full-width so it anchors
   the bottom of the pane.
   GLASSMORPHISM LAW (2026-08-04, JD): was a solid accent fill -- this is the PRIMARY (Buy Now)
   button, so it keeps the heaviest glass tier (--lpos-accent-glass-strong) to still read as the
   featured action next to --secondary's fully-transparent outline below, but it is translucent
   now, never a solid block. Text is --lpos-ink (light-on-dark-glass), NOT the accent: on this
   fill the accent measures under 2:1 while ink measures about 11.9:1. */
.lpos-c-cta__buy{all:unset;box-sizing:border-box;cursor:pointer;display:flex;align-items:center;justify-content:center;gap:var(--lpos-space-sm,8px);
  flex:0 0 auto;width:100%;min-height:var(--lpos-control-size,46px);margin-top:auto;
  padding:0 var(--lpos-space-md,12px);
  background:var(--lpos-accent-glass-strong,color-mix(in srgb,var(--lpos-accent) 46%,transparent));color:var(--lpos-ink,#EAF2FB);
  font:700 var(--lpos-text-sm,14px)/1 var(--lpos-font-ui,'Inter', ui-sans-serif, system-ui, sans-serif);
  border-radius:var(--lpos-radius-control,8px);
  border:var(--lpos-border-width,1px) solid var(--lpos-accent);
  transition:box-shadow var(--lpos-duration-fast,120ms) var(--lpos-ease-tech,cubic-bezier(0.16, 1, 0.3, 1)),transform var(--lpos-duration-fast,120ms) var(--lpos-ease-tech,cubic-bezier(0.16, 1, 0.3, 1)),opacity var(--lpos-duration-fast,120ms) var(--lpos-ease-tech,cubic-bezier(0.16, 1, 0.3, 1))}
.lpos-c-cta__buy svg{width:var(--lpos-icon-size-sm,24px);height:var(--lpos-icon-size-sm,24px);flex:0 0 auto;fill:none!important;stroke:currentColor}
.lpos-c-cta__buy:hover{box-shadow:var(--lpos-accent-glow-lg,0 0 32px rgba(0,212,255,.35));transform:translateY(-1px)}
.lpos-c-cta__buy:active{transform:translateY(0);}
.lpos-c-cta__buy:focus-visible{outline:none;box-shadow:var(--lpos-focus-ring,0 0 0 2px rgba(0,212,255,.9),0 0 12px rgba(0,212,255,.6))}
/* JS sets this while the store-api/add-to-cart request is in flight or once it has succeeded --
   dims + kills the pointer without a layout shift (no icon/label swap owned here). */
.lpos-c-cta__buy[disabled],.lpos-c-cta__buy.is-loading{opacity:.55;cursor:default;pointer-events:none}

/* ================= PDP CORRECTED LAYOUT (2026-08-04) =================
   JD's live 2026-08-04 correction: LEFT=3D (panel_left(), unchanged, already reads the real-data
   contract correctly), CENTER=video+gallery-thumb-switches-paginated-text (below), RIGHT/Focus=buy
   box (dedupe -- the .lpos-c-cta recipe above, now actually consumed by BlueprintRenderer::
   panel_right_focus_cta()). ========================================================= */

/* ---- (c) CENTER gap fix: the video->text gap in SINGLE mode must be TIGHT -- v1.0.194's
   translucency pass left the base `.lpos-cell` 16px row-gap (see the base .lpos-cell rule far
   above) applying between .lpos-feat__body (video) and .lpos-feat__spare (text/gallery) exactly
   like every other cell-child gap, which read as too loose under the video. Archive/dashboard
   center modes are untouched (:not() exclusions -- they have their own gap rules already). Net gap
   becomes --lpos-space-sm (8px) instead of --lpos-gap (16px), tabtwin->video spacing unchanged. */
/* (task #9, 2026-08-05: dead .lpos-feat__spare gap-tighten rule deleted -- the tight video-to-text
   gap is owned by the feat__body/titlecap flex rules now.) */

/* ---- (f) LEFT media switcher, 'image' asset type (2026-08-04, CANONICAL DISPLAY LAYOUT): a plain,
   token-styled image pane -- same canonical --lpos-* image-component recipe as .lpos-c-cta__media
   (item 8): control radius, accent-ramp border, glass frame, fills whatever height .lpos-col__media
   gives it (same contract every other media engine here -- flipbook/3d/video -- already honors).
   FIT FIX (2026-08-04, JD live): was object-fit:cover -- this is the PRIMARY product/media viewer
   (3D, gallery, supplement-facts), not a thumbnail, so cover was cropping/zooming real product
   photos edge-to-edge instead of showing the whole item. object-fit:contain + centered below shows
   the FULL image (portrait or landscape) with only whatever letterbox the wrap's own token-driven
   size already carries -- no new padding introduced, the wrap dimensions are unchanged. */
/* JD 2026-08-04 (live): the mid-left media viewer is a real frosted PANEL (glass + accent border +
   padding, like every other component) and a single image FILLS the container (object-fit:cover) --
   no giant top/bottom letterbox gaps on non-portrait images. Supersedes the earlier contain/no-panel
   treatment. */
/* Phase 2: divergent chrome (blur-sm, 55% border, shadow-1, 12px radius fallback) stripped -- this
   wrap is in the ONE-PANEL law lists below, which own its chrome. Layout only here. */
.lpos-media-image-wrap{width:100%;height:100%;min-height:0;overflow:hidden;
  padding:var(--lpos-space-sm,8px);box-sizing:border-box;
  /* DEFECT FIX (2026-08-07, JD-reported tiny/broken toolbar squares): image_player_html()'s
     .lpos-imgbar toolbar (BlueprintRenderer.php) sits inside THIS wrap, never inside a real
     .lpos-media element -- so the --lpm-* chain .lpos-media declares (lpos_dm_css(), media.php)
     never reaches its buttons and their background/border collapse to IACVT-invalid (the exact
     "zero chrome" bug already diagnosed + fixed for .lpos-media__extbar-wrap in media.php). Same
     re-declared fallback chain here so the toolbar gets byte-identical glass/border button chrome. */
  --lpm-btn: var(--lpos-panel-hover, rgba(0,212,255,.10));
  --lpm-txt: var(--lpos-ink, #EAF2FB);
  --lpm-accent: var(--lpos-accent, #00D4FF);
  --lpm-ctl: var(--lpos-radius-control, 8px);}
.lpos-media-image{width:100%;height:100%;object-fit:cover;object-position:center;display:block;border-radius:var(--lpos-radius-control,8px)}
/* ARCHIVE/SINGLE CONSISTENCY (2026-08-04, QA sweep blocker #4/G4): the media-switcher shell's
   honest-empty state (a recommended archive item with a real title but no bound image yet, e.g.
   Events/Community today) -- same wrap, just centers its "no media yet" message instead of an
   <img>, so the panel still reads as the SAME component, never a different structure. */
.lpos-media-image-wrap--empty{display:flex;align-items:center;justify-content:center;padding:var(--lpos-space-md,12px);text-align:center}

/* ---- (d) CENTER gallery: the thumb rail reuses .lpos-c-thumb-rail/.lpos-c-thumb (a) above
   verbatim (same family, same tenant-accent ring) -- only the panel switcher beneath it is new.
   Every section renders once in the DOM (BlueprintRenderer::render_center()); JS only ever moves
   the -active flag, so switching is instant and needs no fetch. */
.lpos-gallery__panels{width:100%;min-width:0;overflow:hidden}
.lpos-gallery__panel{display:none}
.lpos-gallery__panel.-active{display:block}
.lpos-gallery__panel-title{margin:0 0 var(--lpos-space-sm,8px);font:700 var(--lpos-text-md,17px)/1.3 var(--lpos-font-ui,'Inter', ui-sans-serif, system-ui, sans-serif);color:var(--lpos-ink,#EAF2FB)}
.lpos-gallery__item{margin:0 0 var(--lpos-space-sm,8px)}
.lpos-gallery__item:last-child{margin-bottom:0}
.lpos-gallery__item h4{margin:0 0 2px;font:600 var(--lpos-text-sm,14px)/1.3 var(--lpos-font-ui,'Inter', ui-sans-serif, system-ui, sans-serif);color:var(--lpos-ink,#EAF2FB)}
.lpos-gallery__item p{margin:0;font:400 var(--lpos-text-sm,14px)/1.6 var(--lpos-font-ui,'Inter', ui-sans-serif, system-ui, sans-serif);color:var(--lpos-muted,#A8B2C7)}

/* ---- (e) RIGHT/Focus buy box additions: the Subscribe & Save toggle + the booklet download link
   -- same control-radius-rectangle, no-pills family as .lpos-c-cta__buy above, sized to sit inside
   the same pane without competing with it for visual weight (muted/outline vs. the buy button's
   solid accent fill). */
/* JD 2026-08-04 item 3: One-Time / Subscribe & Save render INLINE side-by-side (a 2-up segmented
   row), not stacked -- flex-direction was column; row + flex:1 1 0 on each option splits the width
   evenly. Wraps to 2 lines only if the panel is ever narrower than both labels can share (min-width
   0 on the option lets its own text ellipsis rather than force an overflow). */
.lpos-c-buytoggle{display:flex;flex-direction:row;gap:var(--lpos-space-xs,4px);width:100%}
.lpos-c-buytoggle__opt{all:unset;box-sizing:border-box;cursor:pointer;flex:1 1 0;min-width:0;text-align:center;
  min-height:var(--lpos-control-size,46px);display:flex;align-items:center;justify-content:center;
  padding:var(--lpos-space-sm,8px) var(--lpos-space-md,12px); /* JD 2026-08-04: bumped horizontal space-sm->space-md (panel-pad(16) made the longer "Subscribe & Save -- $x/mo" label overflow its half-width slot -- space-md is the largest step that still leaves ellipsis room) + a real min-height/flex-center so the control's vertical rhythm matches every other 46px control */
  background:var(--lpos-glass-1,rgba(255,255,255,0.035));
  border:var(--lpos-border-width,1px) solid color-mix(in srgb,var(--lpos-border-tint,var(--lpos-accent)) var(--lpos-border-alpha-1,30%),transparent);
  border-radius:var(--lpos-radius-control,8px);
  color:var(--lpos-muted,#A8B2C7);font:600 var(--lpos-text-xs,13px)/1.3 var(--lpos-font-ui,'Inter', ui-sans-serif, system-ui, sans-serif);
  transition:border-color var(--lpos-duration-fast,120ms) var(--lpos-ease-tech,cubic-bezier(0.16, 1, 0.3, 1)),color var(--lpos-duration-fast,120ms) var(--lpos-ease-tech,cubic-bezier(0.16, 1, 0.3, 1))}
/* text-overflow:ellipsis on a flex CONTAINER's own raw text doesn't reliably truncate (the "Subscribe
   & Save -- $x/mo" overflow bug) -- moved onto this explicit inner span, min-width:0 so it can shrink
   below its content size inside the flex row. */
.lpos-c-buytoggle__opt-text{display:block;max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0}
/* GLASSMORPHISM LAW (2026-08-04, JD): the active option had border+ring but NO translucent fill --
   the law requires active/selected states to read as a translucent brand-tint glass. Added
   --lpos-accent-glass-soft (18% color-mix) as the fill; border/ring/text untouched. */
.lpos-c-buytoggle__opt.is-active{background:var(--lpos-accent-glass-soft,color-mix(in srgb,var(--lpos-accent) 18%,transparent));border-color:var(--lpos-accent);color:var(--lpos-ink,#EAF2FB);box-shadow:0 0 0 1px var(--lpos-accent) inset}
.lpos-c-buytoggle__opt:focus-visible{outline:none;box-shadow:var(--lpos-focus-ring,0 0 0 2px rgba(0,212,255,.9),0 0 12px rgba(0,212,255,.6))}
/* JD 2026-08-04 item 5: quantity stepper sits LEFT of the price, same row. item 4: Add to Cart +
   Buy Now sit inline in their own actions row below the body (was one full-width button). */
/* JD 2026-08-04: gap bumped space-xs->space-sm (already inset by the pane's own panel-pad, see
   .lpos-c-cta -- no SECOND inset needed here, just more breathing room between qty/price). */
.lpos-c-cta__pricerow{display:flex;align-items:center;gap:var(--lpos-space-md,12px)}
.lpos-c-cta__pricerow .lpos-c-cta__price{margin:0}
.lpos-c-cta__qtywrap{display:flex;align-items:center;gap:var(--lpos-space-sm,8px);flex:0 0 auto}
.lpos-c-cta__qtylabel{font:600 var(--lpos-text-xs,13px)/1 var(--lpos-font-ui,'Inter', ui-sans-serif, system-ui, sans-serif);color:var(--lpos-muted,#A8B2C7);text-transform:uppercase;letter-spacing:.06em}
.lpos-c-cta__qty{all:unset;box-sizing:border-box;width:56px;min-height:var(--lpos-control-size,46px);text-align:center;
  padding:0 var(--lpos-space-xs,4px);
  background:var(--lpos-glass-1,rgba(255,255,255,0.035));color:var(--lpos-ink,#EAF2FB);
  font:700 var(--lpos-text-sm,14px)/1 var(--lpos-font-ui,'Inter', ui-sans-serif, system-ui, sans-serif);
  border-radius:var(--lpos-radius-control,8px);
  border:var(--lpos-border-width,1px) solid color-mix(in srgb,var(--lpos-border-tint,var(--lpos-accent)) var(--lpos-border-alpha-1,30%),transparent)}
.lpos-c-cta__qty:focus-visible{outline:none;border-color:var(--lpos-accent);box-shadow:var(--lpos-focus-ring,0 0 0 2px rgba(0,212,255,.9),0 0 12px rgba(0,212,255,.6))}
.lpos-c-cta__actions{display:flex;gap:var(--lpos-space-sm,8px);width:100%;margin-top:auto}
.lpos-c-cta__actions .lpos-c-cta__buy{width:auto;flex:1 1 0;min-width:0;margin-top:0}
/* BUY BOX FINALIZATION item d: `--secondary` is a TREATMENT modifier (outline), not tied to a
   specific button -- Add to Cart wears it now, Buy Now is the default solid/primary (swapped). */
.lpos-c-cta__buy--secondary{background:transparent;color:var(--lpos-accent)}
.lpos-c-cta__buy--secondary:hover{background:var(--lpos-accent-soft,color-mix(in srgb, var(--lpos-accent) 10%, transparent))}
.lpos-c-cta__booklet{all:unset;box-sizing:border-box;cursor:pointer;display:flex;align-items:center;justify-content:center;gap:var(--lpos-space-sm,8px);
  flex:0 0 auto;width:100%;min-height:var(--lpos-control-size,46px);
  padding:0 var(--lpos-space-md,12px);
  background:transparent;color:var(--lpos-muted,#A8B2C7);
  font:600 var(--lpos-text-sm,14px)/1 var(--lpos-font-ui,'Inter', ui-sans-serif, system-ui, sans-serif);
  border-radius:var(--lpos-radius-control,8px);
  border:var(--lpos-border-width,1px) solid color-mix(in srgb,var(--lpos-border-tint,var(--lpos-accent)) var(--lpos-border-alpha-1,30%),transparent)}
.lpos-c-cta__booklet svg{width:var(--lpos-icon-size-sm,24px);height:var(--lpos-icon-size-sm,24px);flex:0 0 auto;fill:none!important;stroke:currentColor}
.lpos-c-cta__booklet:hover{color:var(--lpos-ink,#EAF2FB);border-color:var(--lpos-accent)}
.lpos-c-cta__booklet:focus-visible{outline:none;box-shadow:var(--lpos-focus-ring,0 0 0 2px rgba(0,212,255,.9),0 0 12px rgba(0,212,255,.6))}
/* the .lpos-c-cta pane sits inside .lpos-col__media (panel_right_focus_cta()'s wrapper, same as the
   3D viewer it replaces) -- that ancestor is display:flex/overflow:hidden with no scroll, so the
   pane itself scrolls its own content rather than overflowing the column when it's tall (booklet +
   toggle + sku all present at once on a narrow midright track). */


/* ===== JD 2026-08-04 LAW: ONE ATOMIC PANEL COMPONENT (authoritative, last-word) =====
   Every panel/container surface renders its CHROME (glass, blur, border, radius, shadow) from this
   SINGLE token-driven definition -- the same as the .lpos-c-panel atomic component. Per-instance
   SIZE + PADDING + LAYOUT come from the Blueprint; CONTENT comes from Components. Editing these
   tokens (or this rule) changes EVERY panel everywhere. No panel may define its own divergent chrome. */
.lpos-blueprint .lpos-cell,
.lpos-blueprint .lpos-c-panel,
.lpos-blueprint .lpos-c-title-panel,
.lpos-blueprint .lpos-c-subpanel {
  background: var(--lpos-glass-panel) !important;
  -webkit-backdrop-filter: var(--lpos-blur-md) !important;
  backdrop-filter: var(--lpos-blur-md) !important;
  /* (Phase 2: dead box-shadow:var(--lpos-shadow-2) deleted -- the NO-SHADOWS law below always won) */
  border: var(--lpos-border-width, 1px) solid color-mix(in srgb, var(--lpos-border-tint,var(--lpos-accent)) var(--lpos-border-alpha-2, 40%), transparent) !important;
  border-radius: var(--lpos-radius-panel) !important;
}

/* ===== JD 2026-08-04 LAW (extend): the ONE atomic panel is EVERY component's frame too =====
   Every component -- cards, CTAs, media viewers, thumbnails, buttons, inputs, progress, badges --
   renders its container chrome (glass, blur, border, radius, shadow) from the SAME atomic panel
   definition. One component, everywhere. Per-instance size/content still varies.
   ONE-PANEL LAW (2026-08-04): .lpos-c-cta and .lpos-c-buytoggle were REMOVED from this grant list --
   both are grouping wrappers that house OTHER already-panelled Components (.lpos-c-cta wraps
   .lpos-c-cta__info/.lpos-c-cta__qtypanel/.lpos-c-cta__pricepanel/.lpos-c-cta__trust, all real
   panels of their own now; .lpos-c-buytoggle is not even used as a wrapper in the current markup,
   BlueprintRenderer's buy-toggle buttons carry .lpos-c-panel directly per its own "ONE PANEL LAW"
   comment) -- a Component may only house Assets, never other Components, so a grouping wrapper must
   not ALSO be a panel (that's panel-in-panel). This list used to grant them chrome here while a
   separate block further down force-ghosted them back to transparent -- two conflicting chrome
   sources for the same classes, the exact bug this law forbids. Neither block touches them now: no
   forced chrome, no forced ghost, just their own (chrome-free) layout rule earlier in this file --
   the correct fix is deleting these wrapper <div>s in the PHP markup, out of this CSS-only pass's
   scope (BlueprintRenderer::panel_right_focus_cta() already did exactly that for .lpos-c-cta's
   OWN former sub-wrappers -- .lpos-c-cta__body/__qtywrap/__pricerow are gone from the PHP entirely,
   replaced with .lpos-c-panel.lpos-c-cta__info/__qtypanel/__pricepanel, each already covered by the
   .lpos-c-panel selector below, no dedicated rule needed).
   .lpos-c-title-panel already covers the center title+subtitle: BlueprintRenderer's midcenter
   branches now render `<div class="lpos-c-title-panel lpos-feat__titlecap"><h2>...<h3>` (the
   .lpos-feat__spare/.lpos-feat__titlerow grouping wrappers that used to leave the title as bare
   floating text are gone from the PHP too) -- no title-specific addition needed in this list. */
.lpos-blueprint .lpos-c-icon-btn,
.lpos-blueprint .lpos-c-thumb,
.lpos-blueprint .lpos-switch__thumb,
.lpos-blueprint .lpos-media,
.lpos-blueprint .lpos-media__stagev,
.lpos-blueprint .lpos-media-image-wrap,
.lpos-blueprint .lpos-c-cta__media,
.lpos-blueprint .lpos-c-select,
.lpos-blueprint .lpos-search {
  /* NOTE: .lpos-c-archive-card (outer) is intentionally NOT here -- it is a GHOST positioning wrapper;
     .lpos-c-archive-card__hit is the ONE visible card panel (its full glass recipe lives above). One card = one panel. */
  /* JD 2026-08-04 #2 GAP FIX: every component panel is REAL frosted glass, not a bare outline.
     The frame gave border+blur+radius but NO background, so media viewers / CTAs / selects /
     toggles read as empty boxes. Adding the atomic panel's glass fill heals all of them at once. */
  background: var(--lpos-glass-panel) !important;
  -webkit-backdrop-filter: var(--lpos-blur-md) !important;
  backdrop-filter: var(--lpos-blur-md) !important;
  /* (Phase 2: dead box-shadow:var(--lpos-shadow-2) deleted -- the NO-SHADOWS law below always won) */
  border: var(--lpos-border-width, 1px) solid color-mix(in srgb, var(--lpos-border-tint,var(--lpos-accent)) var(--lpos-border-alpha-2, 40%), transparent) !important;
  border-radius: var(--lpos-radius-panel) !important;
}

/* ===== JD 2026-08-04: NO SHADOWS on ANY item (app-wide) ===== last-word override. Keyboard
   focus-visible rings have higher specificity and survive (accessibility); resting drop/inset
   shadows are removed everywhere. */
.lpos-blueprint .lpos-cell,
.lpos-blueprint .lpos-c-panel,
.lpos-blueprint .lpos-c-title-panel,
.lpos-blueprint .lpos-c-subpanel,
.lpos-blueprint .lpos-c-icon-btn,
.lpos-blueprint .lpos-c-archive-card,
.lpos-blueprint .lpos-c-archive-card__hit,
.lpos-blueprint .lpos-c-cta,
.lpos-blueprint .lpos-c-thumb,
.lpos-blueprint .lpos-switch__thumb,
.lpos-blueprint .lpos-media,
.lpos-blueprint .lpos-media-image-wrap,
.lpos-blueprint .lpos-c-select,
.lpos-blueprint .lpos-search,
.lpos-blueprint .lpos-c-buytoggle,
.lpos-blueprint [class*="lpos-c-"] {
  box-shadow: none !important;
}

/* ===== JD 2026-08-04: ZERO shadows anywhere in the app -- UNIVERSAL last-word ===== */
.lpos-blueprint, .lpos-blueprint *, .lpos-blueprint *::before, .lpos-blueprint *::after,
.lpos-drawer, .lpos-drawer *, .lpos-drawer-scrim,
[id^="lpos-drawer"], [id^="lpos-drawer"] *,
.lpos-media, .lpos-media * {
  box-shadow: none !important;
}

/* ===== JD 2026-08-04: EVERY panel + EVERY component -- the SAME EXACT padding, margin, radius.
   One set of tokens, across the board, no exceptions. (No Standard-vs-Compound: just Components.) ===== */
.lpos-blueprint .lpos-cell,
.lpos-blueprint .lpos-c-panel,
.lpos-blueprint .lpos-c-title-panel,
.lpos-blueprint .lpos-c-subpanel,
/* (.lpos-c-cta REMOVED 2026-08-05: it is a chromeless grouping WRAPPER, not a panel -- its forced
   16px padding inset the media/Focus/info panels 16px narrower than the tab row beside them,
   breaking the one-panel alignment JD flagged. Wrappers carry ZERO padding; the panels inside it
   keep the token padding from this same list.) */
.lpos-blueprint .lpos-c-cta__media,
.lpos-blueprint .lpos-c-cta__buy,
.lpos-blueprint .lpos-c-cta__trust,
.lpos-blueprint .lpos-c-archive-card__hit,
.lpos-blueprint .lpos-c-archive-card__btn,
.lpos-blueprint .lpos-media,
.lpos-blueprint .lpos-media__stagev,
.lpos-blueprint .lpos-c-select,
.lpos-blueprint .lpos-search,
.lpos-blueprint .lpos-c-buytoggle {
  padding: var(--lpos-panel-pad, 12px) !important;
  margin: 0 !important;
  border-radius: var(--lpos-radius-panel) !important;
}
/* .lpos-c-archive-card__price is REMOVED from the list above (JD 2026-08-06): it is a small badge
   SUBPANEL, not a full Component panel -- it keeps its own compact padding + CONTROL radius (see
   its dedicated rule) instead of the 16px pad / panel radius every full panel gets. */
/* AUDIT FIX (2026-08-05, consolidation plan Phase 2 item pulled forward): the fixed-square
   components (.lpos-c-icon-btn/.lpos-c-thumb/.lpos-switch__thumb) are REMOVED from the forced
   16px-padding/0-margin list above -- 16px padding inside a 46px square crushed every icon glyph,
   and margin:0!important blocked the rail foot group's auto-margin pin. Their padding is intrinsic
   to their square (the ".lpos-cell .lpos-c-icon-btn" rule owns it); their chrome still comes from
   the byte-identical law block. .lpos-c-buytoggle__opt/.lpos-c-next-action keep their padding via
   their own later re-assert block. Radius for the removed set still comes from the law block. */

/* JD 2026-08-04: Buy-box INLINE layout -- flex-wrap + widths on the panels THEMSELVES (no wrapper divs,
   panels do NOT all take 100% width). qty + price share one row; the two toggle options share one row
   (2-up); Add to Cart + Buy Now share one row (2-up). Layout only -- chrome stays the one identical panel. */
.lpos-blueprint .lpos-c-cta{display:grid!important;grid-template-columns:1fr 1fr!important;gap:var(--lpos-gap,12px)!important} /* 2026-08-10 review D3: `align-content:start!important` deleted -- the identical selector further down (the Focus-proportions block) sets `stretch` and wins on source order, so this declaration never rendered and only misled readers. */
/* full-width panels span both columns; qty+price, the two toggle options, and Add-to-Cart+Buy-Now each
   auto-pair into one row (each takes one column). No wrapper divs. */
.lpos-blueprint .lpos-c-cta__media,
.lpos-blueprint .lpos-c-cta__info,
.lpos-blueprint .lpos-c-cta__trust{grid-column:1 / -1}
/* Product image fills its panel (no tiny floating image).
   2026-08-10 review D1: the two hard 170px floors could push the buy-button row out of a column
   that clips (overflow:hidden end to end, no scrollbars by law) on short viewports -- the buttons
   just vanished. The floor is a min() against viewport height now, so it yields on short screens
   and behaves exactly as before on normal ones. The 16:9 frame rule further down still governs
   the shape; these declarations only stop the panel collapsing to nothing.
   D3: `aspect-ratio:auto` dropped here -- two later blocks set the ratio (the last one wins), so
   declaring it a third time only hid which rule was live. */
.lpos-blueprint .lpos-c-cta__media{overflow:hidden;min-height:min(170px,22dvh);max-height:none}
.lpos-blueprint .lpos-c-cta__media img{width:100%!important;height:100%!important;min-height:min(170px,22dvh);object-fit:cover!important;border-radius:inherit;display:block}
/* JD 2026-08-06: qty stepper + price readout merged into ONE panel (.lpos-c-cta__qtyprice, built by
   BlueprintRenderer::panel_right_focus_cta()) -- the old .lpos-c-cta__qtypanel/.lpos-c-cta__pricepanel
   pair is no longer emitted anywhere (grepped the PHP to confirm), so their layout rule is replaced
   rather than left dead. The combined panel spans the full cta grid row and lays its two Assets
   (qty label+input, price) out side by side, price pushed to the right edge. */
.lpos-blueprint .lpos-c-cta__qtyprice{grid-column:1 / -1;display:flex;align-items:center;gap:var(--lpos-gap,12px)}
/* JD 2026-08-06 (rev 2): the row itself is CHROMELESS flow -- the qty panel stretches, the price
   lives in ITS OWN panel chip. Price typography fully token-driven: title scale, ui font, ink. */
.lpos-blueprint .lpos-c-cta__qtyprice{background:transparent!important;border:0!important;
  -webkit-backdrop-filter:none;backdrop-filter:none;padding:0!important;box-shadow:none!important}
/* JD 2026-08-06 rev 3: QTY chip HUGS (short), the PRICE chip takes the rest of the row with the
   price LEFT-aligned and the purchase-mode suffix reading after it. */
.lpos-blueprint .lpos-c-cta__qtyprice .lpos-c-cta__qtypanel{flex:0 0 auto;min-width:0;
  display:flex;align-items:center;gap:var(--lpos-gap,12px)}
.lpos-blueprint .lpos-c-cta__qtyprice .lpos-c-cta__pricepanel{flex:1 1 auto;min-width:0;margin-left:0;
  display:flex;align-items:center;justify-content:center;gap:var(--lpos-subpanel-pad,6px)} /* JD 2026-08-06: price + suffix CENTER-MIDDLE in the panel */
.lpos-blueprint .lpos-c-cta__pricemode{font:500 var(--lpos-text-sm,14px)/1 var(--lpos-font-ui,'Inter', ui-sans-serif, system-ui, sans-serif);
  color:var(--lpos-muted);white-space:nowrap}
.lpos-blueprint .lpos-c-cta__qtyprice .lpos-c-cta__price{margin:0;
  font:700 var(--lpos-title-size,1.5rem)/1 var(--lpos-font-ui,'Inter', ui-sans-serif, system-ui, sans-serif);
  color:var(--lpos-ink,#EAF2FB)}
.lpos-blueprint .lpos-c-cta__actions{display:contents}

/* JD 2026-08-04: NO free-floating assets. The buy-box title/description, qty, and price are Components
   that house text Assets -> each gets the ONE atomic panel (glass/blur/border/radius/16px pad).
   VERIFIED AGAINST THE LIVE RENDERER (2026-08-04, grepped BlueprintRenderer.php, not guessed) --
   these three old class names now split across TWO different call sites that evolved apart:
     - panel_right_focus_cta() (the real single-item buy box) renamed all three away: qty and price
       are now their OWN standalone .lpos-c-panel.lpos-c-cta__qtypanel / .lpos-c-panel.lpos-c-cta__
       pricepanel, and name+excerpt are now .lpos-c-panel.lpos-c-cta__info -- each already carries the
       base .lpos-c-panel class, so each already gets the exact same chrome from the single LAW
       definition above (search "ONE ATOMIC PANEL COMPONENT (authoritative, last-word)"). No rule for
       .lpos-c-cta__qtywrap is kept -- it is not emitted anywhere in the plugin anymore (confirmed).
     - archive_recommended_cta_html() (the simpler card-grid/archive recommended-item CTA) still uses
       the OLD pattern verbatim: `.lpos-c-cta__body` wraps name + excerpt + `.lpos-c-cta__pricerow`
       (which wraps just the price paragraph) with NO `.lpos-c-panel` class on either. This function
       was not part of this pass's rewrite, so its markup is real and live -- .lpos-c-cta__body is
       kept below as the ONE visible panel for it (it directly houses the name/excerpt text Assets).
       .lpos-c-cta__pricerow is deliberately NOT given its own chrome: it only ever appears NESTED
       inside .lpos-c-cta__body, so giving it a second panel would be panel-in-panel; its price text
       already renders visibly once its .lpos-c-cta__body parent is a real panel. */
.lpos-blueprint .lpos-c-cta__body {
  background: var(--lpos-glass-panel) !important;
  -webkit-backdrop-filter: var(--lpos-blur-md) !important;
  backdrop-filter: var(--lpos-blur-md) !important;
  border: var(--lpos-border-width, 1px) solid color-mix(in srgb, var(--lpos-border-tint,var(--lpos-accent)) var(--lpos-border-alpha-2, 40%), transparent) !important;
  border-radius: var(--lpos-radius-panel) !important;
  padding: var(--lpos-panel-pad, 12px) !important;
}

/* ===== JD 2026-08-04: CONSISTENCY PASS across all Worlds (padding, spacing, alignment, distribution) ===== */
/* #1 Labeled buttons (Back/Dashboard/Log in): 16px horizontal padding token; vertical padding stays 0 so
   they keep the fixed control-size (46px) height and DON'T overflow the fixed-height top bar (no scroll). */
.lpos-blueprint .lpos-c-icon-btn.lpos-c-icon-btn--labeled {
  padding: 0 var(--lpos-panel-pad, 12px) !important;
}
/* ⛔ NO SCROLLBARS (JD law). Panels never scroll -- content is clipped, never a scrollbar. The buy box
   (.lpos-c-cta) shipped overflow:auto; force hidden here along with every blueprint panel surface. */
.lpos-blueprint .lpos-c-cta,
.lpos-blueprint .lpos-cell,
.lpos-blueprint .lpos-media,
.lpos-blueprint .lpos-c-title-panel,
.lpos-blueprint .lpos-c-subpanel {
  overflow: hidden !important;
}
/* #2 ONE spacing token for the children of EVERY component container -- no more 4 / 8 / 12 / none drift.
   Same gap as the Display cells, so inner and outer rhythm match everywhere. */
.lpos-blueprint .lpos-c-cta,
.lpos-blueprint .lpos-c-buytoggle,
.lpos-blueprint .lpos-c-select,
.lpos-blueprint .lpos-search,
.lpos-blueprint .lpos-c-title-panel,
.lpos-blueprint .lpos-media,
.lpos-blueprint .lpos-col {
  gap: var(--lpos-gap, 12px) !important;
}
/* #3 Display cells: uniform vertical centering on the bar rows; deliberate horizontal distribution by
   column (left cells pack left, center cells pack left, right cells pack right). No accidental justify drift. */
.lpos-blueprint .lpos-cell--topleft,
.lpos-blueprint .lpos-cell--botleft,
.lpos-blueprint .lpos-cell--topcenter,
.lpos-blueprint .lpos-cell--botcenter {
  align-items: center !important;
  justify-content: flex-start !important;
}
.lpos-blueprint .lpos-cell--topright,
.lpos-blueprint .lpos-cell--botright {
  align-items: center !important;
  justify-content: flex-end !important;
}
/* #4 NO CLUSTERS (JD 2026-08-04). There is no "cluster" layer -- only Components and Assets inside a
   Display cell; they still lay out (flex + gap) via their own layout rules elsewhere in this file.
   ONE-PANEL LAW REMOVAL (2026-08-04): this used to be a force-transparent "ghost" block --
   background:transparent/border:0/box-shadow:none/padding:0 !important on [class*="cluster"],
   .lpos-c-subpanel--tabbar, .lpos-c-subpanel--menu, .lpos-c-select__value, .lpos-c-cta,
   .lpos-c-buytoggle, .lpos-media__bar/__stagev/__big/__embedwrap/__embedposter, .lpos-col/__slot/
   __media, .lpos-feat__body/__titlerow. Per the law, ghosting via a forced-transparent override is
   forbidden everywhere except .lpos-blueprint__region -- and [class*="cluster"] is a substring match
   that also caught .lpos-c-subpanel--cluster, silently voiding the topright/botright/tabbar icon
   clusters' real, intentional panel chrome anywhere in the app. Block deleted; no replacement ghost
   added. Per class, the correct behaviour now falls out naturally:
     - [class*="cluster"] / .lpos-c-subpanel--tabbar / .lpos-c-select__value: these carry the base
       .lpos-c-subpanel (or .lpos-c-panel) class already, so they now correctly render that class's
       real panel chrome from the LAW block above -- they were the ones actually WRONGLY ghosted.
     - .lpos-c-subpanel--menu: kept its own narrow, !important chrome-cancel override (search
       ".lpos-c-subpanel--menu{" earlier in this file) so the already-panelled icon button inside it
       doesn't get a second box -- pre-existing, out of this ghost block, PHP-fix documented there.
     - .lpos-c-cta / .lpos-c-buytoggle / .lpos-media__bar / .lpos-media__big / .lpos-media__embedwrap /
       .lpos-media__embedposter / .lpos-col / .lpos-col__slot / .lpos-col__media / .lpos-feat__body:
       real grouping/layout wrappers (each houses other already-panelled Components) -- removed from
       the chrome-grant list above too, so now carry NO explicit background/border/shadow at all
       (plain div default), never a forced-transparent override either. Deleting these wrapper <div>s
       in the PHP markup remains the real fix; out of this CSS-only pass's scope.
     - .lpos-media__stagev: a real content-housing wrapper -- moved into the chrome-GRANT list above
       instead (it IS the one visible panel now).
     - .lpos-feat__titlerow: as of this pass BlueprintRenderer no longer emits this class at all --
       the PHP deleted it (and its sibling .lpos-feat__spare) outright and bundles the center title
       + subtitle into one `.lpos-c-title-panel.lpos-feat__titlecap` instead (verified by grepping
       the renderer), which already gets full chrome from the LAW block via the existing
       .lpos-c-title-panel selector -- no dedicated .lpos-feat__titlerow rule needed or added. */
/* (Removed the chevron-ghost exception -- ONE PANEL, zero exceptions: the chevron button is the same
   identical panel as every other button.) */

/* 4-WORLD MODEL (JD naming canon, NO CLUSTERS 2026-08-05) -- ONE atomic Panel, four worlds:
     World 1  BLUEPRINT (Archetypal) -- the 9 grid regions (.lpos-blueprint__region), GHOST/invisible frame.
     World 2  DISPLAY (Patterns)     -- the frosted cell that fills a region (.lpos-cell). A panel.
     World 3  COMPONENT (Activity)   -- a panel around an asset or GROUP OF ASSETS (button, thumbnail, price,
              toggle, search, progress). EVERY component has its own identical panel. Sits DIRECTLY in a Display
              cell. THERE IS NO CLUSTER WORLD -- a group of components is never wrapped in a panel.
     World 4  ASSET (Form)           -- the content itself: text, icon, image. NOT a panel; lives inside a Component.
   Blueprint > Display > Component > Asset. Panels (Display + Component) render the SAME atomic
   glass/blur/border/radius; only size + content differ. Wrapper divs that merely lay out a group of
   components are invisible flow, never a panel. */

/* (MEDIA RATIO LAW 2026-08-05: the midleft 3D display:none band-aid is REMOVED -- the model pane is a real aspect-locked component now, not an empty shell.) */

/* JD 2026-08-05: EXTRA icon-group panels removed. The wrapper box around the top-right chrome icons,
   the bottom-right view-switcher, and the top-left hamburger is dissolved with display:contents so the
   icons sit DIRECTLY in the Display cell -- no extra panel. The cell's own flex + gap lays them out. */
/* (Phase 3: the entire display:contents bar-cell dissolving block is DELETED -- the PHP no longer
   emits any of those wrappers (topright/botright clusters, topleft --menu); botcenter never had a
   subpanel child (search_html emits .lpos-search). The real fix replaced the CSS hack.) */
/* No Component panel exceeds its cell (fixes the Focus image box clipping on the right edge). */
.lpos-blueprint .lpos-c-panel,
.lpos-blueprint .lpos-c-cta__media,
.lpos-blueprint .lpos-c-cta > * { max-width: 100% !important; box-sizing: border-box !important; }

/* JD 2026-08-05: bar cells (top + bottom rows) must NOT clip their controls or the dropdown popup.
   overflow:visible shows them without ever creating a scrollbar (visible != scroll, so the no-scrollbar
   law holds). Fixes: cut-off dropdown menu, cut-off progress bar, cut-off search input. */
.lpos-blueprint .lpos-cell--topleft,
.lpos-blueprint .lpos-cell--topcenter,
.lpos-blueprint .lpos-cell--topright,
.lpos-blueprint .lpos-cell--botleft,
.lpos-blueprint .lpos-cell--botcenter,
.lpos-blueprint .lpos-cell--botright { overflow: visible !important; }
/* Search field fills its bar (was collapsing to ~12px). */
.lpos-blueprint .lpos-search { padding: 0 var(--lpos-panel-pad, 12px) !important; }
.lpos-blueprint .lpos-search input { flex: 1 1 auto !important; width: 100% !important; height: 100% !important; min-height: 2.2em; background: transparent; border: 0; }
/* (progress-pill sizing rules removed 2026-08-10 with the rest of the dead XP block, above.) */

/* JD 2026-08-05: the "Next" control is a fixed-size button, NOT a full-width bar -- shrink to content
   and pin to the end of the row (its own panel chrome stays the one identical style). */

/* ⛔ ONE PANEL, BYTE-IDENTICAL (JD 2026-08-04, absolute last word). Every panel-bearing element renders
   the EXACT same chrome: same glass, same blur, same 1px 40% accent border, same 16px radius. Zero
   variance in color/border/radius/transparency/blur. This overrides any divergent alpha/no-border rule. */
.lpos-blueprint .lpos-cell,
.lpos-blueprint .lpos-rail,
.lpos-blueprint .lpos-c-panel,
.lpos-blueprint .lpos-c-title-panel,
.lpos-blueprint .lpos-c-subpanel,
.lpos-blueprint .lpos-c-icon-btn,
.lpos-blueprint .lpos-c-thumb,
.lpos-blueprint .lpos-c-buytoggle__opt,
.lpos-blueprint .lpos-c-next-action,
.lpos-blueprint .lpos-c-archive-card__hit,
.lpos-blueprint .lpos-c-cta__buy,
.lpos-blueprint .lpos-c-cta__booklet,
.lpos-blueprint .lpos-c-archive-card__btn,
.lpos-blueprint .lpos-menu__link,
.lpos-blueprint .lpos-menu__toggle,
.lpos-blueprint .lpos-c-select__menu,
.lpos-blueprint .lpos-c-select__value,
.lpos-blueprint .lpos-c-select__option,
.lpos-blueprint .lpos-topbar__search,
.lpos-blueprint .lpos-search,
.lpos-blueprint .lpos-switch--icons,
.lpos-drawer .lpos-menu__link,
.lpos-drawer .lpos-menu__toggle {
  background: var(--lpos-glass-panel) !important;
  -webkit-backdrop-filter: var(--lpos-blur-md) !important;
  backdrop-filter: var(--lpos-blur-md) !important;
  border: var(--lpos-border-width,1px) solid color-mix(in srgb, var(--lpos-border-tint,var(--lpos-accent)) var(--lpos-border-alpha-2,40%), transparent) !important; /* Phase 2: literals -> tokens */
  border-radius: var(--lpos-radius-panel) !important;
  box-shadow: none !important;
}
/* Switcher is ONE panel: the outer .lpos-c-select is a chromeless control shell (the critic's rank-3
   fix); its inner .lpos-c-select__value is the single visible panel holding logo + chevron Assets.
   Wrapper subpanels (menu/cluster/tabbar) are content flow, never a second panel. */
.lpos-blueprint .lpos-c-select,
.lpos-blueprint .lpos-c-subpanel--menu,
.lpos-blueprint .lpos-c-subpanel--cluster,
.lpos-blueprint .lpos-c-subpanel--tabbar {
  background: transparent !important;
  border: 0 !important;
  box-shadow: none !important;
  padding: 0 !important;
}
/* JD 2026-08-05 (ABSOLUTE LAW): THERE ARE NO CLUSTERS. Zero. Only Components (each REQUIRED to have its
   own panel) and Assets. A group of buttons/thumbnails is NEVER a cluster panel -- every button and every
   thumbnail is a standalone Component with its own identical panel, sitting DIRECTLY in the Display cell.
   The wrapper div (--cluster/--tabbar) is pure invisible layout flow (flex+gap), NOT a panel: it carries
   zero chrome (the force-transparent block above governs it). Do NOT give any cluster wrapper a border,
   background, or padding anywhere. */
/* DEAD-TOKEN WIRING 2026-08-10 (JD's call: "wire them up"). Brand Styling exposed these as editable
   fields, saved them, emitted them -- and NOTHING consumed them, so a tenant could change any of
   them and see no effect. Each now has exactly one real consumer, with the value it used to paint
   as the fallback, so nothing moves for a tenant who leaves them alone.
     --lpos-font-body : prose blocks (Display copy, buy-box description, card summaries). Previously
                        these all read --lpos-font-ui, which stays the fallback -- so "Body font
                        family" now actually separates reading copy from UI chrome.
     --lpos-glass-3   : the RAISED glass tier, used on hover. The hover rule below re-painted the
                        resting --lpos-glass-panel, i.e. hover changed nothing at all on the surface.
     --lpos-info      : informational status text (the form's own aria-live line lives in its
                        component sheet; this covers the console's inline notes).
   The two shadow tokens are NOT wired -- see the note in BrandStylingPage.php. */
.lpos-blueprint .lpos-feat__copy,
.lpos-blueprint .lpos-feat__copy p,
.lpos-blueprint .lpos-c-cta__info,
.lpos-blueprint .lpos-m8card__ptext{font-family:var(--lpos-font-body,var(--lpos-font-ui,'Inter', ui-sans-serif, system-ui, sans-serif))}
.lpos-blueprint .lpos-c-note,
.lpos-blueprint .lpos-c-chat__note{color:var(--lpos-info,var(--lpos-muted,#A8B2C7))}

/* Hover/active never change the panel chrome -- only the Asset (icon/text) color may change. */
.lpos-blueprint .lpos-menu__link:hover,
.lpos-blueprint .lpos-c-icon-btn:hover,
.lpos-blueprint .lpos-c-cta__buy:hover {
  border-color: color-mix(in srgb, var(--lpos-border-tint,var(--lpos-accent)) var(--lpos-border-alpha-2,40%), transparent) !important;
  /* the RAISED glass tier (--lpos-glass-3) over the resting panel: same chrome, one step brighter.
     Was a plain re-paint of --lpos-glass-panel, which made hover a no-op on the surface. */
  background: linear-gradient(0deg, var(--lpos-glass-3, transparent), var(--lpos-glass-3, transparent)), var(--lpos-glass-panel) !important;
}
/* Same 16px padding on every content panel (fixed-size icon buttons/thumbnails center their icon, so
   padding there is intrinsic to their square -- their chrome above is still identical). */
.lpos-blueprint .lpos-cell,
.lpos-blueprint .lpos-c-panel,
.lpos-blueprint .lpos-c-title-panel,
.lpos-blueprint .lpos-c-subpanel,
.lpos-blueprint .lpos-c-buytoggle__opt,
.lpos-blueprint .lpos-c-next-action,
.lpos-blueprint .lpos-c-archive-card__hit {
  padding: var(--lpos-panel-pad) !important;
  margin: 0 !important;
}

/* DIAGNOSTIC LAYER DELETED 2026-08-10 (JD: "delete totally the debug panel"). This was the
   temporary 4-world panel map -- ~84 rules of red/blue/yellow/green outlines gated behind
   html.lpos-diag-*, driven by a floating dev switch in lpos-drawers.js. Both are gone: the
   switch, its localStorage state, the window.lposDiag API and every rule here. */
/* ==== JD 2026-08-05 STANDARD-VIEW BATCH (items 1,3,4,5,6 -- item 2 lived at the since-removed .lpos-progress rule) ====
   JD EXPLICIT: the midleft thumbnail strip and the midright tab group ARE panels -- they get the ONE
   identical panel chrome ("either the panel gets removed or it gets panel styling"). Higher
   specificity than the transparent-wrapper block, so these two specific groups win. */
/* 1. thumbnail strip panel (midleft, open view) */
.lpos-blueprint .lpos-cell--midleft .lpos-col > .lpos-switch,
/* 3. mid-right tab-group panel */
.lpos-blueprint .lpos-cell--midright .lpos-c-subpanel--tabbar,
.lpos-blueprint .lpos-cell--midright .lpos-c-subpanel--cluster {
  background: var(--lpos-glass-panel) !important;
  -webkit-backdrop-filter: var(--lpos-blur-md) !important;
  backdrop-filter: var(--lpos-blur-md) !important;
  border: var(--lpos-border-width,1px) solid color-mix(in srgb, var(--lpos-border-tint,var(--lpos-accent)) var(--lpos-border-alpha-2,40%), transparent) !important;
  border-radius: var(--lpos-radius-panel) !important;
  box-shadow: none !important;
  padding: var(--lpos-subpanel-pad,6px) !important;
}
/* 4+5+6. Focus column proportions: the media box (6) absorbs the free height (taller); the Focus
   title block (5) rides below it (moved down); the buy/Not-Available button (4) pins to the
   BOTTOM-RIGHT of the panel, with a reserved lane so nothing underlaps it. */
.lpos-blueprint .lpos-c-cta {
  position: relative;
  align-content: stretch !important;
  /* JD 2026-08-05 (Focus tab proportions v2): the media box holds a NORMAL LANDSCAPE ratio (row
     auto + its own aspect-ratio below); the Focus container takes the freed height (row 1fr). */
  grid-template-rows: auto minmax(0,1fr) !important;
  padding-bottom: calc(var(--lpos-control-size,46px) + var(--lpos-gap,12px)) !important; /* button lane */
  min-height: 100%;
}
.lpos-blueprint .lpos-c-cta__media { min-height: 0; height: auto !important; width: 100%;
  aspect-ratio: var(--lpos-media-switch-ratio, 16/9); }
.lpos-blueprint .lpos-c-cta__buy {
  position: absolute; right: 0; bottom: 0;
  width: auto !important; min-width: var(--lpos-control-size,46px);
}
/* ==== /STANDARD-VIEW BATCH ==== */

/* ==== JD 2026-08-05 RIGHT-COLLAPSED BATCH (items 2,3,4+5; 1 and 6 live at their state blocks) ==== */
/* 2. The corner reopen toggle is ALONE in its 64px box while either side is collapsed -- the five
   view switches live in the right rail there, so their cell copies hide instead of crushing the
   toggle off-center. */
.lpos-blueprint--console .lpos-cell--botright .lpos-c-icon-btn:not([data-lpos-collapse]):not([data-lpos-command-palette]):not([data-a]){display:none!important} /* rev: the corner PAGER chevron ([data-a]) must render (JD: missing icon) */
.lpos-pagination--corner{display:flex;align-items:center;justify-content:center;flex:0 0 auto}
.lpos-blueprint .lpos-cell--botleft .lpos-pagination--corner .lpos-c-icon-btn,
.lpos-blueprint .lpos-cell--botright .lpos-pagination--corner .lpos-c-icon-btn{flex:0 0 auto!important;width:var(--lpos-control-size,46px)!important;height:var(--lpos-control-size,46px)!important;min-width:0!important} /* corner chevrons: one square control style, both corners (JD) */ /* stage B 2026-08-09: state-free -- the switch copies live on the full-height right rail in BOTH states now; the corner box holds only the plus */ /* JD 2026-08-06: the plus (ex right-toggle) button stays visible in every state */
/* 4+5. Previous + Next share ONE chromeless flow row: Previous left, Next right (the Next button's
   own margin-left:auto does the split). Wrapper is pure layout flow, never a panel. */
.lpos-blueprint .lpos-feat__actions{display:flex;align-items:center;justify-content:space-between;gap:var(--lpos-gap,12px);width:100%;flex:0 0 auto}
/* ==== /RIGHT-COLLAPSED BATCH ==== */

/* ==== JD 2026-08-05 EVENING TWEAKS (5 point-at items) ==== */
/* Focus title panel 2 blocks taller; the media box above (row 1fr) gives the height back. */
.lpos-blueprint .lpos-c-cta__info{min-height:calc(var(--lpos-control-size,46px) + 2*(var(--lpos-control-size,46px) + var(--lpos-gap,12px)))}
/* Midcenter: the title panel grows UP to the video's bottom edge -- no dead gap between them.
   The video block may SHRINK (its 16:9 stage rescales) but never grows past its ratio; the title
   panel absorbs any free height but never compresses below its own text (the 1px-subtitle-clip
   fix: min-height:max-content, not 0). */
/* RATIO LOCK rev 3 (JD 2026-08-06, "video down, text grows"): the TEXT panel owns the flexible
   height now and the video panel hugs the column bottom with the normal cell padding below it.
   The video went back to WIDTH-driven sizing -- the rebalanced narrow center column is what keeps
   the 16:9 height honest in every state (verified per state). */
/* RATIO LOCK rev 4 (JD 2026-08-09, "text is cut off under the video"): the 2:1 RATIO LAW made the
   center column WIDER, so the width-driven 16:9 video overflowed the cell and pushed the title
   panel past the bottom. The BODY is the flexible row now (definite height from the cell flex),
   the video sizes HEIGHT-driven inside it (stage rules below), and the title panel keeps its full
   natural height -- text always visible, never clipped. */
.lpos-blueprint .lpos-cell--midcenter .lpos-feat__body{flex:1 1 0;min-height:0;
  display:flex;align-items:center;justify-content:center}
/* AMBIENT FILL (JD 2026-08-09 rev 2, research-backed: YouTube Ambient / Apple Music pattern):
   the blurred, DIMMED cover of the Display's own artwork fills the WHOLE center panel -- behind
   the player, its toolbar, and the text panel (--lpos-m8card-bg, stamped on the cell by
   panel_centerfeature() and re-stamped by the JS center swap; honest-empty = no var = no paint).
   Exact same z-index:-1 anatomy as the midright cover below; a glass VEIL (::after) frosts the
   raw glow so it reads as ambient light, never a photo (the research's dark-mode caution). */
/* VIDEO PLAYER PANEL (JD 2026-08-09 rev 3, his sketch): the body is a REAL full-width panel --
   the featured image covers IT (lightly blurred, scaled past its own blur edge) under the same
   glass veil, the true-ratio video floats centered inside, and the cover simply stays put while
   the video plays (it IS the video's glassmorphism background). Poster-until-play is the video
   engine's own embedposter, fed by the same artwork chain. */
.lpos-blueprint .lpos-cell--midcenter .lpos-feat__body{
  position:relative;z-index:0;overflow:hidden;align-self:stretch;padding:var(--lpos-subpanel-pad,6px);box-sizing:border-box;
  border-radius:var(--lpos-radius-panel,10px);
  border:var(--lpos-border-width,1px) solid color-mix(in srgb,var(--lpos-border-tint,var(--lpos-accent)) var(--lpos-border-alpha-2,40%),transparent);
  background:var(--lpos-glass-panel)}
.lpos-blueprint .lpos-cell--midcenter .lpos-feat__body::before{content:'';position:absolute;inset:0;z-index:-1;
  background-image:var(--lpos-m8card-bg,none);background-size:cover;background-position:center;
  transform:scale(1.06);filter:blur(10px) saturate(1.05) brightness(0.7);opacity:0.55;pointer-events:none}
.lpos-blueprint .lpos-cell--midcenter .lpos-feat__body::after{content:'';position:absolute;inset:0;z-index:-1;
  background:color-mix(in srgb,var(--lpos-panel,#0D111C) 45%,transparent);pointer-events:none}
.lpos-blueprint .lpos-cell--midcenter{position:relative;z-index:0;overflow:hidden}
.lpos-blueprint .lpos-cell--midcenter::before{content:'';position:absolute;inset:-24px;z-index:-1;
  background-image:var(--lpos-m8card-bg,none);background-size:cover;background-position:center;
  filter:blur(44px) saturate(1.1) brightness(0.55);opacity:0.4;pointer-events:none}
.lpos-blueprint .lpos-cell--midcenter::after{content:'';position:absolute;inset:0;z-index:-1;
  background:color-mix(in srgb,var(--lpos-panel,#0D111C) 40%,transparent);
  pointer-events:none} /* the glassmorphism veil over the glow (JD: "opacity and glassmorphism overlay") */
.lpos-blueprint .lpos-cell--midcenter .lpos-feat__titlecap{flex:0 0 auto;min-height:max-content}
/* Second bottom action: LEFT end of the same line as the right one. */
.lpos-blueprint .lpos-c-cta__buy--secondary{left:0;right:auto}
/* ==== /EVENING TWEAKS ==== */

/* ==== JD 2026-08-05 TASK 7: BOTH-COLLAPSED RIGHT BOX ====
   The clicked rail item's live pane docks into this panel (cinematic sidebar area, col 2) and
   swaps on every select (lpos-drawers.js returnRailBoxPane/dock). Hidden + inert everywhere else. */
.lpos-feat__boxhost[hidden]{display:none!important}
/* JD 2026-08-05 (both-collapsed item 6): the sidebar spans DOWN beside the action row too -- no
   empty gap right of the Next button; the actions row stays aligned with the primary column. */
/* JD 2026-08-06 REWORK: the TEXT panel moves to col 1 ABOVE the video (row 2); the sidebar box
   (col 2, rows 2-4) is ALWAYS populated -- Focus pane docked by default, rail clicks swap it.
   The old "sidebar shows the text / hide it when a pane docks" pair is deleted. */
/* JD 2026-08-06: the THEME's page title/site header sit behind the fixed Magick8 overlay and
   BLUR THROUGH its translucent glass surfaces -- hide the whole underlying page layer, then
   re-show the blueprint itself (visibility re-enables on descendants). */
body:has(.lpos-blueprint--magick8) .wp-site-blocks{visibility:hidden}
.lpos-blueprint--magick8{visibility:visible}

/* ==== JD 2026-08-06 MAGICK8 WELCOME STACK ====
   Five centered components over the backdrop; ONLY the two CTA buttons carry panel chrome
   (they reuse the menu CTA classes verbatim). Everything else is bare text/image on the veil. */
.lpos-blueprint--magick8 .lpos-magick8__stack{position:relative;z-index:1;margin:auto;display:flex;flex-direction:column;align-items:center;gap:var(--lpos-gap,12px);width:min(92vw,560px);text-align:center;
  padding-top:calc(2*var(--lpos-gap,12px));padding-bottom:calc(2*var(--lpos-gap,12px))} /* JD 2026-08-06: guaranteed breathing room against the viewport top + bottom */
.lpos-blueprint--magick8 .lpos-magick8__welcome{margin:0;font:300 clamp(1rem,.85rem + .7vw,1.35rem)/1.2 var(--lpos-font-display,'Space Grotesk', ui-sans-serif, system-ui, sans-serif);letter-spacing:calc(2*var(--lpos-tracking-label,0.08em));text-transform:uppercase;color:var(--lpos-ink,#EAF2FB)}
.lpos-blueprint--magick8 .lpos-magick8__logo{display:block;width:min(84vw,520px);height:auto;margin-bottom:calc(2*var(--lpos-gap,12px))}
/* JD 2026-08-06: logo panel LEADS the stack (logo on top, tagline under it), breathing room
   below the panel before the tagline */
.lpos-blueprint--magick8 .lpos-magick8__logopanel{margin:0;
  width:calc(var(--lpos-m8-car-w,min(96vw,1240px))/3);display:flex;align-items:center;justify-content:center} /* JD 2026-08-06: bare logo (no panel chrome) -- the PANEL moved to the tagline below it */
.lpos-blueprint--magick8 .lpos-magick8__logopanel .lpos-magick8__logo{width:min(58vw,320px);margin-bottom:0}
.lpos-blueprint--magick8 .lpos-magick8__ctas{width:calc(var(--lpos-m8-car-w,min(96vw,1240px))*0.42);margin-top:var(--lpos-gap,12px);margin-bottom:calc(0.5*var(--lpos-gap,12px))} /* JD 2026-08-06: slimmed CTA pair, wide enough that the edge icons never touch the label */
/* JD 2026-08-06: breathing room between the logo panel and the tagline (as the TEXT's top
   margin -- a base panel rule !important-zeroes margin-bottom on .lpos-c-panel) */
.lpos-blueprint--magick8 .lpos-magick8__stack[data-lpos-route-display="welcome"] .lpos-magick8__welcome{margin-top:var(--lpos-gap,12px)!important;
  padding:var(--lpos-subpanel-pad,6px) calc(3*var(--lpos-panel-pad,12px))!important;
  background:var(--lpos-glass-panel,linear-gradient(180deg, rgba(30,42,66,0.34), rgba(16,24,40,0.45)))!important;
  -webkit-backdrop-filter:var(--lpos-blur-md,blur(16px) saturate(140%))!important;backdrop-filter:var(--lpos-blur-md,blur(16px) saturate(140%))!important} /* glass fallbacks: the blueprint stack sits outside the token scope, same pattern as the CTA buttons */ /* JD 2026-08-06: 50/50 of the FEATURED SLIDE width */ /* JD 2026-08-06: CTA row spans the video panel's full width, 50/50 buttons */
/* the player is the CENTERPIECE -- wider than the rest of the stack, true 16:9 panel included */
.lpos-blueprint--magick8 .lpos-magick8__player{width:var(--lpos-m8-w,min(92vw,860px));margin-bottom:var(--lpos-gap,12px)}
.lpos-blueprint--magick8 .lpos-magick8__player .lpos-media{width:100%!important;height:auto!important;aspect-ratio:auto!important}
.lpos-blueprint--magick8 .lpos-magick8__player .lpos-media .lpos-media__stage,
.lpos-blueprint--magick8 .lpos-magick8__player .lpos-media .lpos-media__stagev{width:100%;height:auto;aspect-ratio:16/9;min-height:0} /* JD 2026-08-06: the STAGE carries the 16:9 (inner box stays true 16:9 after panel padding -- no pillarbox bars); the panel wraps it */
/* cover safeguard (JD 2026-08-07): hairline borders shave 1-2px off the inner box; a fit-inside
   embed letterboxes that difference as a black band. The iframe keeps true 16:9 and COVERS the
   box instead (sub-pixel crop, never a band). */
.lpos-blueprint--magick8 .lpos-magick8__player .lpos-media .lpos-media__embedwrap iframe{position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);aspect-ratio:16/9;min-width:100%;min-height:100%;width:auto;height:auto}
.lpos-blueprint--magick8 .lpos-magick8__ctas .lpos-menu__cta,
.lpos-blueprint--magick8 .lpos-magick8__next{cursor:pointer;text-decoration:none;display:flex;align-items:center;justify-content:center;
  min-height:calc(var(--lpos-control-size,46px) + 2*var(--lpos-panel-pad,12px));padding:calc(1.5*var(--lpos-panel-pad,12px)) calc(2*var(--lpos-panel-pad,12px))!important;
  font:700 clamp(1.1rem,1rem + .5vw,1.35rem)/1 var(--lpos-font-ui,'Inter', ui-sans-serif, system-ui, sans-serif)!important;letter-spacing:var(--lpos-tracking-label,0.08em);text-transform:uppercase;
  background:var(--lpos-glass-panel,linear-gradient(180deg, rgba(30,42,66,0.34), rgba(16,24,40,0.45)))!important;
  -webkit-backdrop-filter:var(--lpos-blur-md,blur(16px) saturate(140%))!important;backdrop-filter:var(--lpos-blur-md,blur(16px) saturate(140%))!important;
  border:var(--lpos-border-width,1px) solid color-mix(in srgb,var(--lpos-border-tint,var(--lpos-accent)) var(--lpos-border-alpha-2,40%),transparent)!important}
/* Login = the QUIET tertiary control, styled COMPLETELY apart from the CTA pair: small pill,
   near-invisible glass-1 tint, hairline low-alpha border, no blur weight, small muted
   sentence-case label. position:static beats the menu-scoped absolute placement. */
.lpos-blueprint--magick8 .lpos-magick8__login{position:static!important;display:inline-flex;align-items:center;justify-content:center;cursor:pointer;
  width:auto;min-width:0;flex:0 0 auto!important;margin:0 auto;text-decoration:none!important;
  min-height:var(--lpos-control-size,46px);min-width:220px;padding:var(--lpos-panel-pad,12px) calc(3*var(--lpos-panel-pad,12px))!important;
  font:400 var(--lpos-text-md,17px)/1 var(--lpos-font-ui,'Inter', ui-sans-serif, system-ui, sans-serif)!important;letter-spacing:var(--lpos-tracking-label,0.08em);text-transform:uppercase;color:var(--lpos-muted,#A8B2C7)!important;
  background:var(--lpos-glass-1,rgba(255,255,255,0.035))!important;
  -webkit-backdrop-filter:none!important;backdrop-filter:none!important;
  border:var(--lpos-border-width,1px) solid color-mix(in srgb,var(--lpos-border-tint,var(--lpos-accent)) var(--lpos-border-alpha-1,30%),transparent)!important;
  border-radius:var(--lpos-radius-control,8px)}
.lpos-blueprint--magick8 .lpos-magick8__login:hover{color:var(--lpos-ink,#EAF2FB)!important}
/* JD 2026-08-06: button icons -- compass pinned LEFT in Explore, forward arrow pinned RIGHT in
   Get Started, lock pinned LEFT in Login; text stays centered (icons are edge-anchored). */
.lpos-blueprint--magick8 .lpos-magick8__ctas .lpos-menu__cta,
.lpos-blueprint--magick8 .lpos-magick8__stack .lpos-magick8__login{position:relative!important}
.lpos-blueprint--magick8 .lpos-magick8__bicon{position:absolute;top:50%;transform:translateY(-50%);display:flex;align-items:center;justify-content:center;color:currentColor}
.lpos-blueprint--magick8 .lpos-magick8__bicon--left{left:var(--lpos-subpanel-pad,6px)} /* JD 2026-08-06: side inset == vertical gap */
.lpos-blueprint--magick8 .lpos-magick8__bicon--right{right:var(--lpos-subpanel-pad,6px)}
/* JD 2026-08-06: the CTA pair's icons sit in their own icon-button subpanel INSIDE the button */
.lpos-blueprint--magick8 .lpos-magick8__ctas .lpos-magick8__bicon{width:var(--lpos-control-size,46px);height:var(--lpos-control-size,46px);
  background:var(--lpos-glass-1,rgba(255,255,255,0.035));
  border:var(--lpos-border-width,1px) solid color-mix(in srgb,var(--lpos-border-tint,var(--lpos-accent)) var(--lpos-border-alpha-2,40%),transparent);
  border-radius:var(--lpos-radius-control,8px)}
.lpos-blueprint--magick8 .lpos-magick8__bicon svg{width:var(--lpos-icon-size-sm,24px);height:var(--lpos-icon-size-sm,24px);fill:none!important;stroke:currentColor}

/* JD 2026-08-06: the LOGIN heading hugs the logo (less space above) and breathes below, at a
   larger size than the welcome line. Scoped to the login stack only. */
.lpos-blueprint--magick8 .lpos-magick8__stack--login .lpos-magick8__welcome{margin:calc(-3.5*var(--lpos-gap,12px)) 0 calc(3*var(--lpos-gap,12px));font-size:clamp(1.3rem,1.1rem + .9vw,1.75rem);font-weight:400} /* JD 2026-08-06: hugs the logo tighter, more air below before the fields */

/* ==== ATOMIC FEATURED-CONTENT CAROUSEL (JD 2026-08-06) ====
   Center panel large, flanks recede (landscape 16:9 slides). Token-driven, ONE PANEL chrome
   per slide; the CENTER earns border emphasis via the border-alpha-3 token -- NO shadows.
   Works anywhere; sized here by the shared magick8 width token when inside magick8. */
.lpos-c-carousel{position:relative;width:var(--lpos-m8-car-w,min(96vw,1240px));
  display:flex;flex-direction:column;align-items:center;min-height:0} /* JD 2026-08-09 rev 4: the carousel CONTAINS its dot strip -- as a plain block its box ended at the stage and the dots hung outside it, landing on the video above and the CTA row below whatever margin they carried. The stage yields the room now (flex shrink), so the strip can never collide again. */
.lpos-c-carousel__dots{flex:0 0 auto} /* the flex column centers the strip; the legacy left/transform pair is deleted at its source below, so no !important mask is needed here */
.lpos-c-carousel__stage{position:relative;min-height:0;overflow:hidden;
  /* rev 5 (JD 2026-08-10, "the slides are cut off"): rev 4 let the stage shrink in HEIGHT only.
     Slides are absolutely sized at 56% of stage WIDTH with a 16:9 ratio, so a shorter stage with
     the same width clipped their top and bottom. The stage keeps its own ratio now
     (width / (0.56*9/16) = 3.175) and shrinks in BOTH axes: the flex column sets its height, the
     ratio derives the width, and the engine -- which reads stage.clientWidth for its step -- stays
     in sync automatically. */
  flex:0 1 auto;height:calc(var(--lpos-m8-car-w,min(96vw,1240px))*0.56*9/16 + 2*var(--lpos-gap,12px));
  max-height:100%;width:auto;max-width:100%;aspect-ratio:3.175;
  -webkit-mask-image:linear-gradient(90deg,transparent 0,rgba(0,0,0,.2) 4%,rgba(0,0,0,.72) 10%,#000 16%,#000 84%,rgba(0,0,0,.72) 90%,rgba(0,0,0,.2) 96%,transparent 100%);
  mask-image:linear-gradient(90deg,transparent 0,rgba(0,0,0,.2) 4%,rgba(0,0,0,.72) 10%,#000 16%,#000 84%,rgba(0,0,0,.72) 90%,rgba(0,0,0,.2) 96%,transparent 100%)} /* POSITION-based edge fade (JD): flanks dissolve smoothly into transparency approaching the edges -- the clip line sits where alpha is already 0, so no hard cutoff can exist */
.lpos-c-carousel__slide{position:absolute;left:50%;top:50%;width:56%;min-height:0;
  height:auto!important;aspect-ratio:16/9!important;contain:size layout;padding:0!important; /* EVERY slide is a true 16:9 box derived from its OWN width. The old explicit height used var(--lpos-m8-car-w), a JS-measured width that drifts from the real carousel width (scrollbar/resize), leaving the panel off-ratio and the video letterboxed (JD 2026-08-07). contain:size still stops content from stretching it (JD law). */
  -webkit-backdrop-filter:none!important;backdrop-filter:none!important; /* research finding: backdrop-filter inside an animating 3D transform tree = Chromium repaint flicker; the glass GRADIENT stays */
  transform:translate(-50%,-50%);cursor:pointer;overflow:hidden;box-sizing:border-box;
  transition:border-color var(--lpos-duration-base,220ms) var(--lpos-ease-tech,cubic-bezier(0.16, 1, 0.3, 1)),padding var(--lpos-duration-base,220ms) var(--lpos-ease-tech,cubic-bezier(0.16, 1, 0.3, 1))} /* transform/opacity are rAF-driven now -- transitions would trail the engine */
.lpos-c-carousel__slide[data-offset="0"]{z-index:5;cursor:default;
  border-color:color-mix(in srgb,var(--lpos-ink,#EAF2FB) var(--lpos-border-alpha-3,55%),transparent)!important} /* JD 2026-08-06: FOCUS slide wears the light-white (ink-token) outline; important beats the panel base chrome */
/* static filmstrip fallback (reduced-motion first paint): full-card steps, no overlap */
.lpos-c-carousel__slide[data-offset="-1"]{transform:translate(-50%,-50%) translateX(-102%);z-index:4}
.lpos-c-carousel__slide[data-offset="1"]{transform:translate(-50%,-50%) translateX(102%);z-index:4}
.lpos-c-carousel__slide[data-offset="-2"]{transform:translate(-50%,-50%) translateX(-204%);z-index:3;opacity:0}
.lpos-c-carousel__slide[data-offset="2"]{transform:translate(-50%,-50%) translateX(204%);z-index:3;opacity:0}
/* slide CONTENT fills the slide panel edge to edge inside the token padding */
.lpos-c-carousel__slide .lpos-magick8__player,
.lpos-c-carousel__slide .lpos-magick8__imgpanel{width:100%!important;height:100%;margin:0!important}
/* JD 2026-08-06: ONE panel only -- the slide carries the chrome, the inner media panel sheds
   its own (background/border/padding stripped, radius handed to the stage) */
.lpos-c-carousel__slide .lpos-media{height:100%!important;background:transparent!important;border:0!important;padding:0!important;box-shadow:none!important}
.lpos-c-carousel__slide .lpos-media .lpos-media__stage,
.lpos-c-carousel__slide .lpos-media .lpos-media__embedwrap{border-radius:inherit;overflow:hidden}
/* inside magick8 the stack centers it and gives the standard rhythm below */
.lpos-blueprint--magick8 .lpos-c-carousel{margin-top:0;margin-bottom:calc(var(--lpos-gap,12px) + var(--lpos-subpanel-pad,6px))} /* JD 2026-08-09: the -2.5gap PULL is deleted. It existed to compensate for the dot strip's old negative margin (dots overlapped the stage's dead band, so the carousel sat lower than it measured). With the strip now INSIDE the carousel box, that compensation dragged the slides up over the tagline panel above -- the overlap JD circled. */
/* nav chevrons flank the stage, vertically centered at the stage's midline */
.lpos-c-carousel__nav{position:absolute;top:50%;transform:translateY(-50%);z-index:4000;cursor:pointer;color:var(--lpos-ink,#EAF2FB)!important;
  width:calc(1.4*var(--lpos-control-size,46px))!important;height:calc(1.4*var(--lpos-control-size,46px))!important} /* JD 2026-08-06: ENLARGED chevrons, ABOVE every slide, floating over the edge-fade zones */
.lpos-c-carousel__nav svg{width:calc(1.3*var(--lpos-icon-size-sm,24px));height:calc(1.3*var(--lpos-icon-size-sm,24px))}
.lpos-c-carousel__nav--prev{left:calc(2*var(--lpos-gap,12px))}
.lpos-c-carousel__nav--next{right:calc(2*var(--lpos-gap,12px))}
/* dots: a centered subpanel under the stage; the active dot fills with the accent token */
.lpos-c-carousel__dots{position:relative;z-index:6;display:flex;flex-direction:row-reverse;align-items:center;justify-content:center;gap:calc(6*var(--lpos-subpanel-pad,6px)); /* row-reverse (JD): the strip travels RIGHT (index decreases), so reversed dots make progress read left-to-right */
  width:max-content;top:0;
  padding:var(--lpos-subpanel-pad,6px) calc(6*var(--lpos-panel-pad,12px))!important} /* rev 2: the -2.75-gap upward pull rode the dots INTO the video/slider as the stage grew. rev 5 (2026-08-10 review D3): left:50%/translateX(-50%) DELETED rather than left masked by !important further up -- the flex column centers the strip, and a masked rule means any future !important cleanup silently reintroduces the double-offset. */
/* rev 3 (JD 2026-08-09): EQUAL air on BOTH sides. Needs 3 classes -- the shared panel base rule
   (`.lpos-blueprint .lpos-c-subpanel{margin:0!important}`, 2 classes) outranked a 1-class
   margin-block, which is why rev 2 left the strip pinched (0px above, 2px below the CTA row). */
.lpos-blueprint .lpos-c-carousel .lpos-c-carousel__dots{margin-block:var(--lpos-gap,12px)!important}
.lpos-c-carousel__dot{cursor:pointer;width:14px;height:14px;padding:0;box-sizing:border-box;
  background:var(--lpos-glass-1,rgba(255,255,255,0.035));
  border:var(--lpos-border-width,1px) solid color-mix(in srgb,var(--lpos-border-tint,var(--lpos-accent)) var(--lpos-border-alpha-2,40%),transparent);
  border-radius:var(--lpos-radius-pill,999px);
  transition:background var(--lpos-duration-fast,120ms) var(--lpos-ease-tech,cubic-bezier(0.16, 1, 0.3, 1)),border-color var(--lpos-duration-fast,120ms) var(--lpos-ease-tech,cubic-bezier(0.16, 1, 0.3, 1))}
.lpos-c-carousel__dot[aria-pressed="true"]{background:var(--lpos-accent-3,var(--lpos-accent));border-color:var(--lpos-accent-3,var(--lpos-accent))}
.lpos-c-carousel__dot:hover{border-color:var(--lpos-border-tint,var(--lpos-accent))}
/* ---- composite product slide (JD sketch 2026-08-06): tabbed media stage LEFT, thumb +
   callout + CTA pair RIGHT. Subpanel chrome throughout; honest-empty per part. ---- */
.lpos-m8slide{display:flex;gap:var(--lpos-subpanel-pad,6px);position:absolute;inset:0;box-sizing:border-box;padding:var(--lpos-subpanel-pad,6px);text-align:left} /* absolute inset: the media components inside can NEVER stretch the slide -- the 16:9 landscape ratio is locked (JD) */
.lpos-m8slide__main{flex:1.35 1 0;min-width:0;display:flex;flex-direction:column;gap:var(--lpos-subpanel-pad,6px)} /* JD 2026-08-06: left column slightly thinner -- the side column earns a larger, true-ratio image */
.lpos-m8slide__tabs{display:flex;gap:var(--lpos-subpanel-pad,6px)}
.lpos-m8slide__tab{cursor:pointer;flex:1 1 0!important;min-width:0;min-height:calc(0.62*var(--lpos-control-size,46px));
  display:flex!important;align-items:center!important;justify-content:center!important; /* JD: the 3 tabs share the main column evenly, labels centered */
  font:600 var(--lpos-text-sm,14px)/1 var(--lpos-font-ui,'Inter', ui-sans-serif, system-ui, sans-serif);letter-spacing:var(--lpos-tracking-label,0.08em);text-transform:uppercase;color:var(--lpos-muted,#A8B2C7)}
.lpos-m8slide__tab[aria-pressed="true"]{color:var(--lpos-ink,#EAF2FB);
  border-color:color-mix(in srgb,var(--lpos-border-tint,var(--lpos-accent)) var(--lpos-border-alpha-3,55%),transparent)!important}
.lpos-m8slide__stagepane{flex:1 1 0;min-height:0;overflow:hidden;position:relative}
/* loading choreography (research 2026-08-06): media fades IN when it arrives; while empty the
   pane wears a soft token shimmer -- staged arrival reads as design, not breakage */
.lpos-m8slide__stagepane:empty::after,.lpos-m8slide__stagepane .lpos-media__loading{content:"";position:absolute;inset:0;
  background:linear-gradient(100deg,transparent 30%,color-mix(in srgb,var(--lpos-ink,#EAF2FB) 5%,transparent) 50%,transparent 70%);
  background-size:220% 100%;animation:lposShimmer 1.4s ease-in-out infinite}
@keyframes lposShimmer{from{background-position:130% 0}to{background-position:-70% 0}}
.lpos-m8slide__stagepane .lpos-media__mount,.lpos-m8slide__stagepane model-viewer{animation:lposMediaIn var(--lpos-duration-reveal,180ms) ease}
@keyframes lposMediaIn{from{opacity:0}to{opacity:1}}
.lpos-m8slide__stagepane[hidden]{display:none}
.lpos-m8slide__stagepane .lpos-media{width:100%!important;height:100%!important;background:transparent!important;border:0!important;padding:0!important;gap:0!important}
/* JD 2026-08-06: the PDF sits edge-to-edge in its pane -- no inner margins/space; slim chrome rows */
.lpos-m8slide__stagepane .lpos-media .lpos-media__stage{padding:0!important;margin:0!important;
  display:flex;align-items:center;justify-content:center} /* the book centers in the leftover box -- no lopsided gaps (JD) */
.lpos-m8slide__stagepane .lpos-media .lpos-media__bar{margin:0!important;padding:calc(0.5*var(--lpos-subpanel-pad,6px)) 0!important}
.lpos-m8slide__side{flex:1 1 0;min-width:0;display:flex;flex-direction:column;gap:var(--lpos-subpanel-pad,6px)}
.lpos-m8slide__thumb{flex:0 0 auto;width:100%;aspect-ratio:16/9;min-height:0;overflow:hidden;padding:0!important} /* JD 2026-08-06: featured image panel is ALWAYS true 16:9 -- height derives from the column width, never squished */
.lpos-m8slide__thumb img{width:100%;height:100%;object-fit:cover;display:block;border-radius:inherit}
.lpos-m8slide__callout{flex:1 1 0;min-height:0;overflow:hidden;padding:calc(2*var(--lpos-subpanel-pad,6px)) calc(3*var(--lpos-subpanel-pad,6px))!important;
  display:flex!important;flex-direction:column!important;justify-content:flex-start!important;align-items:stretch!important;gap:calc(2*var(--lpos-subpanel-pad,6px))} /* title pinned TOP, a full breath, then the excerpt (JD) -- never side-by-side (important: the subpanel base is a flex ROW) */
.lpos-m8slide__callout h4,.lpos-m8slide__callout p{width:100%}
.lpos-m8slide__callout h4{margin:0 0 calc(0.5*var(--lpos-subpanel-pad,6px));font:700 var(--lpos-text-md,17px)/1.2 var(--lpos-font-display,'Space Grotesk', ui-sans-serif, system-ui, sans-serif);color:var(--lpos-ink,#EAF2FB)}
.lpos-m8slide__callout p{margin:0;font:400 var(--lpos-text-sm,14px)/1.45 var(--lpos-font-ui,'Inter', ui-sans-serif, system-ui, sans-serif);color:var(--lpos-muted,#A8B2C7);
  display:-webkit-box;-webkit-line-clamp:4;-webkit-box-orient:vertical;overflow:hidden} /* 4 lines in the taller callout (JD sketch), nothing clips */
.lpos-m8slide__ctarow{display:flex;gap:var(--lpos-subpanel-pad,6px)}
.lpos-m8slide__cta{cursor:pointer;flex:1 1 0;min-height:var(--lpos-control-size,46px);
  display:flex!important;align-items:center!important;justify-content:center!important;text-align:center; /* JD: CTA labels centered */
  font:700 var(--lpos-text-sm,14px)/1 var(--lpos-font-ui,'Inter', ui-sans-serif, system-ui, sans-serif);letter-spacing:var(--lpos-tracking-label,0.08em);text-transform:uppercase;color:var(--lpos-ink,#EAF2FB)}
/* slide ASSETS: token radius (panel radius minus the hairline) + the asset alpha token */
/* (v455 root-cause fix: the old content-box "panel ring" slide override lived HERE and, at
   higher specificity, silently beat the base slide geometry -- it was the composite slides'
   height stretch and several "rule not applying" mysteries. Slide geometry now has exactly
   one owner: the base .lpos-c-carousel__slide rule; inner padding belongs to .lpos-m8slide.) */
.lpos-blueprint--magick8 .lpos-c-carousel .lpos-c-carousel__slide .lpos-media,
.lpos-blueprint--magick8 .lpos-c-carousel .lpos-c-carousel__slide .lpos-magick8__imgpanel{height:100%!important}
.lpos-c-carousel__slide .lpos-magick8__imgpanel,
.lpos-c-carousel__slide .lpos-magick8__imgpanel img,
.lpos-c-carousel__slide .lpos-media .lpos-media__stage,
.lpos-c-carousel__slide .lpos-media .lpos-media__stagev,
.lpos-c-carousel__slide .lpos-media .lpos-media__embedwrap{border-radius:calc(var(--lpos-radius-panel,10px) - var(--lpos-border-width,1px))!important}
.lpos-c-carousel__slide .lpos-magick8__imgpanel img,
.lpos-c-carousel__slide .lpos-media iframe,
.lpos-c-carousel__slide .lpos-media video{opacity:var(--lpos-asset-alpha,0.9)}
.lpos-c-carousel__slide .lpos-media .lpos-media__stagev{border:0!important} /* stray hairline found in the chain probe -- the slide owns the one border */
/* ==== /ATOMIC FEATURED-CONTENT CAROUSEL ==== */

/* JD 2026-08-06 (audit HIGH, left-collapsed): the midright buy pane's tall media starved the
   info row to zero height and its text bled out from behind the buttons. Same law as the
   docked pane: the IMAGE row flexes, text always fits, clamp lifted, no bleed possible. */
/* JD 2026-08-10 spacing pass: the commit bar left this grid (it is a sibling of the column now),
   but its `[button|button]` track stayed behind as an empty trailing row -- costing a 12px gap of
   dead space under the text panel, JD's "gap below the text panel is too large". Track dropped. */
.lpos-blueprint--console.-left-collapsed:not(.-right-collapsed) .lpos-cell--midright .lpos-c-cta{grid-template-rows:auto auto auto minmax(120px,1fr)!important}
.lpos-blueprint--console.-left-collapsed:not(.-right-collapsed) .lpos-cell--midright .lpos-c-cta__media{min-height:0!important;aspect-ratio:auto!important;overflow:hidden}
.lpos-blueprint--console.-left-collapsed:not(.-right-collapsed) .lpos-cell--midright .lpos-c-cta__media img{width:100%;height:100%;object-fit:cover}
.lpos-blueprint--console.-left-collapsed:not(.-right-collapsed) .lpos-cell--midright .lpos-c-cta__info{min-height:0!important;overflow:hidden}
.lpos-blueprint--console.-left-collapsed:not(.-right-collapsed) .lpos-cell--midright .lpos-c-cta__excerpt{overflow:visible;display:block;max-height:none;-webkit-line-clamp:unset}

/* JD 2026-08-06 FAILED LOGIN DISPLAY: stacked full-width fields in place of the media panel;
   [back | Login] row with the Login stretching; inline icons inside the quiet buttons */
.lpos-blueprint--magick8 .lpos-magick8__field--stacked{width:100%}
.lpos-blueprint--magick8 .lpos-magick8__next.lpos-magick8__next--wide{flex:1 1 auto!important}
.lpos-blueprint--magick8 .lpos-magick8__sicon{display:inline-flex;align-items:center;margin-right:var(--lpos-space-sm,8px)}
.lpos-blueprint--magick8 .lpos-magick8__sicon svg{width:var(--lpos-icon-size-xs,20px);height:var(--lpos-icon-size-xs,20px);fill:none!important;stroke:currentColor}

/* LOGIN ROUTE DISPLAY (JD 2026-08-06): image panel sits exactly where the video panel does --
   same width, same 16:9, same ONE PANEL chrome; the inline form row takes the CTA row's slot. */
.lpos-blueprint--magick8 .lpos-magick8__stack[hidden]{display:none}
.lpos-blueprint--magick8 [data-lpos-route-part][hidden]{display:none!important} /* route parts REALLY hide -- component display rules (flex etc.) must never beat the hidden attr */
/* EXPLORE route display: the guest console fills the takeover viewport */
.lpos-blueprint--magick8 .lpos-magick8__explore{position:fixed;inset:0;z-index:10;overflow:hidden}
.lpos-blueprint--magick8 .lpos-magick8__explore[hidden]{display:none!important}
.lpos-blueprint .lpos-magick8__productgrid{display:grid!important;grid-template-columns:repeat(4,1fr)!important;grid-template-rows:repeat(2,1fr);gap:var(--lpos-subpanel-pad,6px);height:100%;min-height:0} /* JD option 1: FLUID 4x2 -- cards fill their tracks at every screen size, gaps = the half token, sides = the container inset; the card ratio follows the panel (~2% off pure 63:88) */ /* JD: HALVED gaps (subpanel token) -- taller rows = wider ratio-locked cards */ /* SELF-SUFFICIENT 4x2: ratio-locked cards, SIDES flush to the container inset (space-between) so left/right = top/bottom exactly (JD #1/#2); gutters distribute evenly */
/* JD 2026-08-06: the hidden tab strip's empty grid track + row-gaps left a fat band above the
   cards -- collapse them so the grid's top/bottom inset equals its sides, cards take the height */
/* JD 2026-08-06 ARCHIVE COLUMN LAW: every archive replicates the both-collapsed shop proportions
   -- the card grid ALWAYS holds the 4fr track and whatever companion display is open takes the
   2fr track. The in-cell [grid 4fr | pane 2fr] split exists ONLY in both-collapsed, where the
   focus pane physically docks into the cell's boxhost (dockDefaultFocusPane); in every other
   state (both open, or one side open) the companion lives in its own COLUMN, so the cell is
   single-track -- the old always-on 2fr companion track was pure dead space crushing the grid. */
.lpos-blueprint .lpos-cell--midcenter.lpos-cell--archive{row-gap:0!important;grid-template-columns:minmax(0,1fr)!important;grid-template-rows:minmax(0,1fr);column-gap:var(--lpos-gap,12px)} /* rows minmax(0,1fr): the body row must FILL the cell -- with no docked pane sibling to stretch against, the implicit auto row collapsed to card min-content (crushed excerpts, dead band below the grid) */
/* the both-collapsed docked-pane split and the single-collapsed row-level mirrors are deleted
   (Phase D 2026-08-09 dead-code group) -- the flat-grid stage A block carries the ARCHIVE COLUMN
   LAW forward on the console's own grid-template-columns instead (see BLUEPRINT SHIFT stage A). */
.lpos-blueprint .lpos-feat__body--archive{align-self:stretch;height:100%;min-height:0}
.lpos-blueprint .lpos-c-archive-grid{height:100%}
/* PRODUCT flavor of the atomic guest card (explore grid, JD 2026-08-06): grid-cell sized,
   landscape 16:9 art, excerpt box, 50/50 button row */
.lpos-blueprint .lpos-m8card.-product{height:100%;width:100%;transform:none;cursor:default;
  display:flex!important;flex-direction:column!important;gap:var(--lpos-subpanel-pad,6px);
  position:relative;overflow:hidden;isolation:isolate} /* one token seam between EVERY zone (JD #4); positioned+isolated for the glass background layer below */
/* JD 2026-08-06 CARD GLASS LAW (app-wide atomic card): the card's OWN featured image full-covers
   the panel -- edge to edge, no padding/margins, behind title/art/text/buttons -- dimmed so the
   zones' token glass chrome (blur + tint) frosts it. One rule, every card, everywhere. */
.lpos-blueprint .lpos-m8card.-product::before{content:'';position:absolute;inset:-24px;z-index:-1;
  background-image:var(--lpos-m8card-bg,none);background-size:cover;background-position:center;
  filter:blur(18px) saturate(1.15);opacity:0.22;pointer-events:none} /* JD rev 2: MORE blur + MORE transparency (negative inset overscans the blur's soft edge) */
/* 3D GLOW (JD backlog item 3, 2026-08-09): a blurred cover of the Display's featured artwork
   glows BEHIND the 3D object -- hotter and tighter than the column cover, scoped to the model
   stage only. Reads the same --lpos-m8card-bg var (midright cell + midleft cell both carry it);
   honest-empty without artwork. model-viewer lifts above the glow inside the stage's own
   stacking context. */
.lpos-blueprint .lpos-media.-model{position:relative;isolation:isolate;overflow:hidden}
.lpos-blueprint .lpos-media.-model::before{content:'';position:absolute;inset:-24px;z-index:0;
  background-image:var(--lpos-m8card-bg,none);background-size:cover;background-position:center;
  filter:blur(28px) saturate(1.25);opacity:0.45;pointer-events:none}
.lpos-blueprint .lpos-media.-model>*:not(.lpos-media__bar){position:relative;z-index:1} /* the pane has NO __stage wrapper in the switcher (model-viewer is a direct child) -- the glow lives on the -model panel itself. The toolbar is EXCLUDED: this rule ties (0,3,0) with the engine's floating-bar position:absolute and loads later, so an unqualified >* flattened the bar into flex flow -- its wrapped button column then stacked above the viewer (order:-1) and crushed the model to a strip (the 2026-08-09 carousel-slide breakage). The bar's own z-index:25 already clears the z0 glow. */
/* RIGHT COLUMN wears the SAME cover (JD 2026-08-07): the whole midright panel's background is the
   Display's featured artwork, covered + frosted exactly like the cards -- PHP sets the same
   --lpos-m8card-bg var on the cell ({@see BlueprintRenderer::midright_cell_open()}); honest-empty
   (no var) paints nothing. Inner subpanels' own glass frosts over it, same as card zones. */
/* JD 2026-08-10: the ambient cover + veil paint the CONTENT COLUMN, not the whole lane -- painting
   the lane made one continuous surface behind the commit bar too, so the buttons still read as
   part of the secondary content panel. */
.lpos-blueprint .lpos-cell--midright>.lpos-col{position:relative;z-index:0;overflow:hidden}
.lpos-blueprint .lpos-cell--midright>.lpos-col::before{content:'';position:absolute;inset:-24px;z-index:-1;
  background-image:var(--lpos-m8card-bg,none);background-size:cover;background-position:center;
  filter:blur(20px) saturate(1.2);opacity:0.5;pointer-events:none} /* JD 2026-08-07 rev 2: the card recipe (0.22/18) read invisible here -- the column's inner subpanels carry the DARK glass gradient (cards' zones are near-transparent), so the column cover runs hotter to shine through. Tuned live at 1911x953. */
.lpos-blueprint .lpos-cell--midright>.lpos-col::after{content:'';position:absolute;inset:0;z-index:-1;
  background:color-mix(in srgb,var(--lpos-panel,#0D111C) 40%,transparent);
  pointer-events:none} /* JD 2026-08-09 rev 2: the SAME glassmorphism veil as the center's ambient fill -- both columns frost their glow identically */
.lpos-blueprint .lpos-m8card.-product .lpos-m8card__titlebar,
.lpos-blueprint .lpos-m8card.-product .lpos-m8card__textbox,
.lpos-blueprint .lpos-m8card.-product .lpos-m8card__btn{
  -webkit-backdrop-filter:var(--lpos-blur-md,blur(16px) saturate(140%));backdrop-filter:var(--lpos-blur-md,blur(16px) saturate(140%))}
/* FLUSH internals (JD #5/#6): all four zones share the card's exact inner edges -- the card's
   own token padding is the ONLY inset */
.lpos-blueprint .lpos-m8card.-product .lpos-m8card__titlebar,
.lpos-blueprint .lpos-m8card.-product .lpos-m8card__frame--video,
.lpos-blueprint .lpos-m8card.-product .lpos-m8card__textbox,
.lpos-blueprint .lpos-m8card.-product .lpos-m8card__btnrow{margin:0!important;width:100%;box-sizing:border-box}
/* buttons BOTTOM-ANCHORED; the text panel grows to absorb the slack (JD #3) */
.lpos-blueprint .lpos-m8card.-product .lpos-m8card__btnrow{margin-top:auto!important}
/* NO-THUMBNAIL CARDS ARE TEXT-ONLY (JD 2026-08-10, an explicit exception to "everything follows the
   card archive": "for the faqs and knowledge base I think we remove the image and just make it text.
   only no content thumbnail").
   The card anatomy is UNCHANGED for anything that has art. When a card carries no real image, the
   media well was still claiming its fixed 16:9 slice and showing a placeholder glyph, which squeezed
   the text panel down to about one line -- FAQs made that obvious because their answers are the whole
   point of the card. Where there is no `img`, the well is removed and the text takes that height.
   `:has()` keeps this a pure render-time condition: nothing to pass down, no second card variant, and
   a card gains its media back the moment real art is bound. */
.lpos-blueprint .lpos-m8card.-product .lpos-m8card__frame:not(:has(.lpos-m8card__img)){display:none}
.lpos-blueprint .lpos-m8card.-product:not(:has(.lpos-m8card__img)) .lpos-m8card__textbox{
  align-items:flex-start!important;text-align:left!important;overflow:hidden}
.lpos-blueprint .lpos-m8card.-product:not(:has(.lpos-m8card__img)) .lpos-m8card__ptext{
  -webkit-line-clamp:12;max-height:100%}
@media (max-width:1600px){.lpos-blueprint .lpos-m8card.-product:not(:has(.lpos-m8card__img)) .lpos-m8card__ptext{-webkit-line-clamp:10}}
.lpos-blueprint .lpos-m8card.-product .lpos-m8card__frame--video{flex:0 0 auto;aspect-ratio:16/9;min-height:0}
.lpos-blueprint .lpos-m8card.-product .lpos-m8card__textbox{flex:1 1 0;min-height:0;
  align-items:center!important;justify-content:center!important;font-size:var(--lpos-text-xs,13px);line-height:1.45;overflow:hidden!important;text-align:center!important} /* JD: excerpt centered + middle-aligned in its panel */
.lpos-blueprint .lpos-m8card.-product .lpos-m8card__ptext{display:-webkit-box;-webkit-line-clamp:6;-webkit-box-orient:vertical;overflow:hidden;width:100%;
  /* 2026-08-10, caught reading a screenshot: the line-clamp bounds the text by LINE COUNT, but
     the box it sits in is `flex:1 1 0`, so whenever the card is short the box shrinks BELOW the
     clamped line count and the text spills upward over the media well. A clamp cannot fix that
     -- it does not know the box got smaller. `max-height:100%` makes the BOX the hard bound and
     leaves the clamp as the safety net it was always described as. Applies to every archive
     card app-wide, not just the long FAQ answers that made it obvious. */
  max-height:100%} /* wider cards fit the full excerpts -- 6 lines covers every current summary at desktop; the clamp stays as a safety net only */
@media (max-width:1600px){.lpos-blueprint .lpos-m8card.-product .lpos-m8card__ptext{-webkit-line-clamp:4}} /* narrower screens = shorter text area -- clamp adapts so nothing ever tears mid-line */ /* clamp the INNER text node -- the box clips at its padding edge, which let line 6 peek through the bottom padding */ /* JD: LEFT-aligned; audit #3: one step below the title (xs) */ /* whole-line cap (lh units) -- text ends on a full line, never a torn half-row; immune to external display overrides (-webkit-box clamp was being beaten by a theme flow-root) */
/* 2026-08-10 review D6: the clamp adapted to screen WIDTH only, so on a short viewport the text
   box (flex:1 1 0) shrank BELOW its own clamped line count and the last line tore against the
   padding edge. Two halves to the fix: step the clamp down by viewport HEIGHT as well, and stop
   the box shrinking under whatever the clamp allows -- the 16:9 art absorbs the squeeze instead
   (it can crop harmlessly; text cannot). */
@media (max-height:900px){
  .lpos-blueprint .lpos-m8card.-product .lpos-m8card__ptext{-webkit-line-clamp:3}
  .lpos-blueprint .lpos-m8card.-product .lpos-m8card__textbox{flex:0 0 auto;min-height:calc(3lh + 2*var(--lpos-subpanel-pad,6px))}
  .lpos-blueprint .lpos-m8card.-product .lpos-m8card__frame--video{flex:1 1 auto;min-height:0;aspect-ratio:auto;overflow:hidden}
}
@media (max-height:780px){
  .lpos-blueprint .lpos-m8card.-product .lpos-m8card__ptext{-webkit-line-clamp:2}
  .lpos-blueprint .lpos-m8card.-product .lpos-m8card__textbox{min-height:calc(2lh + 2*var(--lpos-subpanel-pad,6px))}
}
@media (max-height:660px){
  .lpos-blueprint .lpos-m8card.-product .lpos-m8card__ptext{-webkit-line-clamp:1}
  .lpos-blueprint .lpos-m8card.-product .lpos-m8card__textbox{min-height:calc(1lh + 2*var(--lpos-subpanel-pad,6px))}
}
.lpos-blueprint .lpos-m8card__btnrow{display:flex;gap:var(--lpos-subpanel-pad,6px);margin:0 0 0 0;flex:0 0 auto;min-width:0} /* 2026-08-10: min-width:0 so the row itself can shrink -- without it the two buttons forced the row wider than the card and the first label lost its left edge ("EARN MORE") */
/* 2026-08-10: the label is a BLOCK line, not a centered flex child. With flex centering + nowrap
   an over-long label overflowed EQUALLY on both sides and overflow:hidden ate its left edge
   ("EARN MORE"); text-overflow:ellipsis cannot act on a flex container's anonymous text either.
   As a block line with line-height doing the vertical centering, the label truncates from the
   RIGHT with a real ellipsis, exactly as the "long labels degrade gracefully" note below intends. */
.lpos-blueprint .lpos-m8card__btn{flex:1 1 0;min-width:0;display:block;cursor:pointer;text-decoration:none!important;
  min-height:0!important;height:calc(0.8*var(--lpos-control-size,46px))!important;line-height:calc(0.8*var(--lpos-control-size,46px))!important;padding:0 var(--lpos-subpanel-pad,6px)!important;text-align:center;
  background:var(--lpos-glass-1,rgba(255,255,255,0.035));
  border:var(--lpos-border-width,1px) solid color-mix(in srgb,var(--lpos-border-tint,var(--lpos-accent)) var(--lpos-border-alpha-2,40%),transparent);
  border-radius:calc(var(--lpos-radius-panel,10px) - var(--lpos-subpanel-pad,6px))!important; /* JD: same NESTED radius as the card text/title chips -- one corner language inside the card */
  overflow:hidden;text-overflow:ellipsis; /* audit #4: long labels degrade gracefully */
  font-weight:500;font-size:var(--lpos-text-2xs,12px);font-family:var(--lpos-font-ui,'Inter', ui-sans-serif, system-ui, sans-serif);letter-spacing:var(--lpos-tracking-label,0.08em);text-transform:uppercase;color:var(--lpos-ink,#EAF2FB);white-space:nowrap} /* audit #3: true type stairstep -- title sm(14)/excerpt xs(13)/buttons 2xs(12). Longhand (was a `font:` shorthand) so the line-height set above for vertical centering is not reset to 1 here. */
/* failed-login heading PANEL (JD 2026-08-06; rev 2 2026-08-09): the exclamation ICON BUTTON box
   leads the row, the two text lines stack beside it (texts shifted over per JD's markup). */
.lpos-blueprint--magick8 .lpos-magick8__failhead{display:flex!important;flex-direction:row!important;align-items:center!important;justify-content:center!important;gap:var(--lpos-gap,12px);
  position:relative;top:calc(-2*var(--lpos-gap,12px)); /* offset shift (panel base !important eats margins): hugs the logo, and the vacated flow slot doubles the air below (JD) */
  padding:calc(2*var(--lpos-subpanel-pad,6px)) calc(4*var(--lpos-panel-pad,12px))!important;
  background:var(--lpos-glass-panel,linear-gradient(180deg, rgba(30,42,66,0.34), rgba(16,24,40,0.45)))!important;
  -webkit-backdrop-filter:var(--lpos-blur-md,blur(16px) saturate(140%))!important;backdrop-filter:var(--lpos-blur-md,blur(16px) saturate(140%))!important}
.lpos-blueprint--magick8 .lpos-magick8__failtitle{font:600 clamp(1.15rem,1rem + .7vw,1.5rem)/1.2 var(--lpos-font-display,'Space Grotesk', ui-sans-serif, system-ui, sans-serif);letter-spacing:calc(1.5*var(--lpos-tracking-label,0.08em));text-transform:uppercase;color:var(--lpos-ink,#EAF2FB)}
.lpos-blueprint--magick8 .lpos-magick8__failsub{font:400 var(--lpos-text-md,17px)/1.2 var(--lpos-font-ui,'Inter', ui-sans-serif, system-ui, sans-serif);letter-spacing:var(--lpos-tracking-label,0.08em);text-transform:uppercase;color:var(--lpos-muted,#A8B2C7)}
.lpos-blueprint--magick8 .lpos-magick8__failtexts{display:flex;flex-direction:column;align-items:flex-start;gap:calc(0.5*var(--lpos-subpanel-pad,6px))}
.lpos-blueprint--magick8 .lpos-magick8__failicon{flex:0 0 auto;width:var(--lpos-control-size,46px);height:var(--lpos-control-size,46px);display:flex;align-items:center;justify-content:center;color:var(--lpos-ink,#EAF2FB)}
.lpos-blueprint--magick8 .lpos-magick8__failicon svg{width:var(--lpos-icon-size,26px);height:var(--lpos-icon-size,26px);fill:none;stroke:currentColor}
/* EMPTY CORNER CELLS (JD 2026-08-10 visual check): with the prev/next chevrons deleted, the
   botleft and botright cells still painted their panel chrome -- two empty 64px boxes under the
   rails. They render nothing now; the rails own those corners. */
.lpos-blueprint--console.-left-collapsed .lpos-cell--botleft:empty,
.lpos-blueprint--console.-left-collapsed .lpos-cell--botright:empty{display:none!important}
/* FOCUS PANE HUGS ITS CONTENT (JD 2026-08-10 visual check): the description panel was a 120px box
   holding 42px of text, with another 36px gap before the buttons. The pane stacks tight from the
   top now and the commit bar follows it directly; leftover height falls at the column foot as
   clean margin instead of a hole between two panels. */
/* JD 2026-08-10 rev 3: the pane fills the content panel again and the DESCRIPTION panel is the
   flexible row -- JD asked for a taller text panel, so the slack goes to it (tabs, media and the
   qty row stay content-sized). The commit bar is outside this panel entirely now, so a filling
   pane no longer pushes it anywhere. */
.lpos-blueprint .lpos-cell--midright .lpos-col__slot>.lpos-c-cta{flex:1 1 auto;align-content:stretch!important;
  grid-template-rows:auto auto auto minmax(0,1fr)!important;padding:0!important;
  min-height:0!important;height:auto!important} /* the content panel already pads; the pane's own extra bottom padding doubled the inset under the text panel (JD: "spacing at the bottom is a tiny bit too long") */
/* PLAYER SKIP BUTTONS (JD 2026-08-10): Previous/Next were 60px next to their 82px siblings, so
   they read as bare icons rather than their own panels. Same flex share as every other transport
   control now, so each one wears the identical panel. */
.lpos-blueprint .lpos-cell--midcenter .lpos-c-skip-action{flex:1 1 0!important;width:auto!important;min-width:0!important}
.lpos-blueprint .lpos-cell--midright .lpos-c-cta__info{min-height:0!important;align-self:stretch}
/* the media frame yields height so the pane + commit bar always fit the column (the pane was
   overflowing by ~96px, which pushed the bar past the bottom edge). Cover-crop, ratio intact. */
.lpos-blueprint .lpos-cell--midright .lpos-c-cta__media{max-height:34dvh}
/* PRIMARY CONTENT SWITCH HOST (JD 2026-08-10 control law): the centre now holds the Display's own
   primary slot plus the chat/bookmarks/calendar/notes/share slots; exactly one is active. */
.lpos-blueprint .lpos-cell--midcenter .lpos-col--center{display:flex;flex-direction:column;flex:1 1 auto;min-height:0;width:100%}
.lpos-blueprint .lpos-cell--midcenter .lpos-col--center>.lpos-col__slot{display:none}
.lpos-blueprint .lpos-cell--midcenter .lpos-col--center>.lpos-col__slot.-active{display:flex;flex-direction:column;flex:1 1 auto;min-height:0}
/* COMMIT BAR (JD 2026-08-10): Add to Cart / Buy Now are their OWN panel at the foot of the right
   column, outside the Focus pane. Two equal buttons, panel chrome from the shared token set.
   The slot stacks pane-then-bar and the PANE yields the height -- without this the bar rendered
   below the fold, since the cta still claimed the whole slot. */
.lpos-blueprint .lpos-cell--midright .lpos-col__slot{display:flex;flex-direction:column;min-height:0}
/* the pane HUGS its content (see the hug block above) -- it used to stretch, which inflated the
   description panel into a 120px box around 42px of text (JD's circled dead space). */
/* (the pane's flex is set once, in the rev-3 block above -- this duplicate selector used to set
   flex:0 0 auto and, being later in the file, silently won and stopped the description panel from
   filling. Left as a pointer so the next reader does not re-add it.) */
/* RIGHT RAIL CONNECTORS (JD 2026-08-10): the secondary switcher reads as ONE chain -- a hairline
   runs between consecutive items, same token recipe as the login flow's step connectors
   (.lpos-magick8__connector): border-tint at the 40% alpha step, 1px. Drawn as a ::after on each
   item except the last, spanning the gap to the next one, so it needs no extra markup and adapts
   to however many buttons the rail holds. */
   The rail DISTRIBUTES its items (space-between), so the gaps are large and uneven -- a fixed-height
   stub under each item could never span them. One continuous hairline runs the length of the rail
   instead, from the first item's centre to the last, with the items riding above it. */
.lpos-blueprint .lpos-rail--right{position:relative}
.lpos-blueprint .lpos-rail--right::before{content:'';position:absolute;left:50%;transform:translateX(-50%);
  top:calc(var(--lpos-panel-pad,12px) + 0.5*var(--lpos-control-size,46px));
  bottom:calc(var(--lpos-panel-pad,12px) + 0.5*var(--lpos-control-size,46px));
  width:var(--lpos-border-width,1px);
  background:color-mix(in srgb,var(--lpos-border-tint,var(--lpos-accent)) var(--lpos-border-alpha-2,40%),transparent);
  pointer-events:none;z-index:0}
.lpos-blueprint .lpos-rail--right>*{position:relative;z-index:1}
/* COMMIT ROW (JD 2026-08-10 rev 2): the bar is a SIBLING of the content column, not a row inside
   it -- so the secondary content panel ends level with the primary content panel and the bar forms
   its own row underneath, the same height as the search-bar row. */
/* the cell becomes a pure LAYOUT LANE for this column (JD 2026-08-10 rev 2): its panel chrome moves
   onto the content column, so the secondary content PANEL visibly ends level with the primary
   content panel and the commit bar is a separate panel underneath, not wrapped by the same frame. */
.lpos-blueprint--console.-left-collapsed .lpos-cell--midright{padding:0!important;background:transparent!important;
  border:0!important;-webkit-backdrop-filter:none!important;backdrop-filter:none!important;box-shadow:none!important;
  gap:0!important} /* the lane's own flex gap stacked with the bar's margin, leaving the content panel 9px short of the primary; spacing is single-sourced on the bar now */
.lpos-blueprint .lpos-cell--midright>.lpos-col{flex:1 1 auto;min-height:0;
  padding:var(--lpos-panel-pad,12px);box-sizing:border-box;border-radius:var(--lpos-radius-panel,10px);
  background:var(--lpos-glass-panel);-webkit-backdrop-filter:var(--lpos-blur-md);backdrop-filter:var(--lpos-blur-md);
  border:var(--lpos-border-width,1px) solid color-mix(in srgb,var(--lpos-border-tint,var(--lpos-accent)) var(--lpos-border-alpha-2,40%),transparent)}
/* the display title panel rides above that content panel, so it needs the lane's own inset back */
/* JD 2026-08-10: the title panel sat FLUSH on the content panel ("the text bar bumps into the panel
   below it"). This margin was already declared -- the universal `.lpos-c-title-panel{margin:0!important}`
   panel law simply outranked it. !important here makes the lane's one seam actually apply. */
.lpos-blueprint .lpos-cell--midright>.lpos-c-title-panel--display{margin-bottom:var(--lpos-gap,12px)!important}
.lpos-blueprint .lpos-cell--midright>.lpos-c-cta__actionbar{flex:0 0 var(--lpos-titlebar-h,64px);
  height:var(--lpos-titlebar-h,64px);min-height:var(--lpos-titlebar-h,64px);box-sizing:border-box;
  display:flex;gap:var(--lpos-gap,12px);align-items:stretch;width:100%;
  margin-top:var(--lpos-gap,12px)!important;padding:var(--lpos-subpanel-pad,6px)!important} /* JD 2026-08-10: was 0.75*gap (9px), which read as an odd seam against the 12px used at every other panel edge. Full gap now -- the content panel's bottom lands EXACTLY level with the primary content panel (both 865px at 1911x953). */
.lpos-blueprint .lpos-cell--midright>.lpos-c-cta__actionbar .lpos-c-cta__buy{position:static!important;flex:1 1 0;
  width:auto!important;min-width:0;margin:0!important;left:auto!important;right:auto!important;bottom:auto!important;
  height:100%!important;min-height:0!important} /* buttons size to the row, not the other way round */
.lpos-blueprint .lpos-cell--midright .lpos-c-cta__actionbar .lpos-c-cta__buy{position:static!important;flex:1 1 0;
  width:auto!important;min-width:0;margin:0!important;left:auto!important;right:auto!important;bottom:auto!important;
  height:calc(var(--lpos-control-size,46px) + 2*var(--lpos-subpanel-pad,6px))}
/* the pane no longer reserves the old absolute button lane at its foot */
.lpos-blueprint .lpos-cell--midright .lpos-c-cta{padding-bottom:var(--lpos-panel-pad,12px)!important}
/* TOP BAR TRAILING GROUP (JD 2026-08-10): alerts, vault, account, cart, power sit at the FAR
   RIGHT of the tab bar, in that order, with the profile corner box beyond the bar's own gap. */
.lpos-blueprint .lpos-cell--topcenter .lpos-topbar__trail{margin-left:auto;display:flex;align-items:center;gap:var(--lpos-gap,12px);flex:0 0 auto}
/* SHORT VERTICAL RULE (JD 2026-08-10): parts the portal selector from the tab system now that the
   Back button is gone. Token-driven -- same hairline tint every panel edge uses, half control height. */
.lpos-blueprint .lpos-cell--topcenter .lpos-topbar__rule{flex:0 0 auto;width:var(--lpos-border-width,1px);
  height:calc(0.5*var(--lpos-control-size,46px));align-self:center;
  background:color-mix(in srgb,var(--lpos-border-tint,var(--lpos-accent)) var(--lpos-border-alpha-3,55%),transparent);
  border-radius:var(--lpos-radius-pill,999px)}
/* LOGIN HEAD ROW (JD 2026-08-09 rev 3): TWO SEPARATE PANELS on one line -- the Login panel keeps
   dead-center, its own Forgot Login panel sits beside it, right-aligned (text + double chevrons). */
/* rev 5 (JD): the Login TITLE panel is gone -- ONE centered Forgot Login panel above the slides,
   with real air below it so it never crowds the carousel. */
.lpos-blueprint--magick8 .lpos-magick8__loginhead{display:flex!important;align-items:center;justify-content:center;
  margin-block-end:var(--lpos-gap,12px)!important}
.lpos-blueprint--magick8 .lpos-magick8__loginhead[hidden]{display:none!important}
/* (the login-mode pull cancel is retired -- the carousel's -2.5gap pull itself is gone now) */
/* JD 2026-08-10: the same Forgot Login control repeated at the FOOT of the Invalid Credentials
   display, centred under the Google/Facebook/Support row. Its own row so it centres on the
   form's full width rather than inheriting the 3-up grid above it. */
.lpos-blueprint--magick8 .lpos-magick8__forgotrow{display:flex;justify-content:center;width:100%}
.lpos-blueprint--magick8 .lpos-magick8__forgot{margin:0!important;
  display:inline-flex!important;align-items:center;justify-content:center;gap:calc(0.5*var(--lpos-gap,12px));
  text-decoration:none;cursor:pointer;color:var(--lpos-muted,#A8B2C7)}
.lpos-blueprint--magick8 .lpos-magick8__forgot:hover{color:var(--lpos-ink,#EAF2FB)}
.lpos-blueprint--magick8 .lpos-magick8__forgottext{white-space:nowrap}
.lpos-blueprint--magick8 .lpos-magick8__forgotbtn{flex:0 0 auto;display:flex;align-items:center;justify-content:center}
.lpos-blueprint--magick8 .lpos-magick8__forgotbtn svg{width:var(--lpos-icon-size-sm,24px);height:var(--lpos-icon-size-sm,24px);fill:none;stroke:currentColor}
/* SOCIAL BRAND TINTS (JD 2026-08-09): Google + Facebook keep the glass transparency but wear a
   slight overlay in their own brand color (border tint follows); Support stays token-styled.
   Applies EVERYWHERE the buttons render (welcome inline form + failed-login form share these classes). */
.lpos-blueprint--magick8 .lpos-magick8__login--google{background:color-mix(in srgb,#4285F4 16%,transparent)!important;border-color:color-mix(in srgb,#4285F4 45%,transparent)!important}
.lpos-blueprint--magick8 .lpos-magick8__login--facebook{background:color-mix(in srgb,#1877F2 16%,transparent)!important;border-color:color-mix(in srgb,#1877F2 45%,transparent)!important}
/* ==== GUEST SUPPORT CARDS (JD 2026-08-06): one atomic card, three collectible-card styles.
   Shared height; each family keeps its REAL ratio, so the trio reads as a lineup. ==== */
.lpos-blueprint--magick8 .lpos-magick8__cards{display:flex;flex-wrap:wrap;gap:calc(2*var(--lpos-gap,12px));align-items:center;justify-content:center;margin-top:var(--lpos-gap,12px)} /* review fix: wrap, never clip, on narrow viewports */
.lpos-blueprint .lpos-m8card{position:relative;display:flex;flex-direction:column;cursor:pointer;text-decoration:none!important;color:var(--lpos-ink,#EAF2FB);
  height:clamp(calc(24*var(--lpos-gap,12px)),var(--lpos-m8card-h,44vh),calc(38*var(--lpos-gap,12px)));box-sizing:border-box;overflow:hidden;flex:0 0 auto; /* preferred height tokenized (review) */
  padding:var(--lpos-subpanel-pad,6px)!important; /* thin card border ring -- the panel's 12px mat read as a picture frame, not a card */
  transition:border-color var(--lpos-duration-fast,120ms) var(--lpos-ease-tech,cubic-bezier(0.16, 1, 0.3, 1))}
.lpos-blueprint .lpos-m8card:hover{border-color:color-mix(in srgb,var(--lpos-border-tint,var(--lpos-accent)) var(--lpos-border-alpha-3,55%),transparent)!important}
.lpos-blueprint .lpos-m8card.-playing{aspect-ratio:5/7}
.lpos-blueprint .lpos-m8card.-tarot{aspect-ratio:11/19}
.lpos-blueprint .lpos-m8card.-collector{aspect-ratio:63/88}
.lpos-blueprint .lpos-m8card svg{width:var(--lpos-icon-size-sm,24px);height:var(--lpos-icon-size-sm,24px);fill:none;stroke:currentColor}
/* playing card: corner pips + big center art + quiet label */
.lpos-blueprint .lpos-m8card__pip{position:absolute;display:flex;color:var(--lpos-muted,#A8B2C7)}
.lpos-blueprint .lpos-m8card__pip--tl{top:var(--lpos-subpanel-pad,6px);left:var(--lpos-subpanel-pad,6px)}
.lpos-blueprint .lpos-m8card__pip--br{bottom:var(--lpos-subpanel-pad,6px);right:var(--lpos-subpanel-pad,6px);transform:rotate(180deg)}
.lpos-blueprint .lpos-m8card.-playing .lpos-m8card__art{flex:1 1 auto;display:flex;align-items:center;justify-content:center}
.lpos-blueprint .lpos-m8card.-playing .lpos-m8card__art svg{width:calc(2*var(--lpos-icon-size,26px));height:calc(2*var(--lpos-icon-size,26px))}
.lpos-blueprint .lpos-m8card__label{flex:0 0 auto;text-align:center;padding-bottom:calc(2*var(--lpos-subpanel-pad,6px));
  font:600 var(--lpos-text-sm,14px)/1.2 var(--lpos-font-ui,'Inter', ui-sans-serif, system-ui, sans-serif);letter-spacing:var(--lpos-tracking-label,0.08em);text-transform:uppercase}
/* tarot: full-bleed inner frame + bottom caption banner */
.lpos-blueprint .lpos-m8card__frame{flex:1 1 auto;min-height:0;display:flex;align-items:center;justify-content:center;
  margin:var(--lpos-subpanel-pad,6px);border:var(--lpos-border-width,1px) solid color-mix(in srgb,var(--lpos-border-tint,var(--lpos-accent)) var(--lpos-border-alpha-2,40%),transparent);
  border-radius:calc(var(--lpos-radius-panel,10px) - var(--lpos-subpanel-pad,6px));background:var(--lpos-glass-1,rgba(255,255,255,0.035))}
.lpos-blueprint .lpos-m8card.-tarot .lpos-m8card__frame svg{width:calc(1.6*var(--lpos-icon-size,26px));height:calc(1.6*var(--lpos-icon-size,26px))}
.lpos-blueprint .lpos-m8card__banner{flex:0 0 auto;text-align:center;margin:0 var(--lpos-subpanel-pad,6px) var(--lpos-subpanel-pad,6px);padding:var(--lpos-subpanel-pad,6px);
  border:var(--lpos-border-width,1px) solid color-mix(in srgb,var(--lpos-border-tint,var(--lpos-accent)) var(--lpos-border-alpha-2,40%),transparent);
  border-radius:calc(var(--lpos-radius-panel,10px) - var(--lpos-subpanel-pad,6px));
  font:600 var(--lpos-text-sm,14px)/1.2 var(--lpos-font-display,'Space Grotesk', ui-sans-serif, system-ui, sans-serif);letter-spacing:calc(1.5*var(--lpos-tracking-label,0.08em));text-transform:uppercase}
/* collector: title bar top + art window + text box bottom */
.lpos-blueprint .lpos-m8card__titlebar{flex:0 0 auto;margin:var(--lpos-subpanel-pad,6px) var(--lpos-subpanel-pad,6px) 0;padding:var(--lpos-subpanel-pad,6px);text-align:center;
  border:var(--lpos-border-width,1px) solid color-mix(in srgb,var(--lpos-border-tint,var(--lpos-accent)) var(--lpos-border-alpha-2,40%),transparent);
  border-radius:calc(var(--lpos-radius-panel,10px) - var(--lpos-subpanel-pad,6px));background:var(--lpos-glass-1,rgba(255,255,255,0.035));
  font:700 var(--lpos-text-sm,14px)/1.2 var(--lpos-font-ui,'Inter', ui-sans-serif, system-ui, sans-serif);letter-spacing:var(--lpos-tracking-label,0.08em);text-transform:uppercase}
.lpos-blueprint .lpos-m8card.-collector .lpos-m8card__frame{flex:1.4 1 0}
.lpos-blueprint .lpos-m8card__textbox{flex:0 0 22%;margin:0;display:flex;align-items:center;justify-content:center;text-align:center;
  padding:var(--lpos-subpanel-pad,6px) calc(2*var(--lpos-subpanel-pad,6px));
  font:400 var(--lpos-text-sm,14px)/1.45 var(--lpos-font-ui,'Inter', ui-sans-serif, system-ui, sans-serif);color:var(--lpos-muted,#A8B2C7);
  border:var(--lpos-border-width,1px) solid color-mix(in srgb,var(--lpos-border-tint,var(--lpos-accent)) var(--lpos-border-alpha-2,40%),transparent);
  border-radius:calc(var(--lpos-radius-panel,10px) - var(--lpos-subpanel-pad,6px));background:var(--lpos-glass-1,rgba(255,255,255,0.035))}
.lpos-blueprint--magick8 .lpos-magick8__stack:has(.lpos-magick8__cards){width:fit-content;max-width:92vw} /* hugs the card lineup for real edge-alignment, but NEVER exceeds the viewport (review fix: max-content + no-shrink cards + ancestor overflow:hidden = clipped row on phones) */
.lpos-blueprint--magick8 .lpos-magick8__back.lpos-magick8__back--support{margin-top:calc(2*var(--lpos-gap,12px));position:static!important;align-self:flex-start!important;margin-left:0;margin-right:auto;
  width:auto!important;height:calc(1.4*var(--lpos-control-size,46px))!important; /* JD: chevron chrome + a Back label to its right */
  gap:calc(1.5*var(--lpos-subpanel-pad,6px));padding:0 calc(2*var(--lpos-panel-pad,12px))!important;
  font:600 var(--lpos-text-sm,14px)/1 var(--lpos-font-ui,'Inter', ui-sans-serif, system-ui, sans-serif);letter-spacing:var(--lpos-tracking-label,0.08em);text-transform:uppercase;
  background:var(--lpos-glass-panel,linear-gradient(180deg, rgba(30,42,66,0.34), rgba(16,24,40,0.45)))!important;color:var(--lpos-ink,#EAF2FB)!important;
  border:var(--lpos-border-width,1px) solid color-mix(in srgb,var(--lpos-border-tint,var(--lpos-accent)) var(--lpos-border-alpha-2,40%),transparent)!important;
  border-radius:var(--lpos-radius-panel,10px)!important} /* nav chevrons carry the panel radius */
/* demo art (real BL assets) in the card art slots -- asset alpha + inherited radius per law */
.lpos-blueprint .lpos-m8card__art{position:relative;overflow:hidden;border-radius:inherit}
.lpos-blueprint .lpos-m8card__img{width:100%;height:100%;object-fit:cover;display:block;opacity:var(--lpos-asset-alpha,0.9);border-radius:inherit}
.lpos-blueprint .lpos-m8card.-playing .lpos-m8card__art{flex:1 1 auto;margin:0;border-radius:calc(var(--lpos-radius-panel,10px) - var(--lpos-subpanel-pad,6px))} /* playing-card art BLEEDS to the thin ring */
.lpos-blueprint .lpos-m8card__pip{z-index:2}
.lpos-blueprint .lpos-m8card__frame{overflow:hidden;padding:0;position:relative}
.lpos-blueprint .lpos-m8card.-tarot .lpos-m8card__art,
.lpos-blueprint .lpos-m8card.-collector .lpos-m8card__art{position:absolute;inset:0;display:flex;align-items:center;justify-content:center} /* art FILLS its window -- cover, never a letterboxed strip */
/* Chrome/Edge AUTOFILL guard (JD 2026-08-06): the UA paints autofilled inputs WHITE. The
   text-fill + 10000s background transition freeze keep the field's own glass styling; the
   inset paint-fill is the standard functional autofill override, not decorative shadow. */
.lpos-blueprint--magick8 .lpos-magick8__field:-webkit-autofill,
.lpos-blueprint--magick8 .lpos-magick8__field:-webkit-autofill:hover,
.lpos-blueprint--magick8 .lpos-magick8__field:-webkit-autofill:focus,
.lpos-blueprint--magick8 .lpos-magick8__field:-webkit-autofill:active,
.lpos-blueprint--magick8 .lpos-magick8__field:autofill{
  -webkit-text-fill-color:var(--lpos-ink,#EAF2FB)!important; /* WHITE text from the FIRST paint (JD: it landed black, then flipped) */
  color:var(--lpos-ink,#EAF2FB)!important;
  caret-color:var(--lpos-ink,#EAF2FB)!important;
  -webkit-background-clip:text!important;background-clip:text!important; /* clips the UA's white autofill fill to the glyphs (invisible) -- the field's own transparent glass stays, no box-shadow trick needed */
  transition:background-color 9999999s ease-in-out 0s,color 9999999s ease-in-out 0s}
.lpos-blueprint--magick8 .lpos-magick8__form{display:flex;flex-direction:column;align-items:center;gap:calc(2*var(--lpos-gap,12px));width:var(--lpos-m8-w,min(92vw,860px))}
.lpos-blueprint--magick8 .lpos-magick8__inline{display:flex;gap:var(--lpos-gap,12px);width:100%}
.lpos-blueprint--magick8 .lpos-magick8__inline[hidden]{display:none}
.lpos-blueprint--magick8 .lpos-magick8__field{flex:1 1 auto;min-width:0;box-sizing:border-box;
  min-height:calc(var(--lpos-control-size,46px) + 2*var(--lpos-panel-pad,12px));padding:var(--lpos-panel-pad,12px) calc(2*var(--lpos-panel-pad,12px));
  font:400 var(--lpos-text-md,17px)/1.2 var(--lpos-font-ui,'Inter', ui-sans-serif, system-ui, sans-serif);color:var(--lpos-ink,#EAF2FB);
  background:var(--lpos-glass-1,rgba(255,255,255,0.035));
  border:var(--lpos-border-width,1px) solid color-mix(in srgb,var(--lpos-border-tint,var(--lpos-accent)) var(--lpos-border-alpha-2,40%),transparent);
  border-radius:var(--lpos-radius-control,8px);outline:none}
.lpos-blueprint--magick8 .lpos-magick8__field::placeholder{color:var(--lpos-muted,#A8B2C7)}
.lpos-blueprint--magick8 .lpos-magick8__field:focus{border-color:var(--lpos-border-tint,var(--lpos-accent))}
.lpos-blueprint--magick8 .lpos-magick8__next{flex:0 0 auto!important;min-width:160px;position:static!important}
/* Back = a square glass icon button matching the row height; the input takes every spare px */
.lpos-blueprint--magick8 .lpos-magick8__back{flex:0 0 auto!important;width:calc(var(--lpos-control-size,46px) + 2*var(--lpos-panel-pad,12px))!important;height:auto!important;align-self:stretch;display:flex;align-items:center;justify-content:center;cursor:pointer;
  background:var(--lpos-glass-1,rgba(255,255,255,0.035))!important;color:var(--lpos-muted,#A8B2C7);
  border:var(--lpos-border-width,1px) solid color-mix(in srgb,var(--lpos-border-tint,var(--lpos-accent)) var(--lpos-border-alpha-2,40%),transparent)!important;
  border-radius:var(--lpos-radius-control,8px)}
.lpos-blueprint--magick8 .lpos-magick8__back:hover{color:var(--lpos-ink,#EAF2FB)}
.lpos-blueprint--magick8 .lpos-magick8__back svg{width:var(--lpos-icon-size,26px);height:var(--lpos-icon-size,26px)}
.lpos-blueprint--magick8 .lpos-magick8__login[hidden]{display:none}
/* JD 2026-08-06: under-row -- Google / Facebook / Forgot as THREE EQUAL columns, evenly
   distributed across the full row (display:contents flattens the social wrapper so all three
   quiet buttons share the same flex line and the same 1fr share). */
.lpos-blueprint--magick8 .lpos-magick8__subrow{display:flex;align-items:stretch;gap:var(--lpos-gap,12px);width:100%;min-width:0}
.lpos-blueprint--magick8 .lpos-magick8__subrow .lpos-magick8__login{margin:0;flex:1 1 0!important;min-width:0;white-space:nowrap;padding:var(--lpos-panel-pad,12px) var(--lpos-panel-pad,12px)!important}
.lpos-blueprint--magick8 .lpos-magick8__social{display:contents}
/* ==== VERIFYING ACCESS MODAL (JD 2026-08-06): glassy blur locks the display; 1/3-viewport
   panel at the video panel's 16:9; XP-style progress bar driven by the sign-in fetch ==== */
.lpos-blueprint--magick8 .lpos-magick8__verify{position:fixed;inset:0;z-index:9000;display:flex;align-items:center;justify-content:center;
  background:color-mix(in srgb,var(--lpos-bg,#0A0E17) 38%,transparent);
  -webkit-backdrop-filter:var(--lpos-blur-md,blur(16px) saturate(140%));backdrop-filter:var(--lpos-blur-md,blur(16px) saturate(140%))}
.lpos-blueprint--magick8 .lpos-magick8__verify[hidden]{display:none}
.lpos-blueprint--magick8 .lpos-magick8__verifypanel{width:calc(100vw/3);aspect-ratio:16/9;box-sizing:border-box;
  display:flex;flex-direction:column;align-items:center;justify-content:center;gap:calc(2*var(--lpos-gap,12px));
  background:var(--lpos-glass-panel,linear-gradient(180deg, rgba(30,42,66,0.34), rgba(16,24,40,0.45)))!important;
  -webkit-backdrop-filter:var(--lpos-blur-md,blur(16px) saturate(140%))!important;backdrop-filter:var(--lpos-blur-md,blur(16px) saturate(140%))!important}
.lpos-blueprint--magick8 .lpos-magick8__verifytext{margin:0;padding:var(--lpos-subpanel-pad,6px) calc(3*var(--lpos-panel-pad,12px))!important;
  font:600 clamp(1.05rem,.9rem + .6vw,1.35rem)/1.2 var(--lpos-font-display,'Space Grotesk', ui-sans-serif, system-ui, sans-serif);letter-spacing:calc(1.5*var(--lpos-tracking-label,0.08em));text-transform:uppercase;color:var(--lpos-ink,#EAF2FB)}
.lpos-blueprint--magick8 .lpos-magick8__xpbar{width:70%;height:calc(2.5*var(--lpos-subpanel-pad,6px));padding:calc(0.5*var(--lpos-subpanel-pad,6px))!important;
  border-radius:var(--lpos-radius-pill,999px)!important;overflow:hidden}
.lpos-blueprint--magick8 .lpos-magick8__xpfill{height:100%;width:0;border-radius:inherit;
  background:linear-gradient(90deg,var(--lpos-accent,#00D4FF),var(--lpos-accent-3,var(--lpos-accent)),var(--lpos-accent,#00D4FF));
  background-size:200% 100%;animation:lposXpSheen 1.2s linear infinite;
  transition:width var(--lpos-duration-base,220ms) var(--lpos-ease-tech,cubic-bezier(0.16, 1, 0.3, 1))}
@keyframes lposXpSheen{from{background-position:200% 0}to{background-position:0 0}}
@media (prefers-reduced-motion: reduce){.lpos-blueprint--magick8 .lpos-magick8__xpfill{animation:none}}
.lpos-blueprint--magick8 .lpos-magick8__verifyicon{width:calc(1.4*var(--lpos-control-size,46px))!important;height:calc(1.4*var(--lpos-control-size,46px))!important;
  display:flex;align-items:center;justify-content:center;pointer-events:none;
  background:var(--lpos-glass-1,rgba(255,255,255,0.035))!important;color:var(--lpos-ink,#EAF2FB);
  border:var(--lpos-border-width,1px) solid color-mix(in srgb,var(--lpos-border-tint,var(--lpos-accent)) var(--lpos-border-alpha-2,40%),transparent)!important;
  border-radius:var(--lpos-radius-panel,10px)!important}
.lpos-blueprint--magick8 .lpos-magick8__verifyicon svg{width:var(--lpos-icon-size,26px);height:var(--lpos-icon-size,26px);fill:none;stroke:currentColor}
/* SUPPORT FLOW stepper (JD 2026-08-06): numbered badges over the cards, progress connectors
   1->2->3; steps 2+3 and their cards land MUTED until Troubleshoot runs */
.lpos-blueprint--magick8 .lpos-magick8__flow{display:flex;flex-direction:column;margin-top:calc(1.5*var(--lpos-gap,12px))} /* JD: stepper hugs the title panel */
.lpos-blueprint--magick8 .lpos-magick8__steprow{position:relative;display:flex;gap:calc(2*var(--lpos-gap,12px));margin-bottom:calc(2.5*var(--lpos-gap,12px))} /* JD: air between the step bar and the cards */ /* same gaps as the card row = badge centers land EXACTLY over card centers */
.lpos-blueprint--magick8 .lpos-magick8__stepcol{flex:1 1 0;display:flex;justify-content:center;position:relative;z-index:2}
.lpos-blueprint--magick8 .lpos-magick8__stepnum{width:var(--lpos-control-size,46px)!important;height:var(--lpos-control-size,46px)!important;
  display:flex;align-items:center;justify-content:center;cursor:default;
  font:700 var(--lpos-text-md,17px)/1 var(--lpos-font-ui,'Inter', ui-sans-serif, system-ui, sans-serif);color:var(--lpos-ink,#EAF2FB);
  background:var(--lpos-glass-panel,linear-gradient(180deg, rgba(30,42,66,0.34), rgba(16,24,40,0.45)))!important;
  border:var(--lpos-border-width,1px) solid color-mix(in srgb,var(--lpos-border-tint,var(--lpos-accent)) var(--lpos-border-alpha-3,55%),transparent)!important;
  border-radius:var(--lpos-radius-panel,10px)!important} /* JD: token panel radius -- same chrome family as every icon button, not a circle */
.lpos-blueprint--magick8 .lpos-magick8__stepnum.-muted{color:var(--lpos-muted,#A8B2C7);
  border-color:color-mix(in srgb,var(--lpos-border-tint,var(--lpos-accent)) var(--lpos-border-alpha-1,30%),transparent)!important}
.lpos-blueprint--magick8 .lpos-magick8__connector{position:absolute;top:50%;height:var(--lpos-border-width,1px);transform:translateY(-50%);z-index:1;
  background:color-mix(in srgb,var(--lpos-border-tint,var(--lpos-accent)) var(--lpos-border-alpha-2,40%),transparent)}
.lpos-blueprint--magick8 .lpos-magick8__connector[data-lpos-conn="1"]{left:calc((100% - 4*var(--lpos-gap,12px))/6);width:calc((100% - 4*var(--lpos-gap,12px))/3 + 2*var(--lpos-gap,12px))}
.lpos-blueprint--magick8 .lpos-magick8__connector[data-lpos-conn="2"]{left:50%;width:calc((100% - 4*var(--lpos-gap,12px))/3 + 2*var(--lpos-gap,12px))}
.lpos-blueprint .lpos-m8card.-muted{opacity:0.45;pointer-events:none;filter:saturate(0.4)}
/* CURRENT-step emphasis (JD): the active card + badge run LARGER; emphasis glides between
   steps as each completes */
.lpos-blueprint--magick8 .lpos-magick8__cards{align-items:center}
.lpos-blueprint .lpos-m8card{transition:transform var(--lpos-duration-base,220ms) var(--lpos-ease-tech,cubic-bezier(0.16, 1, 0.3, 1)),opacity var(--lpos-duration-base,220ms) var(--lpos-ease-tech,cubic-bezier(0.16, 1, 0.3, 1)),filter var(--lpos-duration-base,220ms) var(--lpos-ease-tech,cubic-bezier(0.16, 1, 0.3, 1)),border-color var(--lpos-duration-fast,120ms) var(--lpos-ease-tech,cubic-bezier(0.16, 1, 0.3, 1))}
.lpos-blueprint .lpos-m8card.-active{transform:scale(1.08);z-index:2;
  border-color:color-mix(in srgb,var(--lpos-ink,#EAF2FB) var(--lpos-border-alpha-3,55%),transparent)!important} /* focus treatment matches the carousel's focused slide */
.lpos-blueprint--magick8 .lpos-magick8__stepnum{transition:width var(--lpos-duration-base,220ms) var(--lpos-ease-tech,cubic-bezier(0.16, 1, 0.3, 1)),height var(--lpos-duration-base,220ms) var(--lpos-ease-tech,cubic-bezier(0.16, 1, 0.3, 1)),color var(--lpos-duration-fast,120ms) var(--lpos-ease-tech,cubic-bezier(0.16, 1, 0.3, 1))}
.lpos-blueprint--magick8 .lpos-magick8__stepnum.-active{width:calc(1.35*var(--lpos-control-size,46px))!important;height:calc(1.35*var(--lpos-control-size,46px))!important;
  font-size:var(--lpos-text-lg,20px);color:var(--lpos-ink,#EAF2FB);
  border-color:color-mix(in srgb,var(--lpos-ink,#EAF2FB) var(--lpos-border-alpha-3,55%),transparent)!important}
/* Troubleshoot modal shell: same overlay family as Verifying Access, wider panel, closable */
.lpos-blueprint--magick8 .lpos-magick8__modalpanel{position:relative;width:calc(100vw/2.4);aspect-ratio:16/9}
.lpos-blueprint--magick8 .lpos-magick8__modalx{position:absolute;top:var(--lpos-panel-pad,12px);right:var(--lpos-panel-pad,12px)}
.lpos-blueprint--magick8 .lpos-magick8__modalbody{width:80%;flex:0 0 45%;border-radius:var(--lpos-radius-panel,10px)!important}
/* ==== /MAGICK8 WELCOME STACK ==== */

/* the both-collapsed sidebar-balance rules (docked card-grid split) are deleted -- unreachable
   state (Phase D 2026-08-09 dead-code group). */
/* docked buy pane: the product IMAGE is the flexible row -- it absorbs all slack (object-fit
   cover) so the qty/price row and the full info text always fit; the 3-line excerpt clamp is
   lifted here (JD: text under price/quantity must not be cut off). */
.lpos-feat__boxhost .lpos-c-cta{grid-template-rows:auto auto auto minmax(120px,1fr)!important}
.lpos-feat__boxhost .lpos-c-cta__media{min-height:0!important;aspect-ratio:auto!important;overflow:hidden}
.lpos-feat__boxhost .lpos-c-cta__media img{width:100%;height:100%;object-fit:cover}
.lpos-feat__boxhost .lpos-c-cta__info{min-height:0!important}
.lpos-feat__boxhost .lpos-c-cta__excerpt{overflow:visible;display:block;max-height:none;-webkit-line-clamp:unset}
/* TEXT COMPONENT RHYTHM (JD 2026-08-06): one spacing scale inside every text panel --
   header, subheader 4px under it, body copy 8px under that. Kills the per-panel drift. */
.lpos-c-title-panel h2,.lpos-c-title-panel h3,.lpos-c-cta__info h2,.lpos-c-cta__info h3,.lpos-c-cta__info .lpos-c-cta__subtitle{margin:0}
.lpos-c-title-panel h3,.lpos-c-cta__info .lpos-c-cta__subtitle{margin-top:var(--lpos-space-xs,4px)}
.lpos-c-title-panel p,.lpos-c-cta__info p,.lpos-c-cta__excerpt{margin-top:var(--lpos-space-sm,8px)!important}

/* JD 2026-08-06 CONSISTENCY: a docked media pane's title panel becomes its TOOL PANEL (text
   hidden, the pane's own bars adopted in -- lpos-drawers.js toolifyDockedPane). Same row layout
   as [data-lpos-left-tools]; the distribution law's flexible buttons apply as-is. */
.lpos-c-title-panel.-tools{display:flex;align-items:center;gap:var(--lpos-subpanel-pad,6px)}
.lpos-c-title-panel.-tools .lpos-media__bar,
.lpos-c-title-panel.-tools .lpos-media__bar--above,
.lpos-c-title-panel.-tools .lpos-media__bar--below{flex:1 1 auto;display:flex;min-width:0}
/* distribution law: the adopted bar's buttons stretch evenly, same as every other tool bar */
.lpos-c-title-panel.-tools .lpos-c-icon-btn:not([data-lpos-switch-add]):not([data-lpos-collapse]){flex:1 1 0!important;width:auto!important;min-width:calc(var(--lpos-icon-size-sm,24px) + 2*var(--lpos-subpanel-pad,6px))!important}

/* the both-collapsed titlecap/boxhost/actions grid-row placements are deleted -- unreachable
   state (Phase D 2026-08-09 dead-code group). */
/* the docked pane fills the box */
.lpos-feat__boxhost>*{width:100%!important;height:100%!important;min-height:0;max-width:100%}
/* ==== /TASK 7 ==== */

/* JD 2026-08-05: center TOOL BAR panel -- stretches the gap between Previous and Next at the same
   control height. Chrome from the ONE-PANEL law (.lpos-c-panel); layout only here. */
/* CLONE of the approved midright tabbar geometry (subpanel--tabbar: 8px pad, 16px gap, FULL-SIZE
   46px token buttons inside) -- the transport is the same panel-styled button group as every other
   one, never a downsized one-off. Prev/Next center on the taller bar via the row's alignment. */
.lpos-blueprint .lpos-feat__toolbar{flex:1 1 auto;min-width:0;align-self:center;
  height:auto;box-sizing:border-box;
  padding:var(--lpos-subpanel-pad,6px)!important;
  display:flex;align-items:center;justify-content:center;gap:var(--lpos-gap,12px);overflow:hidden}
/* buttons STRETCH to share their panel's width evenly (same adaptive-stretch law as the menu
   drawer tabs) -- height stays the 46px control token. JD 2026-08-06: the width floor drops to
   icon+pad so tight columns COMPRESS the buttons instead of clipping them at the panel edge. */
.lpos-blueprint .lpos-feat__toolbar .lpos-c-icon-btn{
  width:auto!important;min-width:calc(var(--lpos-icon-size-sm,24px) + 2*var(--lpos-subpanel-pad,6px))!important;
  height:var(--lpos-control-size,46px)!important;
  flex:1 1 0!important}
/* THREE-PANEL TRANSPORT (JD 2026-08-06): left/right bars share the gap equally; the middle panel
   hugs the lone play button. Rewind pins to the left bar's RIGHT edge, fast-forward leads the
   right bar's LEFT edge -- so the skip controls flank play across the panel seams. */
/* JD 2026-08-06 rebalance: the play panel takes a real SHARE of the gap (sides 2 : mid 1) so the
   stretched play button reads wider; the side bars give up that width. */
.lpos-blueprint .lpos-feat__toolbar--left{flex:2 1 0;justify-content:flex-end}
.lpos-blueprint .lpos-feat__toolbar--mid{flex:1 1 0}
.lpos-blueprint .lpos-feat__toolbar--right{flex:2 1 0;justify-content:flex-start}
/* the rate button is the bar's one TEXT control (same 46px chrome, "1x" label like the in-player bar) */
.lpos-blueprint .lpos-feat__toolbar .lpos-vt__rate{
  font:700 var(--lpos-text-sm,14px)/1 var(--lpos-font-ui,'Inter', ui-sans-serif, system-ui, sans-serif);color:var(--lpos-muted)}
.lpos-blueprint .lpos-feat__toolbar .lpos-vt__rate:hover{color:var(--lpos-ink)}
.lpos-blueprint .lpos-cell--midcenter .lpos-feat__actions{align-items:center}
/* JD 2026-08-06 (rev): Prev/Next are ICON-ONLY skip buttons now -- squares at the transport bar's
   full height (same token math), freeing the row width for the tool bars. */
.lpos-blueprint .lpos-cell--midcenter .lpos-feat__actions > .lpos-c-skip-action{
  width:calc(var(--lpos-control-size,46px) + 2*var(--lpos-subpanel-pad,6px) + 2*var(--lpos-border-width,1px))!important;
  height:calc(var(--lpos-control-size,46px) + 2*var(--lpos-subpanel-pad,6px) + 2*var(--lpos-border-width,1px))!important;
  flex:0 0 auto;align-self:center}

/* ==== FOCAL-POINT IMAGE SYSTEM (task #14, JD APPROVED 2026-08-05) ====
   ONE object-position contract for every cover-cropped image component: the crop anchors on the
   focal tokens (default center; per-image inline vars re-anchor). Archive cards crop their
   BACKGROUND image on the same tokens. Zero visual change until an asset carries focal data. */
.lpos-blueprint .lpos-c-thumb img,
.lpos-blueprint .lpos-switch__thumb img,
.lpos-blueprint .lpos-media-image,
.lpos-blueprint .lpos-c-cta__media img,
.lpos-blueprint .lpos-c-icon-btn--avatar .lpos-c-avatar {
  object-position: var(--lpos-focal-x, 50%) var(--lpos-focal-y, 50%);
}
.lpos-blueprint .lpos-c-archive-card__hit {
  background-position: var(--lpos-focal-x, 50%) var(--lpos-focal-y, 50%);
}
/* ==== /FOCAL-POINT SYSTEM ==== */

/* ==== JD 2026-08-05 RIGHT-COLLAPSED POLISH (4 items, this state only) ==== */
/* 3. rail buttons distribute EVENLY down the right bar -- JD 2026-08-05 refinement (all views):
   the TOP button aligns with the neighbor panels' first items (space-between + the standard
   16px top inset), spacing stays even between all buttons. */
.lpos-blueprint--console.-left-collapsed .lpos-rail--right{justify-content:space-between;gap:0;
  padding-top:var(--lpos-gap,12px)!important;padding-bottom:var(--lpos-gap,12px)!important}
/* ==== /RIGHT-COLLAPSED POLISH ==== */

/* ==== JD 2026-08-05 LEFT-COLLAPSED POLISH (7 items; item 1 = the rail-thumb min-width fix above) ==== */
/* 2. hamburger dead-center in its 64px box */
.lpos-blueprint--console.-left-collapsed .lpos-cell--topleft{justify-content:center!important;padding:var(--lpos-space-sm,8px)!important}
/* 4. botleft corner toggle dead-center */
.lpos-blueprint--console.-left-collapsed .lpos-cell--botleft{justify-content:center!important;padding:var(--lpos-space-sm,8px)!important}
/* 5. botright corner toggle dead-center (was scoped to right-collapsed only) */
.lpos-blueprint--console.-left-collapsed .lpos-cell--botright{justify-content:center!important;align-items:center!important;padding:var(--lpos-space-sm,8px)!important}
/* 6. the tabbar portal-twin pill keeps a REAL switcher width (was collapsing to its label) */
.lpos-blueprint--console.-left-collapsed [data-lpos-portal-twin] .lpos-c-select__value{min-width:calc(6*var(--lpos-control-size,46px))}
/* 7. (folded into the shared right-rail distribution rule above -- space-between, 16px top inset.) */
/* ==== /LEFT-COLLAPSED POLISH ==== */

/* ==== JD 2026-08-05 EVENING BATCH 2 ==== */
/* MENU DRAWER rework: drawer icon buttons carry the exact cell icon-button recipe; the tab strip
   pins to the drawer bottom directly above Logout; the search bar leads the body. */
.lpos-drawer .lpos-c-icon-btn{width:var(--lpos-control-size,46px)!important;height:var(--lpos-control-size,46px)!important;flex:0 0 auto;padding:0!important;display:inline-flex;align-items:center;justify-content:center;cursor:pointer;color:var(--lpos-muted)}
.lpos-drawer .lpos-c-icon-btn svg{width:var(--lpos-icon-size,26px)!important;height:var(--lpos-icon-size,26px)!important;flex:0 0 auto;display:block;fill:none!important;stroke:currentColor;color:inherit}
.lpos-drawer .lpos-c-icon-btn[disabled]{opacity:.45;cursor:default}
.lpos-menu .lpos-drawer__tabs{margin-top:auto;display:flex;gap:var(--lpos-space-sm,8px);padding-top:var(--lpos-space-sm,8px)}
.lpos-menu .lpos-menu__logout{margin-top:0!important}
/* ==== /EVENING BATCH 2 ==== */

/* ==== MEDIA RATIO LAW (JD review, 2026-08-05): every ratio-bearing media component keeps ITS OWN
   aspect -- panel AND asset -- in every mid column. Video/3D panels take the asset's --lpm-aspect
   (canonical 16/9 fallback) instead of force-filling the column height; the stage fills the panel
   exactly. Images keep the approved cover-fill (no distortion, crop via the focal system);
   calendar/chat are grid components, not ratio media. ==== */
/* MIDLEFT (JD 2026-08-06): the media PANEL extends DOWN to fill the column (title to thumbnail
   strip); the ASSET inside keeps its own ratio, centered. */
.lpos-cell--midleft .lpos-col__media>.lpos-media.-video,
.lpos-cell--midleft .lpos-col__media>.lpos-media.-model{
  height:100%!important;aspect-ratio:auto;min-height:0;width:100%;
  align-self:stretch!important;flex:1 1 auto!important;
  display:flex;flex-direction:column;align-items:center;justify-content:center}
.lpos-cell--midleft .lpos-media.-video .lpos-media__stagev{
  width:100%!important;height:auto!important;aspect-ratio:var(--lpm-aspect,var(--lpos-media-switch-ratio,16/9));
  max-height:100%!important;flex:0 0 auto}
/* JD 2026-08-06: the midleft 3D/poster ASSET covers the FULL panel -- width AND height -- no
   letterboxed aspect box in this column (the poster crops via the focal system like every image). */
.lpos-cell--midleft .lpos-media.-model .lpos-media__mv{
  width:100%!important;height:100%!important;aspect-ratio:auto;flex:1 1 auto;min-height:0}
/* MIDRIGHT: the media panel keeps the asset's own ratio (aspect-locked box, top-aligned). */
.lpos-cell--midright .lpos-col__media>.lpos-media.-video,
.lpos-cell--midright .lpos-col__media>.lpos-media.-model{
  height:auto!important;aspect-ratio:var(--lpm-aspect,var(--lpos-media-switch-ratio,16/9));
  max-height:100%;min-height:0;width:100%;
  align-self:flex-start!important;flex:0 0 auto!important}
/* DEFECT FIX (2026-08-07, JD-reported "small square 3D mount, huge empty band below"): the
   MIDRIGHT ratio-locked/top-aligned rule above was reviewed against the LEGACY row-height
   midright cell -- under BLUEPRINT SHIFT stage A that cell is now the FULL viewport height
   (console-tokens.css BLUEPRINT SHIFT stage A block, ~line 1784), so a 16:9-capped, top-aligned
   box leaves most of the tall column empty. Scoped to the boot/-left-collapsed state ONLY (the
   both-open legacy row layout above keeps the reviewed ratio-locked contract untouched); mirrors
   the midleft full-fill 3D contract (panel fills the column, asset covers the full panel) -- 3D
   ONLY, video keeps its 16:9 letterbox everywhere (no JD report against video). Specificity
   (extra `.lpos-blueprint--console.-left-collapsed` class) beats the rule above regardless of
   source order. */
.lpos-blueprint--console.-left-collapsed .lpos-cell--midright .lpos-col__media>.lpos-media.-model{
  height:100%!important;aspect-ratio:auto;min-height:0;width:100%;
  align-self:stretch!important;flex:1 1 auto!important;
  display:flex;flex-direction:column;align-items:center;justify-content:center}
.lpos-blueprint--console.-left-collapsed .lpos-cell--midright .lpos-media.-model .lpos-media__mv{
  width:100%!important;height:100%!important;aspect-ratio:auto;flex:1 1 auto;min-height:0}
/* the CENTER video panel locks to the same contract (the old width-forced stage drifted to 1.87
   vs its 16/9 token; panel=aspect + stage fills = exact). */
/* RATIO LOCK (JD 2026-08-06, rev CONTENT-BOX lock): the panel's BORDER box was locked to 16:9
   before, which left the CONTENT box (inside the panel's pad + border) off-ratio -- the Vimeo
   iframe letterboxed inside its own stage. Now the CONTENT box is the exact 16:9 lock: width is
   the SMALLER of the body's width and its height-derived content-box width, with the panel's own
   pad+border added back on top of that math so the outer panel still fits the body (no max-height
   clamp ever breaks it again). The stage below carries the real aspect-ratio and owns the height
   now -- the panel itself no longer declares aspect-ratio. --lpm-aspect substitutes textually
   ("16 / 9") into the calc division. */
/* ONE FRAME TOO MANY (JD 2026-08-10): the centre stacked THREE bordered boxes around the player --
   the video's own outline, this media panel, and the outer body panel. The middle one sheds its
   chrome (same treatment .lpos-c-cta__media already gets in the right column), leaving the video
   outline inside the one body panel. */
.lpos-cell--midcenter .lpos-feat__body>.lpos-media{border:0!important;background:transparent!important;
  -webkit-backdrop-filter:none!important;backdrop-filter:none!important;padding:0!important;box-shadow:none!important}
.lpos-cell--midcenter .lpos-feat__body>.lpos-media.-video{
  flex:0 0 auto;height:100%!important;min-height:0;
  aspect-ratio:auto!important; /* the media engine's own base rule re-locks the BORDER box to 16:9 without this -- the stage below owns the ratio */
  width:auto!important; /* rev 4 (JD 2026-08-09): HEIGHT-driven -- the 2:1 center is wider than its height affords, so the body's definite height governs and the stage's ratio derives the width (the cut-off-title fix) */
  max-width:100%}
/* JD 2026-08-06: the stage is the exact 16:9 CONTENT box and clips its iframe to the panel radius
   (border-radius already comes from the ASSET RADIUS LAW below). flex:0 0 auto stops the panel's
   own column flex from stretching the stage past its ratio (flex sizing beats aspect-ratio). */
.lpos-cell--midcenter .lpos-feat__body>.lpos-media.-video .lpos-media__stagev{
  width:auto!important;height:100%!important;flex:0 0 auto!important; /* rev 4: height-driven, ratio derives the width */
  aspect-ratio:var(--lpm-aspect,var(--lpos-media-switch-ratio,16/9));overflow:hidden}
.lpos-cell--midcenter .lpos-feat__body>.lpos-media.-video .lpos-media__stagev,
.lpos-cell--midleft .lpos-media.-video .lpos-media__stagev,
.lpos-cell--midright .lpos-media.-video .lpos-media__stagev{width:100%;height:100%;max-height:none;
  box-sizing:border-box!important} /* JD 2026-08-06 fix: content-box width:100% + the stage's own inset pushed it 17px past the panel's right edge (the "cut off" video) -- border-box keeps it exactly inside */
/* 3D: the model-viewer fills its aspect-locked panel (the old midleft display:none band-aid is
   removed below -- the pane is a real sized component again, no empty shell). */
.lpos-media.-model .lpos-media__mv{display:block;width:100%!important;height:100%!important}
/* ==== /MEDIA RATIO LAW ==== */

/* ==== JD 2026-08-06 MENU DRAWER POLISH ==== */
/* Parent rows (with secondary menus) = ONE segmented pill: label + step-in chevron share one
   panel outline -- never a pill inside an outlined box. The li is pure layout flow. */
.lpos-menu .lpos-menu__item--haskids{background:transparent!important;border:0!important;box-shadow:none!important;padding:0!important;display:flex;align-items:stretch;gap:0}
.lpos-menu .lpos-menu__item--haskids>.lpos-menu__link{flex:1 1 auto;min-width:0;
  border-top-right-radius:0!important;border-bottom-right-radius:0!important;border-right:0!important}
.lpos-menu .lpos-menu__item--haskids>.lpos-menu__stepin{
  flex:0 0 auto;width:var(--lpos-control-size,46px);display:inline-flex;align-items:center;justify-content:center;
  cursor:pointer;color:var(--lpos-muted);
  background:var(--lpos-glass-panel)!important;-webkit-backdrop-filter:var(--lpos-blur-md);backdrop-filter:var(--lpos-blur-md);
  border:var(--lpos-border-width,1px) solid color-mix(in srgb,var(--lpos-border-tint,var(--lpos-accent)) var(--lpos-border-alpha-2,40%),transparent)!important;
  border-top-left-radius:0!important;border-bottom-left-radius:0!important;
  border-top-right-radius:var(--lpos-radius-panel,10px)!important;border-bottom-right-radius:var(--lpos-radius-panel,10px)!important}
.lpos-menu .lpos-menu__item--haskids>.lpos-menu__stepin svg{width:var(--lpos-icon-size-sm,24px);height:var(--lpos-icon-size-sm,24px);fill:none!important;stroke:currentColor}
.lpos-menu .lpos-menu__item--haskids>.lpos-menu__stepin:hover{color:var(--lpos-ink)}
/* The bottom tab strip buttons STRETCH to share the drawer width evenly. */
.lpos-menu .lpos-drawer__tabs .lpos-c-icon-btn{flex:1 1 0!important;width:auto!important;min-width:var(--lpos-control-size,46px)!important}
/* JD 2026-08-06 (menu rework 2): the top CTA pair -- chromeless flow row, two 50/50 buttons at
   control height (secondary left, primary Get Started right). */
.lpos-menu__ctas{display:flex;gap:var(--lpos-gap,12px);align-items:stretch}
/* the buy-box override further up absolutizes .lpos-c-cta__buy corner-style -- these two are
   in-flow 50/50 drawer CTAs, re-assert static flow at higher specificity */
.lpos-blueprint .lpos-menu__ctas .lpos-menu__cta{position:static!important;flex:1 1 0!important;
  width:auto!important;min-width:0!important;min-height:var(--lpos-control-size,46px)}
/* ==== /MENU DRAWER POLISH ==== */

/* JD 2026-08-06: the 3D viewer's hover toolbar is anchored to ITS OWN media panel in every column
   (never a fixed column offset) and must FIT that panel -- with the new 16:9 ratio panels the
   old single-column button stack (374px) poked out both ends. Cap to the panel height and let
   the buttons wrap into additional columns leftward. */
.lpos-blueprint .lpos-media.-model .lpos-media__bar{
  max-height:calc(100% - 2*var(--lpos-subpanel-pad,6px))!important;
  flex-wrap:wrap!important;align-content:flex-start;
  gap:var(--lpos-space-sm,8px)!important}

/* ==== JD 2026-08-06 LAW: ALL image and video ASSETS share the GLOBAL radius token -- no derived
   calcs, no divergent inner radii. One token, every asset corner, everywhere. ==== */
.lpos-blueprint .lpos-media-image,
.lpos-blueprint .lpos-c-thumb img,
.lpos-blueprint .lpos-switch__thumb img,
.lpos-blueprint .lpos-c-cta__media img,
.lpos-blueprint .lpos-c-icon-btn--avatar .lpos-c-avatar,
.lpos-blueprint .lpos-media__stagev,
.lpos-blueprint .lpos-media__stagev video,
.lpos-blueprint .lpos-media__stagev iframe,
.lpos-blueprint .lpos-media__embedwrap,
.lpos-blueprint .lpos-media__embedwrap iframe,
.lpos-blueprint .lpos-media__mv,
.lpos-blueprint .lpos-media video,
.lpos-blueprint model-viewer {
  border-radius: var(--lpos-radius-panel,10px) !important;
  /* JD 2026-08-06 LAYERED TRANSPARENCY: every ASSET carries the (smallest) transparency tier --
     the ambient bg video's motion is visible through the whole stack, assets least of all. */
  opacity: var(--lpos-asset-alpha, 0.9);
}
/* (3D poster note: model-viewer's shadow poster has no ::part hook in this build, so
   lpos-drawers.js ownModelPosters() lifts the poster onto the HOST as a cover background --
   which the radius rule above already clips. No shadow-DOM styling needed.) */
/* ==== /ASSET RADIUS LAW ==== */

/* JD 2026-08-06: the BIG PLAY overlay is a standard icon button of OUR token system inside the
   console -- ONE-PANEL chrome (glass, blur, 40% accent hairline, the GLOBAL radius token) on the
   existing size token. No bespoke circle, no custom color mixes, no shadows, no pulse. */
.lpos-blueprint .lpos-media__big{
  border-radius:var(--lpos-radius-panel,10px)!important;
  background:var(--lpos-glass-panel)!important;
  -webkit-backdrop-filter:var(--lpos-blur-md);backdrop-filter:var(--lpos-blur-md);
  border:var(--lpos-border-width,1px) solid color-mix(in srgb,var(--lpos-border-tint,var(--lpos-accent)) var(--lpos-border-alpha-2,40%),transparent)!important;
  box-shadow:none!important;animation:none!important}
.lpos-blueprint .lpos-media__big svg{color:var(--lpos-muted);transform:none}
.lpos-blueprint .lpos-media__big:hover{border-color:var(--lpos-accent);box-shadow:none!important;
  transform:translate(-50%,-50%)}
.lpos-blueprint .lpos-media__big:hover svg{color:var(--lpos-ink)}

/* ==== JD 2026-08-06 OWNED VIDEO PLAYER + CHAT PANE ==== */
/* The video stage carries NO inner panel chrome -- the media panel is THE one panel; the stage is
   just the aspect box the frame fills exactly (kills the double border + the compounding insets). */
.lpos-blueprint .lpos-media.-video .lpos-media__stagev{
  border:0!important;background:transparent!important;padding:0!important;box-shadow:none!important}
/* ASSET BORDER LAW (JD 2026-08-06, items 2/3/4): the media ASSET inside each player panel carries
   its OWN hairline -- the same 1px token border every panel wears -- on top of the panel's border:
   midleft image/3D host, the center video stage, the Focus image. box-sizing keeps the frame
   inside the asset's box (no layout shift). */
.lpos-blueprint .lpos-media-image,
.lpos-blueprint .lpos-c-cta__media img,
.lpos-blueprint .lpos-media.-model .lpos-media__mv,
.lpos-blueprint .lpos-media.-video .lpos-media__stagev{
  border:var(--lpos-border-width,1px) solid color-mix(in srgb,var(--lpos-border-tint,var(--lpos-accent)) var(--lpos-border-alpha-2,40%),transparent)!important;
  box-sizing:border-box!important}

/* ==== JD 2026-08-06 FOCUS PANE REORDER (adaptive/no-commerce cta only) ====
   Row map: [tab|tab] / [image span] / [text span, fills what's left but SHORTER than before] /
   [button|button]. Buttons leave the absolute corner treatment and become real 50/50 grid
   children (the actions wrapper is already display:contents); the button lane padding goes. */
.lpos-blueprint .lpos-c-cta--adaptive{
  grid-template-rows:auto auto minmax(0,1fr)!important;
  padding-bottom:0!important} /* JD 2026-08-06: buttons sit flush on the pane bottom -- their row
  aligns with the center column's Prev/toolbar row; the text panel's 1fr absorbs the reclaimed 16px */
/* with the qty + live-price row present (real bound price only), the row map gains one line:
   [tab|tab] / [image] / [qty|price] / [text 1fr] / [button|button] (JD 2026-08-06) */
.lpos-blueprint .lpos-c-cta--adaptive.lpos-c-cta--priced{
  grid-template-rows:auto auto auto minmax(0,1fr)!important}
.lpos-blueprint .lpos-c-cta--adaptive .lpos-c-cta__buy{position:static;width:auto!important;min-width:0;
  height:calc(var(--lpos-control-size,46px) + 2*var(--lpos-subpanel-pad,6px) + 2*var(--lpos-border-width,1px))} /* matches the Prev/Next skip buttons */
.lpos-blueprint .lpos-c-cta--adaptive .lpos-c-cta__info{min-height:calc(2*var(--lpos-control-size,46px))}
/* ==== /FOCUS PANE REORDER ==== */

/* ==== JD 2026-08-06 MIDLEFT TOOL PANEL ====
   The old per-slot title TEXT panel is retired; this persistent panel (tabbar-clone geometry)
   hosts the active pane's ADOPTED tool bar inline -- 3D orbit tools or PDF tools + pagination --
   with the plus LAST. The glue-rendered title panels are suppressed (text removed by JD order). */
.lpos-blueprint .lpos-cell--midleft .lpos-col__tools{
  display:flex;align-items:center;gap:var(--lpos-gap,12px);
  padding:var(--lpos-subpanel-pad,6px)!important;box-sizing:border-box;
  min-height:var(--lpos-titlebar-h,64px);flex:0 0 auto}
.lpos-blueprint .lpos-cell--midleft .lpos-col__tools>[data-lpos-switch-add]{margin-left:auto;flex:0 0 auto}
.lpos-blueprint .lpos-cell--midleft .lpos-col__slot .lpos-c-title-panel{display:none!important}
/* adopted bars: static inline flow -- the tool panel is THE panel, the bar itself is chromeless */
/* JD 2026-08-06 sidequest: `.lpos-c-title-panel.-tools` (toolifyDockedPane's adopted title row --
   the docked/midright pane's 3D + PDF tools) joins EVERY rule here so its buttons are the same
   individual icon-button Components as the midleft tool panel, never bare glyphs in one bar. */
[data-lpos-left-tools] .lpos-media__bar,
[data-lpos-left-tools] .lpos-media__bar--above,
[data-lpos-left-tools] .lpos-media__bar--below,
.lpos-c-title-panel.-tools .lpos-media__bar,
.lpos-c-title-panel.-tools .lpos-media__bar--above,
.lpos-c-title-panel.-tools .lpos-media__bar--below{
  position:static!important;opacity:1!important;transform:none!important;pointer-events:auto!important;
  display:flex!important;flex:1 1 0!important;width:auto!important;min-width:0!important;
  align-items:center;gap:var(--lpos-gap,12px)!important;
  background:transparent!important;border:0!important;box-shadow:none!important;
  padding:0!important;margin:0!important;max-height:none!important;flex-wrap:nowrap!important;overflow:hidden}
/* every adopted tool = a NORMAL icon button (byte-identical chrome clone), stretch-shared width */
[data-lpos-left-tools] .lpos-media__bar button,
[data-lpos-left-tools] .lpos-media__bar a,
[data-lpos-left-tools] .lpos-media__bar--above button,
[data-lpos-left-tools] .lpos-media__bar--above a,
.lpos-c-title-panel.-tools .lpos-media__bar button,
.lpos-c-title-panel.-tools .lpos-media__bar a,
.lpos-c-title-panel.-tools .lpos-media__bar--above button,
.lpos-c-title-panel.-tools .lpos-media__bar--above a,
.lpos-c-title-panel.-tools .lpos-media__bar--below button,
.lpos-c-title-panel.-tools .lpos-media__bar--below a{
  all:unset;box-sizing:border-box;cursor:pointer;
  height:var(--lpos-control-size,46px);flex:1 1 0;min-width:0;
  display:inline-flex;align-items:center;justify-content:center;color:var(--lpos-muted);
  background:var(--lpos-glass-panel);-webkit-backdrop-filter:var(--lpos-blur-md);backdrop-filter:var(--lpos-blur-md);
  border:var(--lpos-border-width,1px) solid color-mix(in srgb,var(--lpos-border-tint,var(--lpos-accent)) var(--lpos-border-alpha-2,40%),transparent);
  border-radius:var(--lpos-radius-panel,10px)}
[data-lpos-left-tools] .lpos-media__bar button:hover,
[data-lpos-left-tools] .lpos-media__bar--above button:hover,
.lpos-c-title-panel.-tools .lpos-media__bar button:hover,
.lpos-c-title-panel.-tools .lpos-media__bar--above button:hover,
.lpos-c-title-panel.-tools .lpos-media__bar--below button:hover{color:var(--lpos-ink);border-color:var(--lpos-accent)}
[data-lpos-left-tools] .lpos-media__bar svg,
[data-lpos-left-tools] .lpos-media__bar--above svg,
[data-lpos-left-tools] .lpos-media__bar--below svg,
.lpos-c-title-panel.-tools .lpos-media__bar svg,
.lpos-c-title-panel.-tools .lpos-media__bar--above svg,
.lpos-c-title-panel.-tools .lpos-media__bar--below svg{
  width:var(--lpos-icon-size-sm,24px);height:var(--lpos-icon-size-sm,24px);fill:none!important;stroke:currentColor;flex:0 0 auto}
/* AR is touch-only (research verdict, JD option 1): fine-pointer/desktop viewers never see an
   inert AR control -- the tools-panel button chrome outranked the engine's own gate, so re-gate
   at this scope. */
@media (hover: hover) and (pointer: fine){
  [data-lpos-left-tools] [data-a="ar"],
  .lpos-c-title-panel.-tools [data-a="ar"]{display:none!important}
}
/* JD 2026-08-06: pagination in the tool panel shows ONLY the prev/next arrows -- the count text
   never renders here (the panel is a tool bar, not a page-position readout). */
[data-lpos-left-tools] .lpos-pagination__count{display:none!important}
/* JD 2026-08-06: the exit-fullscreen X never renders in the tool panel (fullscreen toggle lives
   on the media's own hover bar, not the adopted tool panel copy). */
[data-lpos-left-tools] .lpos-media__fsx,
.lpos-c-title-panel.-tools .lpos-media__fsx{display:none!important}
/* JD 2026-08-09 BELT-AND-SUSPENDERS: media_switcher_cell_html() (BlueprintRenderer.php) already
   emits the column in DOM order media, tools, thumbs -- this rule just guarantees the VISUAL
   order matches even if some future insertion (JS or a different render branch) ever lands a
   node out of sequence. Cheap, harmless when the DOM is already correct. */
.lpos-blueprint .lpos-cell--midleft .lpos-col>.lpos-col__slot{order:1}
.lpos-blueprint .lpos-cell--midleft .lpos-col>.lpos-col__tools{order:2}
.lpos-blueprint .lpos-cell--midleft .lpos-col>.lpos-switch{order:3}
/* ==== /MIDLEFT TOOL PANEL ==== */
/* Chat pane: back+peer header row (chromeless flow); peer chip = one compact title panel; the chat
   component inside the pane body is pure flow (the body subpanel is THE panel). */
.lpos-view__chathead{display:flex;align-items:center;gap:var(--lpos-gap,12px);flex:0 0 auto}
.lpos-view__chathead .lpos-c-icon-btn--labeled{flex:0 0 auto}
.lpos-blueprint .lpos-c-title-panel.lpos-view__peer{flex:1 1 auto;display:flex;align-items:center;gap:var(--lpos-space-sm,8px);
  min-height:var(--lpos-control-size,46px);padding:0 var(--lpos-panel-pad,12px)!important}
.lpos-blueprint .lpos-view__peer h2{margin:0!important;font-size:var(--lpos-subtitle-size,1rem)!important;line-height:1.2!important}
.lpos-view__body .lpos-c-chat{border:0!important;background:transparent!important;padding:0!important;box-shadow:none!important;-webkit-backdrop-filter:none!important;backdrop-filter:none!important}
/* ==== /OWNED VIDEO PLAYER + CHAT PANE ==== */

/* JD 2026-08-06: chat header LAW fix -- the avatar chip is its OWN Component panel (initial = the
   asset), the name is its OWN title panel; and the 3D toolbar renders ONLY when a real model has
   loaded (-modelready from lpos-drawers.js), never over a poster-only pane. */
.lpos-blueprint .lpos-c-panel.lpos-view__peer-avatar{flex:0 0 auto;width:var(--lpos-control-size,46px);height:var(--lpos-control-size,46px);
  padding:0!important;display:inline-flex;align-items:center;justify-content:center;
  color:var(--lpos-muted);font-weight:600;font-size:var(--lpos-subtitle-size,1rem)}
.lpos-blueprint .lpos-media.-model:not(.-modelready) .lpos-media__bar{display:none!important}

/* PERSPECTIVE SYSTEM removed entirely (JD 2026-08-09: "remove completely") -- the cockpit tilt was parked at 0deg and computed to identity since the flat-grid rebuild; tokens gone from :root too. */

/* JD 2026-08-09 reversal: featured media ABOVE, the text/title panel at the BOTTOM of the
   center column (the 2026-08-06 order:-1 text-first rule is retired). */
.lpos-blueprint--console .lpos-cell--midcenter .lpos-feat__titlecap{order:99}

/* ==== TOOLBAR DISTRIBUTION LAW (JD 2026-08-06) ====
   EVERY icon-button tool bar distributes its buttons across the full row width -- the same
   adaptive stretch the transport and drawer tabs already use. The PLUS buttons (and the corner
   collapse toggles) are the one exception: they always keep the square control shape. */
.lpos-blueprint .lpos-cell--topright .lpos-c-icon-btn,
.lpos-blueprint .lpos-cell--botright .lpos-c-icon-btn,
.lpos-blueprint .lpos-c-subpanel--tabbar .lpos-c-icon-btn{
  flex:1 1 0!important;width:auto!important;
  min-width:calc(var(--lpos-icon-size-sm,24px) + 2*var(--lpos-subpanel-pad,6px))!important}
.lpos-blueprint [data-lpos-tabbar="plus"],
.lpos-blueprint [data-lpos-switch-add],
.lpos-blueprint .lpos-c-icon-btn[data-lpos-collapse]{
  flex:0 0 auto!important;width:var(--lpos-control-size,46px)!important;min-width:var(--lpos-control-size,46px)!important}
/* ==== /TOOLBAR DISTRIBUTION LAW ==== */

/* JD 2026-08-06 qty+price polish: the two chips share ONE height (the control token) and sit
   flush -- the qty label reads as a muted small cap, the input is a bare centered field inside
   its chip, and the price never clips its chip (content-sized, nowrap). */
.lpos-blueprint .lpos-c-cta__qtyprice{align-items:stretch;min-height:calc(var(--lpos-control-size,46px) + 2*var(--lpos-subpanel-pad,6px))}
.lpos-blueprint .lpos-c-cta__qtyprice .lpos-c-cta__qtypanel{padding:var(--lpos-subpanel-pad,6px) var(--lpos-panel-pad,12px)!important}
.lpos-blueprint .lpos-c-cta__qtyprice .lpos-c-cta__qtylabel{font:600 var(--lpos-text-xs,13px)/1 var(--lpos-font-ui,'Inter', ui-sans-serif, system-ui, sans-serif);
  letter-spacing:.08em;text-transform:uppercase;color:var(--lpos-muted)}
.lpos-blueprint .lpos-c-cta__qtyprice .lpos-c-cta__qty{text-align:center}
.lpos-blueprint .lpos-c-cta__qtyprice .lpos-c-cta__pricepanel{padding:var(--lpos-subpanel-pad,6px) var(--lpos-panel-pad,12px)!important}
.lpos-blueprint .lpos-c-cta__qtyprice .lpos-c-cta__price{white-space:nowrap;display:flex;align-items:baseline;justify-content:center;column-gap:var(--lpos-space-xs,4px);min-width:0}
/* JD 2026-08-06 (audit defect 3): "One-Time Purchase" was clipped mid-word in the box sized for
   "per Month" -- the suffix keeps one line, shrinks a step, and the pair may wrap as a pair
   instead of slicing letters off. */
.lpos-blueprint .lpos-c-cta__pricemode{font-size:var(--lpos-text-xs,13px);white-space:nowrap;flex:0 1 auto;overflow:visible}

/* PLACEHOLDER QTY/PRICE ROW (JD 2026-08-10, archive layout parity): the row now renders honestly
   empty instead of not rendering at all -- the qty input goes inert (dimmed, not-allowed, same
   "disabled placeholders... no fake interactivity" idiom the disabled icon-button rule above
   already uses) and the price panel carries a sentence, not a number, so it needs to WRAP instead
   of the numeric price's nowrap/accent-color treatment (no scrollbars law -- a clipped sentence
   would read as broken, same as a scrollbar would). */
.lpos-blueprint .lpos-c-cta__qty:disabled{opacity:.4;cursor:not-allowed;color:var(--lpos-ink-disabled,#6C7A93)}
.lpos-blueprint .lpos-c-cta__qtyprice .lpos-c-cta__price--placeholder{white-space:normal;text-align:center;
  font:400 var(--lpos-text-sm,14px)/1.3 var(--lpos-font-ui,'Inter', ui-sans-serif, system-ui, sans-serif);
  color:var(--lpos-muted,#A8B2C7)}

/* ==== OWNED VIDEO OVERLAY (JD 2026-08-06) ====
   OUR in-player controls over the chromeless embed: a hover play/pause chip center-stage and a
   timeline pinned to the stage bottom, both driven by the postMessage transport in
   lpos-drawers.js. Hidden while the click-to-play poster facade is still up (its own big play
   owns that state); ONE-PANEL chrome, tokens only, no shadows. */
.lpos-blueprint .lpos-media__embedwrap{position:relative}
.lpos-blueprint .lpos-media__hoverplay{position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);z-index:6;
  width:var(--lpos-play-btn-size,80px);height:var(--lpos-play-btn-size,80px);box-sizing:border-box;
  display:inline-flex;align-items:center;justify-content:center;cursor:pointer;
  background:var(--lpos-glass-panel);-webkit-backdrop-filter:var(--lpos-blur-md);backdrop-filter:var(--lpos-blur-md);
  border:var(--lpos-border-width,1px) solid color-mix(in srgb,var(--lpos-border-tint,var(--lpos-accent)) var(--lpos-border-alpha-2,40%),transparent);
  border-radius:var(--lpos-radius-panel,10px);color:var(--lpos-muted);
  opacity:0;pointer-events:none;transition:opacity var(--lpos-duration-fast,120ms)}
.lpos-blueprint .lpos-media__embedwrap:hover .lpos-media__hoverplay{opacity:1;pointer-events:auto}
.lpos-blueprint .lpos-media__hoverplay:hover{color:var(--lpos-ink);border-color:var(--lpos-accent)}
.lpos-blueprint .lpos-media__hoverplay svg{width:var(--lpos-icon-size-lg,32px);height:var(--lpos-icon-size-lg,32px);fill:none!important;stroke:currentColor}
.lpos-blueprint .lpos-media__timeline{position:absolute;z-index:6;cursor:pointer;box-sizing:border-box;
  left:var(--lpos-panel-pad,12px);right:var(--lpos-panel-pad,12px);bottom:var(--lpos-panel-pad,12px);
  height:calc(2*var(--lpos-subpanel-pad,6px));
  background:var(--lpos-glass-panel);-webkit-backdrop-filter:var(--lpos-blur-md);backdrop-filter:var(--lpos-blur-md);
  border:var(--lpos-border-width,1px) solid color-mix(in srgb,var(--lpos-border-tint,var(--lpos-accent)) var(--lpos-border-alpha-2,40%),transparent);
  border-radius:var(--lpos-radius-panel,10px);overflow:hidden}
/* fill = a THIN clone of the botleft XP bar's fill recipe (JD 2026-08-06: "like a much thinner
   version of our bottom left progress bar, I love the gradient out at the front") -- same accent
   glass, same soft leading-edge fade via the identical mask formula. No shadows (law). */
.lpos-blueprint .lpos-media__timeline-fill{height:100%;width:0;
  border-radius:var(--lpos-radius-panel,10px) 0 0 var(--lpos-radius-panel,10px);
  background:var(--lpos-accent-glass,color-mix(in srgb,var(--lpos-accent) 32%,transparent));
  -webkit-mask-image:linear-gradient(to right,#000 0,#000 calc(100% - 2*var(--lpos-panel-pad,12px)),transparent 100%);
  mask-image:linear-gradient(to right,#000 0,#000 calc(100% - 2*var(--lpos-panel-pad,12px)),transparent 100%);
  transition:width var(--lpos-duration-fast,120ms) linear}
/* while the poster facade is visible the overlay stays out of the way (facade owns first-play) */
.lpos-blueprint .lpos-media__embedwrap:has(.lpos-media__embedposter:not([hidden])) .lpos-media__hoverplay,
.lpos-blueprint .lpos-media__embedwrap:has(.lpos-media__embedposter:not([hidden])) .lpos-media__timeline{display:none}
/* JD 2026-08-06: the timeline shows on HOVER only, same reveal as the play chip. */
.lpos-blueprint .lpos-media__timeline{opacity:0;pointer-events:none;transition:opacity var(--lpos-duration-fast,120ms)}
.lpos-blueprint .lpos-media__embedwrap:hover .lpos-media__timeline{opacity:1;pointer-events:auto}
/* ==== /OWNED VIDEO OVERLAY ==== */

/* ==== JD 2026-08-06 SCREENSHOT BATCH ==== */
/* 3D tool panel: FULLSCREEN takes the leftmost slot, the PLUS moves to the far right (swap). */
[data-lpos-left-tools]{display:flex}
[data-lpos-left-tools] .lpos-media__bar [data-a="full"]{order:-1}
[data-lpos-left-tools]>[data-lpos-switch-add]{order:99;margin-left:auto}
/* PDF tool bars: every adopted button shares the width evenly (prev/next pagination included) --
   the plus keeps its square via the order/width rules above. */
[data-lpos-left-tools] .lpos-media__bar--below .lpos-pagination__navwide{flex:1 1 0!important;width:auto!important}
/* the full-bleed page crops its few overflow px inside the stage, never outside the panel */
.lpos-cell--midleft .lpos-media.-flip{overflow:hidden}
.lpos-cell--midleft .lpos-media.-flip .lpos-media__mount{margin-left:auto;margin-right:auto}
/* the PDF document itself carries the GLOBAL radius token like every other asset (JD 2026-08-06) */
.lpos-blueprint .lpos-media.-flip .lpos-media__mount,
.lpos-blueprint .lpos-media.-flip .lpos-media__page,
.lpos-blueprint .lpos-media.-flip .lpos-media__page img,
.lpos-blueprint .lpos-media.-flip .stf__parent,
.lpos-blueprint .lpos-media.-flip .stf__item{
  border-radius:var(--lpos-radius-panel,10px)!important;overflow:hidden}
/* view-switch buttons remember their click: accent border + ink while active */
.lpos-blueprint .lpos-c-icon-btn[data-lpos-switch-target][aria-pressed="true"],
.lpos-blueprint .lpos-rail .lpos-c-icon-btn[aria-pressed="true"]{
  border-color:var(--lpos-accent)!important;color:var(--lpos-ink,#EAF2FB)}
/* chat switch lights the composer: type HERE to talk to the AI on the right */
.lpos-blueprint .lpos-search.-attn{border-color:var(--lpos-accent)!important}
/* Subscribe tab + active-look buy pair: the is-active tab carries the accent hairline + ink */
.lpos-blueprint .lpos-c-cta__tab.is-active{border-color:var(--lpos-accent)!important;color:var(--lpos-ink,#EAF2FB)}
/* Focus text panel subtitle (JD 2026-08-06) */
.lpos-blueprint .lpos-c-cta__subtitle{margin:0;font:500 var(--lpos-subtitle-size-secondary,.75rem)/1.3 var(--lpos-font-ui,'Inter', ui-sans-serif, system-ui, sans-serif);
  color:var(--lpos-muted);text-transform:uppercase;letter-spacing:.08em}
/* Collapsed rail thumbs keep their preview image UNDER the badge like the open strip -- the rail
   re-assert squashed the img (JD 2026-08-06 screenshot: icon on flat glass, no artwork). */
.lpos-blueprint .lpos-rail .lpos-switch__thumb img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover}
.lpos-blueprint .lpos-rail .lpos-switch__thumb .lpos-switch__thumb-badge{
  width:calc(var(--lpos-control-size,46px) - 2*var(--lpos-subpanel-pad,6px));
  height:calc(var(--lpos-control-size,46px) - 2*var(--lpos-subpanel-pad,6px))} /* fits the 46px rail square; radius token unchanged */
/* ==== /SCREENSHOT BATCH ==== */

/* =====================================================================================
 * SMALL SCREENS (JD backlog item 1, 2026-08-10; rewritten token-pure 2026-08-10).
 *
 * The resting layout is four lanes -- rail | primary | secondary | rail -- which needs room to
 * breathe. Below the tablet breakpoint the two content lanes STACK: primary, then secondary, then
 * the composer, both spanning the full width between the rails. Nothing is hidden and no lane is
 * dropped; the same Panels re-flow.
 *
 * TOKEN LAW: every size here comes from the ladder declared in the token block
 * (--lpos-control-size-md/-sm, --lpos-rail-w-md/-sm, --lpos-icon-size-md/-phone,
 * --lpos-media-floor-sm, --lpos-media-cap-sm) or from an existing spacing token. The only bare
 * numbers are the two BREAKPOINTS -- CSS cannot read a custom property inside a media query, so
 * they are declared once here and nowhere else in the file:
 *     tablet and below : 1100px
 *     phone            :  640px
 * ===================================================================================== */
@media (max-width: 1100px) {
  .lpos-blueprint--console.-left-collapsed{
    grid-template-columns:var(--lpos-rail-w-md) minmax(0,1fr) var(--lpos-rail-w-md)!important;
    grid-template-rows:auto minmax(0,1.15fr) minmax(0,1fr) var(--lpos-titlebar-h)!important}
  /* header row: menu box, tab bar, profile corner */
  .lpos-blueprint--console.-left-collapsed>.lpos-blueprint__row>.lpos-blueprint__region--topleft{grid-column:1!important;grid-row:1!important}
  .lpos-blueprint--console.-left-collapsed>.lpos-blueprint__row>.lpos-blueprint__region--topcenter{grid-column:2!important;grid-row:1!important}
  .lpos-blueprint--console.-left-collapsed>.lpos-blueprint__row>.lpos-blueprint__region--topright{grid-column:3!important;grid-row:1!important}
  /* content lanes stack; composer keeps the foot */
  .lpos-blueprint--console.-left-collapsed>.lpos-blueprint__row>.lpos-blueprint__region--midcenter{grid-column:2!important;grid-row:2!important}
  .lpos-blueprint--console.-left-collapsed>.lpos-blueprint__row>.lpos-blueprint__region--midright{grid-column:2!important;grid-row:3!important}
  .lpos-blueprint--console.-left-collapsed>.lpos-blueprint__row>.lpos-blueprint__region--botcenter{grid-column:2!important;grid-row:4!important}
  .lpos-blueprint--console.-left-collapsed .lpos-rail--left{grid-column:1!important;grid-row:2/5!important}
  .lpos-blueprint--console.-left-collapsed .lpos-rail--right{grid-column:3!important;grid-row:2/5!important}
  .lpos-blueprint--console.-left-collapsed>.lpos-blueprint__row>.lpos-blueprint__region--botleft,
  .lpos-blueprint--console.-left-collapsed>.lpos-blueprint__row>.lpos-blueprint__region--botright{display:none!important}
  /* the tab bar wraps rather than squashing its Components below their token size */
  .lpos-blueprint .lpos-cell--topcenter{flex-wrap:wrap;row-gap:var(--lpos-subpanel-pad)}
  .lpos-blueprint .lpos-cell--topcenter .lpos-topbar__trail{margin-left:0}
  /* rail Components step down one rung of the control ladder */
  .lpos-blueprint .lpos-rail{padding:var(--lpos-subpanel-pad)!important}
  .lpos-blueprint .lpos-rail .lpos-c-icon-btn,
  .lpos-blueprint .lpos-rail .lpos-switch__thumb{width:var(--lpos-control-size-md)!important;height:var(--lpos-control-size-md)!important}
  .lpos-blueprint .lpos-rail .lpos-c-icon-btn svg{width:var(--lpos-icon-size-md)!important;height:var(--lpos-icon-size-md)!important}
  /* stacked secondary lane: media keeps a floor and a cap, the lane itself scrolls (hidden bars,
     the same treatment the menu drawer already uses) instead of hiding Components */
  .lpos-blueprint .lpos-cell--midright .lpos-c-cta__media{min-height:var(--lpos-media-floor-sm);max-height:var(--lpos-media-cap-sm)}
  .lpos-blueprint .lpos-cell--midright>.lpos-col{overflow-y:auto;overscroll-behavior:contain;scrollbar-width:none;-ms-overflow-style:none}
  .lpos-blueprint .lpos-cell--midright>.lpos-col::-webkit-scrollbar{width:0;height:0}
  .lpos-blueprint .lpos-cell--midright .lpos-col__slot>.lpos-c-cta{flex:0 0 auto}
  /* the centre transport row is `.lpos-feat__actions` (11 controls), not a media bar; it wraps
     here, every control holding its full token size */
  .lpos-blueprint .lpos-cell--midcenter .lpos-feat__actions{flex-wrap:wrap!important;row-gap:var(--lpos-subpanel-pad);justify-content:center}
  .lpos-blueprint .lpos-cell--midcenter .lpos-feat__actions>*{flex:0 0 auto!important;min-width:var(--lpos-control-size)!important}
}

@media (max-width: 640px) {
  .lpos-blueprint--console.-left-collapsed{
    grid-template-columns:var(--lpos-rail-w-sm) minmax(0,1fr) var(--lpos-rail-w-sm)!important;
    grid-template-rows:auto minmax(0,1fr) minmax(0,1fr) var(--lpos-titlebar-h)!important;
    gap:var(--lpos-subpanel-pad)!important;padding:var(--lpos-subpanel-pad)!important}
  .lpos-blueprint .lpos-rail .lpos-c-icon-btn,
  .lpos-blueprint .lpos-rail .lpos-switch__thumb{width:var(--lpos-control-size-sm)!important;height:var(--lpos-control-size-sm)!important}
  .lpos-blueprint .lpos-rail .lpos-c-icon-btn svg{width:var(--lpos-icon-size-phone)!important;height:var(--lpos-icon-size-phone)!important}
  /* the commit row wraps rather than shrinking its two Components below a tappable size */
  .lpos-blueprint .lpos-cell--midright>.lpos-c-cta__actionbar{flex-wrap:wrap;height:auto;min-height:0;flex:0 0 auto}
  .lpos-blueprint .lpos-cell--midright>.lpos-c-cta__actionbar .lpos-c-cta__buy{flex:1 1 auto;min-width:calc(3*var(--lpos-control-size));height:var(--lpos-control-size)!important}
  .lpos-blueprint .lpos-c-cta__qtyprice{flex-wrap:wrap;gap:var(--lpos-subpanel-pad)}
  .lpos-blueprint .lpos-c-cta__qtyprice .lpos-c-cta__pricepanel{flex:1 1 auto;min-width:0}
  .lpos-blueprint .lpos-cell--botcenter .lpos-search{flex:1 1 100%;min-width:0}
  /* PHONE transport: wrapping 11 controls cost four rows and squashed the player. One row that
     scrolls sideways (hidden bars) keeps every control reachable AND the player its height. */
  .lpos-blueprint .lpos-cell--midcenter .lpos-feat__actions{flex-wrap:nowrap!important;
    overflow-x:auto;overscroll-behavior-x:contain;scrollbar-width:none;-ms-overflow-style:none;justify-content:flex-start}
  .lpos-blueprint .lpos-cell--midcenter .lpos-feat__actions::-webkit-scrollbar{width:0;height:0}
  .lpos-blueprint .lpos-cell--midcenter .lpos-feat__actions .lpos-c-icon-btn{flex:0 0 auto!important;width:var(--lpos-control-size)!important}
}

/* =====================================================================================
   CONSOLE SHELL + SLOT BRIDGE (moved here 2026-08-10, JD's token-law pass).
   These two surfaces are NOT part of the dark HUD console: they are the report shell and the
   slot bridge, deliberately LIGHT. Their rules used to live in two inline <style> blocks inside
   ConsoleRenderer.php, which meant a full palette (bg/ink/muted/line/panel/accent/good/warn/bad/
   info, the font stack, gap/pad/radius) existed as PHP string literals in two places, drifting
   independently from this file and from each other. Same CSS, one home. The palette is still
   SCOPED to these two class roots, so it re-declares the tokens for its own subtree only and
   never leaks into `.lpos-blueprint` (the dark-HUD law is untouched).
   ===================================================================================== */
.lpos-console-shell{--lpos-bg:#f6f7f9;--lpos-ink:#152033;--lpos-muted:#5f6b7a;--lpos-line:#d9dee7;--lpos-panel:#fff;--lpos-panel-hover:#eef7f6;--lpos-overlay:#152033;--lpos-accent:#166466;--lpos-accent-2:#2f4f66;--lpos-accent-3:#7c5f27;--lpos-good:#236a35;--lpos-warn:#a06100;--lpos-bad:#9f1d1d;--lpos-info:#245f8f;--lpos-font-ui:Inter,system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif;--lpos-gap:16px;--lpos-pad:20px;--lpos-panel-pad:14px;--lpos-radius-panel:8px;--lpos-radius-control:8px;background:var(--lpos-bg);color:var(--lpos-ink);font-family:var(--lpos-font-ui);min-height:720px;padding:var(--lpos-pad);box-sizing:border-box}
.lpos-console-shell *{box-sizing:border-box}
.lpos-console-header{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:var(--lpos-gap);align-items:start;border-bottom:1px solid var(--lpos-line);padding-bottom:var(--lpos-gap);margin-bottom:var(--lpos-gap)}
.lpos-console-eyebrow{color:var(--lpos-muted);font-size:12px;text-transform:uppercase;letter-spacing:.08em;margin:0 0 6px}
.lpos-console-title{font-size:28px;line-height:1.15;margin:0}
.lpos-console-meta{display:flex;flex-wrap:wrap;gap:8px;margin-top:10px}
.lpos-console-badge{display:inline-flex;align-items:center;min-height:28px;border:1px solid var(--lpos-line);border-radius:var(--lpos-radius-control);background:var(--lpos-panel);padding:4px 9px;color:var(--lpos-muted);font-size:13px}
.lpos-console-badge strong{color:var(--lpos-ink);font-weight:650;margin-left:4px}
.lpos-console-grid{display:grid;grid-template-columns:240px minmax(0,1fr) 300px;gap:var(--lpos-gap);align-items:start}
.lpos-console-panel{background:var(--lpos-panel);border:1px solid var(--lpos-line);border-radius:var(--lpos-radius-panel);padding:var(--lpos-panel-pad)}
.lpos-console-panel h2,.lpos-console-panel h3{font-size:14px;line-height:1.2;margin:0 0 12px}
.lpos-module-list{display:grid;gap:6px;margin:0;padding:0;list-style:none}
.lpos-module-item{border:1px solid var(--lpos-line);border-radius:var(--lpos-radius-control);padding:9px 10px;background:var(--lpos-panel);color:var(--lpos-muted);font-size:13px}
.lpos-module-item.is-active{border-color:var(--lpos-accent);color:var(--lpos-ink);background:var(--lpos-panel-hover)}
.lpos-kpi-grid{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:12px;margin-bottom:14px}
.lpos-kpi{background:var(--lpos-panel);border:1px solid var(--lpos-line);border-radius:var(--lpos-radius-panel);padding:13px;min-height:112px}
.lpos-kpi-label{color:var(--lpos-muted);font-size:12px;margin:0 0 8px}
.lpos-kpi-value{font-size:26px;line-height:1.1;margin:0 0 8px;font-weight:700}
.lpos-kpi-delta{font-size:12px;color:var(--lpos-muted)}
.lpos-kpi-delta.is-up{color:var(--lpos-good)}
.lpos-kpi-delta.is-down{color:var(--lpos-bad)}
.lpos-chart-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:12px;margin-top:14px}
.lpos-chart{border:1px solid var(--lpos-line);border-radius:var(--lpos-radius-panel);padding:13px;background:var(--lpos-panel)}
.lpos-chart-heading{display:flex;justify-content:space-between;gap:10px;align-items:flex-start;margin-bottom:10px}
.lpos-chart-title{font-weight:700;margin:0;line-height:1.25}
.lpos-chart-type{color:var(--lpos-muted);font-size:12px;white-space:nowrap;text-transform:uppercase}
.lpos-chart-bars{display:grid;gap:8px}
.lpos-chart-row{display:grid;grid-template-columns:minmax(96px,1fr) minmax(110px,2fr) minmax(54px,auto);gap:8px;align-items:center;font-size:12px}
.lpos-chart-label{color:var(--lpos-muted);overflow-wrap:anywhere}
.lpos-chart-track{height:10px;background:var(--lpos-bg);border:1px solid var(--lpos-line);border-radius:999px;overflow:hidden}
.lpos-chart-bar{display:block;height:100%;min-width:2px;background:var(--lpos-chart-1, var(--lpos-accent))}
.lpos-chart-value{font-weight:650;text-align:right;white-space:nowrap}
.lpos-chart-meta{color:var(--lpos-muted);font-size:12px;margin:10px 0 0}
.lpos-list{display:grid;gap:10px;margin:0;padding:0;list-style:none}
.lpos-list-item{border-top:1px solid var(--lpos-line);padding-top:10px}
.lpos-list-item:first-child{border-top:0;padding-top:0}
.lpos-list-title{font-weight:650;margin:0 0 4px}
.lpos-list-text{color:var(--lpos-muted);font-size:13px;line-height:1.45;margin:0}
.lpos-source-row{display:flex;justify-content:space-between;gap:10px;border-top:1px solid var(--lpos-line);padding-top:9px;margin-top:9px;font-size:13px}
.lpos-source-row:first-of-type{border-top:0;padding-top:0;margin-top:0}
.lpos-source-status{font-weight:650;color:var(--lpos-muted);white-space:nowrap}
.lpos-source-status.is-ok{color:var(--lpos-good)}
.lpos-source-status.is-partial,.lpos-source-status.is-warning,.lpos-source-status.is-pending,.lpos-source-status.is-received,.lpos-source-status.is-validating{color:var(--lpos-warn)}
.lpos-source-status.is-error,.lpos-source-status.is-failed,.lpos-source-status.is-rejected,.lpos-source-status.is-disabled,.lpos-source-status.is-archived{color:var(--lpos-bad)}
.lpos-empty{border:1px dashed var(--lpos-line);border-radius:var(--lpos-radius-panel);padding:18px;color:var(--lpos-muted);background:var(--lpos-panel)}
.lpos-stack{display:grid;gap:14px}
.lpos-density-dense{--lpos-gap:12px;--lpos-pad:16px;--lpos-panel-pad:12px}
.lpos-density-loose{--lpos-gap:20px;--lpos-pad:24px;--lpos-panel-pad:18px}
@media (max-width:1100px){.lpos-console-grid{grid-template-columns:200px minmax(0,1fr)}.lpos-console-side{grid-column:1 / -1}.lpos-kpi-grid{grid-template-columns:repeat(2,minmax(0,1fr))}.lpos-chart-grid{grid-template-columns:1fr}}
@media (max-width:760px){.lpos-console-shell{padding:14px}.lpos-console-header{grid-template-columns:1fr}.lpos-console-grid{grid-template-columns:1fr}.lpos-kpi-grid{grid-template-columns:1fr}.lpos-console-title{font-size:23px}.lpos-module-list{grid-template-columns:repeat(2,minmax(0,1fr))}.lpos-chart-row{grid-template-columns:minmax(0,1fr);gap:4px}.lpos-chart-value{text-align:left}}
.lpos-console-slot-bridge{--lpos-bg:#f6f7f9;--lpos-ink:#152033;--lpos-muted:#5f6b7a;--lpos-line:#d9dee7;--lpos-panel:#fff;--lpos-panel-hover:#eef7f6;--lpos-accent:#166466;--lpos-good:#236a35;--lpos-warn:#a06100;--lpos-bad:#9f1d1d;--lpos-font-ui:Inter,system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif;--lpos-gap:16px;--lpos-panel-pad:14px;--lpos-radius-panel:8px;--lpos-radius-control:8px;color:var(--lpos-ink);font-family:var(--lpos-font-ui)}
.lpos-console-slot-bridge *{box-sizing:border-box}
.lpos-slot{background:var(--lpos-panel);border:1px solid var(--lpos-line);border-radius:var(--lpos-radius-panel);padding:var(--lpos-panel-pad)}
.lpos-slot h2{font-size:16px;line-height:1.2;margin:0 0 10px}
.lpos-console-eyebrow{color:var(--lpos-muted);font-size:12px;text-transform:uppercase;letter-spacing:.08em;margin:0 0 6px}
.lpos-console-meta{display:flex;flex-wrap:wrap;gap:8px;margin-top:10px}
.lpos-console-badge{display:inline-flex;align-items:center;min-height:28px;border:1px solid var(--lpos-line);border-radius:var(--lpos-radius-control);background:var(--lpos-panel);padding:4px 9px;color:var(--lpos-muted);font-size:13px}
.lpos-console-badge strong{color:var(--lpos-ink);font-weight:650;margin-left:4px}
.lpos-module-list{display:grid;gap:6px;margin:0;padding:0;list-style:none}
.lpos-module-item{border:1px solid var(--lpos-line);border-radius:var(--lpos-radius-control);padding:9px 10px;background:var(--lpos-panel);color:var(--lpos-muted);font-size:13px}
.lpos-module-item.is-active{border-color:var(--lpos-accent);color:var(--lpos-ink);background:var(--lpos-panel-hover)}
.lpos-kpi-grid{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:12px}
.lpos-kpi{background:var(--lpos-panel);border:1px solid var(--lpos-line);border-radius:var(--lpos-radius-panel);padding:13px;min-height:112px}
.lpos-kpi-label{color:var(--lpos-muted);font-size:12px;margin:0 0 8px}
.lpos-kpi-value{font-size:26px;line-height:1.1;margin:0 0 8px;font-weight:700}
.lpos-kpi-delta{font-size:12px;color:var(--lpos-muted)}
.lpos-kpi-delta.is-up{color:var(--lpos-good)}
.lpos-kpi-delta.is-down{color:var(--lpos-bad)}
.lpos-chart-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:12px;margin-top:14px}
.lpos-chart{border:1px solid var(--lpos-line);border-radius:var(--lpos-radius-panel);padding:13px;background:var(--lpos-panel)}
.lpos-chart-heading{display:flex;justify-content:space-between;gap:10px;align-items:flex-start;margin-bottom:10px}
.lpos-chart-title{font-weight:700;margin:0;line-height:1.25}
.lpos-chart-type{color:var(--lpos-muted);font-size:12px;white-space:nowrap;text-transform:uppercase}
.lpos-chart-bars{display:grid;gap:8px}
.lpos-chart-row{display:grid;grid-template-columns:minmax(96px,1fr) minmax(110px,2fr) minmax(54px,auto);gap:8px;align-items:center;font-size:12px}
.lpos-chart-label{color:var(--lpos-muted);overflow-wrap:anywhere}
.lpos-chart-track{height:10px;background:var(--lpos-bg);border:1px solid var(--lpos-line);border-radius:999px;overflow:hidden}
.lpos-chart-bar{display:block;height:100%;min-width:2px;background:var(--lpos-chart-1, var(--lpos-accent))}
.lpos-chart-value{font-weight:650;text-align:right;white-space:nowrap}
.lpos-chart-meta{color:var(--lpos-muted);font-size:12px;margin:10px 0 0}
.lpos-list{display:grid;gap:10px;margin:0;padding:0;list-style:none}
.lpos-list-item{border-top:1px solid var(--lpos-line);padding-top:10px}
.lpos-list-item:first-child{border-top:0;padding-top:0}
.lpos-list-title{font-weight:650;margin:0 0 4px}
.lpos-list-text{color:var(--lpos-muted);font-size:13px;line-height:1.45;margin:0}
.lpos-source-row{display:flex;justify-content:space-between;gap:10px;border-top:1px solid var(--lpos-line);padding-top:9px;margin-top:9px;font-size:13px}
.lpos-source-row:first-of-type{border-top:0;padding-top:0;margin-top:0}
.lpos-source-status{font-weight:650;color:var(--lpos-muted);white-space:nowrap}
.lpos-source-status.is-ok{color:var(--lpos-good)}
.lpos-source-status.is-warning{color:var(--lpos-warn)}
.lpos-empty{border:1px dashed var(--lpos-line);border-radius:var(--lpos-radius-panel);padding:18px;color:var(--lpos-muted);background:var(--lpos-panel)}
/* density modifiers ride the two shells above ONLY -- scoped on the move (2026-08-10) so that
   loading this file site-wide can never retune the dark console's own spacing tokens. */
.lpos-console-shell.lpos-density-dense,.lpos-console-slot-bridge.lpos-density-dense{--lpos-gap:12px;--lpos-panel-pad:12px}
.lpos-console-shell.lpos-density-loose,.lpos-console-slot-bridge.lpos-density-loose{--lpos-gap:20px;--lpos-panel-pad:18px}
@media (max-width:760px){.lpos-kpi-grid{grid-template-columns:1fr}.lpos-module-list{grid-template-columns:repeat(2,minmax(0,1fr))}.lpos-chart-grid{grid-template-columns:1fr}.lpos-chart-row{grid-template-columns:minmax(0,1fr);gap:4px}.lpos-chart-value{text-align:left}}

/* =====================================================================================
   COMPONENT PANEL FILL -- one home for the glass recipe (2026-08-10, JD's duplicate pass).
   data-table's __body, form-panel's __control, kanban's __card and stat-tile's tile + group
   title each hand-copied `background: glass-panel` + both backdrop-filters into their own
   sheet: five byte-identical copies of the same three declarations, in four files. They are
   deliberately NOT scoped to .lpos-blueprint (a Component can render as a bare shortcode),
   which is why they could not use the blueprint-scoped panel law -- so the recipe lives here,
   unscoped, once. Border tint and radius stay in each component's own rule: those genuinely
   differ (kanban tints per column, stat-tile per tile, form uses the control radius).
   ===================================================================================== */
.lpos-c-table__body,
.lpos-c-field__control,
.lpos-kanban__card,
.lpos-c-stat-tile,
.lpos-c-stat-group__title{
  background: var(--lpos-glass-panel);
  -webkit-backdrop-filter: var(--lpos-blur-md);
  backdrop-filter: var(--lpos-blur-md);
}

/* =====================================================================================
   COMPONENT ICON BUTTON -- one recipe for all four (2026-08-10, JD: "make all four match").
   chat / form / kanban / calendar each shipped their OWN icon-button rule, because a Component
   can render as a bare shortcode outside any cell and so cannot rely on the blueprint-scoped
   panel law. Those four copies had drifted into four different buttons: chat and form painted a
   glass box with DIFFERENT border tints, kanban painted no box at all, calendar reset itself with
   `all:unset` and kept only a radius. This rule is the console's own button -- measured off the
   calendar arrows rendering inside a cell (46px square, panel radius, accent-40 hairline, glass
   fill + blur-md, muted icon at --lpos-icon-size) -- written once, unscoped, so a Component looks
   the same wherever it renders. The four local copies are deleted.
   ===================================================================================== */
.lpos-c-form .lpos-c-icon-btn,
.lpos-c-chat .lpos-c-icon-btn,
.lpos-kanban .lpos-c-icon-btn,
.lpos-c-calendar .lpos-c-icon-btn{
  all: unset;
  box-sizing: border-box;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  width: var(--lpos-control-size);
  height: var(--lpos-control-size);
  padding: 0;
  color: var(--lpos-muted);
  background: var(--lpos-glass-panel);
  -webkit-backdrop-filter: var(--lpos-blur-md);
  backdrop-filter: var(--lpos-blur-md);
  border: var(--lpos-border-width) solid color-mix(in srgb, var(--lpos-border-tint,var(--lpos-accent)) var(--lpos-border-alpha-2), transparent);
  border-radius: var(--lpos-radius-panel);
  transition: color var(--lpos-duration-fast), background var(--lpos-duration-fast), border-color var(--lpos-duration-fast);
}
.lpos-c-form .lpos-c-icon-btn svg,
.lpos-c-chat .lpos-c-icon-btn svg,
.lpos-kanban .lpos-c-icon-btn svg,
.lpos-c-calendar .lpos-c-icon-btn svg{
  width: var(--lpos-icon-size);
  height: var(--lpos-icon-size);
  flex: 0 0 auto;
  display: block;
  color: inherit;
  fill: none;
  stroke: currentColor;
}
.lpos-c-form .lpos-c-icon-btn:hover,
.lpos-c-chat .lpos-c-icon-btn:hover,
.lpos-kanban .lpos-c-icon-btn:hover,
.lpos-c-calendar .lpos-c-icon-btn:hover{
  color: var(--lpos-ink);
  border-color: var(--lpos-accent);
}
.lpos-c-form .lpos-c-icon-btn[disabled],
.lpos-c-chat .lpos-c-icon-btn[disabled],
.lpos-kanban .lpos-c-icon-btn[disabled],
.lpos-c-calendar .lpos-c-icon-btn[disabled]{ opacity: .45; cursor: default; }
/* the labelled variant keeps its auto width and text child (form's submit/reset row). */
.lpos-c-form .lpos-c-icon-btn.lpos-c-icon-btn--labeled{
  width: auto;
  min-width: 0;
  padding: 0 var(--lpos-panel-pad);
  gap: var(--lpos-space-sm);
}
.lpos-c-form .lpos-c-icon-btn__text{
  font: 700 var(--lpos-text-sm)/1 var(--lpos-font-ui);
  color: inherit;
  white-space: nowrap;
}

/* =====================================================================================
   LOAD SCREEN (JD 2026-08-10) -- the app-wide "something is loading" treatment.
   Replaces the old in-cell loading bar, which sat on top of the outgoing display's ambient
   artwork and so showed a giant blurred product bottle behind every load. Same recipe as the
   login VERIFYING-ACCESS modal, with JD's two changes: it spans the full viewport instead of a
   centred popup panel, and it leads with the TENANT LOGO instead of a glyph. Progress bar
   unchanged. Every value token-driven; nothing here is tenant-specific.
   ===================================================================================== */
.lpos-c-loadscreen{position:fixed;inset:0;z-index:var(--lpos-z-loadscreen);
  display:flex;flex-direction:column;align-items:center;justify-content:center;
  gap:calc(2*var(--lpos-gap));padding:var(--lpos-panel-pad);box-sizing:border-box;
  background:color-mix(in srgb,var(--lpos-bg) 38%,transparent);
  -webkit-backdrop-filter:var(--lpos-blur-md);backdrop-filter:var(--lpos-blur-md)}
.lpos-c-loadscreen[hidden]{display:none}
.lpos-c-loadscreen__logo{max-width:min(38vw,420px);max-height:22dvh;width:auto;height:auto;object-fit:contain}
/* the overlay lives on <body>, OUTSIDE .lpos-blueprint, so the blueprint-scoped panel law does not
   reach it -- caught in verify: the bar rendered as a bare sliver with no track. Both pieces carry
   the panel recipe explicitly here, same tokens the law would have given them. */
.lpos-c-loadscreen__label{margin:0;padding:var(--lpos-subpanel-pad) calc(3*var(--lpos-panel-pad));
  font:600 clamp(1.05rem,.9rem + .6vw,1.35rem)/1.2 var(--lpos-font-display);
  letter-spacing:calc(1.5*var(--lpos-tracking-label));text-transform:uppercase;color:var(--lpos-ink);
  background:var(--lpos-glass-panel);-webkit-backdrop-filter:var(--lpos-blur-md);backdrop-filter:var(--lpos-blur-md);
  border:var(--lpos-border-width) solid color-mix(in srgb,var(--lpos-border-tint,var(--lpos-accent)) var(--lpos-border-alpha-2),transparent);
  border-radius:var(--lpos-radius-panel)}
.lpos-c-loadscreen__bar{position:relative;box-sizing:border-box;
  width:min(70vw,520px);height:calc(3*var(--lpos-subpanel-pad));
  background:var(--lpos-glass-2);
  border:var(--lpos-border-width) solid color-mix(in srgb,var(--lpos-border-tint,var(--lpos-accent)) var(--lpos-border-alpha-2),transparent);
  border-radius:var(--lpos-radius-pill);overflow:hidden}
.lpos-c-loadscreen__fill{position:absolute;top:0;bottom:0;left:0;width:38%;border-radius:inherit;
  background:linear-gradient(90deg,var(--lpos-accent),var(--lpos-accent-3,var(--lpos-accent)),var(--lpos-accent));
  background-size:200% 100%;
  animation:lpos-c-loading-sweep var(--lpos-duration-loading) ease-in-out infinite,lposXpSheen 1.2s linear infinite}
@media (prefers-reduced-motion:reduce){.lpos-c-loadscreen__fill{animation:none;width:46%;left:27%}}

/* =====================================================================================
   STUDIO (JD 2026-08-10, handwritten spec part 1). NOT a second layout -- a modifier on the same
   console root, so every panel, token and law already in force keeps applying. Four regions are
   re-tasked; regions 1-3 (flyout menu, logo/tab bar/power, profile) are untouched by design.
     4 + 8  both rails render empty (PHP); they stay as structural lanes so nothing else shifts
     5      the primary canvas extends DOWN through the bottom row -- no search bar
     6      the right column is Chat (PHP)
     7      the commit row carries the chat input instead of Add to Cart / Buy Now (PHP)
   ===================================================================================== */
/* 1 + 2 + 3 (JD 2026-08-10): Studio's centre is ONE canvas panel filling the whole column -- no
   Coming Soon carousel, no transport row, no pagination. The panel takes the full height rather
   than leaving the gap those two rows used to occupy. */
.lpos-blueprint--console.-studio .lpos-cell--midcenter .lpos-col--center{height:100%;min-height:0}
.lpos-blueprint--console.-studio .lpos-cell--midcenter .lpos-col__slot.-active{flex:1 1 auto;min-height:0;display:flex}
.lpos-blueprint--console.-studio .lpos-feat__body--studio{flex:1 1 auto;width:100%;min-height:0;
  background:var(--lpos-glass-panel);-webkit-backdrop-filter:var(--lpos-blur-md);backdrop-filter:var(--lpos-blur-md);
  border:var(--lpos-border-width) solid color-mix(in srgb,var(--lpos-border-tint,var(--lpos-accent)) var(--lpos-border-alpha-2),transparent);
  border-radius:var(--lpos-radius-panel);box-sizing:border-box}

/* 5 (rev 2, JD 2026-08-10): the composer runs the FULL WIDTH of the bottom row, under BOTH the
   canvas and the chat column -- the earlier version parked it beside the right column and left a
   gap under the canvas. So the centre no longer spans the bottom row: the bottom row is the
   composer, and its centre cell spans every column. */
/* Two things had to be measured to get this right, both caught by reading computed styles:
   (1) the grid ITEM is the region wrapper, not the cell inside it -- the rows are display:contents,
       so the regions are items of the BLUEPRINT ROOT's grid, and a span on the cell did nothing;
   (2) that root grid is FOUR tracks -- [left rail | centre | right column | right rail] -- and an
       existing rule already places this region in track 2, so the span needs to outrank it.
   JD's ask is "under both the primary and secondary content panels", i.e. tracks 2 THROUGH 3 --
   not 1/-1, which would run the composer under the rails as well. */
/* (3) it also has to OUTRANK the one-state rule at line ~1677, which pins this region to track 2
   with !important and a 4-class selector. Same selector shape, later in the file. */
.lpos-blueprint--console.-studio>.lpos-blueprint__row>.lpos-blueprint__region--botcenter{grid-column:2 / 4!important}
.lpos-blueprint--console.-studio .lpos-blueprint__region--botleft,
.lpos-blueprint--console.-studio .lpos-blueprint__region--botright{display:none}
/* 4 + 8: the rails keep their WIDTH so the three columns hold their proportions -- only their
   buttons go. Server-side the rails render empty; on a centre SWAP the rails are page shell and
   outside every swapped region, so this hides their contents instead (same end state, no reload,
   which the no-page-loads law requires). */
.lpos-blueprint--console.-studio .lpos-rail{justify-content:flex-start}
.lpos-blueprint--console.-studio .lpos-rail>*{display:none!important}
/* 7: the composer is the bottom bar's own recipe with a text field in place of the search. */
/* JD 2026-08-10: the input read as flush -- it had no panel of its own, unlike every other field
   in the app. Same panel recipe the search bar carries, so the composer row is [attach][field][mic]
   [send] with the field as a real inset panel between them. */
.lpos-blueprint--console.-studio .lpos-search--studio{flex:1 1 auto;min-width:0;display:flex;align-items:center;
  gap:var(--lpos-space-sm);height:var(--lpos-control-size);box-sizing:border-box;
  padding:0 var(--lpos-panel-pad);
  background:var(--lpos-glass-panel);-webkit-backdrop-filter:var(--lpos-blur-md);backdrop-filter:var(--lpos-blur-md);
  border:var(--lpos-border-width) solid color-mix(in srgb,var(--lpos-border-tint,var(--lpos-accent)) var(--lpos-border-alpha-2),transparent);
  border-radius:var(--lpos-radius-panel)}
/* the chat body is an inset panel inside the column, matching every other secondary content pane. */
.lpos-blueprint--console.-studio .lpos-cell--midright .lpos-view__body{flex:1 1 auto;min-height:0;width:100%;
  display:flex;box-sizing:border-box}
.lpos-blueprint--console.-studio .lpos-search--studio input{all:unset;flex:1 1 auto;min-width:0;
  font:500 var(--lpos-text-sm)/1.2 var(--lpos-font-ui);color:var(--lpos-ink)}
.lpos-blueprint--console.-studio .lpos-search--studio input::placeholder{color:var(--lpos-muted)}
.lpos-blueprint--console.-studio .lpos-search__icon{flex:0 0 auto;display:flex;color:var(--lpos-muted)}
.lpos-blueprint--console.-studio .lpos-search__icon svg{width:var(--lpos-icon-size-sm);height:var(--lpos-icon-size-sm);fill:none;stroke:currentColor}

/* ===== TOP BAR SPLIT INTO TWO PANELS (JD 2026-08-10 rev 4) =====================================
   JD: "seperate the top bar so that the top right has it's own panel and then the pagination will
   be right aligned in the tab/portal bar which is a panel".
   The topcenter CELL is a layout container, not a panel - it has no chrome of its own, which is why
   two panels can sit inside it without breaking the one-panel law (no panel inside a panel).
   Chrome recipe is the shared one: glass-panel + blur-md + border-alpha-2 + radius-panel. Nothing
   new is introduced here, so a token change still moves both panels with everything else. */
.lpos-blueprint .lpos-topbar__panel{
  /* JD 2026-08-10 (screenshot, app-wide): the top bar is TWO VISIBLE PANELS. The logo/tab panel holds
     the pagination at its own right end, then a gap, then the icon buttons in their own panel at the
     far right.
     My first attempt right-aligned the pager, which pushed it into the empty space next to the icons
     and made it look like it belonged to neither panel. The pager belongs INSIDE the tab panel, so the
     tab panel is content-width and the pager simply sits last in it.
     Chrome is the shared panel recipe, so a token change moves these with every other panel. */
  display: flex;
  align-items: center;
  flex-direction: row;
  gap: var(--lpos-gap,12px);
  height: 100%;
  padding: 0 var(--lpos-space-sm,8px);
  background: var(--lpos-glass-panel);
  -webkit-backdrop-filter: var(--lpos-blur-md);
  backdrop-filter: var(--lpos-blur-md);
  border: var(--lpos-border-width) solid color-mix(in srgb, var(--lpos-border-tint,var(--lpos-accent)) var(--lpos-border-alpha-2, 40%), transparent);
  border-radius: var(--lpos-radius-panel);
  box-sizing: border-box;
}
/* The tab/portal panel takes the slack so its right edge is the far edge of the bar -- that is what
   pushes the pager fully right. min-width:0 lets it shrink instead of forcing the utility panel off. */
/* Content-width, NOT stretched: the panel ends where its controls end, which is what creates the
   visible gap before the icon panel in JD's screenshot. min-width:0 lets it shrink on narrow screens
   rather than shoving the icons off. */
.lpos-blueprint .lpos-topbar__panel--tabs{flex:0 1 auto;min-width:0}
/* The utility cluster is content-width: it never stretches and never shrinks its icons. */
/* margin-left:auto is what parks this at the FAR right, leaving the gap between the two panels. */
.lpos-blueprint .lpos-topbar__panel--utils{flex:0 0 auto;margin-left:auto}
/* The pager is right-aligned INSIDE the tab panel. This restates the existing cell-level rule at a
   specificity that survives the new wrapper, rather than relying on the descendant rule alone. */
/* No margin-left:auto here any more - that is what flung the pager into the gap. It is simply the
   last control in the tab panel. */
.lpos-blueprint .lpos-topbar__panel--tabs .lpos-pagination--nav{margin-left:0;flex:0 0 auto}
/* `.lpos-topbar__trail` is retired -- the utility panel replaces it. The old rule set margin-left:auto
   on the trail to shove the icons right; that job now belongs to the flexing tab panel. Kept as a
   no-op guard so any cached markup still renders sanely instead of collapsing. */
.lpos-blueprint .lpos-cell--topcenter .lpos-topbar__trail{margin-left:0}

/* EMPTY MEDIA SLOT MUST HOLD ITS SIZE (JD 2026-08-10, app-wide law: "the panels always keep their
   sizes even if they are empty").
   The base `.lpos-media-image-wrap` is `height:100%;min-height:0`, so it only holds a size when its
   PARENT is already sized. In the archive right column nothing above it pins a height, so the empty
   variant would collapse to its own text and reproduce the exact "thin skeleton bar" this work is
   meant to remove. Pinning the same 16/9 ratio the real media stage uses (`--lpm-aspect`, the token
   `.lpos-feat__body>.lpos-media` already reads) makes the empty slot occupy the identical footprint
   the filled one would, so the archive layout matches the single layout whether or not media is
   bound. Token-driven, so a ratio change still moves both together. */
.lpos-blueprint .lpos-media-image-wrap--empty{
  aspect-ratio: var(--lpm-aspect, 16/9);
  height: auto;
  min-height: 0;
  width: 100%;
}
