/* Louvre interactive viewer — CSS for js/louvre-viewer.js.
   Ported from the approved sandbox prototype
   (sandbox/louvre-product-page/stage4-static-background.html), integrated
   into pages/v2/louvres.njk in place of the old .lsys deity-card grid.

   No scoped custom properties or @font-face here — every token this file
   needs (--bronze, --ink, --soft, --mono) and the Hanken @font-face are
   already declared by css/style-v2.css's own :root (verbatim same values —
   this viewer was designed against V2's own palette from the start), loaded
   on every V2 page before this file. Duplicating either here would just be
   dead weight. */
  /* ---- New interactive viewer (replaces the .lsys card grid) ---- */
  /* Tabs spread across the full width — each takes an equal share rather
     than packing left, so the row reads as "six systems, evenly weighted"
     instead of a left-aligned menu. */
  /* Existing customer-facing series header row (150mm/100mm/50mm/
     Screening — NOT the separate corporate product taxonomy), mirroring
     the tab row's flex proportions so each label sits directly above its
     cluster: Zeus/Zeus Hydra-Shield/Odin share the 150mm span (3 tabs),
     Thor/Magni/Loki each get a single-tab span of their own series. Text
     content comes from SERIES_LABELS in JS, not hardcoded here — see the
     module script. Desktop/tablet only — on narrow viewports the tab row
     below becomes independently horizontally-scrollable, which this
     static row can no longer stay aligned with, so it's hidden there (see
     the mobile media query below) in favour of a per-group caption that
     scrolls with its own tab instead. */
  #lc-tab-groups{display:flex;gap:8px;margin-top:80px;margin-bottom:24px}
  .lc-group-label{font-family:var(--mono);text-transform:uppercase;letter-spacing:.1em;font-size:10px;
    color:rgba(232,236,241,.4);text-align:center;padding-bottom:5px;border-bottom:1px solid rgba(232,236,241,.14);
    transition:color .18s,border-color .18s}
  /* Marks which series the active tab belongs to — same bronze the tab
     itself uses, so the two highlights read as one connected state. */
  .lc-group-label.active{color:#f5c877;border-bottom-color:#f5c877}
  /* Tabs now float on top of the 3D viewport (moved into #liteconfig) rather
     than sitting in page flow above it — same overlay technique as the
     bottom readout bar: a top-anchored scrim in the page's own teal-navy
     tone for legibility, fading to transparent so the model still shows
     through underneath. */
  #lc-tabs{position:absolute;top:0;left:0;right:0;z-index:5;display:flex;gap:8px;
    padding:18px 24px 34px;background:linear-gradient(180deg,rgba(14,26,32,.85),rgba(14,26,32,.35) 65%,transparent)}
  /* Tightened from the original 150px — with the viewer's own bottom
     padding already pushed up (see #lc-readout), 150px here left too much
     dead space before Technical Snapshot. */
  /* A hairline before the first tab of each new series — quiet enough not to
     reintroduce the boxed look, just enough to mark where one group ends
     and the next begins. */
  .lc-tab--group-start{border-left:1px solid rgba(232,236,241,.14);padding-left:12px}
  /* Unboxed — no border, no filled block. The picked tab is marked by a
     bronze glow anchored to the bottom edge that fades out toward the top,
     rather than a solid highlight wrapping the whole tab. */
  .lc-tab{all:unset;position:relative;flex:1;display:flex;align-items:center;justify-content:center;gap:10px;
    font-family:var(--mono);text-transform:uppercase;letter-spacing:.08em;font-size:15px;font-weight:700;
    color:var(--soft);
    padding:10px 12px;cursor:pointer;transition:color .18s;white-space:nowrap}
  .lc-tab svg{flex-shrink:0;width:34px;height:34px;color:var(--soft);transition:color .18s}
  .lc-tab:hover{color:var(--ink)}
  .lc-tab:hover svg{color:var(--ink)}
  .lc-tab.active{color:#f5c877;font-weight:700}
  .lc-tab.active::before{
    content:'';position:absolute;inset:0;z-index:-1;
    background:linear-gradient(0deg,rgba(245,166,35,.55),rgba(245,166,35,.16) 55%,transparent);
  }
  /* The picked tab's blade glows — draws the eye straight to "this is the
     one you're looking at" without needing a caption. */
  .lc-tab.active svg{color:#fff;animation:pickedGlow 2.2s ease-in-out infinite}
  @keyframes pickedGlow{
    0%,100%{filter:drop-shadow(0 0 2px #fff) drop-shadow(0 0 4px rgba(255,255,255,.8))}
    50%{filter:drop-shadow(0 0 4px #fff) drop-shadow(0 0 10px rgba(255,255,255,.9))}
  }
  /* Per-group caption — mobile-only replacement for #lc-tab-groups (which
     can't track an independently-scrolling row). Lives on the FIRST tab of
     each series group only (the same one that already gets the divider),
     so it travels with its own tab rather than sitting in a separate row
     that would desync the moment the user scrolls. Text is set from the
     same SERIES_LABELS map in JS — no separate copy of the names. */
  .lc-tab-series-caption{display:none}
  /* Edge-fade scroll cue — two thin gradients over the tab row's own ends,
     visibility driven by JS (updateTabsScrollFade()) rather than left
     always-on, so it never falsely claims there's more to scroll past
     the actual start/end. Hidden entirely above the mobile breakpoint,
     where the tab row doesn't scroll. */
  #lc-tabs-fade-l,#lc-tabs-fade-r{position:absolute;top:0;height:92px;width:26px;z-index:6;
    pointer-events:none;opacity:0;transition:opacity .2s ease;display:none}
  #lc-tabs-fade-l{left:0;background:linear-gradient(to right,rgba(14,26,32,.92),transparent)}
  #lc-tabs-fade-r{right:0;background:linear-gradient(to left,rgba(14,26,32,.92),transparent)}
  @media (max-width:760px){
    /* The static heading row can't track the now-independently-scrolling
       tab row beneath it — see the per-tab caption below instead. */
    #lc-tab-groups{display:none}
    /* flex:0 0 auto (not the desktop flex:1) — tabs keep their natural
       readable size and the row scrolls, rather than all six shrinking to
       fit one screen width. min-width is a floor, not a squeeze target. */
    #lc-tabs{overflow-x:auto;-webkit-overflow-scrolling:touch;
      scroll-snap-type:x proximity;scrollbar-width:none;padding-top:34px}
    #lc-tabs::-webkit-scrollbar{display:none}
    .lc-tab{flex:0 0 auto;min-width:100px;padding-top:26px;scroll-snap-align:center}
    .lc-tab--group-start{padding-left:18px}
    .lc-tab-series-caption{
      display:block;position:absolute;top:6px;left:0;right:0;max-width:100%;
      overflow:hidden;text-overflow:ellipsis;white-space:nowrap;text-align:center;
      font:600 8px/1.2 -apple-system,BlinkMacSystemFont,sans-serif;letter-spacing:.08em;
      text-transform:uppercase;color:rgba(232,236,241,.4);
    }
    .lc-tab--group-start .lc-tab-series-caption{left:18px} /* clear the divider */
    #lc-tabs-fade-l,#lc-tabs-fade-r{display:block}
    #liteconfig.lc-tabs-at-start #lc-tabs-fade-l{opacity:0}
    #liteconfig:not(.lc-tabs-at-start) #lc-tabs-fade-l{opacity:1}
    #liteconfig.lc-tabs-at-end #lc-tabs-fade-r{opacity:0}
    #liteconfig:not(.lc-tabs-at-end) #lc-tabs-fade-r{opacity:1}
  }
  /* Viewer FOOTPRINT (how much page space the section occupies) is now
     budgeted from available viewport HEIGHT, not just width — a fixed
     "121vh" made a wide-but-short laptop screen's viewer eat the entire
     window just because 121% of its own height looked fine on a tall
     monitor. The 260px subtracted is the fixed nav bar (~90px) plus the
     tab row / breathing room this section needs above and below it, so
     surrounding page content stays visibly in view. `svh` (not `vh`)
     because it accounts for mobile browser chrome reliably. MODEL FRAMING
     (how large the louvre looks inside this box) is a separate concern —
     see computeFramingDistance() below, which reacts to the canvas's own
     aspect ratio rather than assuming this fixed footprint. */
  #liteconfig{position:relative;height:clamp(420px, calc(100svh - 260px), 900px)}
  /* Wide-but-short laptop displays (e.g. 13-16" screens in the ~700-820px
     tall range) — width alone never catches this; only height does. */
  @media (max-height:820px) and (min-width:900px){
    #liteconfig{height:clamp(400px, calc(100svh - 220px), 640px)}
  }
  @media (max-width:760px){
    #liteconfig{height:clamp(380px, calc(100svh - 210px), 620px)}
  }
  @media (max-width:480px){
    #liteconfig{height:clamp(340px, 68svh, 560px)}
  }
  /* ---- Expand 3D — a dedicated on-demand overlay, not a permanently
     larger inline section. Same element, same canvas, same event wiring —
     only its CSS box changes, so drag/wheel/activation/Esc all keep
     working unmodified once expanded (see JS below). A restrained ~18px
     fillet (smaller on mobile) on the ONE outer boundary — overflow:hidden
     on that same boundary clips the background image, canvas, gradient
     overlays and edge effects to it consistently, rather than rounding
     each of those individually. The outer inset keeps a visible margin
     around the shape even at small viewports, and folds in the safe-area
     insets so the fillet stays clear of notches/home-indicators. */
  #liteconfig.lc-expanded{
    position:fixed;height:auto;z-index:1000;
    inset:calc(clamp(12px,3vh,40px) + env(safe-area-inset-top))
          calc(clamp(12px,3vh,40px) + env(safe-area-inset-right))
          calc(clamp(12px,3vh,40px) + env(safe-area-inset-bottom))
          calc(clamp(12px,3vh,40px) + env(safe-area-inset-left));
    border-radius:18px;overflow:hidden;box-shadow:0 40px 100px rgba(0,0,0,.6);
  }
  @media (max-width:600px){
    #liteconfig.lc-expanded{border-radius:14px}
  }
  #lc-expand-backdrop{
    position:fixed;inset:0;z-index:999;background:rgba(6,8,10,.74);
    backdrop-filter:blur(5px);opacity:0;visibility:hidden;transition:opacity .2s ease;
  }
  body.lc-expand-open{overflow:hidden}
  body.lc-expand-open #lc-expand-backdrop{opacity:1;visibility:visible}
  /* STAGE 4 — plain static-image background, no canvas/WebGL involved.
     bg-static-wrap sits at z-index:0; lc-canvas gets an explicit z-index:1
     so it stacks above (position:static children would otherwise paint
     OVER position:absolute z-index:0 siblings per normal CSS stacking —
     same fix used in every earlier background-layer stage). */
  #bg-static-wrap{position:absolute;inset:0;z-index:0;overflow:hidden;pointer-events:none}
  .bg-static-img{
    position:absolute;
    /* object-fit:contain, NOT cover — preserves the artwork's full aspect
       ratio and its focal fracture region rather than cropping to fill,
       per "avoid excessive cropping / avoid stretching."
       Scale/X/Y/opacity/fade are all LOCKED baseline values now — the dev
       panel and its sliders (opacity, left/right fade, top/bottom fade)
       have been removed; these are hardcoded directly instead of routed
       through custom properties. */
    left:50%;top:50%;
    width:200%;
    height:200%;
    transform:translate(-50%,-50%);
    object-fit:contain;
    opacity:0.7;
    transition:opacity .6s ease; /* the crossfade itself */
  }
  #bg-static-b{opacity:0}
  /* Two INDEPENDENT fade axes, replacing the single radial fade — a radial
     shape couldn't be tuned to "conceal top/bottom only, leave left/right
     alone," since one radius controls both axes together. Both are plain
     overlay gradients in the page's own #0e1a20 tone (not a mask).
     Locked baseline: left/right fade 20%, top/bottom fade 50% (the dev
     panel and its sliders have been removed). */
  #bg-fade-lr{
    position:absolute;inset:0;z-index:1;
    background:linear-gradient(to right,
      #0e1a20 0%, transparent 20%,
      transparent 80%, #0e1a20 100%);
  }
  #bg-fade-tb{
    position:absolute;inset:0;z-index:1;
    background:linear-gradient(to bottom,
      #0e1a20 0%, transparent 50%,
      transparent 50%, #0e1a20 100%);
  }
  /* INLINE = select and preview, EXPANDED = fully explore. Two distinct
     modes, one entry point (the centre prompt) and one exit (Exit 3D /
     Esc / backdrop click) — not three overlapping activation/expand/
     fullscreen concepts. Cursor only implies "draggable" once expanded,
     since inline drag genuinely does nothing to the model. */
  #lc-canvas{display:block;width:100%;height:100%;cursor:default;position:absolute;inset:0;z-index:2}
  #liteconfig.lc-expanded #lc-canvas{cursor:grab}
  #liteconfig.lc-expanded #lc-canvas:active{cursor:grabbing}
  /* Subtle outline while expanded — matches the embedded-map convention of
     showing whether a scroll gesture stays with the page or engages the
     thing sitting inside it. */
  #liteconfig{outline:2px solid transparent;outline-offset:-2px;transition:outline-color .25s ease}
  #liteconfig.lc-active{outline-color:rgba(245,166,35,.55)}
  /* The ONLY entry point into 3D exploration — a real button, not a
     decorative overlay, since nothing else on the inline canvas responds
     to a click any more. */
  #lc-activate-hint{
    all:unset;position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);z-index:6;
    cursor:pointer;
    font:600 13px/1 -apple-system,BlinkMacSystemFont,sans-serif;letter-spacing:.02em;
    color:rgba(232,236,241,.92);background:rgba(18,22,28,.62);backdrop-filter:blur(6px);
    border:1px solid rgba(232,236,241,.2);border-radius:24px;padding:12px 22px;
    transition:opacity .2s ease,background .15s ease,border-color .15s ease;
  }
  #lc-activate-hint:hover{background:rgba(18,22,28,.85);border-color:var(--bronze);color:#fff}
  #liteconfig.lc-expanded #lc-activate-hint{opacity:0;visibility:hidden;pointer-events:none}
  /* Reset View and Exit 3D are both real user controls, grouped in one
     small toolbar — hidden entirely inline (this is a lightweight preview
     state, not an interactive workspace) and shown only once expanded.
     Top pushed down to clear the tab row, which overlays this same top
     edge of the box. */
  #lc-toolbar{position:absolute;top:96px;right:16px;z-index:5;display:none;gap:8px}
  #liteconfig.lc-expanded #lc-toolbar{display:flex}
  #lc-reset-view,#lc-exit-3d{
    all:unset;display:flex;align-items:center;gap:7px;cursor:pointer;
    font:600 11.5px/1 -apple-system,BlinkMacSystemFont,sans-serif;letter-spacing:.02em;
    color:rgba(232,236,241,.85);background:rgba(18,22,28,.6);backdrop-filter:blur(6px);
    border:1px solid rgba(232,236,241,.16);border-radius:20px;padding:8px 14px 8px 12px;
    transition:background .15s,border-color .15s,color .15s;
  }
  #lc-reset-view svg,#lc-exit-3d svg{width:14px;height:14px;flex-shrink:0}
  #lc-reset-view:hover,#lc-exit-3d:hover{background:rgba(18,22,28,.85);border-color:var(--bronze);color:#fff}
  /* ---- Proposal A: one unified bottom bar, replacing the 4 scattered
     floating boxes (top-right spec card, bottom-left zoom%, bottom-left hint,
     bottom-right Configure button). Same technique as the homepage viewer's
     .louvre3d__readout — a bottom gradient strip, not a separate panel. ---- */
  #lc-readout{
    position:absolute;left:0;right:0;bottom:0;z-index:5;
    /* Bottom padding raised well past the top/side 22px/24px — #liteconfig
       is deliberately taller than the model needs (headroom for 150% zoom,
       see that rule's comment), which left the info/CTA row sitting flush
       against the box's true bottom edge with a big dead gap above it.
       Lifting via padding (not by moving the box off bottom:0) keeps the
       gradient still reaching all the way down to the true edge, so there's
       no uncovered strip of bare background below the row. */
    padding:22px 24px 130px;
    display:flex;align-items:flex-end;justify-content:space-between;gap:24px;
    /* Matches the page's own #0e1a20 teal-navy (rgb 14,26,32) instead of the
       neutral near-black this gradient inherited from the homepage's
       .louvre3d__readout — that component sits on a photo, so any dark tone
       blended in; here it was standing out against this page's actual bg. */
    background:linear-gradient(0deg,rgba(14,26,32,.88),rgba(14,26,32,.4) 60%,transparent);
  }
  #lc-readout-info{display:flex;flex-direction:column;gap:4px;min-width:0}
  /* Only shown once expanded — inline, #lc-activate-hint is the one clue
     the model leads to a 3D experience, so this doesn't need to compete
     with it. */
  #lc-hint{font-size:11px;color:rgba(232,236,241,.4);pointer-events:none;
    display:none;
    animation:hintGlow 2.6s ease-in-out infinite}
  #liteconfig.lc-expanded #lc-hint{display:block}
  @keyframes hintGlow{
    0%,100%{color:rgba(232,236,241,.4);text-shadow:none}
    50%{color:rgba(255,255,255,.95);text-shadow:0 0 10px rgba(245,166,35,.65)}
  }
  @media (prefers-reduced-motion: reduce){
    #lc-hint{animation:none}
  }
  #lc-configure{flex-shrink:0;display:flex;align-items:center;gap:8px;background:#f5a623;color:#141413;border:none;border-radius:8px;padding:13px 20px;font:600 14px/1 -apple-system,BlinkMacSystemFont,sans-serif;cursor:pointer;box-shadow:0 8px 24px rgba(245,166,35,.28);text-decoration:none}
  #lc-configure:hover{background:#ffb43d}
  #lc-configure svg{width:14px;height:14px}

  /* ---- Technical annotation — a spec-sheet marginal note that belongs to
     the scene, not a product card dropped on top of it. No box, no border
     on three sides, no rounded card: one thin rule on the edge facing the
     model (doubling as the leader line's origin), a soft directional wash
     fading away from that rule, and restrained architectural typography.
     Position (left/right/compact) is decided by positionAnnotation() in JS
     from the model's actual projected width and the real clearance either
     side has against the tabs/toolbar/readout — recomputed only at
     controlled moments (profile switch, expand/collapse, resize), never
     chasing the model's continuous idle rotation. */
  #lc-annotation{
    position:absolute;z-index:4;top:50%;transform:translateY(-50%);
    width:186px;pointer-events:none;
  }
  #lc-annotation.lc-annot-left{
    left:24px;
    border-right:1px solid rgba(232,236,241,.16);padding:18px 22px 18px 0;
    background:linear-gradient(to left,rgba(14,26,32,.5),transparent 85%);
    text-align:right;
  }
  #lc-annotation.lc-annot-right{
    right:24px;
    border-left:1px solid rgba(232,236,241,.16);padding:18px 0 18px 22px;
    background:linear-gradient(to right,rgba(14,26,32,.5),transparent 85%);
    text-align:left;
  }
  /* The leader-line endpoint — a small bronze marker sitting on the rule,
     with a short line reaching a little further toward the model. Bronze
     is reserved for this and for the headline numbers, per the "important
     numbers + leader endpoint only" accent rule. */
  #lc-annotation.lc-annot-left::before,#lc-annotation.lc-annot-right::before{
    content:"";position:absolute;top:50%;width:6px;height:6px;border-radius:50%;
    background:#f5a623;box-shadow:0 0 8px rgba(245,166,35,.7);transform:translateY(-50%);
  }
  #lc-annotation.lc-annot-left::before{right:-3px}
  #lc-annotation.lc-annot-right::before{left:-3px}
  #lc-annotation.lc-annot-left::after,#lc-annotation.lc-annot-right::after{
    content:"";position:absolute;top:50%;height:1px;width:22px;transform:translateY(-50%);
  }
  #lc-annotation.lc-annot-left::after{right:-25px;background:linear-gradient(to right,rgba(245,166,35,.6),transparent)}
  #lc-annotation.lc-annot-right::after{left:-25px;background:linear-gradient(to left,rgba(245,166,35,.6),transparent)}
  /* Quieter than #lc-annot-name (.32 vs .5 opacity, no bronze) — series
     context is supporting information, the system name is the headline. */
  #lc-annot-series{font:600 9px/1.3 -apple-system,BlinkMacSystemFont,sans-serif;letter-spacing:.14em;text-transform:uppercase;color:rgba(232,236,241,.32);margin-bottom:5px}
  #lc-annot-name{font:600 10px/1 -apple-system,BlinkMacSystemFont,sans-serif;letter-spacing:.16em;text-transform:uppercase;color:rgba(232,236,241,.5)}
  #lc-annot-rule{height:1px;width:26px;margin:10px 0;background:rgba(232,236,241,.22)}
  .lc-annot-left #lc-annot-rule{margin-left:auto}
  #lc-annot-metrics{display:flex;gap:20px;justify-content:flex-end}
  .lc-annot-right #lc-annot-metrics{justify-content:flex-start}
  .lc-annot-metric{display:flex;flex-direction:column;gap:3px}
  .lc-annot-value{font:600 28px/1 -apple-system,BlinkMacSystemFont,sans-serif;color:#f5a623;letter-spacing:-.01em}
  .lc-annot-unit{font-size:14px;font-weight:500;color:rgba(232,236,241,.55);margin-left:1px}
  .lc-annot-metric-label{font:600 9px/1.2 -apple-system,BlinkMacSystemFont,sans-serif;letter-spacing:.1em;text-transform:uppercase;color:rgba(232,236,241,.45)}
  #lc-annot-class{margin-top:14px;font:600 10.5px/1 -apple-system,BlinkMacSystemFont,sans-serif;letter-spacing:.12em;text-transform:uppercase;color:#f5c877}
  #lc-annot-app{margin-top:6px;font:13px/1.42 -apple-system,BlinkMacSystemFont,sans-serif;color:#c9cdd3;max-width:180px}
  .lc-annot-left #lc-annot-app{margin-left:auto}
  /* Project links carried over from the deity-cards this viewer replaces
     (see PROJECT_LINKS in js/louvre-viewer.js) — quieter than #lc-annot-app,
     a footnote rather than another line of narrative. Hidden via inline
     style (not a class) when a product has none, set in updateAnnotation(). */
  #lc-annot-projects{margin-top:8px;font:12px/1.4 -apple-system,BlinkMacSystemFont,sans-serif;color:rgba(232,236,241,.45);max-width:180px}
  #lc-annot-projects a{color:#f5c877;text-decoration:none;border-bottom:1px solid rgba(245,166,35,.35)}
  #lc-annot-projects a:hover{border-bottom-color:#f5c877}
  .lc-annot-left #lc-annot-projects{margin-left:auto}
  #lc-annotation.lc-annot-compact #lc-annot-projects{display:none} /* same "no room in a slim strip" rule as #lc-annot-app */
  /* Collapse control — expanded mode only, so a user actively inspecting
     the model can dismiss the annotation without it ever obstructing
     rotation. Re-enables pointer-events on itself only (the panel body
     stays click-through). Open panel = panel with x; closed panel = pulsing
     marker only — so the x is excluded from the "keep visible while
     collapsed" list below, not included in it. */
  #lc-annot-collapse{
    all:unset;position:absolute;top:-2px;pointer-events:auto;cursor:pointer;
    display:none;width:20px;height:20px;align-items:center;justify-content:center;
    color:rgba(232,236,241,.45);transition:color .15s ease;
  }
  #lc-annot-collapse svg{width:12px;height:12px}
  #lc-annot-collapse:hover{color:#fff}
  .lc-annot-left #lc-annot-collapse{right:0}
  .lc-annot-right #lc-annot-collapse{left:0}
  #liteconfig.lc-expanded #lc-annot-collapse{display:flex}
  /* Higher specificity than the rule above (adds #lc-annotation + the
     .lc-annot-collapsed class) so it wins regardless of source order —
     the x must never coexist with the collapsed state. */
  #liteconfig.lc-expanded #lc-annotation.lc-annot-collapsed #lc-annot-collapse{display:none}
  #lc-annotation.lc-annot-collapsed>*:not(#lc-annot-collapse):not(#lc-annot-reopen){display:none}
  #lc-annotation.lc-annot-collapsed{width:auto;background:none;border-color:rgba(232,236,241,.1)}
  /* The dot (::before) stays at full brightness while collapsed — it's now
     the sole reopening control, not a dimmed leftover. Only the fading
     leader line (::after) stays subdued. */
  #lc-annotation.lc-annot-collapsed::after{opacity:.5}

  /* Reopen control — a real focusable <button> sized to a comfortable
     40x40 hit area, centred exactly over the same point as the ::before
     dot (right:-3px/left:-3px, 6px wide -> centre sits at the panel edge),
     without visually enlarging the dot itself. Expanded + collapsed only —
     mirrors the x's own expanded-only scope, and :not(.lc-annot-compact)
     guards the one edge case where positionAnnotation() could leave a
     compact-positioned panel collapsed (it early-returns while collapsed,
     so compact+collapsed can only persist, never newly form, but the
     guard keeps the 40px box from rendering with no left/right anchor). */
  #lc-annot-reopen{
    all:unset;position:absolute;top:50%;transform:translateY(-50%);
    width:40px;height:40px;display:none;align-items:center;justify-content:center;
    cursor:pointer;pointer-events:auto;
  }
  .lc-annot-left #lc-annot-reopen{right:-20px}
  .lc-annot-right #lc-annot-reopen{left:-20px}
  #liteconfig.lc-expanded #lc-annotation.lc-annot-collapsed:not(.lc-annot-compact) #lc-annot-reopen{display:flex}
  .lc-annot-reopen-dot{
    position:absolute;width:6px;height:6px;border-radius:50%;
    background:#f5a623;box-shadow:0 0 8px rgba(245,166,35,.7);
    transition:box-shadow .15s ease,background .15s ease;
  }
  #lc-annot-reopen:hover .lc-annot-reopen-dot,
  #lc-annot-reopen:focus-visible .lc-annot-reopen-dot{
    background:#ffc25c;box-shadow:0 0 12px rgba(245,166,35,.95);
  }
  #lc-annot-reopen:focus-visible{outline:none}
  #lc-annot-reopen:focus-visible .lc-annot-reopen-dot{
    box-shadow:0 0 0 4px rgba(245,166,35,.32),0 0 12px rgba(245,166,35,.95);
  }
  /* Ripple — one or two thin rings expanding outward from the stationary
     dot and fading, ~2.3s per cycle (within the requested 2-2.5s window).
     Only runs while #lc-annot-reopen is actually rendered (display:flex),
     i.e. only while collapsed — becoming display:none on reopen stops and
     discards the animation immediately, no separate JS teardown needed. */
  .lc-annot-reopen-ring{
    position:absolute;top:50%;left:50%;width:14px;height:14px;border-radius:50%;
    border:1px solid rgba(245,166,35,.6);pointer-events:none;
    transform:translate(-50%,-50%) scale(.6);opacity:0;
    animation:lcReopenRipple 2.3s ease-out infinite;
  }
  .lc-annot-reopen-ring--2{animation-delay:1.15s}
  @keyframes lcReopenRipple{
    0%{transform:translate(-50%,-50%) scale(.6);opacity:.55}
    70%{opacity:.12}
    100%{transform:translate(-50%,-50%) scale(2.2);opacity:0}
  }
  @media (prefers-reduced-motion: reduce){
    .lc-annot-reopen-ring{animation:none;opacity:.4;transform:translate(-50%,-50%) scale(1)}
    .lc-annot-reopen-ring--2{display:none}
  }
  /* Discreet hover/focus label, on the panel's original side (the space
     the collapsed panel vacated) so it never reads toward the model. */
  .lc-annot-reopen-label{
    position:absolute;top:50%;white-space:nowrap;
    font:600 10px/1 -apple-system,BlinkMacSystemFont,sans-serif;letter-spacing:.06em;
    text-transform:uppercase;color:rgba(232,236,241,.85);
    background:rgba(14,26,32,.85);border:1px solid rgba(232,236,241,.16);
    padding:5px 9px;border-radius:4px;opacity:0;pointer-events:none;
    transition:opacity .15s ease,transform .15s ease;
  }
  /* Collapsing shrinks the panel box toward its left/right anchor (24px
     from that viewport edge) rather than toward the model, since width
     collapses to auto with the real content hidden — so the dot itself
     ends up close to the SIDE edge, not the model. The label points
     inward toward the open canvas, where there's always room, not further
     toward the edge the dot already sits near. */
  .lc-annot-left .lc-annot-reopen-label{left:28px;transform:translateY(-50%) translateX(-4px);text-align:left}
  .lc-annot-right .lc-annot-reopen-label{right:28px;transform:translateY(-50%) translateX(4px);text-align:right}
  #lc-annot-reopen:hover .lc-annot-reopen-label,
  #lc-annot-reopen:focus-visible .lc-annot-reopen-label{opacity:1;transform:translateY(-50%) translateX(0)}
  /* Compact mode — a slim single-row technical strip instead of the full
     side annotation, used whenever neither side has genuine clearance
     (narrow/short canvases) or when explicitly requested in expanded mode.
     Sits just below the tab row — the one band that's clear at every size
     — rather than crowding the bottom readout/configure cluster. */
  #lc-annotation.lc-annot-compact{
    top:112px;left:24px;right:24px;bottom:auto;transform:none;width:auto;
    display:flex;align-items:baseline;gap:14px;flex-wrap:wrap;
    padding:9px 14px;text-align:left;
    border-left:none;border-right:none;border-top:1px solid rgba(232,236,241,.16);
    background:linear-gradient(180deg,rgba(14,26,32,.55),transparent);
  }
  #lc-annotation.lc-annot-compact::before,#lc-annotation.lc-annot-compact::after{display:none}
  #lc-annotation.lc-annot-compact #lc-annot-series{order:-2;margin-bottom:0}
  #lc-annotation.lc-annot-compact #lc-annot-name{order:-1}
  #lc-annotation.lc-annot-compact #lc-annot-rule{display:none}
  #lc-annotation.lc-annot-compact #lc-annot-metrics{gap:16px;justify-content:flex-start}
  #lc-annotation.lc-annot-compact .lc-annot-metric{flex-direction:row;align-items:baseline;gap:5px}
  #lc-annotation.lc-annot-compact .lc-annot-value{font-size:16px}
  #lc-annotation.lc-annot-compact #lc-annot-class{margin-top:0}
  #lc-annotation.lc-annot-compact #lc-annot-app{display:none} /* metrics + classification only — no room for the full sentence in a slim strip */
  /* Entrance sequence — restrained: a short rule draw, then metrics/
     classification/application fade upward with a brief stagger. Total
     ~380ms, replayed on every blade switch by toggling .lc-annot-enter
     (removed + reflowed + re-added in JS) rather than on page load. */
  @keyframes lcAnnotRule{from{width:0}to{width:26px}}
  @keyframes lcAnnotIn{from{opacity:0;transform:translateY(7px)}to{opacity:1;transform:translateY(0)}}
  .lc-annot-enter #lc-annot-rule{animation:lcAnnotRule .26s ease both}
  .lc-annot-enter .lc-annot-metric{animation:lcAnnotIn .3s ease both}
  .lc-annot-enter .lc-annot-metric:nth-child(2){animation-delay:.06s}
  .lc-annot-enter #lc-annot-class{animation:lcAnnotIn .3s ease both;animation-delay:.13s}
  .lc-annot-enter #lc-annot-app{animation:lcAnnotIn .34s ease both;animation-delay:.18s}
  .lc-annot-enter #lc-annot-projects{animation:lcAnnotIn .34s ease both;animation-delay:.22s}
  @media (prefers-reduced-motion: reduce){
    .lc-annot-enter #lc-annot-rule,.lc-annot-enter .lc-annot-metric,.lc-annot-enter #lc-annot-class,.lc-annot-enter #lc-annot-app,.lc-annot-enter #lc-annot-projects{animation:none}
  }
  /* The whole panel still gets a soft opacity/position transition when it
     relocates between left/right/compact (not just on blade-switch content
     changes). */
  #lc-annotation{transition:opacity .3s ease}
