/* ============================================================================
   wci-modules.css: the Module shell (INTEL-426 Sticky modules, INTEL-392 Width toggle).
   The rules WciModuleRow and WciModule share: the row, the chat as the buckle, drawers tucked behind it,
   nested drawers one layer deeper, the width tiers, the drag seams and the progress restore tab.
   Global rather than scoped because the belt is a relationship between components: the row's rules reach
   modules rendered by other components, and a scoped sheet cannot.

   Source (ip-b2b, served by the prototype host 2026-09-29; see REGISTRY.md rule 7):
     pages/wise.css 3482-3542  #modules-row, the tuck tokens and child sizing
     pages/wise.css 3587-3641  the z-index ladder and the generic .sticky-mod.is-sticky drawer
     pages/wise.css 3653-3694  drawers whose card is an inner element (the progress tracker)
     pages/wise.css 3695-3705  a drawer with an open menu keeps its layer
     pages/wise.css 3718-3730  stickySlideRight and its reduced-motion guard
     pages/wise.css 3732-3759  nested drawers (z-index 0, the 50px tuck)
     pages/wise.css 3843-3882  the progress restore tab
     pages/wise.css 3891-3900  the row's thin scrollbar
     pages/wise.css 3910-3939  the <= 560px stack
     js/chat-history.js 395-441  the docked History (left) and Turns (right) drawers and their head
     js/pane-width.js 631-657    the fill / custom / carousel rules the script injects
     js/pane-resize.js 823-853   the drag seam grip the script injects
   Class names are the design's, with one change: the design's row is an id (#modules-row) because a
   prototype page has one; a Blazor page can hold two (the chat page and an AI drawer), so the id is the
   class .modules-row here, which pane-width.js already accepts as a synonym. The design's list of
   per-page chat and drawer ids (#wa-chat, #agent-main, #nfp-panel, ...) collapses to the classes
   WciModule renders for its Layer.
   ============================================================================ */

/* ---- Row and tuck tokens (wise.css 3482-3514) ---- */
.modules-row {
  flex: 1 1 0%;
  min-height: 0;
  max-height: 100%;
  display: flex;
  flex-direction: row;
  align-items: stretch;
  overflow-x: auto;
  overflow-y: hidden;
  background: var(--bg);
  --sticky-tuck: 14px;
  --sticky-pad: 14px;
  --sticky-nested-tuck: 50px;
  --sticky-nested-pad: 30px;
  --sticky-nested-inner: 20px;
  --sticky-nested-face-pad: 50px;
  padding: 0 16px;
  gap: 8px;
  scrollbar-gutter: stable;
}

/* ---- Children fill the row (wise.css 3538-3542) ---- */
.modules-row > * {
  height: 100%;
  max-height: 100%;
  align-self: stretch;
}

/* ---- The chat is the buckle (wise.css 3587-3602) ---- */
.modules-row { position: relative; }
.modules-row > .sticky-chat {
  position: relative;
  z-index: 3 !important;
}

/* ---- Output sits under the chat and over its peers (wise.css 3613-3619) ---- */
.modules-row > .wci-module--output.sticky-mod.is-sticky { z-index: 2; }

/* ---- The generic drawer (wise.css 3620-3641) ---- */
.modules-row .sticky-mod.is-sticky {
  position: relative;
  z-index: 1;
  background: var(--surface);
  box-shadow: none;
  align-self: center;
  height: calc(100% - 30px);
  margin-left: calc(-1 * var(--sticky-tuck) - var(--modules-gap, 8px));
  padding-left: var(--sticky-pad);
  border-top-left-radius: 0;
  border-bottom-left-radius: 0;
  border-top-right-radius: var(--r-md, 16px);
  border-bottom-right-radius: var(--r-md, 16px);
  border-left: 0;
  animation: stickySlideRight .42s cubic-bezier(.34, 1.45, .64, 1) both;
}

/* ---- Drawers whose card frame is an inner element (the progress tracker's .vfp-inner)
   (wise.css 3653-3694, the design's list trimmed to the classes the app renders) ---- */
.modules-row .vf-progress-pane > .vfp-inner {
  border-top-left-radius: 0 !important;
  border-bottom-left-radius: 0 !important;
  border-top-right-radius: var(--r-md, 16px) !important;
  border-bottom-right-radius: var(--r-md, 16px) !important;
  border-left: 0 !important;
  box-shadow: none !important;
}
.modules-row .vf-progress-pane.sticky-mod.is-sticky > .vfp-inner {
  padding-left: var(--sticky-nested-inner);
  box-sizing: border-box;
}
.modules-row .sticky-mod.is-sticky:has(> [class*="-inner"]) {
  background: transparent;
}
.modules-row .sticky-mod.is-sticky:has(> [class*="-inner"])::before {
  content: "";
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  width: var(--sticky-pad);
  background: var(--surface);
  pointer-events: none;
  z-index: 0;
}

/* ---- A drawer's open menu never lifts it over the chat (wise.css 3695-3705) ---- */
.modules-row .sticky-mod.is-sticky:has(.panel-more-btn.is-open),
.modules-row .sticky-mod.is-sticky:has(.topbar-popover:not(.hidden)) {
  z-index: 1;
}
.modules-row .wci-module--output.sticky-mod.is-sticky:has(.panel-more-btn.is-open),
.modules-row .wci-module--output.sticky-mod.is-sticky:has(.topbar-popover:not(.hidden)) {
  z-index: 2;
}

/* ---- Slide-in (wise.css 3718-3730) ---- */
@keyframes stickySlideRight {
  from { transform: translateX(-26px); opacity: .35; }
  to   { transform: none; opacity: 1; }
}
.modules-row .sticky-mod.is-sticky.is-entered { animation: none; }
@media (prefers-reduced-motion: reduce) {
  .modules-row .sticky-mod.is-sticky { animation: none !important; }
}

/* ---- Nested drawers: z-index 0, tucked 50px under their parent (wise.css 3732-3759) ----
   The design's comment (3740-3741) settles the card's "~30px shorter still": the same 15px inset as the
   module it tucks behind, never a second, shorter height. */
.modules-row .wci-module--nested.sticky-mod.is-sticky,
.modules-row .vf-progress-pane.sticky-mod.is-sticky {
  z-index: 0;
  height: calc(100% - 30px) !important;
  max-height: calc(100% - 30px) !important;
  align-self: center !important;
  margin-left: calc(-1 * var(--sticky-nested-tuck) - var(--modules-gap, 8px)) !important;
  padding-left: var(--sticky-nested-pad) !important;
}
/* A nested WciModule draws its head and body straight on the module (no inner card like the progress tracker's
   .vfp-inner), so it carries the inner inset itself: its content starts at the parent card's edge, as the design's
   #ia-panel does (add-product.html: face pad + radius against a tuck + radius + gap). Without it the head's 20px sat
   under the parent and the title met the drawer's visible edge. */
.modules-row .wci-module--nested.sticky-mod.is-sticky {
  padding-left: calc(var(--sticky-nested-pad) + var(--sticky-nested-inner)) !important;
}
/* The Ingredient List drawer (INTEL-404) tucks a radius deeper and pads its face past the Product Details
   drawer it sits behind (pages/view-product.html 326-339, `#ia-panel`, ip-b2b afe74ad), so its content
   is never covered. A host opts in with the design's own class, `ia-pane`. Only the tuck and the face padding
   differ from the generic nested drawer above, and only while the row is a row: below the stacking breakpoint
   (560px) the drawers stack and take the stacked reset instead. */
@media (min-width: 561px) {
  .modules-row .wci-module--nested.ia-pane.sticky-mod.is-sticky {
    margin-left: calc(-1 * var(--sticky-nested-tuck) - var(--r-md, 16px) - var(--modules-gap, 8px)) !important;
    padding-left: calc(var(--sticky-nested-face-pad) + var(--r-md, 16px)) !important;
  }
}
/* Nested drawers stay on layer 0 while their menu is open (wise.css 3830-3841). */
.modules-row .wci-module--nested.sticky-mod.is-sticky:has(.panel-more-btn.is-open),
.modules-row .vf-progress-pane.sticky-mod.is-sticky:has(.panel-more-btn.is-open),
.modules-row .vf-progress-pane.sticky-mod.is-sticky:has(.topbar-popover:not(.hidden)) {
  z-index: 0;
}

/* ---- Progress restore tab (wise.css 3843-3882) ---- */
.modules-row .wise-progress-restore {
  position: absolute;
  top: 50%;
  right: 0;
  transform: translateY(-50%);
  z-index: 4;
  display: inline-flex;
  align-items: center;
  gap: 4px;
  height: auto;
  padding: 10px 6px;
  border: 1px solid var(--border);
  border-right: 0;
  border-top-left-radius: 12px;
  border-bottom-left-radius: 12px;
  border-top-right-radius: 0;
  border-bottom-right-radius: 0;
  background: var(--surface);
  color: var(--text-muted);
  box-shadow: var(--shadow-1);
  cursor: pointer;
  font: inherit;
  font-size: 0.7rem;
  font-weight: 600;
  writing-mode: vertical-rl;
  transition: color .15s ease, background .15s ease;
}
.modules-row .wise-progress-restore:hover {
  color: var(--text);
  background: var(--surface-2);
  border-color: var(--primary);
}
.modules-row .wise-progress-restore .material-symbols-outlined {
  font-size: 18px;
  writing-mode: horizontal-tb;
}
.modules-row .wise-progress-restore .wpr-label { letter-spacing: 0.04em; }

/* ---- Scrollbar (wise.css 3891-3900) ---- */
.modules-row::-webkit-scrollbar { height: 8px; }
.modules-row::-webkit-scrollbar-track { background: transparent; }
.modules-row::-webkit-scrollbar-thumb {
  background: color-mix(in srgb, var(--text-subtle) 35%, transparent);
  border-radius: 999px;
}
.modules-row {
  scrollbar-width: thin;
  scrollbar-color: color-mix(in srgb, var(--text-subtle) 35%, transparent) transparent;
}

/* ---- Docked History (left) and Turns (right) (js/chat-history.js 395-441) ----
   The design's .wch-sidebar.wch-docked drawers under .modules-sticky, which is permanent on the WISEcodeAI
   page (wiseai.html 4436-4439): here the recessed drawer is .wci-module--recessed, the right one is the
   plain .sticky-mod rule above, and the left one mirrors it. */
.modules-row .wci-module--recessed.sticky-mod.is-sticky {
  z-index: 1;
  background: var(--surface-2, var(--surface));
  box-shadow: none;
}
.modules-row .wci-module--left.sticky-mod.is-sticky {
  margin-left: 0;
  padding-left: 0;
  margin-right: calc(-1 * var(--sticky-tuck, 14px) - var(--modules-gap, 8px));
  padding-right: var(--sticky-pad, 14px);
  border-top-left-radius: var(--r-md, 16px);
  border-bottom-left-radius: var(--r-md, 16px);
  border-top-right-radius: 0;
  border-bottom-right-radius: 0;
  border-left: 1px solid var(--border);
  border-right: 0;
  animation: none;
}
.modules-row .wci-module .wch-head {
  display: flex;
  align-items: flex-start;
  gap: 8px;
  flex-shrink: 0;
  padding: var(--module-head-pad-t, 26px) var(--module-head-ctrl-inset, 12px) var(--module-head-pad-b, 14px) var(--module-head-pad-l, 20px);
  border-bottom: 1px solid var(--border, rgba(0, 0, 0, 0.08));
}
.modules-row .wci-module .wch-head-title {
  flex: 1;
  min-width: 0;
  font-family: "WISE Digits", var(--module-title-family, "DM Sans", system-ui, sans-serif);
  font-weight: var(--module-title-weight, 800);
  font-size: var(--module-title-size, 1.2rem);
  letter-spacing: -.01em;
  line-height: var(--module-title-lh, 1.16);
  color: var(--text);
  margin: 0;
}
.modules-row .wci-module .wch-controls {
  display: inline-flex;
  align-items: center;
  gap: var(--module-head-ctrl-gap, 2px);
  margin-top: 0;
}
@keyframes wchDockRevealL { from { opacity: 0; transform: translateX(46px) scale(.97) } to { opacity: 1; transform: none } }
.modules-row .wci-module--left.sticky-mod.is-sticky.wch-dock-reveal { animation: wchDockRevealL .44s cubic-bezier(.34, 1.4, .64, 1) both; }
@media (prefers-reduced-motion: reduce) {
  .modules-row .wci-module--left.sticky-mod.is-sticky.wch-dock-reveal { animation: none; }
}

/* ---- Width tiers: fill, custom and the carousel rail (js/pane-width.js injectStyles() 631-657) ----
   The design writes each host's preset widths into that host's own rules (the chat's 380 / 580px, Turns'
   280 / 420px, ...). WciModule carries them as --wci-mod-single / --wci-mod-double on the module, so one
   set of rules serves every host; see the app-owned block below. */
.modules-row.modules-carousel {
  overflow-x: auto !important;
  overflow-y: hidden;
  scrollbar-gutter: stable;
}
.modules-row.modules-carousel::-webkit-scrollbar { height: 10px; }
.modules-row.modules-carousel::-webkit-scrollbar-thumb {
  background: color-mix(in srgb, var(--text-subtle) 55%, transparent);
  border-radius: 999px;
}
.modules-row.modules-carousel > * { flex-shrink: 0 !important; }

/* ---- Drag seams (js/pane-resize.js injectStyles() 823-853) ---- */
.pr-handle {
  position: absolute;
  display: flex;
  align-items: center;
  justify-content: center;
  pointer-events: auto;
  cursor: col-resize;
  touch-action: none;
  -webkit-user-select: none;
  user-select: none;
}
.pr-grip {
  display: block;
  width: 6px;
  height: 40px;
  border-radius: 6px;
  background: rgba(16, 24, 32, .78);
  border: 1px solid rgba(255, 255, 255, .6);
  box-shadow: 0 2px 10px rgba(0, 0, 0, .45);
  position: relative;
  opacity: 0;
  transform: scaleY(.5);
  transition: opacity .12s ease, transform .12s ease, width .12s, background .12s, border-color .12s;
}
.pr-grip::before {
  content: "";
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: 2px;
  height: 2px;
  border-radius: 50%;
  background: #fff;
  box-shadow: 0 -5px 0 #fff, 0 5px 0 #fff;
}
.pr-handle:hover .pr-grip,
.pr-handle:focus-visible .pr-grip,
.pr-handle.pr-active .pr-grip { opacity: 1; transform: scaleY(1); }
.pr-handle.pr-active .pr-grip {
  width: 8px;
  background: var(--primary, #25507C);
  border-color: var(--primary, #25507C);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--primary, #25507C) 32%, transparent), 0 3px 14px rgba(0, 0, 0, .5);
}
html.pr-dragging,
html.pr-dragging * {
  cursor: col-resize !important;
  -webkit-user-select: none !important;
  user-select: none !important;
}

/* ---- The <= 560px stack (wise.css 3910-3939) ----
   Below this width the row drops into a single column. The design names its page modules by id; every
   WciModule takes the stacked shape here, and the tuck, the inset and the seams stand down. */
@media (max-width: 560px) {
  .modules-row {
    flex-direction: column;
    flex-wrap: nowrap;
    overflow-x: hidden;
    overflow-y: auto;
  }
  .modules-row > .wci-module,
  .modules-row > .vf-progress-pane {
    width: 100% !important;
    max-width: 100% !important;
    min-width: 0 !important;
    height: auto !important;
    max-height: none !important;
    flex: 0 0 auto !important;
    align-self: stretch !important;
    margin: 0 !important;
    padding: 0 !important;
    border: 1px solid var(--border) !important;
    border-radius: var(--r-md, 16px) !important;
  }
  /* A custom width leaves the carousel class on the row; its sideways overflow must not survive the stack. */
  .modules-row.modules-carousel { overflow-x: hidden !important; overflow-y: auto; }
  .modules-row > .sticky-chat { min-height: 70dvh; }
  .modules-row > .sticky-mod { min-height: 50dvh; }
  .modules-row .wci-seams { display: none !important; }
}

/* ============================================================================
   APP-OWNED ADDITIONS (not in wise.css)
   ============================================================================ */

/* The module card. The design's modules are each their own card (.sc-card for the chat, the page's pane
   classes for the rest); WciModule is one element for all of them, so the frame lives here. The sticky
   rules above then square, tuck and recess it. */
.wci-module {
  display: flex;
  flex-direction: column;
  min-width: 0;
  min-height: 0;
  box-sizing: border-box;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-md, 16px);
  overflow: hidden;
}
.modules-row > .sticky-chat { box-shadow: var(--chat-elev, var(--shadow-card)); }
/* The chat module wears the chat wash (wci-tokens.css, WI v2 D48), and the chats drawn inside it are see-through so
   the wash reads behind the welcome, the transcript and the composer (the WISEai chat's own paper ground, wise-chat.css,
   is for the v1 drawers). */
.wci-module.sticky-chat { background: var(--chat-wash); }
.wci-module.sticky-chat .wiseai-chat { background: transparent; }
/* HEADER FLOAT (wise.css 6570-6580, 6675-6738, checkout ab499e3): the chat module has no header bar. Its head strip
   takes no height, and the controls (the chat's ⋯ and the width toggle, WciModule) float over the top-right corner,
   above the welcome (z-index 12 beats its 10). */
.wci-module.sticky-chat > .chat-topbar {
  position: relative;
  height: 0;
  min-height: 0;
  padding: 0;
  border-bottom: 0;
  background: transparent;
  overflow: visible;
  flex-shrink: 0;
  z-index: 12;
}
.wci-module.sticky-chat > .chat-topbar > .sc-topbar-controls {
  position: absolute;
  top: 8px;
  right: 8px;
  margin: 0;
  z-index: 6;
  display: inline-flex;
  align-items: center;
  gap: 2px;
}
.wci-module-body {
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

/* A dialog opened from inside a module. A module's z-index (3 for the chat, 0-2 for drawers) makes it a
   stacking context, so a WciModal or a fullscreen card overlay rendered inside it (the chat's Export
   dialog, TurnCard's overlay) would paint under the page's own layers, the nav at 55-70 among them. The
   design never meets this because its popovers portal to <body>; here the module lifts to the dialog
   layer (wci-dialog.css, 10100) only while one is open, and drops back to its place on the belt after. */
.modules-row > .wci-module:has(.wise-modal-scrim),
.modules-row > .wci-module:has(.fixed.inset-0) {
  z-index: 10100 !important;
}

/* Preset widths. Single and double are the host's own lengths (WciModule SingleWidth / DoubleWidth), fill
   absorbs the rest of the row, custom holds the dragged pixel width. The design's fill is
   flex-basis: auto, which sizes a module from its max-content first; a chat's 860px reading column then
   out-shouts its neighbours before the grow is shared, so fill here starts from 0. */
.modules-row > .wci-module {
  flex: 0 0 var(--wci-mod-single, 380px);
  width: var(--wci-mod-single, 380px);
}
.modules-row > .wci-module.panel-wide {
  flex-basis: var(--wci-mod-double, 580px);
  width: var(--wci-mod-double, 580px);
}
.modules-row > .wci-module.panel-fill,
.modules-row > .wci-module.wci-module--solo {
  flex: 1000 1 0%;
  width: auto;
  max-width: none;
}
.modules-row > .wci-module.panel-custom {
  flex: 0 0 var(--wci-mod-w, var(--wci-mod-single, 380px));
  width: var(--wci-mod-w, var(--wci-mod-single, 380px));
  max-width: none;
}
/* Every drawer keeps a 300px floor (pane-resize.js MIN_W) so a filling neighbour never crushes it; a
   module narrower by design (the History rail) declares its own. */
.modules-row > .wci-module.sticky-mod { min-width: min(var(--wci-mod-min, 300px), var(--wci-mod-single, 380px)); }
.modules-row > .wci-module.sticky-chat { min-width: min(300px, var(--wci-mod-single, 380px)); }

/* A standalone module (WciModule Standalone: ordinary page flow, no row) takes its presets directly. */
.wci-module--standalone {
  width: var(--wci-mod-single, 380px);
  max-width: 100%;
  transition: width .22s ease;
}
.wci-module--standalone.panel-wide { width: var(--wci-mod-double, 580px); }
@media (prefers-reduced-motion: reduce) {
  .wci-module--standalone { transition: none; }
}

/* The width tween: a tap eases to the new width, a drag does not (the script sets .pr-dragging). */
.modules-row > .wci-module { transition: flex-basis .22s ease, width .22s ease; }
html.pr-dragging .modules-row > .wci-module { transition: none; }
@media (prefers-reduced-motion: reduce) {
  .modules-row > .wci-module { transition: none; }
}

/* The seam layer: the script draws the handles inside the row's own .wci-seams layer (the design uses a
   body-level fixed overlay, which lands in the wrong place inside the AI drawer's transform), above every
   layer, the restore tab included. The layer itself takes no pointer and no slot in the flex row. */
.wci-seams {
  position: absolute;
  inset: 0;
  z-index: 6;
  pointer-events: none;
  height: auto !important;
  max-height: none !important;
  align-self: auto !important;
  width: auto;
  flex: none;
}
.wci-seams > .pr-handle { pointer-events: auto; }

/* A dock (the AI drawer) is not in a row: its one handle rides its left edge. */
.wci-dock > .wci-seams > .pr-handle { top: 12%; bottom: 12%; left: -9px; width: 18px; }
/* A closed dock stays mounted, slid off the right edge; its handle pokes 9px out of its left edge, which
   would leave a live strip on the viewport's edge. Hidden, it also leaves the tab order. */
.wci-dock:not(.is-open) > .wci-seams { display: none; }

/* The AI drawer's four widths (the design's .wiseai-dock tiers, wise.css 7867-7895: 380px, min(580px, 90vw),
   fill). The drawer floats over the page instead of taking a slot in a row, so fill reaches from the
   primary nav's edge (the same offset sidebar.css gives .main-content) to the viewport's right edge. */
body { --wci-dock-inset: 0px; }
/* The nav is always the icon rail (its hover overlay floats over the page), so the drawer starts at the rail's edge, or
   History's while it is open beside the rail (sidebar.css --wci-history-w). */
body:has(#sidebar) { --wci-dock-inset: calc(var(--sidebar-w-collapsed, 54px) + var(--wci-history-w, 0px) + 16px); }
@media (max-width: 768px) {
  body:has(#sidebar) { --wci-dock-inset: 0px; }
}
.wci-dock { width: 380px; max-width: 100vw; transition: width .22s ease, transform .3s ease-in-out; }
.wci-dock.panel-wide { width: min(580px, 90vw); }
.wci-dock.panel-fill { width: calc(100vw - var(--wci-dock-inset)); }
.wci-dock.panel-custom { width: min(var(--wci-mod-w, 380px), 100vw); }
html.pr-dragging .wci-dock { transition: none; }
@media (prefers-reduced-motion: reduce) {
  .wci-dock { transition: none; }
}
@media (max-width: 560px) {
  .wci-dock, .wci-dock.panel-wide, .wci-dock.panel-fill, .wci-dock.panel-custom { width: 100vw; }
  .wci-dock > .wci-seams { display: none; }
}

/* The global WISEcode AI dock (WciChatDock, WI v2, D34): the pane is a slot between the primary nav and the
   page, not an overlay, so the layout's content starts after it (the design's default left dock). Wide tables then
   scroll inside their own card. :has(#sidebar) lifts this above sidebar.css's id-weighted margin-left rules. The pane
   never covers the page (D40). Phones have no room beside the page: the pane is the whole screen there
   (WciChatDock.razor.css). */
/* On a phone the open pane is the bottom 60dvh (WciChatDock.razor.css), so the page scrolls in the space above it.
   Folded, only the owl circle is left (52px, 16px from the bottom), so the page keeps clear of that instead. */
@media (max-width: 768px) {
  body:has(.wci-chat-dock.wiseai-dock-open) .main-content { padding-bottom: calc(60dvh + 12px); }
  body:has(.wci-chat-dock.wiseai-dock-open.wiseai-dock-collapsed) .main-content { padding-bottom: 80px; }
}
/* The design's full-bleed shell (ip-b2b html.full-bleed.fb-chat-only, product-portfolio.html, read 2026-10-22): the
   nav rail sits flush on the linen field, the chat runs the full height beside it with no card, and the page is a white
   sheet joined to the chat's right edge (#portfolio-panel .panel-inner: square on the chat side, 16px rounding on the
   other, white to linen). The chat is the design's single tier (380px) at every width
   (Kevin, 2026-10-23: the double tier left the page too little room). The sheet is a fixed pane that scrolls inside
   itself, as the design's #pf-body: its frame never moves, and PageShell's pinned band (.wise-page-pin: breadcrumbs,
   header row, Toolbar) sticks to its top while the rest of the page scrolls under it (Kevin, 2026-10-23).
   js/wci/wci-page-sheet.js puts a new page back at the top and marks the sheet scrolled. */
body {
  --wci-chat-dock-w: 380px;
  /* The rail, and History beside it while open: everything left of the pane. */
  --wci-chat-rail-w: calc(var(--sidebar-w-collapsed, 54px) + var(--wci-history-w, 0px));
}
@media (min-width: 769px) {
  body:has(.wci-chat-dock.wiseai-dock-open) { background: var(--wci-sheet-field); }
  body:has(#sidebar):has(.wci-chat-dock.wiseai-dock-open) .main-content,
  body:has(.wci-chat-dock.wiseai-dock-open) .main-content {
    margin: 28px 22px 28px calc(var(--wci-chat-rail-w) + var(--wci-chat-dock-w));
    height: calc(100dvh - 56px);
    overflow-y: auto;
    overscroll-behavior: contain;
    background: linear-gradient(165deg, var(--surface) 0%, var(--surface-2) 100%);
    border: 1px solid var(--border);
    border-left: 0;
    border-radius: 0 16px 16px 0;
    transition: margin-left 500ms ease-in-out;
  }
  /* The sheet's inset is the design's module head (--module-head-pad-t 26px, --module-head-pad-x 40px), set once on the
     layout's page wrapper, so a PageShell page does not add its own padding on top. */
  body:has(.wci-chat-dock.wiseai-dock-open) .main-content > .p-8 { padding: 26px 40px 32px; }
  body:has(.wci-chat-dock.wiseai-dock-open) .main-content .wise-page { padding: 0; }
  /* The design's .pf-pin: bled over the sheet's top and side inset so nothing scrolling under it shows in the gutters,
     and keeping that inset above the title once it sticks. Always opaque: it paints the sheet's own gradient, pinned to
     the sheet's box on screen (fixed attachment at the sheet's margins above), so there is no seam against the sheet and
     nothing shows through while a fast scroll outruns the script. Only the hairline waits for .is-scrolled. */
  body:has(.wci-chat-dock.wiseai-dock-open) .main-content .wise-page-pin {
    position: sticky;
    top: 0;
    z-index: 40;
    display: flow-root;
    margin: -26px -40px 0;
    padding: 26px 40px 0;
    background: linear-gradient(165deg, var(--surface) 0%, var(--surface-2) 100%) fixed;
    background-position: calc(var(--wci-chat-rail-w) + var(--wci-chat-dock-w)) 28px;
    background-size: calc(100vw - var(--wci-chat-rail-w) - var(--wci-chat-dock-w) - 22px) calc(100dvh - 56px);
    background-repeat: no-repeat;
  }
  body:has(.wci-chat-dock.wiseai-dock-open) .main-content.is-scrolled .wise-page-pin { box-shadow: 0 1px 0 var(--border); }

  /* The full WISEcode AI page (WISEaiAgent, .wci-agent-shell) runs as the design's wiseai.html: the chat fills
     everything right of the flush rail, square, with no card margin. History is the nav's (Kevin, 2026-10-23): it
     opens beside the rail on every page, and the chat starts at its edge. Turns, on the right, is flat too. */
  body:has(.wci-agent-shell) { background: var(--wci-sheet-field); }
  /* .sidebar-shell in the :has: it ties sidebar.css's offset rule on weight, and sidebar.css loads last. */
  body:has(#sidebar.sidebar-shell):has(.wci-agent-shell) .main-content,
  body:has(.wci-agent-shell) .main-content { margin: 0 0 0 var(--wci-chat-rail-w); }
  body:has(.wci-agent-shell) .main-content > .p-8 { padding: 0; }
  .modules-row.wci-agent-shell {
    height: 100vh;
    padding: 0;
    background: transparent;
  }
  .modules-row.wci-agent-shell > .wci-module {
    border-radius: 0;
    border-top: 0;
    border-bottom: 0;
    box-shadow: none;
  }
  .modules-row.wci-agent-shell > .wci-module--left.sticky-mod.is-sticky {
    margin-right: 0;
    padding-right: 0;
    align-self: stretch;
    height: 100%;
  }
  .modules-row.wci-agent-shell > .wci-module:last-of-type { border-right: 0; }
}
@media (prefers-reduced-motion: reduce) {
  body:has(.wci-chat-dock) .main-content { transition: none; }
}

/* APP-OWNED: View Product defaultChatTier (ip-b2b js/pane-width.js).
   SingleFoodWorkspace opts in; other module rows keep their own width ladders. */
.modules-row > .wci-product-workspace-chat:not(.panel-fill):not(.wci-module--solo) {
  flex: 0 0 380px; width: 380px;
}
@media (min-width: 1513px) {
  .modules-row > .wci-product-workspace-chat:not(.panel-fill):not(.wci-module--solo) {
    flex-basis: 520px; width: 520px;
  }
}

/* Source: ip-b2b view-product.html #ia-panel .wch-head (188-201).
   Only the product's Ingredient List opts in. */
.modules-row > .wci-product-ingredient-list .wch-head { align-items: flex-start; padding: var(--module-head-pad-t) var(--module-head-ctrl-inset) var(--module-head-pad-b) var(--module-head-pad-l); }
.modules-row > .wci-product-ingredient-list .wch-head-title { font-family: var(--font-serif); font-weight: var(--module-title-weight, 800); font-size: var(--module-title-size, 1.2rem); letter-spacing: -.01em; line-height: var(--module-title-lh, 1.16); color: var(--text); }

/* APP-OWNED: the product page's Product Details takes the row while the Ingredient List is closed (Kevin, 2026-10-09:
   "takes up like three-fourths of a screen" in the design); once the list opens it returns to its 372px and the list
   fills. V2ProductPagePanel sets the class. */
.modules-row > .wci-module.wci-pd--fill {
  flex: 1000 1 0%;
  width: auto;
  max-width: none;
}
