/* Hub shell overlay: sits above the home stack, below nothing else.
   Module roots carry [data-mod] and their own scoped module.css. */
#hubView{position:fixed;inset:0;z-index:9000;background:#f4f8fc;display:none}
#hubView.on{display:block}
#hubView .modRoot{position:absolute;inset:0;overflow-y:auto;-webkit-overflow-scrolling:touch;display:none;background:inherit}
#hubView .modRoot.on{display:block}
/* pull-to-refresh indicator (hub.js tracks the gesture): a plain spinner
   disc that follows the pull down from the top centre and spins while
   the refresh runs. Shell chrome only — it serves the home view and the
   module views alike (phase 8), and never intercepts touches. */
#hubPtr{position:fixed;left:50%;top:0;z-index:9600;width:38px;height:38px;margin-left:-19px;
  border-radius:50%;background:rgba(20,24,32,.88);box-shadow:0 6px 18px rgba(10,20,40,.25);
  display:flex;align-items:center;justify-content:center;opacity:0;pointer-events:none;
  transform:translateY(-52px)}
#hubPtr svg{width:20px;height:20px;stroke:#fff;flex:none}
#hubPtr.spin svg{animation:hubPtrSpin .7s linear infinite}
@keyframes hubPtrSpin{to{transform:rotate(360deg)}}
/* PTR gesture surface (phase 9): the pull tracker in hub.js listens to
   the raw touch stream, which a browser only guarantees where
   touch-action forbids it claiming the pan for its own overscroll /
   pull handling. On the home stack the card viewport has carried
   touch-action:none all along (the home session's gesture design), so
   pulls starting on a card always reached the tracker — but every
   other home surface (pinned header, stage gaps, bottom bar) sat at
   touch-action:auto, and a browser that claims a downward pan at the
   top cancels the stream there (touchstart, then touchcancel, no
   moves reach the page): the pull silently did nothing, exactly as
   ken reported from his phone. In stack mode the home screen is a
   fully gesture-driven surface with no native scroller at all, so
   declare the whole screen the way the viewport is declared. The
   chassis carries .wide-grid-chassis in grid mode, where the screen
   IS the scroller and must keep native touch scrolling (the tracker
   gates on its scrollTop there instead), so the rule lifts in grid
   mode. Gestures starting inside a nested scroller (preview-modal
   list) are unaffected: a gesture's touch-action intersection stops
   at its own scroller, above the screen. */
#masterPhoneChassis:not(.wide-grid-chassis) .iphone18-master-screen{touch-action:none}
#hubSkeleton{padding:18px 16px}
#hubSkeleton .skblock{border-radius:8px;background:linear-gradient(100deg,#e6ecf3 40%,#f4f8fb 50%,#e6ecf3 60%);
  background-size:200% 100%;animation:hubShim 1.2s infinite linear}
@keyframes hubShim{to{background-position:-200% 0}}
/* prototype-grade module rendering helpers (production port reuses each
   site's own row markup; these only carry the prototype) */
.hubGroup{background:#fff;border-radius:16px;margin:12px;padding:6px 14px 10px;box-shadow:0 1px 4px rgba(20,40,80,.06)}
.hubGroup h3{font-size:15px;margin:12px 0 4px;color:#12233f}
.hubGroup .cnt{color:#7a8799;font-size:12px;font-weight:400}
.hubItem{display:flex;align-items:center;gap:10px;padding:10px 0;border-top:1px solid #eef2f6;cursor:pointer}
.hubItem .tt{flex:1;min-width:0;font-size:13.5px;color:#1c2b45;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.hubItem .shop{display:block;color:#8494ab;font-size:11.5px;margin-top:2px}
.hubItem .pr{font-weight:700;color:#0a7d4f;font-size:15px;white-space:nowrap}
.hubItem .stk{font-size:11px;color:#b26a00;background:#fff4e0;border-radius:6px;padding:2px 6px;white-space:nowrap}
.hubShopRow{display:flex;justify-content:space-between;gap:10px;padding:9px 0;border-top:1px solid #eef2f6;font-size:13.5px;color:#1c2b45}
.hubShopRow span:last-child{color:#8494ab;font-size:12px;white-space:nowrap}
.hubBrand{background:#fff;border-radius:16px;margin:12px;padding:14px 16px;box-shadow:0 1px 4px rgba(20,40,80,.06)}
.hubBrand h3{margin:0 0 4px;font-size:15px;color:#12233f}
.hubBrand p{margin:2px 0;font-size:12.5px;color:#5a6b84;line-height:1.55}
.hubBrand .pr{color:#2456c8;font-weight:700}
/* sub-application root (pan, phase 4): the frame owns its own scroll */
#hubView .modRoot.subappRoot{overflow:hidden}
#hubView .modRoot .subappFrame{width:100%;height:100%;border:0;display:block;background:#f3f8fa}
