dsh-zen-remote 2.2.4 → 2.2.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (111) hide show
  1. package/AGENTS.md +15 -3
  2. package/README.md +12 -4
  3. package/README.zh-CN.md +12 -4
  4. package/docs/interface.md +18 -1
  5. package/docs/plugin-bridge.md +1 -1
  6. package/docs/remote-access.en.md +10 -3
  7. package/docs/remote-access.md +10 -3
  8. package/lib/adapters/dsh-better-sidebar/index.js +28 -7
  9. package/lib/adapters/dsh-better-sidebar/index.js.map +1 -1
  10. package/lib/adapters/dsh-better-sidebar/methods.js +2 -0
  11. package/lib/adapters/dsh-better-sidebar/methods.js.map +1 -1
  12. package/lib/client-routes.js +3 -0
  13. package/lib/client-routes.js.map +1 -1
  14. package/lib/client.js +1164 -193
  15. package/lib/fetch-route-intercept.js +1 -1
  16. package/lib/index.js +73 -16
  17. package/lib/index.js.map +1 -1
  18. package/lib/intercept.js +13 -0
  19. package/lib/intercept.js.map +1 -1
  20. package/lib/invoke-binary.js +8 -2
  21. package/lib/invoke-binary.js.map +1 -1
  22. package/lib/lan-gate-server.cjs +109 -2
  23. package/lib/owner-peer.js +23 -0
  24. package/lib/owner-peer.js.map +1 -1
  25. package/lib/plugin-adapter-core.js +2 -2
  26. package/lib/relay-access.js +24 -2
  27. package/lib/relay-access.js.map +1 -1
  28. package/lib/relay-client.js +2 -2
  29. package/lib/relay-server.js +103 -100
  30. package/lib/relay-server.js.map +1 -1
  31. package/lib/types/adapters/dsh-better-sidebar/index.d.ts +1 -1
  32. package/lib/types/adapters/dsh-better-sidebar/index.d.ts.map +1 -1
  33. package/lib/types/adapters/dsh-better-sidebar/methods.d.ts.map +1 -1
  34. package/lib/types/client/MobileAttachButton.d.ts +5 -2
  35. package/lib/types/client/MobileAttachButton.d.ts.map +1 -1
  36. package/lib/types/client/MobileAttachChips.d.ts.map +1 -1
  37. package/lib/types/client/MobileHome.d.ts.map +1 -1
  38. package/lib/types/client/RemoteFileDownload.d.ts +57 -0
  39. package/lib/types/client/RemoteFileDownload.d.ts.map +1 -0
  40. package/lib/types/client/attach-upload.d.ts +32 -0
  41. package/lib/types/client/attach-upload.d.ts.map +1 -1
  42. package/lib/types/client/effects/remote-drop.d.ts +27 -0
  43. package/lib/types/client/effects/remote-drop.d.ts.map +1 -0
  44. package/lib/types/client/index.d.ts.map +1 -1
  45. package/lib/types/client/locales.d.ts +11 -0
  46. package/lib/types/client/locales.d.ts.map +1 -1
  47. package/lib/types/client/remote-file-save.d.ts +112 -0
  48. package/lib/types/client/remote-file-save.d.ts.map +1 -0
  49. package/lib/types/client/settings/SettingsSection.d.ts.map +1 -1
  50. package/lib/types/client/styles/compat.css.d.ts +1 -1
  51. package/lib/types/client/styles/compat.css.d.ts.map +1 -1
  52. package/lib/types/client/styles/header.css.d.ts +1 -1
  53. package/lib/types/client/styles/header.css.d.ts.map +1 -1
  54. package/lib/types/client/styles/home.css.d.ts +1 -1
  55. package/lib/types/client/styles/home.css.d.ts.map +1 -1
  56. package/lib/types/client/styles/layout.css.d.ts +1 -1
  57. package/lib/types/client/styles/layout.css.d.ts.map +1 -1
  58. package/lib/types/client/styles/remote-session.css.d.ts +1 -1
  59. package/lib/types/client/styles/remote-session.css.d.ts.map +1 -1
  60. package/lib/types/client-data/remote-drop.d.ts +99 -0
  61. package/lib/types/client-data/remote-drop.d.ts.map +1 -0
  62. package/lib/types/client-data/settings-form.d.ts +7 -0
  63. package/lib/types/client-data/settings-form.d.ts.map +1 -1
  64. package/lib/types/client-routes.d.ts +6 -0
  65. package/lib/types/client-routes.d.ts.map +1 -1
  66. package/lib/types/index.d.ts.map +1 -1
  67. package/lib/types/intercept.d.ts.map +1 -1
  68. package/lib/types/invoke-binary.d.ts +4 -1
  69. package/lib/types/invoke-binary.d.ts.map +1 -1
  70. package/lib/types/owner-peer.d.ts +9 -0
  71. package/lib/types/owner-peer.d.ts.map +1 -1
  72. package/lib/types/plugin-adapter-core.d.ts +1 -1
  73. package/lib/types/relay-access.d.ts.map +1 -1
  74. package/lib/types/relay-server.d.ts +10 -7
  75. package/lib/types/relay-server.d.ts.map +1 -1
  76. package/package.json +37 -37
  77. package/pwa/inject.js +20 -9
  78. package/pwa/sw.js +97 -21
  79. package/scripts/check-attach-upload.mjs +37 -0
  80. package/scripts/check-remote-drop.mjs +114 -0
  81. package/scripts/check-settings-form.mjs +3 -2
  82. package/scripts/check-upload-endpoint.mjs +14 -3
  83. package/src/adapters/dsh-better-sidebar/index.ts +27 -7
  84. package/src/adapters/dsh-better-sidebar/methods.ts +2 -0
  85. package/src/client/MobileAttachButton.tsx +14 -9
  86. package/src/client/MobileAttachChips.tsx +4 -0
  87. package/src/client/MobileHome.tsx +79 -12
  88. package/src/client/RemoteFileDownload.tsx +173 -0
  89. package/src/client/attach-upload.ts +47 -0
  90. package/src/client/effects/remote-drop.ts +269 -0
  91. package/src/client/index.tsx +47 -0
  92. package/src/client/locales.ts +32 -0
  93. package/src/client/remote-file-save.ts +232 -0
  94. package/src/client/settings/SettingsSection.tsx +61 -1
  95. package/src/client/styles/compat.css.ts +43 -12
  96. package/src/client/styles/header.css.ts +63 -15
  97. package/src/client/styles/home.css.ts +39 -1
  98. package/src/client/styles/layout.css.ts +24 -7
  99. package/src/client/styles/remote-session.css.ts +38 -0
  100. package/src/client-data/remote-drop.ts +127 -0
  101. package/src/client-data/settings-form.ts +10 -0
  102. package/src/client-routes.ts +8 -0
  103. package/src/fetch-route-intercept.ts +1 -1
  104. package/src/index.ts +71 -18
  105. package/src/intercept.ts +13 -0
  106. package/src/invoke-binary.ts +8 -2
  107. package/src/owner-peer.ts +32 -0
  108. package/src/plugin-adapter-core.ts +2 -2
  109. package/src/relay-access.ts +24 -2
  110. package/src/relay-client.ts +2 -2
  111. package/src/relay-server.ts +114 -90
@@ -1,2 +1,2 @@
1
- export declare const HOME_CSS = "/* ---------- phone app shell (< 768px) ---------- */\n\n@media (max-width: 767px) {\n /* --- the document never scrolls (S1.1, 2026-08-17) ---\n Real-device symptom: the workspace title bar, the session header, the\n composer and the FAB all slid with the finger \u2014 every fixed surface\n \"followed the drag\". They are not misplaced; the whole DOCUMENT was\n rubber-banding under them (they are absolute/in-flow inside the frame,\n so a document-level bounce moves them all as one).\n\n After the S2.1 box-sizing fix the document has no overflow at all\n (scrollHeight === clientHeight, measured with ?mobile-nav-inset=54), so\n this is not scrolling \u2014 it is iOS's elastic overscroll, which happens on\n an unscrollable document too, and which an inner scroller chains into as\n soon as it hits its own end.\n\n overscroll-behavior: none on the viewport kills both halves at once: the\n document itself gets no bounce, and overscroll chained up from the\n message flow / session list is absorbed without moving anything.\n overflow: hidden then hard-locks the document scroller so future content\n can never reintroduce a real scroll. Set on html AND body: the spec\n propagates the viewport's value from html, but engines have historically\n read body, and neither is a scroll container we ever want.\n\n Deliberately NOT position: fixed on body \u2014 the app shell does not need\n it, and it is the variant that strands iOS's fixed elements behind the\n on-screen keyboard. With plain overflow: hidden, iOS still pans the\n visual viewport to reveal a focused textarea, so the composer stays\n visible while typing without any visualViewport JS. */\n html,\n body {\n overflow: hidden !important;\n overscroll-behavior: none !important;\n }\n\n /* The message flow is the one scroller that regularly hits its end under a\n finger. Root-level `none` already absorbs the chain, but declaring it\n at the source keeps the guarantee if the root rule is ever weakened\n (the home list and both sheets already declare it).\n\n `none`, NOT `contain` (S4.1 fix, 2026-08-17). The two differ in exactly\n the way that bit us: `contain` stops overscroll from CHAINING OUT to the\n document but deliberately KEEPS this element's own local elastic bounce,\n while `none` suppresses that local bounce too. S1.1 only reasoned about\n the chain, so it picked `contain` \u2014 and the composer went on twitching\n upward on every drag-past-the-end while the header and FAB stayed put.\n\n Why only the composer moved: the official composer seat\n (`[class$=\"_composerSeat\"]`) is `position: sticky; bottom: 0` and lives\n INSIDE this scroller (measured 2026-08-17: seat 0,710 390x134 inside\n _scrollBody 0,131 390x713, contains() === true). A sticky box is laid out\n against its scroll container's content, so the container's own rubber-band\n drags it along. The header/FAB are absolute on the frame, outside this\n scroller entirely \u2014 which is precisely why S1.1's document-level fix\n pinned them and left this one surface behind.\n\n Deliberately NOT re-pinning the seat with position: fixed: sticky inside\n the scroller is what keeps the focused textarea visible when iOS pans the\n visual viewport for the keyboard, and fixed is the variant that strands\n it behind the keyboard (same trap as the body rule above). Kill the\n bounce, keep the sticky. */\n [data-phase] [class$=\"_scrollBody\"] {\n overscroll-behavior: none !important;\n }\n\n /* The official sidebar is no longer a drawer on a phone \u2014 the home screen\n replaced it. Hidden outright (not translated off-screen) so it cannot\n capture taps or hold layout. */\n [data-mobile-nav=\"frame\"] > :first-child {\n display: none !important;\n }\n /* The header's drawer toggle opened that sidebar; with it gone the button\n has nothing to open. (S2 owns the rest of the header layout \u2014\n styles/header.css.ts \u2014 including the Files button's replacement.) */\n [data-mobile-nav=\"toggle\"] {\n display: none !important;\n }\n\n /* --- level 1: the session list ---\n Renders inside the shell overlay layer (absolute, pointer-events: none),\n so the page re-enables pointer events for itself. The layer's containing\n block is the frame's padding box, which still starts under the status\n bar \u2014 hence the safe-area padding here. */\n [data-mobile-nav=\"home\"] {\n position: absolute;\n inset: 0;\n z-index: 5;\n display: flex;\n flex-direction: column;\n pointer-events: auto;\n /* dsw-specific-sidebar-fill, not an alias bg-layer-* token (real-device\n round 2 follow-up, 2026-08-17): fetched and diffed the live theme\n CSS (both light/dark blocks in /assets/index-*.css) because computed\n values, not source-read guesses, are what actually matter here \u2014\n --dsw-alias-bg-base/-layer-1/-layer-2 all resolve to the exact same\n color in the LIGHT theme (neutral-bluish-00, i.e. plain white); they\n only diverge in dark mode.\n\n 2026-08-20: the page and the CARDS swapped tokens. This surface used\n to be --dsw-specific-sidebar-fill, which made the list page a\n different shade from the session page \u2014 measured on-device in dark\n theme, rgb(27,27,28) here against rgb(21,21,23) there, a visible step\n every time you opened a session. The page now takes bg-base, the same\n token the session page and <body> resolve to, so the two screens are\n literally the same colour; the cards took sidebar-fill in exchange, so\n the contrast that separates a row from the page is preserved \u2014 it\n just runs the other way (raised card on a base page, the more\n conventional reading of the two anyway). */\n background: var(--dsw-alias-bg-base, #ffffff);\n color: var(--dsw-alias-label-primary, inherit);\n padding-top: var(--mnav-sat);\n transform: translateX(0);\n opacity: 1;\n transition:\n transform .3s var(--ds-ease-in-out, ease-in-out),\n opacity .3s var(--ds-ease-in-out, ease-in-out);\n }\n /* Push transition: the list slides out to the left as the session takes\n the screen, and comes back from the left. It stays mounted (visibility,\n not display) so the slide has something to animate; the delayed\n visibility keeps it non-interactive the moment the transition ends. */\n [data-mobile-nav=\"home\"][data-view=\"session\"] {\n transform: translateX(-100%);\n opacity: 0;\n visibility: hidden;\n pointer-events: none;\n transition:\n transform .3s var(--ds-ease-in-out, ease-in-out),\n opacity .3s var(--ds-ease-in-out, ease-in-out),\n visibility 0s .3s;\n }\n @media (prefers-reduced-motion: reduce) {\n [data-mobile-nav=\"home\"],\n [data-mobile-nav=\"home\"][data-view=\"session\"] {\n transition: none !important;\n }\n }\n\n /* Title bar: the workspace name IS the switcher. */\n [data-mobile-nav=\"home-top\"] {\n flex: 0 0 auto;\n display: flex;\n align-items: center;\n min-height: 52px;\n padding: 4px 16px 6px;\n }\n /* Site logo (real-device round 2, 2026-08-17): rendered only when\n document.head actually has a <link rel=\"icon\"> (MobileHome.tsx never\n ships a placeholder box), so this rule only ever needs to size the\n image, not reserve space for its absence. */\n [data-mobile-nav=\"home-logo\"] {\n width: 24px;\n height: 24px;\n margin-right: 6px;\n flex: none;\n border-radius: 6px;\n object-fit: contain;\n }\n /* Dark theme (real-device report, 2026-08-17): the runtime favicon is a\n dark-on-transparent whale mark, illegible on the dark page. Force a\n white silhouette regardless of the source image's own colors \u2014\n brightness(0) collapses every opaque pixel to black first, invert(1)\n then flips that to white; transparent pixels stay transparent either\n way. Same body[data-ds-dark-theme] marker as the home-row hairline\n above (AGENTS.md: prefers-color-scheme never fires, the app switches\n themes via this attribute with color-scheme hardcoded to light). */\n body[data-ds-dark-theme] [data-mobile-nav=\"home-logo\"] {\n filter: brightness(0) invert(1);\n }\n [data-mobile-nav=\"ws-switch\"] {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n min-height: 44px;\n max-width: 100%;\n padding: 0 6px 0 0;\n border: none;\n background: transparent;\n color: inherit;\n font-family: inherit;\n font-size: 22px;\n font-weight: 600;\n line-height: 1.2;\n cursor: pointer;\n touch-action: manipulation;\n -webkit-tap-highlight-color: transparent;\n }\n [data-mobile-nav=\"ws-switch\"] > span {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n [data-mobile-nav=\"ws-switch\"] > svg {\n flex: none;\n opacity: .55;\n }\n [data-mobile-nav=\"ws-switch\"]:active {\n opacity: .6;\n }\n\n /* Session list: rounded cards, not bordered rows (real-device round 2\n follow-up, 2026-08-17 \u2014 reference: Claude Code mobile app's session\n list). `gap` on the flex column IS the inter-card spacing; no\n per-row margin bookkeeping. */\n [data-mobile-nav=\"home-list\"] {\n flex: 1 1 auto;\n min-height: 0;\n margin: 0;\n display: flex;\n flex-direction: column;\n gap: 10px;\n padding: 12px 16px calc(var(--mnav-sab) + 96px);\n list-style: none;\n overflow-y: auto;\n overscroll-behavior: contain;\n -webkit-overflow-scrolling: touch;\n }\n /* Swipe-to-archive wrapper (redone 2026-08-25, real-device round): iOS-mail\n mechanics. The wrapper CLIPS (overflow hidden, same 22px radius as the\n card) and the archive button is parked past the right edge, sliding in\n lock-step with the card \u2014 a 1px drag reveals a 1px slice, never a\n fully-drawn button behind a gap. Clipping would eat the card's cast\n shadow, so the light-theme shadow moves up to this wrapper (identical\n values; the dark theme's INSET hairline on the card survives clipping\n untouched). pan-y keeps vertical list scrolling native; the direction\n lock in MobileHome.tsx decides horizontal-vs-vertical once per touch. */\n [data-mobile-nav=\"home-swipe\"] {\n position: relative;\n overflow: hidden;\n border-radius: 22px;\n /* The list is a flex column: without this, an overflowing list SHRINKS\n every row and the clip above slices the squashed card's bottom edge\n flat (real-device report, 2026-08-25). Rows keep natural height; the\n list scrolls. */\n flex: 0 0 auto;\n touch-action: pan-y;\n box-shadow: 0 1px 3px rgba(0, 0, 0, .06), 0 4px 12px rgba(0, 0, 0, .05);\n }\n body[data-ds-dark-theme] [data-mobile-nav=\"home-swipe\"] {\n box-shadow: none;\n }\n /* Press = settle toward the page (mirrors the card's own :active swap,\n which the clip made invisible at wrapper level). */\n [data-mobile-nav=\"home-swipe\"]:has([data-mobile-nav=\"home-row\"]:active) {\n box-shadow: 0 1px 2px rgba(0, 0, 0, .05);\n }\n body[data-ds-dark-theme] [data-mobile-nav=\"home-swipe\"]:has([data-mobile-nav=\"home-row\"]:active) {\n box-shadow: none;\n }\n [data-mobile-nav=\"home-swipe-card\"] {\n position: relative;\n z-index: 1;\n transition: transform .22s var(--ds-ease-out, ease-out);\n will-change: transform;\n }\n /* Inset pill, not a full-bleed slab (real-device feedback: hard edges).\n 5px breathing room on three sides inside the 88px reveal; its own\n radius echoes the card family. It still slides in lock-step from past\n the right edge (transform driven from MobileHome.tsx). */\n [data-mobile-nav=\"home-archive\"] {\n position: absolute;\n z-index: 0;\n top: 5px;\n bottom: 5px;\n right: 5px;\n width: 78px;\n border: none;\n border-radius: 17px;\n background: var(--dsw-alias-state-error-primary, #d4494c);\n color: #fff;\n font-size: 13px;\n font-weight: 600;\n cursor: pointer;\n -webkit-tap-highlight-color: transparent;\n transition: transform .22s var(--ds-ease-out, ease-out);\n will-change: transform;\n }\n [data-mobile-nav=\"home-archive\"]:active {\n filter: brightness(.9);\n }\n\n [data-mobile-nav=\"home-row\"] {\n display: flex;\n align-items: center;\n gap: 12px;\n width: 100%;\n min-height: 60px;\n padding: 14px 16px;\n border: none;\n border-radius: 22px;\n /* The page's old colour (see the swap note on [data-mobile-nav=\"home\"]):\n differs from bg-base in BOTH themes, and is the token\n dsh-better-sidebar's panel already uses for a secondary surface. */\n background: var(--dsw-specific-sidebar-fill, #f5f5f5);\n color: inherit;\n font-family: inherit;\n text-align: left;\n cursor: pointer;\n touch-action: manipulation;\n -webkit-tap-highlight-color: transparent;\n /* Card edge definition (2026-08-17). Light theme only \u2014 see the dark\n override below. Two stacked shadows in the iOS idiom: a tight 1px\n contact shadow that draws the edge itself, plus a wide soft one that\n lifts the card off the page. Both are deliberately weak (.06/.05):\n the page sits on --dsw-specific-sidebar-fill and the card on\n --dsw-alias-bg-base, so there is already a slight tonal step here and\n the shadow only has to sharpen it, not carry it alone. */\n box-shadow: 0 1px 3px rgba(0, 0, 0, .06), 0 4px 12px rgba(0, 0, 0, .05);\n }\n [data-mobile-nav=\"home-row\"]:active {\n background: var(--dsw-alias-interactive-bg-hover, rgba(0, 0, 0, .06));\n /* Press = settle toward the page. Dropping the wide shadow and keeping a\n tighter contact one reads as the card pushing in, which is what the\n darkening background already implies; leaving the lifted shadow under\n a pressed card is the combination that looks wrong. */\n box-shadow: 0 1px 2px rgba(0, 0, 0, .05);\n }\n /* Dark theme: a black shadow on a near-black page is invisible, so the\n edge is drawn instead of cast. A 1px hairline at --dsw-alias-border-l2\n weight, delivered as an INSET box-shadow rather than a real border so\n the card's geometry is untouched (a real 1px border would grow every\n row by 2px unless box-sizing cooperated) and so it overrides the light\n shadow through the same property instead of fighting it.\n\n Chosen over \"brighten the card face\" because in dark theme the card\n (--dsw-alias-bg-base, bluish-950) is already DARKER than the page\n (--dsw-specific-sidebar-fill, bluish-900); lightening the card past the\n page would invert the layering that the light theme establishes, while\n a hairline keeps both themes reading as \"page behind, card in front\".\n\n Theme is read from body[data-ds-dark-theme], never prefers-color-scheme:\n the app hardcodes color-scheme: light on <html> and switches themes with\n this attribute, so a media query would never fire (AGENTS.md). This\n selector also outranks the :active rule above (0,2,1 vs 0,2,0), so one\n declaration covers the pressed state too. */\n body[data-ds-dark-theme] [data-mobile-nav=\"home-row\"] {\n box-shadow: inset 0 0 0 1px var(--dsw-alias-border-l2, rgba(255, 255, 255, .12));\n }\n [data-mobile-nav=\"home-row\"][data-current] [data-mobile-nav=\"home-row-title\"] {\n font-weight: 600;\n }\n /* Avatar: a running/warning/done session shows its existing StateDot\n (same component, same semantics as the old inline dot \u2014 just bigger\n and re-homed); otherwise the title's own first character stands in\n for it, so every row has a mark even when idle. interactive-bg-hover,\n not a bg-layer-* token: same reason as the page background above \u2014\n bg-layer-2 is IDENTICAL to the card's own bg-base in light theme\n (verified against the live theme CSS), so it would render invisible\n there. interactive-bg-hover is a translucent rgba tint rather than a\n solid layer color, so it always reads as \"a shade over the card\" in\n both themes regardless of what the card's base color resolves to. */\n [data-mobile-nav=\"home-row-avatar\"] {\n flex: none;\n display: grid;\n place-items: center;\n width: 40px;\n height: 40px;\n border-radius: 12px;\n background: var(--dsw-alias-interactive-bg-hover, rgba(0, 0, 0, .06));\n color: var(--dsw-alias-label-secondary, rgba(0, 0, 0, .55));\n font-size: 16px;\n font-weight: 600;\n }\n [data-mobile-nav=\"home-row-body\"] {\n flex: 1 1 auto;\n min-width: 0;\n display: flex;\n flex-direction: column;\n gap: 2px;\n }\n [data-mobile-nav=\"home-row-title\"] {\n font-size: 16px;\n line-height: 21px;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n [data-mobile-nav=\"home-row-status\"] {\n color: var(--dsw-alias-label-secondary, rgba(0, 0, 0, .5));\n font-size: 12.5px;\n line-height: 17px;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n [data-mobile-nav=\"home-row-time\"] {\n flex: none;\n align-self: flex-start;\n color: var(--dsw-alias-label-tertiary, rgba(0, 0, 0, .4));\n font-size: 12.5px;\n line-height: 18px;\n }\n [data-mobile-nav=\"home-empty\"] {\n margin: 12px 16px;\n padding: 48px 24px;\n border-radius: 22px;\n /* Stands in for the rows, so it carries the rows' surface. */\n background: var(--dsw-specific-sidebar-fill, #f5f5f5);\n color: var(--dsw-alias-label-secondary, rgba(0, 0, 0, .5));\n font-size: 15px;\n text-align: center;\n }\n\n /* New-session FAB: a labeled pill (real-device round 2 follow-up), not a\n bare circle \u2014 tap starts in the shown workspace, long press picks\n one. Inverted-surface tokens (not a hardcoded accent color): the same\n pair the official git-commit button in dsh-better-sidebar uses for\n its own solid CTA. */\n [data-mobile-nav=\"home-fab\"] {\n position: absolute;\n right: 18px;\n bottom: calc(var(--mnav-sab) + 22px);\n z-index: 6;\n display: inline-flex;\n align-items: center;\n gap: 6px;\n height: 48px;\n padding: 0 20px 0 16px;\n border: none;\n border-radius: 999px;\n background: var(--dsw-alias-button-primary-fill, #1a1a1a);\n color: var(--dsw-alias-label-primary-inverted, #ffffff);\n font-family: inherit;\n font-size: 15px;\n font-weight: 600;\n cursor: pointer;\n box-shadow: 0 6px 20px rgba(0, 0, 0, .24);\n touch-action: manipulation;\n user-select: none;\n -webkit-user-select: none;\n -webkit-touch-callout: none;\n -webkit-tap-highlight-color: transparent;\n }\n [data-mobile-nav=\"home-fab\"]:active {\n transform: scale(.96);\n }\n\n /* Workspace sheet (switcher and long-press New Session share it). */\n [data-mobile-nav=\"home-sheet-layer\"] {\n position: absolute;\n inset: 0;\n z-index: 7;\n }\n [data-mobile-nav=\"home-sheet-mask\"] {\n position: absolute;\n inset: 0;\n background: var(--dsw-alias-bg-mask-3, rgba(0, 0, 0, .45));\n border: none;\n animation: dsh-mobile-nav-fade .18s var(--ds-ease-out, ease-in-out);\n }\n /* Docked to the screen edge, matching the composer's permission/model\n sheets (styles/composer.css.ts section 4) rather than floating.\n\n It used to sit at `bottom: calc(var(--mnav-sab) + 8px)` with all four\n corners rounded, which left a 42px strip of bare mask under it at\n sab: 34 (measured). Docking removes the strip instead of dimming it, and\n the safe area moves INSIDE the card as bottom padding \u2014 so the white\n card body runs all the way to the physical screen edge and the last row\n still clears the home indicator. Same reason the corners go top-only:\n a rounded bottom corner on a card flush with the screen edge reads as a\n rendering mistake. */\n [data-mobile-nav=\"home-sheet\"] {\n position: absolute;\n left: 0;\n right: 0;\n bottom: 0;\n max-height: 70%;\n overflow-y: auto;\n overscroll-behavior: contain;\n box-sizing: border-box;\n padding: 6px 6px calc(var(--mnav-sab) + 14px);\n border-radius: 20px 20px 0 0;\n /* layer-2, not bg-base: in dark mode the sheet must lift off a page that\n shares bg-base, or only the shadow separates them. */\n background: var(--dsw-alias-bg-layer-2, #ffffff);\n box-shadow: 0 -8px 32px rgba(0, 0, 0, .28);\n animation: dsh-mobile-nav-sheet-up .22s var(--ds-ease-out, ease-in-out);\n }\n @media (prefers-reduced-motion: reduce) {\n [data-mobile-nav=\"home-sheet-mask\"],\n [data-mobile-nav=\"home-sheet\"] {\n animation: none !important;\n }\n }\n [data-mobile-nav=\"home-sheet-title\"] {\n padding: 10px 12px 6px;\n color: var(--dsw-alias-label-secondary, rgba(0, 0, 0, .5));\n font-size: 13px;\n }\n [data-mobile-nav=\"home-sheet-item\"] {\n display: flex;\n align-items: center;\n width: 100%;\n min-height: 48px;\n padding: 0 12px;\n border: none;\n border-radius: 12px;\n background: transparent;\n color: inherit;\n font-family: inherit;\n font-size: 16px;\n text-align: left;\n cursor: pointer;\n touch-action: manipulation;\n -webkit-tap-highlight-color: transparent;\n }\n [data-mobile-nav=\"home-sheet-item\"][data-selected] {\n background: var(--dsw-alias-interactive-bg-hover, rgba(0, 0, 0, .06));\n font-weight: 600;\n }\n [data-mobile-nav=\"home-sheet-item\"]:active {\n background: var(--dsw-alias-interactive-bg-hover, rgba(0, 0, 0, .06));\n }\n\n /* --- hero fallback back button ---\n The hero (new blank session) page renders no conversation.session.header,\n so the header-slot back button (S2) does not exist there. This floating\n fallback covers that page and hides itself as soon as the real header\n back mounts. */\n [data-mobile-nav=\"hero-back\"] {\n position: absolute;\n top: calc(var(--mnav-sat) + 8px);\n left: 8px;\n z-index: 6;\n width: 44px;\n height: 44px;\n display: grid;\n place-items: center;\n border: none;\n border-radius: 14px;\n background: transparent;\n color: var(--dsw-alias-label-secondary, inherit);\n pointer-events: auto;\n }\n [data-mobile-nav=\"hero-back\"]:active {\n background: var(--dsw-alias-interactive-bg-hover, rgba(0, 0, 0, .06));\n }\n [data-mobile-nav=\"frame\"]:has([data-mobile-nav=\"header-back\"]) ~ [data-mobile-nav=\"hero-back\"],\n body:has([data-mobile-nav=\"header-back\"]) [data-mobile-nav=\"hero-back\"] {\n display: none;\n }\n}\n";
1
+ export declare const HOME_CSS = "/* ---------- phone app shell (< 768px) ---------- */\n\n@media (max-width: 767px) {\n /* --- the document never scrolls (S1.1, 2026-08-17) ---\n Real-device symptom: the workspace title bar, the session header, the\n composer and the FAB all slid with the finger \u2014 every fixed surface\n \"followed the drag\". They are not misplaced; the whole DOCUMENT was\n rubber-banding under them (they are absolute/in-flow inside the frame,\n so a document-level bounce moves them all as one).\n\n After the S2.1 box-sizing fix the document has no overflow at all\n (scrollHeight === clientHeight, measured with ?mobile-nav-inset=54), so\n this is not scrolling \u2014 it is iOS's elastic overscroll, which happens on\n an unscrollable document too, and which an inner scroller chains into as\n soon as it hits its own end.\n\n overscroll-behavior: none on the viewport kills both halves at once: the\n document itself gets no bounce, and overscroll chained up from the\n message flow / session list is absorbed without moving anything.\n overflow: hidden then hard-locks the document scroller so future content\n can never reintroduce a real scroll. Set on html AND body: the spec\n propagates the viewport's value from html, but engines have historically\n read body, and neither is a scroll container we ever want.\n\n Deliberately NOT position: fixed on body \u2014 the app shell does not need\n it, and it is the variant that strands iOS's fixed elements behind the\n on-screen keyboard. With plain overflow: hidden, iOS still pans the\n visual viewport to reveal a focused textarea, so the composer stays\n visible while typing without any visualViewport JS. */\n html,\n body {\n overflow: hidden !important;\n overscroll-behavior: none !important;\n }\n\n /* The message flow is the one scroller that regularly hits its end under a\n finger. Root-level `none` already absorbs the chain, but declaring it\n at the source keeps the guarantee if the root rule is ever weakened\n (the home list and both sheets already declare it).\n\n `none`, NOT `contain` (S4.1 fix, 2026-08-17). The two differ in exactly\n the way that bit us: `contain` stops overscroll from CHAINING OUT to the\n document but deliberately KEEPS this element's own local elastic bounce,\n while `none` suppresses that local bounce too. S1.1 only reasoned about\n the chain, so it picked `contain` \u2014 and the composer went on twitching\n upward on every drag-past-the-end while the header and FAB stayed put.\n\n Why only the composer moved: the official composer seat\n (`[class$=\"_composerSeat\"]`) is `position: sticky; bottom: 0` and lives\n INSIDE this scroller (measured 2026-08-17: seat 0,710 390x134 inside\n _scrollBody 0,131 390x713, contains() === true). A sticky box is laid out\n against its scroll container's content, so the container's own rubber-band\n drags it along. The header/FAB are absolute on the frame, outside this\n scroller entirely \u2014 which is precisely why S1.1's document-level fix\n pinned them and left this one surface behind.\n\n Deliberately NOT re-pinning the seat with position: fixed: sticky inside\n the scroller is what keeps the focused textarea visible when iOS pans the\n visual viewport for the keyboard, and fixed is the variant that strands\n it behind the keyboard (same trap as the body rule above). Kill the\n bounce, keep the sticky. */\n [data-phase] [class$=\"_scrollBody\"] {\n overscroll-behavior: none !important;\n }\n\n /* The official sidebar is no longer a drawer on a phone \u2014 the home screen\n replaced it. Hidden outright (not translated off-screen) so it cannot\n capture taps or hold layout. */\n [data-mobile-nav=\"frame\"] > :first-child {\n display: none !important;\n }\n /* The header's drawer toggle opened that sidebar; with it gone the button\n has nothing to open. (S2 owns the rest of the header layout \u2014\n styles/header.css.ts \u2014 including the Files button's replacement.) */\n [data-mobile-nav=\"toggle\"] {\n display: none !important;\n }\n\n /* --- level 1: the session list ---\n Renders inside the shell overlay layer (absolute, pointer-events: none),\n so the page re-enables pointer events for itself. The layer's containing\n block is the frame's padding box, which still starts under the status\n bar \u2014 hence the safe-area padding here. */\n [data-mobile-nav=\"home\"] {\n position: absolute;\n inset: 0;\n /* rc.3 raise (real-device report 2026-10-25 \"top strip leaking the\n conversation through\"): this shell layer mounts INSIDE the host's\n PIRFFq_overlayLayer (z-index:20, new in rc.3 \u2014 the conversation\n content itself moved under it too), so the old z:5 let host session\n content (STRONG/CODE rows measured at viewport y=4) paint over the\n shell's top bar on BOTH pages, reading as a faint fixed strip at the\n window top. z:30 puts the whole shell above everything the host\n stacks inside that layer; the shell's own transparent middle and\n pointer-events passthrough keep the conversation visible and tappable\n (verified live via console injection before landing). */\n z-index: 30;\n display: flex;\n flex-direction: column;\n pointer-events: auto;\n /* dsw-specific-sidebar-fill, not an alias bg-layer-* token (real-device\n round 2 follow-up, 2026-08-17): fetched and diffed the live theme\n CSS (both light/dark blocks in /assets/index-*.css) because computed\n values, not source-read guesses, are what actually matter here \u2014\n --dsw-alias-bg-base/-layer-1/-layer-2 all resolve to the exact same\n color in the LIGHT theme (neutral-bluish-00, i.e. plain white); they\n only diverge in dark mode.\n\n 2026-08-20: the page and the CARDS swapped tokens. This surface used\n to be --dsw-specific-sidebar-fill, which made the list page a\n different shade from the session page \u2014 measured on-device in dark\n theme, rgb(27,27,28) here against rgb(21,21,23) there, a visible step\n every time you opened a session. The page now takes bg-base, the same\n token the session page and <body> resolve to, so the two screens are\n literally the same colour; the cards took sidebar-fill in exchange, so\n the contrast that separates a row from the page is preserved \u2014 it\n just runs the other way (raised card on a base page, the more\n conventional reading of the two anyway). */\n background: var(--dsw-alias-bg-base, #ffffff);\n color: var(--dsw-alias-label-primary, inherit);\n padding-top: var(--mnav-sat);\n transform: translateX(0);\n opacity: 1;\n transition:\n transform .3s var(--ds-ease-in-out, ease-in-out),\n opacity .3s var(--ds-ease-in-out, ease-in-out);\n }\n /* Push transition: the list slides out to the left as the session takes\n the screen, and comes back from the left. It stays mounted (visibility,\n not display) so the slide has something to animate; the delayed\n visibility keeps it non-interactive the moment the transition ends. */\n [data-mobile-nav=\"home\"][data-view=\"session\"] {\n transform: translateX(-100%);\n opacity: 0;\n visibility: hidden;\n pointer-events: none;\n transition:\n transform .3s var(--ds-ease-in-out, ease-in-out),\n opacity .3s var(--ds-ease-in-out, ease-in-out),\n visibility 0s .3s;\n }\n /* The host's SESSION header must not sit on top of this list page.\n Real-device report (2026-10-22, DSH 0.2.0-rc.2, dsh-web-mobile 3.2.1,\n 360x792 phone): on the list page the top strip showed the LAST SESSION's\n header \u2014 its title plus the session's tab row \u2014 and the workspace switcher\n underneath was neither visible nor tappable, so \"switch workspace\" did\n nothing at all. Measured with elementFromPoint(150,30) on the phone\n viewport: span.wSkVaW_crumbCurrent, i.e. the host header's crumb, while\n our own workspace button sat at [46,8,208,44] underneath it.\n\n Why z-index is not the fix: this page is position:absolute; z-index:5\n inside the shell overlay layer, and the host header carries its own\n stacking context, so raising us above its z-index:30 changed nothing\n (measured: the crumb still won the hit test). The session header has to\n leave the hit tree while the list page is up \u2014 the list page draws its\n own top bar (home-top, with the workspace switcher).\n\n The gate is this page's own marker: data-view=\"session\" means a session\n is open, so the rule lapses exactly when the host header is wanted again\n (verified: entering a session restores display:grid, the back button in\n that header stays tappable, and going back hides it once more). Two\n selectors on purpose \u2014 the class suffix survives CSS-module hash renames,\n the structural one survives a rename of the class itself. */\n [data-mobile-nav=\"frame\"]:not([data-mobile-view=\"session\"]) header[class*=\"_header\"],\n [data-mobile-nav=\"frame\"]:not([data-mobile-view=\"session\"]) header:has([class*=\"_titleRow\"]),\n body:has([data-mobile-nav=\"home\"]:not([data-view=\"session\"])) [data-mobile-nav=\"frame\"] header[class*=\"_header\"],\n body:has([data-mobile-nav=\"home\"]:not([data-view=\"session\"])) [data-mobile-nav=\"frame\"] header:has([class*=\"_titleRow\"]) {\n display: none !important;\n }\n @media (prefers-reduced-motion: reduce) {\n [data-mobile-nav=\"home\"],\n [data-mobile-nav=\"home\"][data-view=\"session\"] {\n transition: none !important;\n }\n }\n\n /* Title bar: the workspace name IS the switcher. */\n [data-mobile-nav=\"home-top\"] {\n flex: 0 0 auto;\n display: flex;\n align-items: center;\n min-height: 52px;\n padding: 4px 16px 6px;\n }\n /* Site logo (real-device round 2, 2026-08-17): rendered only when\n document.head actually has a <link rel=\"icon\"> (MobileHome.tsx never\n ships a placeholder box), so this rule only ever needs to size the\n image, not reserve space for its absence. */\n [data-mobile-nav=\"home-logo\"] {\n width: 24px;\n height: 24px;\n margin-right: 6px;\n flex: none;\n border-radius: 6px;\n object-fit: contain;\n }\n /* Dark theme (real-device report, 2026-08-17): the runtime favicon is a\n dark-on-transparent whale mark, illegible on the dark page. Force a\n white silhouette regardless of the source image's own colors \u2014\n brightness(0) collapses every opaque pixel to black first, invert(1)\n then flips that to white; transparent pixels stay transparent either\n way. Same body[data-ds-dark-theme] marker as the home-row hairline\n above (AGENTS.md: prefers-color-scheme never fires, the app switches\n themes via this attribute with color-scheme hardcoded to light). */\n body[data-ds-dark-theme] [data-mobile-nav=\"home-logo\"] {\n filter: brightness(0) invert(1);\n }\n [data-mobile-nav=\"ws-switch\"] {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n min-height: 44px;\n max-width: 100%;\n padding: 0 6px 0 0;\n border: none;\n background: transparent;\n color: inherit;\n font-family: inherit;\n font-size: 22px;\n font-weight: 600;\n line-height: 1.2;\n cursor: pointer;\n touch-action: manipulation;\n -webkit-tap-highlight-color: transparent;\n }\n [data-mobile-nav=\"ws-switch\"] > span {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n [data-mobile-nav=\"ws-switch\"] > svg {\n flex: none;\n opacity: .55;\n }\n [data-mobile-nav=\"ws-switch\"]:active {\n opacity: .6;\n }\n\n /* Session list: rounded cards, not bordered rows (real-device round 2\n follow-up, 2026-08-17 \u2014 reference: Claude Code mobile app's session\n list). `gap` on the flex column IS the inter-card spacing; no\n per-row margin bookkeeping. */\n [data-mobile-nav=\"home-list\"] {\n flex: 1 1 auto;\n min-height: 0;\n margin: 0;\n display: flex;\n flex-direction: column;\n gap: 10px;\n padding: 12px 16px calc(var(--mnav-sab) + 96px);\n list-style: none;\n overflow-y: auto;\n overscroll-behavior: contain;\n -webkit-overflow-scrolling: touch;\n }\n /* Swipe-to-archive wrapper (redone 2026-08-25, real-device round): iOS-mail\n mechanics. The wrapper CLIPS (overflow hidden, same 22px radius as the\n card) and the archive button is parked past the right edge, sliding in\n lock-step with the card \u2014 a 1px drag reveals a 1px slice, never a\n fully-drawn button behind a gap. Clipping would eat the card's cast\n shadow, so the light-theme shadow moves up to this wrapper (identical\n values; the dark theme's INSET hairline on the card survives clipping\n untouched). pan-y keeps vertical list scrolling native; the direction\n lock in MobileHome.tsx decides horizontal-vs-vertical once per touch. */\n [data-mobile-nav=\"home-swipe\"] {\n position: relative;\n overflow: hidden;\n border-radius: 22px;\n /* The list is a flex column: without this, an overflowing list SHRINKS\n every row and the clip above slices the squashed card's bottom edge\n flat (real-device report, 2026-08-25). Rows keep natural height; the\n list scrolls. */\n flex: 0 0 auto;\n touch-action: pan-y;\n box-shadow: 0 1px 3px rgba(0, 0, 0, .06), 0 4px 12px rgba(0, 0, 0, .05);\n }\n body[data-ds-dark-theme] [data-mobile-nav=\"home-swipe\"] {\n box-shadow: none;\n }\n /* Press = settle toward the page (mirrors the card's own :active swap,\n which the clip made invisible at wrapper level). */\n [data-mobile-nav=\"home-swipe\"]:has([data-mobile-nav=\"home-row\"]:active) {\n box-shadow: 0 1px 2px rgba(0, 0, 0, .05);\n }\n body[data-ds-dark-theme] [data-mobile-nav=\"home-swipe\"]:has([data-mobile-nav=\"home-row\"]:active) {\n box-shadow: none;\n }\n [data-mobile-nav=\"home-swipe-card\"] {\n position: relative;\n z-index: 1;\n transition: transform .22s var(--ds-ease-out, ease-out);\n will-change: transform;\n }\n /* Inset pill, not a full-bleed slab (real-device feedback: hard edges).\n 5px breathing room on three sides inside the 88px reveal; its own\n radius echoes the card family. It still slides in lock-step from past\n the right edge (transform driven from MobileHome.tsx). */\n [data-mobile-nav=\"home-archive\"] {\n position: absolute;\n z-index: 0;\n top: 5px;\n bottom: 5px;\n right: 5px;\n width: 78px;\n border: none;\n border-radius: 17px;\n background: var(--dsw-alias-state-error-primary, #d4494c);\n color: #fff;\n font-size: 13px;\n font-weight: 600;\n cursor: pointer;\n -webkit-tap-highlight-color: transparent;\n transition: transform .22s var(--ds-ease-out, ease-out);\n will-change: transform;\n }\n [data-mobile-nav=\"home-archive\"]:active {\n filter: brightness(.9);\n }\n\n [data-mobile-nav=\"home-row\"] {\n display: flex;\n align-items: center;\n gap: 12px;\n width: 100%;\n min-height: 60px;\n padding: 14px 16px;\n border: none;\n border-radius: 22px;\n /* The page's old colour (see the swap note on [data-mobile-nav=\"home\"]):\n differs from bg-base in BOTH themes, and is the token\n dsh-better-sidebar's panel already uses for a secondary surface. */\n background: var(--dsw-specific-sidebar-fill, #f5f5f5);\n color: inherit;\n font-family: inherit;\n text-align: left;\n cursor: pointer;\n touch-action: manipulation;\n -webkit-tap-highlight-color: transparent;\n /* Card edge definition (2026-08-17). Light theme only \u2014 see the dark\n override below. Two stacked shadows in the iOS idiom: a tight 1px\n contact shadow that draws the edge itself, plus a wide soft one that\n lifts the card off the page. Both are deliberately weak (.06/.05):\n the page sits on --dsw-specific-sidebar-fill and the card on\n --dsw-alias-bg-base, so there is already a slight tonal step here and\n the shadow only has to sharpen it, not carry it alone. */\n box-shadow: 0 1px 3px rgba(0, 0, 0, .06), 0 4px 12px rgba(0, 0, 0, .05);\n }\n [data-mobile-nav=\"home-row\"]:active {\n background: var(--dsw-alias-interactive-bg-hover, rgba(0, 0, 0, .06));\n /* Press = settle toward the page. Dropping the wide shadow and keeping a\n tighter contact one reads as the card pushing in, which is what the\n darkening background already implies; leaving the lifted shadow under\n a pressed card is the combination that looks wrong. */\n box-shadow: 0 1px 2px rgba(0, 0, 0, .05);\n }\n /* Dark theme: a black shadow on a near-black page is invisible, so the\n edge is drawn instead of cast. A 1px hairline at --dsw-alias-border-l2\n weight, delivered as an INSET box-shadow rather than a real border so\n the card's geometry is untouched (a real 1px border would grow every\n row by 2px unless box-sizing cooperated) and so it overrides the light\n shadow through the same property instead of fighting it.\n\n Chosen over \"brighten the card face\" because in dark theme the card\n (--dsw-alias-bg-base, bluish-950) is already DARKER than the page\n (--dsw-specific-sidebar-fill, bluish-900); lightening the card past the\n page would invert the layering that the light theme establishes, while\n a hairline keeps both themes reading as \"page behind, card in front\".\n\n Theme is read from body[data-ds-dark-theme], never prefers-color-scheme:\n the app hardcodes color-scheme: light on <html> and switches themes with\n this attribute, so a media query would never fire (AGENTS.md). This\n selector also outranks the :active rule above (0,2,1 vs 0,2,0), so one\n declaration covers the pressed state too. */\n body[data-ds-dark-theme] [data-mobile-nav=\"home-row\"] {\n box-shadow: inset 0 0 0 1px var(--dsw-alias-border-l2, rgba(255, 255, 255, .12));\n }\n [data-mobile-nav=\"home-row\"][data-current] [data-mobile-nav=\"home-row-title\"] {\n font-weight: 600;\n }\n /* Avatar: a running/warning/done session shows its existing StateDot\n (same component, same semantics as the old inline dot \u2014 just bigger\n and re-homed); otherwise the title's own first character stands in\n for it, so every row has a mark even when idle. interactive-bg-hover,\n not a bg-layer-* token: same reason as the page background above \u2014\n bg-layer-2 is IDENTICAL to the card's own bg-base in light theme\n (verified against the live theme CSS), so it would render invisible\n there. interactive-bg-hover is a translucent rgba tint rather than a\n solid layer color, so it always reads as \"a shade over the card\" in\n both themes regardless of what the card's base color resolves to. */\n [data-mobile-nav=\"home-row-avatar\"] {\n flex: none;\n display: grid;\n place-items: center;\n width: 40px;\n height: 40px;\n border-radius: 12px;\n background: var(--dsw-alias-interactive-bg-hover, rgba(0, 0, 0, .06));\n color: var(--dsw-alias-label-secondary, rgba(0, 0, 0, .55));\n font-size: 16px;\n font-weight: 600;\n }\n [data-mobile-nav=\"home-row-body\"] {\n flex: 1 1 auto;\n min-width: 0;\n display: flex;\n flex-direction: column;\n gap: 2px;\n }\n [data-mobile-nav=\"home-row-title\"] {\n font-size: 16px;\n line-height: 21px;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n [data-mobile-nav=\"home-row-status\"] {\n color: var(--dsw-alias-label-secondary, rgba(0, 0, 0, .5));\n font-size: 12.5px;\n line-height: 17px;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n [data-mobile-nav=\"home-row-time\"] {\n flex: none;\n align-self: flex-start;\n color: var(--dsw-alias-label-tertiary, rgba(0, 0, 0, .4));\n font-size: 12.5px;\n line-height: 18px;\n }\n [data-mobile-nav=\"home-empty\"] {\n margin: 12px 16px;\n padding: 48px 24px;\n border-radius: 22px;\n /* Stands in for the rows, so it carries the rows' surface. */\n background: var(--dsw-specific-sidebar-fill, #f5f5f5);\n color: var(--dsw-alias-label-secondary, rgba(0, 0, 0, .5));\n font-size: 15px;\n text-align: center;\n }\n\n /* New-session FAB: a labeled pill (real-device round 2 follow-up), not a\n bare circle \u2014 tap starts in the shown workspace, long press picks\n one. Inverted-surface tokens (not a hardcoded accent color): the same\n pair the official git-commit button in dsh-better-sidebar uses for\n its own solid CTA. */\n [data-mobile-nav=\"home-fab\"] {\n position: absolute;\n right: 18px;\n bottom: calc(var(--mnav-sab) + 22px);\n z-index: 6;\n display: inline-flex;\n align-items: center;\n gap: 6px;\n height: 48px;\n padding: 0 20px 0 16px;\n border: none;\n border-radius: 999px;\n background: var(--dsw-alias-button-primary-fill, #1a1a1a);\n color: var(--dsw-alias-label-primary-inverted, #ffffff);\n font-family: inherit;\n font-size: 15px;\n font-weight: 600;\n cursor: pointer;\n box-shadow: 0 6px 20px rgba(0, 0, 0, .24);\n touch-action: manipulation;\n user-select: none;\n -webkit-user-select: none;\n -webkit-touch-callout: none;\n -webkit-tap-highlight-color: transparent;\n }\n [data-mobile-nav=\"home-fab\"]:active {\n transform: scale(.96);\n }\n\n /* Workspace sheet (switcher and long-press New Session share it). */\n [data-mobile-nav=\"home-sheet-layer\"] {\n position: absolute;\n inset: 0;\n z-index: 7;\n }\n [data-mobile-nav=\"home-sheet-mask\"] {\n position: absolute;\n inset: 0;\n background: var(--dsw-alias-bg-mask-3, rgba(0, 0, 0, .45));\n border: none;\n animation: dsh-mobile-nav-fade .18s var(--ds-ease-out, ease-in-out);\n }\n /* Docked to the screen edge, matching the composer's permission/model\n sheets (styles/composer.css.ts section 4) rather than floating.\n\n It used to sit at `bottom: calc(var(--mnav-sab) + 8px)` with all four\n corners rounded, which left a 42px strip of bare mask under it at\n sab: 34 (measured). Docking removes the strip instead of dimming it, and\n the safe area moves INSIDE the card as bottom padding \u2014 so the white\n card body runs all the way to the physical screen edge and the last row\n still clears the home indicator. Same reason the corners go top-only:\n a rounded bottom corner on a card flush with the screen edge reads as a\n rendering mistake. */\n [data-mobile-nav=\"home-sheet\"] {\n position: absolute;\n left: 0;\n right: 0;\n bottom: 0;\n max-height: 70%;\n overflow-y: auto;\n overscroll-behavior: contain;\n box-sizing: border-box;\n padding: 6px 6px calc(var(--mnav-sab) + 14px);\n border-radius: 20px 20px 0 0;\n /* layer-2, not bg-base: in dark mode the sheet must lift off a page that\n shares bg-base, or only the shadow separates them. */\n background: var(--dsw-alias-bg-layer-2, #ffffff);\n box-shadow: 0 -8px 32px rgba(0, 0, 0, .28);\n animation: dsh-mobile-nav-sheet-up .22s var(--ds-ease-out, ease-in-out);\n }\n @media (prefers-reduced-motion: reduce) {\n [data-mobile-nav=\"home-sheet-mask\"],\n [data-mobile-nav=\"home-sheet\"] {\n animation: none !important;\n }\n }\n [data-mobile-nav=\"home-sheet-title\"] {\n padding: 10px 12px 6px;\n color: var(--dsw-alias-label-secondary, rgba(0, 0, 0, .5));\n font-size: 13px;\n }\n [data-mobile-nav=\"home-sheet-item\"] {\n display: flex;\n align-items: center;\n width: 100%;\n min-height: 48px;\n padding: 0 12px;\n border: none;\n border-radius: 12px;\n background: transparent;\n color: inherit;\n font-family: inherit;\n font-size: 16px;\n text-align: left;\n cursor: pointer;\n touch-action: manipulation;\n -webkit-tap-highlight-color: transparent;\n }\n [data-mobile-nav=\"home-sheet-item\"][data-selected] {\n background: var(--dsw-alias-interactive-bg-hover, rgba(0, 0, 0, .06));\n font-weight: 600;\n }\n [data-mobile-nav=\"home-sheet-item\"]:active {\n background: var(--dsw-alias-interactive-bg-hover, rgba(0, 0, 0, .06));\n }\n\n /* --- hero fallback back button ---\n The hero (new blank session) page renders no conversation.session.header,\n so the header-slot back button (S2) does not exist there. This floating\n fallback covers that page and hides itself as soon as the real header\n back mounts. */\n [data-mobile-nav=\"hero-back\"] {\n position: absolute;\n top: calc(var(--mnav-sat) + 8px);\n left: 8px;\n z-index: 6;\n width: 44px;\n height: 44px;\n display: grid;\n place-items: center;\n border: none;\n border-radius: 14px;\n background: transparent;\n color: var(--dsw-alias-label-secondary, inherit);\n pointer-events: auto;\n }\n [data-mobile-nav=\"hero-back\"]:active {\n background: var(--dsw-alias-interactive-bg-hover, rgba(0, 0, 0, .06));\n }\n [data-mobile-nav=\"frame\"]:has([data-mobile-nav=\"header-back\"]) ~ [data-mobile-nav=\"hero-back\"],\n body:has([data-mobile-nav=\"header-back\"]) [data-mobile-nav=\"hero-back\"] {\n display: none;\n }\n}\n";
2
2
  //# sourceMappingURL=home.css.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"home.css.d.ts","sourceRoot":"","sources":["../../../../src/client/styles/home.css.ts"],"names":[],"mappings":"AAOA,eAAO,MAAM,QAAQ,s4sBA8hBpB,CAAA"}
1
+ {"version":3,"file":"home.css.d.ts","sourceRoot":"","sources":["../../../../src/client/styles/home.css.ts"],"names":[],"mappings":"AAOA,eAAO,MAAM,QAAQ,glyBAokBpB,CAAA"}
@@ -1,2 +1,2 @@
1
- export declare const LAYOUT_CSS = "/* ---------- mobile-only layout ---------- */\n\n@media (max-width: 1023px) {\n /* --- Phone chrome ---\n The system status bar stays visible (no fullscreen). Two adjustments\n make it behave:\n - touch-action: manipulation kills double-tap-to-zoom (and the 300ms\n tap delay) while keeping pan and pinch zoom; the client also\n suppresses legacy-iOS gesturestart as a fallback.\n - With the client's viewport-fit=cover, env(safe-area-inset-top) is the\n status bar / notch height; the rules below push the app content below\n it so the status bar never covers anything. Off notched phones (or in\n a normal browser tab where the layout viewport already sits below the\n status bar) the inset is 0 and nothing shifts. */\n html,\n body {\n touch-action: manipulation !important;\n }\n\n /* AppFrame: the drawer takes the sidebar column out of grid flow, so the\n remaining in-flow items (center, details) land in tracks 1..2: give the\n center every pixel and keep the details track at zero. The top padding\n clears the status bar / notch for every in-flow surface (session header,\n messages, composer); the absolutely-positioned drawer is unaffected (its\n containing block is the frame's padding box, i.e. still the frame top). */\n /* box-sizing: border-box is load-bearing (S2.1, 2026-08-17). The official\n frame carries height: 100% with the default content-box, so the\n safe-area padding ADDED 54px to its height instead of taking 54px out\n of the content area: the frame grew past the viewport, the document\n became scrollable by exactly the inset, and the very first scroll put\n the header right back under the notch \u2014 measured with\n ?mobile-nav-inset=54 (frame 898px tall inside an 844px root, html at\n y=-54). Invisible on every desktop browser because the inset is 0\n there, which is how it shipped. */\n [data-mobile-nav=\"frame\"] {\n position: relative !important;\n box-sizing: border-box !important;\n grid-template-columns: minmax(0, 1fr) 0 0 !important;\n padding-top: var(--mnav-sat) !important;\n }\n\n /* The sidebar column (first grid child) becomes a left drawer. The drawer\n hugs the sidebar content exactly (the wide sidebar carries an inline\n width, ~280px): a fixed 92vw box would leave a white strip where the\n container background shows beside the content.\n Closed state: translateX(-110%) \u2014 more than -100% of the max-content\n width \u2014 guarantees the whole drawer (and its shadow, had it one) leaves\n the viewport. A mere -100% leaves a sliver on screen; -105% (as used\n before) left 14px of the drawer plus a long 32px-blur shadow gradient\n visible along the left edge of the main UI. No box-shadow at all: the\n dimmed backdrop already separates drawer from content. */\n [data-mobile-nav=\"frame\"] > :first-child {\n position: absolute !important;\n inset: 0 auto 0 0 !important;\n width: max-content !important;\n max-width: 92vw !important;\n z-index: 40 !important;\n transform: translateX(-110%);\n transition: transform .28s var(--ds-ease-in-out, ease-in-out);\n background: var(--dsw-alias-bg-base, #ffffff);\n /* Keep the drawer's own content below the status bar / notch: the drawer\n spans the full frame height (its absolute containing block is the\n frame's padding box, so the frame's own safe-area padding does NOT\n reach it). The drawer background paints the status-bar strip, which\n the client's theme-color meta matches, so the strip reads seamless. */\n padding-top: var(--mnav-sat) !important;\n /* Kill the official sidebarCol right border: with the backdrop the edge\n reads cleanly, and the settings dialog (width:100% of this box) stays\n pixel-flush with the drawer. */\n border-right: none !important;\n }\n\n /* The official right sidebar (DSH 0.1.5+) in its full-screen mode \u2014 the\n one the phone's header sidebar button opens (sidebar-panels.ts). The\n host promotes the panel to position:fixed; inset:0 there, so exactly\n like the drawer above it escapes the frame's safe-area padding and its\n tab strip + chrome buttons landed under the status bar (real-device\n report, 2026-09-21). Both insets: the status bar / notch on top, the\n home indicator at the bottom. Padding, no box-sizing change: fixed\n with both top and bottom set resolves its used height from the\n containing block minus padding (CSS 2.1 10.6.4), so the content box\n shrinks by itself \u2014 the same reasoning the legacy better-sidebar panel\n rule in compat.css.ts spells out. `fullscreen` is the host's own\n attribute value (`push` while docked, dsh-client-ui-sidebar-right), so\n the docked panel is untouched; a manual full-screen on desktop is\n outside this media block anyway. Verify with ?mobile-nav-inset=54,34 \u2014\n env() is 0 in every desktop browser. */\n [data-sidebar-right-panel=\"fullscreen\"] {\n padding-top: var(--mnav-sat) !important;\n padding-bottom: var(--mnav-sab) !important;\n }\n\n /* Expanded state (frame without data-sidebar-collapsed) slides the drawer in.\n The open state must be transform:none \u2014 NOT translateX(0): an identity\n transform still makes the drawer the containing block for fixed-position\n descendants (the settings dialog's .VOzbGW_overlay is portaled into the\n sidebar DOM). With the identity transform the wide settings sheet\n (100vw-16) overflows the 280px drawer, the dialog's focus scrolls the\n overflow:hidden drawer to scrollLeft=102, and every static child (plus the\n fixed overlay) shifts 102px off-screen. With transform:none the overlay is\n viewport-anchored: it dims the full screen and the sheet sits at left:8. */\n [data-mobile-nav=\"frame\"]:not([data-sidebar-collapsed]) > :first-child {\n transform: none !important;\n }\n\n /* Drag handles are useless on touch and would float over the drawer. */\n [data-side=\"sidebar\"],\n [data-side=\"details\"] {\n display: none !important;\n }\n\n /* --- Conversation text on mobile ---\n The official message flow keeps desktop's 32px side gutters and 16px\n type. On a phone: shrink the type a notch and widen the lines by\n trimming the gutters (the sidebar drawer list keeps its size). The\n flow's scroll container is the only _scroll element holding markdown\n <p> paragraphs \u2014 the composer's own scroll (textarea) is excluded\n via :has(p). */\n /* The official main scroll body reserves scrollbar-gutter for desktop\n scrollbars (8px), which shoves every column off-center on a phone.\n Classic desktop scrollbars (Edge/Chrome) also occupy ~8-17px in a\n phone-sized viewport, shifting the column further. Mobile scrolling\n is touch/wheel, so remove the scrollbar entirely on phones: the\n column is then exactly centered in every browser. */\n [data-phase] [class$=\"_scrollBody\"] {\n scrollbar-gutter: auto !important;\n scrollbar-width: none !important;\n }\n [data-phase] [class$=\"_scrollBody\"]::-webkit-scrollbar {\n display: none !important;\n width: 0 !important;\n height: 0 !important;\n }\n /* Message action rows (copy / run-time badges) can overflow the right\n edge on narrow screens \u2014 keep them inside the message width. */\n [data-phase] [class$=\"_actions\"] {\n overflow: hidden !important;\n }\n [data-phase] [class$=\"_actions\"] [class$=\"_timeEnd\"] {\n flex: 0 1 auto !important;\n min-width: 0 !important;\n overflow: hidden !important;\n text-overflow: ellipsis !important;\n white-space: nowrap !important;\n }\n\n [data-phase] [class$=\"_scroll\"]:has(p) {\n padding-left: 20px !important;\n padding-right: 20px !important;\n font-size: 15px !important;\n }\n /* The official markdown styles set an explicit 16px on paragraphs and\n list items, so the container's inherited 15px is not enough. User\n messages render their text in a div whose class carries _text_\n (16px too) \u2014 cover it as well. */\n [data-phase] [class$=\"_scroll\"]:has(p) p,\n [data-phase] [class$=\"_scroll\"]:has(p) li,\n [data-phase] [class$=\"_scroll\"]:has(p) [class*=\"_text_\"] {\n font-size: 15px !important;\n }\n\n /* Markdown tables: the official table uses width:max-content, so on a phone\n it hugs the content and leaves dead space beside/inside the table. Force\n the table to fill the message column and let the table wrapper handle\n overflow if a cell is genuinely too wide. */\n [data-phase] table {\n width: 100% !important;\n max-width: 100% !important;\n }\n [data-phase] th,\n [data-phase] td {\n max-width: none !important;\n min-width: 0 !important;\n }\n\n /* User bubbles: the official stack is capped at min(525px, 82%), which on a\n phone leaves a large blank strip on the left and pushes the bubble high.\n On mobile let the user message fill the same full width as assistant\n messages (the bubble background then spans the whole message column). */\n [data-phase] [class$=\"_userStack\"],\n [data-phase] [class$=\"_userStack\"] [class$=\"_bubble\"] {\n box-sizing: border-box !important;\n width: fit-content !important;\n max-width: 100% !important;\n }\n\n /* --- Composer bottom row on mobile ---\n The official row gives the model pill (trailing) flex:0 0 auto, which\n squeezes the agent-permission pill (modes) down to 15px: the pill's\n chevron then overflows on top of the model name. Let the permission\n pill keep its natural width and let the model pill shrink instead.\n Anchored by the composer card (:has(textarea)): row = the _row class\n containing a _trailing group, tools = its first child, permission pill\n = its 2nd child, model pill = the _trailing group.\n NOTE: do NOT anchor these by the card's :last-child \u2014 a client effect\n moves the git-graph branch chip INTO the card, which becomes the card's\n new last child and silently disables every :last-child rule (the model\n pill then falls back to the official fixed layout and long model IDs\n overflow instead of ellipsizing). Structural anchors only. */\n /* The official row pads every group with 12px gaps, which on a phone eats\n width the model pill needs for the full model ID. Tighten the row to 8px\n gaps (the modes pill keeps its natural width) so the model name gets\n every spare pixel. */\n [data-phase] [class*=\"_card\"]:has(textarea) [class$=\"_row\"]:has([class$=\"_trailing\"]) {\n gap: 8px !important;\n }\n [data-phase] [class*=\"_card\"]:has(textarea) [class$=\"_row\"]:has([class$=\"_trailing\"]) > :first-child {\n gap: 8px !important;\n }\n [data-phase] [class*=\"_card\"]:has(textarea) [class$=\"_row\"]:has([class$=\"_trailing\"]) > :first-child > :nth-child(2) {\n flex: 0 0 auto !important;\n gap: 8px !important;\n }\n [data-phase] [class*=\"_card\"]:has(textarea) [class$=\"_trailing\"] {\n flex: 1 1 auto !important;\n gap: 8px !important;\n min-width: 0 !important;\n }\n /* Let the model selector take the free space in the trailing group so the\n model name is not squeezed/truncated; the context meter stays fixed. */\n [data-phase] [class*=\"_card\"]:has(textarea) [class$=\"_root\"]:has(> [class$=\"_trigger\"][aria-haspopup=\"menu\"]) {\n flex: 1 1 auto !important;\n min-width: 0 !important;\n }\n [data-phase] [class*=\"_card\"]:has(textarea) [class$=\"_root\"]:has(> [class$=\"_trigger\"][aria-haspopup=\"menu\"]) > [class$=\"_trigger\"] {\n width: 100% !important;\n max-width: 100% !important;\n }\n /* The model label must absorb the trigger's free width: officially it is a\n fixed-content flex item, so the spare width of a grown pill sits unused\n between the chevron and the pill edge. Let the label grow and shrink:\n the full model ID shows whenever the row can fit it, and the ellipsis\n lands exactly at the available width otherwise. */\n [data-phase] [class*=\"_card\"]:has(textarea) [class$=\"_root\"]:has(> [class$=\"_trigger\"][aria-haspopup=\"menu\"]) > [class$=\"_trigger\"] > [class$=\"_triggerLabel\"] {\n flex: 1 1 auto !important;\n min-width: 0 !important;\n }\n [data-phase] [class*=\"_card\"]:has(textarea) [class$=\"_root\"]:has(> [class$=\"_trigger\"]:not([aria-haspopup=\"menu\"])) {\n flex: 0 0 auto !important;\n }\n\n /* Model switcher menu: the official dropdown is right-aligned to the\n trigger (right:0). The model pill sits near the center of the composer,\n so on a phone the 240px menu overflows the left edge and looks off-center.\n Center the menu on the trigger instead. */\n [data-phase] [class*=\"_card\"]:has(textarea) [class$=\"_root\"]:has(> [class$=\"_trigger\"]) > [class$=\"_menu\"] {\n left: 50% !important;\n right: auto !important;\n transform: translateX(-50%) !important;\n }\n\n /* --- Session header on mobile ---\n Layout goal: [toggle] [session title] [mode badge] in a row, with the\n Session log capsule removed from the header (relocated to the drawer\n footer). Stable structural hooks only:\n [data-phase] header the session header element\n header > :first-child titleRow (titleCluster + utilities)\n header > :first-child > :last-child headerUtilities (Session log seat) */\n [data-phase] header {\n padding-right: 12px !important;\n }\n /* Give the title row a lane clear of the absolutely-placed toggle, then\n balance the header: with header padding-right 12px, a 20px left\n padding puts the title's geometric center exactly on the viewport\n center (measured 195/195 at 390px). */\n [data-phase] header > :first-child {\n padding-left: 20px !important;\n }\n /* The directory toggle sits at the far left of the header (the header\n is position:relative; the data-slot wrappers are display:contents). */\n [data-mobile-nav=\"toggle\"] {\n position: absolute !important;\n left: 8px !important;\n top: 12px !important;\n z-index: 2 !important;\n }\n /* The Files action stays in-flow inside headerActions. On mobile headerActions\n does not expand to fill the row: it is pushed to the right edge and keeps\n its content size, so [mode] [subagent/jobs] [files] sit close together\n with the normal 8px gaps \u2014 compact, no artificial blank columns. Explicit\n flex order keeps Files rightmost regardless of DOM order. */\n [data-mobile-nav=\"files\"] {\n position: static !important;\n left: auto !important;\n right: auto !important;\n top: auto !important;\n z-index: auto !important;\n }\n [data-phase] header [class$=\"_headerActions\"] {\n flex: 0 1 auto !important;\n min-width: 0 !important;\n margin-left: auto !important;\n justify-content: flex-end !important;\n }\n /* The session title/crumb must yield space on mobile so the mode label and\n subagent cluster are not squeezed to a single letter. Cap it at ~24vw and\n let it truncate with ellipsis. */\n [data-phase] header [class$=\"_crumbs\"] {\n flex: 0 1 auto !important;\n min-width: 0 !important;\n max-width: 24vw !important;\n }\n /* Mode label (AgentPresetLabel): the official pill uses inline-flex, whose\n direct text node is only clipped \u2014 no ellipsis. Convert the pill to a\n block container, keep its icon absolutely positioned on the left, and let\n it size naturally up to 42vw so the mode name stays readable while the\n subagent/Files cluster still fits on a phone. */\n [data-phase] header [class$=\"_label\"]:has(> svg) {\n order: 1 !important;\n flex: 0 1 auto !important;\n min-width: 0 !important;\n max-width: 42vw !important;\n display: block !important;\n position: relative !important;\n box-sizing: border-box !important;\n padding-left: 18px !important;\n padding-right: 2px !important;\n overflow: hidden !important;\n text-overflow: ellipsis !important;\n white-space: nowrap !important;\n }\n [data-phase] header [class$=\"_label\"]:has(> svg) > svg {\n position: absolute !important;\n left: 0 !important;\n top: 50% !important;\n transform: translateY(-50%) !important;\n }\n /* Subagent/jobs helpers: keep their triggers on one line and never let the\n row grow artificial empty space. */\n [data-phase] header [class$=\"_root\"]:has(> button[class$=\"_trigger\"]) {\n order: 2 !important;\n flex: 0 0 auto !important;\n min-width: max-content !important;\n max-width: none !important;\n white-space: nowrap !important;\n /* On mobile the popover is anchored to the header (viewport-width\n containing block) instead of the trigger, so a small left inset keeps it\n fully on screen and never clips the tree's status dots. */\n position: static !important;\n }\n [data-phase] header [class$=\"_root\"]:has(> button[class$=\"_trigger\"]) > button,\n [data-phase] header [class$=\"_root\"]:has(> button[class$=\"_trigger\"]) > button * {\n white-space: nowrap !important;\n }\n [data-phase] header [data-mobile-nav=\"files\"] {\n order: 3 !important;\n flex: 0 0 auto !important;\n }\n /* Session log download: gone from the header row on mobile (the utilities\n seat holds only the session-log-export capsule). */\n [data-phase] header > :first-child > :last-child {\n display: none !important;\n }\n\n /* --- Header popovers on mobile (dsh-client-ui-jobs / dsh-client-ui-subagent) ---\n The official entries sit in the session header actions. Their popovers\n are anchored to the trigger's LEFT edge (left: 0), so from a right-edge\n trigger the 336px panel spills past the viewport. Re-anchor them to the\n trigger's right edge instead. The popover classes are hashed CSS-module\n names, so target them by the stable _menu suffix inside the header. */\n /* Header popovers on mobile: anchor to the left edge with a small inset and\n clamp the width, instead of right-aligning to a trigger near the right\n edge (which pushed the panel left off-screen and clipped the status dots).\n Also cap the height so the panel does not run into the composer/task bar. */\n [data-phase] header [class$=\"_menu\"] {\n left: 8px !important;\n right: auto !important;\n width: min(336px, calc(100vw - 16px)) !important;\n max-width: none !important;\n max-height: min(420px, calc(100dvh - 120px)) !important;\n }\n /* --- Settings dialog on mobile ---\n Desktop: 800px two-column flex (188px nav + content). Mobile: a\n near-full-width sheet \u2014 nav tabs wrap into rows on top, option rows\n stay horizontal (title+description left, control right). Structural\n selectors are scoped to the unique aria-modal dialog; every\n settings-specific rule is gated with\n :has(> :first-child > :last-child > button) \u2014 the settings nav tab\n list holds <button> tabs, so the transient export dialog (the same\n primitives Modal, header(title+close)+description+body) keeps its\n official centered card layout. Requires :has() support\n (Chromium 105+, 2022).\n\n The directory picker (dsh-client-ui-directory-picker-browse) must be\n excluded too: its footer bar holds <button> children AND its breadcrumb\n trail (role=\"navigation\") \u2014 which the role gate relies on to exclude\n it \u2014 is REPLACED by the path input in edit mode (pencil button), so\n without the ZuhsRW exclusion clicking the pencil would suddenly match\n this sheet rule: the dialog jumps to the top of the screen, the header\n (with the path input) is hidden by the > :first-child > :first-child\n display:none rule below, and the user can no longer type a path\n (issue #12, 2026-08-16). The picker family keeps the official layout\n on mobile in every mode. */\n [aria-modal=\"true\"]:has(> :first-child > :last-child > button):not(:has([role=\"navigation\"])):not(:has([class*=\"ZuhsRW\"])) {\n position: absolute !important;\n left: 8px !important;\n /* Fixed top (no translateY): a transform on the panel combined with the\n panel overflowing the max-content drawer shifts the fixed overlay's\n coordinate frame, dragging the whole sidebar content off-screen. The\n safe-area inset keeps the sheet below the status bar / notch. */\n top: calc(var(--mnav-sat) + 12px) !important;\n width: calc(100vw - 16px) !important;\n max-width: calc(100vw - 16px) !important;\n /* Height follows the content (no dead space under a short page); it\n caps at 100dvh-24 (less the safe-area top) and the options area\n scrolls only then. */\n height: auto !important;\n max-height: min(800px, calc(100vh - 24px - var(--mnav-sat))) !important;\n max-height: min(800px, calc(100dvh - 24px - var(--mnav-sat))) !important;\n flex-direction: column !important;\n border-radius: 14px !important;\n animation: dsh-mobile-nav-sheet-in .22s var(--ds-ease-out, ease-in-out);\n }\n /* The settings sheet's dimmed mask fades in with the panel (the mask is\n the first child of the overlay that directly contains the sheet). */\n :has(> [aria-modal=\"true\"]:has(> :first-child > :last-child > button):not(:has([role=\"navigation\"])):not(:has([class*=\"ZuhsRW\"]))) > :first-child {\n animation: dsh-mobile-nav-fade .18s var(--ds-ease-out, ease-in-out);\n }\n @media (prefers-reduced-motion: reduce) {\n [aria-modal=\"true\"]:has(> :first-child > :last-child > button):not(:has([role=\"navigation\"])):not(:has([class*=\"ZuhsRW\"])),\n :has(> [aria-modal=\"true\"]:has(> :first-child > :last-child > button):not(:has([role=\"navigation\"])):not(:has([class*=\"ZuhsRW\"]))) > :first-child {\n animation: none !important;\n }\n }\n /* The export dialog (not the settings sheet) must never overflow the\n viewport: the official centered card can be wider than 390px.\n :not([data-mobile-nav=\"info-sheet\"]) (S4, 2026-08-17): the session-info\n sheet also carries role=\"dialog\" aria-modal=\"true\" (correct a11y\n semantics for a bottom sheet with a scrim) and has no button as its\n first-child's last-child, so without this exclusion it silently matched\n this generic selector too \u2014 measured 358px (100vw-32px) instead of the\n 374px its own left:8px/right:8px margins specify. Same category of bug\n as the ZuhsRW directory-picker collision below; same fix shape.\n :not([data-mobile-nav=\"share-range-sheet\"]) (share-image, 2026-09-10):\n the share range picker rides the same role=\"dialog\" aria-modal bottom\n -sheet shape and the same margins, so it hit the identical clamp. */\n [aria-modal=\"true\"]:not(:has(> :first-child > :last-child > button)):not([data-mobile-nav=\"info-sheet\"]):not([data-mobile-nav=\"share-range-sheet\"]) {\n max-width: calc(100vw - 32px) !important;\n }\n /* Nav bar: hide the \"Settings\" caption (redundant on a full-width sheet)\n and wrap the tab list so every tab is visible \u2014 a horizontal scroll cut\n the last tab (\"Plugins\") off with no affordance to scroll. */\n [aria-modal=\"true\"]:has(> :first-child > :last-child > button):not(:has([role=\"navigation\"])):not(:has([class*=\"ZuhsRW\"])) > :first-child {\n width: 100% !important;\n flex-direction: row !important;\n align-items: center !important;\n gap: 6px !important;\n padding: 10px 12px 8px !important;\n }\n [aria-modal=\"true\"]:has(> :first-child > :last-child > button):not(:has([role=\"navigation\"])):not(:has([class*=\"ZuhsRW\"])) > :first-child > :first-child {\n display: none !important;\n }\n /* The tab list scrolls in the space left by the toolbar: the toolbar\n (config file + close) is reparented INTO this nav row by a client\n effect (MobileNavOverlay), so the tab list must be anchored by its\n class, NOT by :last-child (the reparented toolbar becomes the nav's\n new last child). */\n [aria-modal=\"true\"]:has(> :first-child > :last-child > button):not(:has([role=\"navigation\"])):not(:has([class*=\"ZuhsRW\"])) > :first-child [class$=\"_navList\"] {\n flex: 1 1 auto !important;\n min-width: 0 !important;\n flex-direction: row !important;\n flex-wrap: wrap !important;\n gap: 6px !important;\n overflow: visible !important;\n }\n /* Content toolbar (Open configuration file + close): grouped flush to\n the right edge, and reparented INTO the nav row on mobile so it shares\n one line with the tabs (user feedback 2026-08-16 \u2014 the toolbar's own\n row left a full-width dead gap under the tabs). Anchored by class: the\n header leaves the content subtree, so :first-child/:last-child anchors\n would now hit the options area. Children carry official auto-margins\n that would defeat flex-end, so neutralize them. The close button gets\n a round tappable base so it reads as its own control, not part of the\n outline button. */\n [aria-modal=\"true\"]:has(> :first-child > :last-child > button):not(:has([role=\"navigation\"])):not(:has([class*=\"ZuhsRW\"])) [class$=\"_header\"] {\n flex: 0 0 auto !important;\n justify-content: flex-end !important;\n align-items: center !important;\n gap: 8px !important;\n padding: 0 0 0 4px !important;\n min-height: 40px !important;\n }\n [aria-modal=\"true\"]:has(> :first-child > :last-child > button):not(:has([role=\"navigation\"])):not(:has([class*=\"ZuhsRW\"])) [class$=\"_header\"] > * {\n margin-left: 0 !important;\n margin-right: 0 !important;\n }\n [aria-modal=\"true\"]:has(> :first-child > :last-child > button):not(:has([role=\"navigation\"])):not(:has([class*=\"ZuhsRW\"])) [class$=\"_header\"] > :last-child {\n width: 32px !important;\n height: 32px !important;\n border-radius: 50% !important;\n display: inline-flex !important;\n align-items: center !important;\n justify-content: center !important;\n background: var(--dsw-alias-interactive-bg-hover, rgba(0, 0, 0, .06)) !important;\n }\n /* Appearance mode cards: the official cube row renders three tall\n vertical cards (~268px) that eat half the sheet. Turn them into a\n compact horizontal trio (icon + label inline, equal widths).\n Relies on the official cube-row class name of this version. */\n [aria-modal=\"true\"] [class$=\"_cubeRow\"] {\n gap: 6px !important;\n }\n [aria-modal=\"true\"] [class$=\"_cubeRow\"] > * {\n flex: 1 1 0 !important;\n flex-direction: row !important;\n align-items: center !important;\n justify-content: center !important;\n gap: 6px !important;\n padding: 10px 8px !important;\n min-height: 0 !important;\n }\n /* Content: the options scroll area gets bottom breathing room so the last\n row never sits flush against the sheet's rounded corner. */\n [aria-modal=\"true\"]:has(> :first-child > :last-child > button):not(:has([role=\"navigation\"])):not(:has([class*=\"ZuhsRW\"])) > :last-child {\n flex: 1 1 auto !important;\n min-height: 0 !important;\n }\n [aria-modal=\"true\"]:has(> :first-child > :last-child > button):not(:has([role=\"navigation\"])):not(:has([class*=\"ZuhsRW\"])) > :last-child > :last-child {\n padding: 0 12px 24px !important;\n }\n";
1
+ export declare const LAYOUT_CSS = "/* ---------- mobile-only layout ---------- */\n\n@media (max-width: 1023px) {\n /* --- Phone chrome ---\n The system status bar stays visible (no fullscreen). Two adjustments\n make it behave:\n - touch-action: manipulation kills double-tap-to-zoom (and the 300ms\n tap delay) while keeping pan and pinch zoom; the client also\n suppresses legacy-iOS gesturestart as a fallback.\n - With the client's viewport-fit=cover, env(safe-area-inset-top) is the\n status bar / notch height; the rules below push the app content below\n it so the status bar never covers anything. Off notched phones (or in\n a normal browser tab where the layout viewport already sits below the\n status bar) the inset is 0 and nothing shifts. */\n html,\n body {\n touch-action: manipulation !important;\n }\n\n /* AppFrame: the drawer takes the sidebar column out of grid flow, so the\n remaining in-flow items (center, details) land in tracks 1..2: give the\n center every pixel and keep the details track at zero. The top padding\n clears the status bar / notch for every in-flow surface (session header,\n messages, composer); the absolutely-positioned drawer is unaffected (its\n containing block is the frame's padding box, i.e. still the frame top). */\n /* box-sizing: border-box is load-bearing (S2.1, 2026-08-17). The official\n frame carries height: 100% with the default content-box, so the\n safe-area padding ADDED 54px to its height instead of taking 54px out\n of the content area: the frame grew past the viewport, the document\n became scrollable by exactly the inset, and the very first scroll put\n the header right back under the notch \u2014 measured with\n ?mobile-nav-inset=54 (frame 898px tall inside an 844px root, html at\n y=-54). Invisible on every desktop browser because the inset is 0\n there, which is how it shipped. */\n [data-mobile-nav=\"frame\"] {\n position: relative !important;\n box-sizing: border-box !important;\n grid-template-columns: minmax(0, 1fr) 0 0 !important;\n padding-top: var(--mnav-sat) !important;\n }\n\n /* The sidebar column (first grid child) becomes a left drawer. The drawer\n hugs the sidebar content exactly (the wide sidebar carries an inline\n width, ~280px): a fixed 92vw box would leave a white strip where the\n container background shows beside the content.\n Closed state: translateX(-110%) \u2014 more than -100% of the max-content\n width \u2014 guarantees the whole drawer (and its shadow, had it one) leaves\n the viewport. A mere -100% leaves a sliver on screen; -105% (as used\n before) left 14px of the drawer plus a long 32px-blur shadow gradient\n visible along the left edge of the main UI. No box-shadow at all: the\n dimmed backdrop already separates drawer from content. */\n [data-mobile-nav=\"frame\"] > :first-child {\n position: absolute !important;\n inset: 0 auto 0 0 !important;\n width: max-content !important;\n max-width: 92vw !important;\n z-index: 40 !important;\n transform: translateX(-110%);\n transition: transform .28s var(--ds-ease-in-out, ease-in-out);\n background: var(--dsw-alias-bg-base, #ffffff);\n /* Keep the drawer's own content below the status bar / notch: the drawer\n spans the full frame height (its absolute containing block is the\n frame's padding box, so the frame's own safe-area padding does NOT\n reach it). The drawer background paints the status-bar strip, which\n the client's theme-color meta matches, so the strip reads seamless. */\n padding-top: var(--mnav-sat) !important;\n /* Kill the official sidebarCol right border: with the backdrop the edge\n reads cleanly, and the settings dialog (width:100% of this box) stays\n pixel-flush with the drawer. */\n border-right: none !important;\n }\n\n /* The official right sidebar (DSH 0.1.5+) in its full-screen mode \u2014 the\n one the phone's header sidebar button opens (sidebar-panels.ts). The\n host promotes the panel to position:fixed; inset:0 there, so exactly\n like the drawer above it escapes the frame's safe-area padding and its\n tab strip + chrome buttons landed under the status bar (real-device\n report, 2026-09-21). Both insets: the status bar / notch on top, the\n home indicator at the bottom. Padding, no box-sizing change: fixed\n with both top and bottom set resolves its used height from the\n containing block minus padding (CSS 2.1 10.6.4), so the content box\n shrinks by itself \u2014 the same reasoning the legacy better-sidebar panel\n rule in compat.css.ts spells out. `fullscreen` is the host's own\n attribute value (`push` while docked, dsh-client-ui-sidebar-right), so\n the docked panel is untouched; a manual full-screen on desktop is\n outside this media block anyway. Verify with ?mobile-nav-inset=54,34 \u2014\n env() is 0 in every desktop browser. */\n [data-sidebar-right-panel=\"fullscreen\"] {\n padding-top: var(--mnav-sat) !important;\n padding-bottom: var(--mnav-sab) !important;\n }\n\n /* Expanded state (frame without data-sidebar-collapsed) slides the drawer in.\n The open state must be transform:none \u2014 NOT translateX(0): an identity\n transform still makes the drawer the containing block for fixed-position\n descendants (the settings dialog's .VOzbGW_overlay is portaled into the\n sidebar DOM). With the identity transform the wide settings sheet\n (100vw-16) overflows the 280px drawer, the dialog's focus scrolls the\n overflow:hidden drawer to scrollLeft=102, and every static child (plus the\n fixed overlay) shifts 102px off-screen. With transform:none the overlay is\n viewport-anchored: it dims the full screen and the sheet sits at left:8. */\n [data-mobile-nav=\"frame\"]:not([data-sidebar-collapsed]) > :first-child {\n transform: none !important;\n }\n\n /* Drag handles are useless on touch and would float over the drawer. */\n [data-side=\"sidebar\"],\n [data-side=\"details\"] {\n display: none !important;\n }\n\n /* --- Conversation text on mobile ---\n The official message flow keeps desktop's 32px side gutters and 16px\n type. On a phone: shrink the type a notch and widen the lines by\n trimming the gutters (the sidebar drawer list keeps its size). The\n flow's scroll container is the only _scroll element holding markdown\n <p> paragraphs \u2014 the composer's own scroll (textarea) is excluded\n via :has(p). */\n /* The official main scroll body reserves scrollbar-gutter for desktop\n scrollbars (8px), which shoves every column off-center on a phone.\n Classic desktop scrollbars (Edge/Chrome) also occupy ~8-17px in a\n phone-sized viewport, shifting the column further. Mobile scrolling\n is touch/wheel, so remove the scrollbar entirely on phones: the\n column is then exactly centered in every browser. */\n [data-phase] [class$=\"_scrollBody\"] {\n scrollbar-gutter: auto !important;\n scrollbar-width: none !important;\n }\n [data-phase] [class$=\"_scrollBody\"]::-webkit-scrollbar {\n display: none !important;\n width: 0 !important;\n height: 0 !important;\n }\n /* Message action rows (copy / run-time badges) can overflow the right\n edge on narrow screens \u2014 keep them inside the message width. */\n [data-phase] [class$=\"_actions\"] {\n overflow: hidden !important;\n }\n [data-phase] [class$=\"_actions\"] [class$=\"_timeEnd\"] {\n flex: 0 1 auto !important;\n min-width: 0 !important;\n overflow: hidden !important;\n text-overflow: ellipsis !important;\n white-space: nowrap !important;\n }\n\n [data-phase] [class$=\"_scroll\"]:has(p) {\n padding-left: 20px !important;\n padding-right: 20px !important;\n font-size: 15px !important;\n }\n /* The official markdown styles set an explicit 16px on paragraphs and\n list items, so the container's inherited 15px is not enough. User\n messages render their text in a div whose class carries _text_\n (16px too) \u2014 cover it as well. */\n [data-phase] [class$=\"_scroll\"]:has(p) p,\n [data-phase] [class$=\"_scroll\"]:has(p) li,\n [data-phase] [class$=\"_scroll\"]:has(p) [class*=\"_text_\"] {\n font-size: 15px !important;\n }\n\n /* Markdown tables: the official table uses width:max-content, so on a phone\n it hugs the content and leaves dead space beside/inside the table. Force\n the table to fill the message column and let the table wrapper handle\n overflow if a cell is genuinely too wide. */\n [data-phase] table {\n width: 100% !important;\n max-width: 100% !important;\n }\n [data-phase] th,\n [data-phase] td {\n max-width: none !important;\n min-width: 0 !important;\n }\n\n /* User bubbles: the official stack is capped at min(525px, 82%), which on a\n phone leaves a large blank strip on the left and pushes the bubble high.\n On mobile let the user message fill the same full width as assistant\n messages (the bubble background then spans the whole message column). */\n [data-phase] [class$=\"_userStack\"],\n [data-phase] [class$=\"_userStack\"] [class$=\"_bubble\"] {\n box-sizing: border-box !important;\n width: fit-content !important;\n max-width: 100% !important;\n }\n\n /* --- Composer bottom row on mobile ---\n The official row gives the model pill (trailing) flex:0 0 auto, which\n squeezes the agent-permission pill (modes) down to 15px: the pill's\n chevron then overflows on top of the model name. Let the permission\n pill keep its natural width and let the model pill shrink instead.\n Anchored by the composer card (:has(textarea)): row = the _row class\n containing a _trailing group, tools = its first child, permission pill\n = its 2nd child, model pill = the _trailing group.\n NOTE: do NOT anchor these by the card's :last-child \u2014 a client effect\n moves the git-graph branch chip INTO the card, which becomes the card's\n new last child and silently disables every :last-child rule (the model\n pill then falls back to the official fixed layout and long model IDs\n overflow instead of ellipsizing). Structural anchors only. */\n /* The official row pads every group with 12px gaps, which on a phone eats\n width the model pill needs for the full model ID. Tighten the row to 8px\n gaps (the modes pill keeps its natural width) so the model name gets\n every spare pixel. */\n [data-phase] [class*=\"_card\"]:has(textarea) [class$=\"_row\"]:has([class$=\"_trailing\"]) {\n gap: 8px !important;\n }\n [data-phase] [class*=\"_card\"]:has(textarea) [class$=\"_row\"]:has([class$=\"_trailing\"]) > :first-child {\n gap: 8px !important;\n }\n [data-phase] [class*=\"_card\"]:has(textarea) [class$=\"_row\"]:has([class$=\"_trailing\"]) > :first-child > :nth-child(2) {\n flex: 0 0 auto !important;\n gap: 8px !important;\n }\n [data-phase] [class*=\"_card\"]:has(textarea) [class$=\"_trailing\"] {\n flex: 1 1 auto !important;\n gap: 8px !important;\n min-width: 0 !important;\n }\n /* Let the model selector take the free space in the trailing group so the\n model name is not squeezed/truncated; the context meter stays fixed. */\n [data-phase] [class*=\"_card\"]:has(textarea) [class$=\"_root\"]:has(> [class$=\"_trigger\"][aria-haspopup=\"menu\"]) {\n flex: 1 1 auto !important;\n min-width: 0 !important;\n }\n [data-phase] [class*=\"_card\"]:has(textarea) [class$=\"_root\"]:has(> [class$=\"_trigger\"][aria-haspopup=\"menu\"]) > [class$=\"_trigger\"] {\n width: 100% !important;\n max-width: 100% !important;\n }\n /* The model label must absorb the trigger's free width: officially it is a\n fixed-content flex item, so the spare width of a grown pill sits unused\n between the chevron and the pill edge. Let the label grow and shrink:\n the full model ID shows whenever the row can fit it, and the ellipsis\n lands exactly at the available width otherwise. */\n [data-phase] [class*=\"_card\"]:has(textarea) [class$=\"_root\"]:has(> [class$=\"_trigger\"][aria-haspopup=\"menu\"]) > [class$=\"_trigger\"] > [class$=\"_triggerLabel\"] {\n flex: 1 1 auto !important;\n min-width: 0 !important;\n }\n [data-phase] [class*=\"_card\"]:has(textarea) [class$=\"_root\"]:has(> [class$=\"_trigger\"]:not([aria-haspopup=\"menu\"])) {\n flex: 0 0 auto !important;\n }\n\n /* Model switcher menu: the official dropdown is right-aligned to the\n trigger (right:0). The model pill sits near the center of the composer,\n so on a phone the 240px menu overflows the left edge and looks off-center.\n Center the menu on the trigger instead. */\n [data-phase] [class*=\"_card\"]:has(textarea) [class$=\"_root\"]:has(> [class$=\"_trigger\"]) > [class$=\"_menu\"] {\n left: 50% !important;\n right: auto !important;\n transform: translateX(-50%) !important;\n }\n\n /* --- Session header on mobile ---\n Layout goal: [toggle] [session title] [mode badge] in a row, with the\n Session log capsule removed from the header (relocated to the drawer\n footer). Stable structural hooks only:\n [data-phase] header the session header element\n header > :first-child titleRow (titleCluster + utilities)\n header > :first-child > :last-child headerUtilities (Session log seat) */\n [data-phase] header {\n padding-right: 12px !important;\n }\n /* Give the title row a lane clear of the absolutely-placed toggle, then\n balance the header: with header padding-right 12px, a 20px left\n padding puts the title's geometric center exactly on the viewport\n center (measured 195/195 at 390px). */\n [data-phase] header > :first-child {\n padding-left: 20px !important;\n }\n /* The directory toggle sits at the far left of the header (the header\n is position:relative; the data-slot wrappers are display:contents). */\n [data-mobile-nav=\"toggle\"] {\n position: absolute !important;\n left: 8px !important;\n top: 12px !important;\n z-index: 2 !important;\n }\n /* The Files action stays in-flow inside headerActions. On mobile headerActions\n does not expand to fill the row: it is pushed to the right edge and keeps\n its content size, so [mode] [subagent/jobs] [files] sit close together\n with the normal 8px gaps \u2014 compact, no artificial blank columns. Explicit\n flex order keeps Files rightmost regardless of DOM order. */\n [data-mobile-nav=\"files\"] {\n position: static !important;\n left: auto !important;\n right: auto !important;\n top: auto !important;\n z-index: auto !important;\n }\n [data-phase] header [class$=\"_headerActions\"] {\n flex: 0 1 auto !important;\n min-width: 0 !important;\n margin-left: auto !important;\n justify-content: flex-end !important;\n }\n /* The session title/crumb must yield space on mobile so the mode label and\n subagent cluster are not squeezed to a single letter. Cap it at ~24vw and\n let it truncate with ellipsis. */\n [data-phase] header [class$=\"_crumbs\"] {\n flex: 0 1 auto !important;\n min-width: 0 !important;\n max-width: 24vw !important;\n }\n /* Mode label (AgentPresetLabel): the official pill uses inline-flex, whose\n direct text node is only clipped \u2014 no ellipsis. Convert the pill to a\n block container, keep its icon absolutely positioned on the left, and let\n it size naturally up to 42vw so the mode name stays readable while the\n subagent/Files cluster still fits on a phone. */\n [data-phase] header [class$=\"_label\"]:has(> svg) {\n order: 1 !important;\n flex: 0 1 auto !important;\n min-width: 0 !important;\n max-width: 42vw !important;\n display: block !important;\n position: relative !important;\n box-sizing: border-box !important;\n padding-left: 18px !important;\n padding-right: 2px !important;\n overflow: hidden !important;\n text-overflow: ellipsis !important;\n white-space: nowrap !important;\n }\n [data-phase] header [class$=\"_label\"]:has(> svg) > svg {\n position: absolute !important;\n left: 0 !important;\n top: 50% !important;\n transform: translateY(-50%) !important;\n }\n /* Subagent/jobs helpers: keep their triggers on one line and never let the\n row grow artificial empty space. */\n [data-phase] header [class$=\"_root\"]:has(> button[class$=\"_trigger\"]) {\n order: 2 !important;\n flex: 0 0 auto !important;\n min-width: max-content !important;\n max-width: none !important;\n white-space: nowrap !important;\n /* On mobile the popover is anchored to the header (viewport-width\n containing block) instead of the trigger, so a small left inset keeps it\n fully on screen and never clips the tree's status dots. */\n position: static !important;\n }\n [data-phase] header [class$=\"_root\"]:has(> button[class$=\"_trigger\"]) > button,\n [data-phase] header [class$=\"_root\"]:has(> button[class$=\"_trigger\"]) > button * {\n white-space: nowrap !important;\n }\n [data-phase] header [data-mobile-nav=\"files\"] {\n order: 3 !important;\n flex: 0 0 auto !important;\n }\n /* Session log download: gone from the header row on mobile (the utilities\n seat holds only the session-log-export capsule). */\n [data-phase] header > :first-child > :last-child {\n display: none !important;\n }\n\n /* --- Header popovers on mobile (dsh-client-ui-jobs / dsh-client-ui-subagent) ---\n The official entries sit in the session header actions. Their popovers\n are anchored to the trigger's LEFT edge (left: 0), so from a right-edge\n trigger the 336px panel spills past the viewport. Re-anchor them to the\n trigger's right edge instead. The popover classes are hashed CSS-module\n names, so target them by the stable _menu suffix inside the header. */\n /* Header popovers on mobile: anchor to the left edge with a small inset and\n clamp the width, instead of right-aligning to a trigger near the right\n edge (which pushed the panel left off-screen and clipped the status dots).\n Also cap the height so the panel does not run into the composer/task bar. */\n [data-phase] header [class$=\"_menu\"] {\n left: 8px !important;\n right: auto !important;\n width: min(336px, calc(100vw - 16px)) !important;\n max-width: none !important;\n max-height: min(420px, calc(100dvh - 120px)) !important;\n }\n /* --- Settings dialog on mobile ---\n Desktop: 800px two-column flex (188px nav + content). Mobile: a\n near-full-width sheet \u2014 nav tabs wrap into rows on top, option rows\n stay horizontal (title+description left, control right). Structural\n selectors are scoped to the unique aria-modal dialog; every\n settings-specific rule is gated with\n :has(> :first-child > :last-child > button) \u2014 the settings nav tab\n list holds <button> tabs, so the transient export dialog (the same\n primitives Modal, header(title+close)+description+body) keeps its\n official centered card layout. Requires :has() support\n (Chromium 105+, 2022).\n\n The directory picker (dsh-client-ui-directory-picker-browse) must be\n excluded too: its footer bar holds <button> children AND its breadcrumb\n trail (role=\"navigation\") \u2014 which the role gate relies on to exclude\n it \u2014 is REPLACED by the path input in edit mode (pencil button), so\n without the ZuhsRW exclusion clicking the pencil would suddenly match\n this sheet rule: the dialog jumps to the top of the screen, the header\n (with the path input) is hidden by the > :first-child > :first-child\n display:none rule below, and the user can no longer type a path\n (issue #12, 2026-08-16). The picker family keeps the official layout\n on mobile in every mode. */\n /* DSH 0.2.1-rc.2 renders this dialog as a body PORTAL\n (body > overlay > panel), so the placement below must key off the nav\n list the panel owns, not off a guessed child depth: that is both the\n stable \"this is the settings sheet\" anchor and the reason the safe-area\n offset below still applies inside the portal (the constants live on\n :root, so they cross the portal boundary). The bottom inset is\n subtracted too \u2014 a tall panel must not run under the home indicator. */\n [aria-modal=\"true\"]:has(> :first-child > :last-child > button):not(:has([role=\"navigation\"])):not(:has([class*=\"ZuhsRW\"])):has([class$=\"_navList\"]) {\n position: absolute !important;\n left: 8px !important;\n /* Fixed top (no translateY): a transform on the panel combined with the\n panel overflowing the max-content drawer shifts the fixed overlay's\n coordinate frame, dragging the whole sidebar content off-screen. The\n safe-area inset keeps the sheet below the status bar / notch. */\n top: calc(var(--mnav-sat) + 12px) !important;\n width: calc(100vw - 16px) !important;\n max-width: calc(100vw - 16px) !important;\n /* Height follows the content (no dead space under a short page); it\n caps at 100dvh-24 (less both safe-area insets) and the options area\n scrolls only then. */\n height: auto !important;\n max-height: min(800px, calc(100vh - 24px - var(--mnav-sat) - var(--mnav-sab))) !important;\n max-height: min(800px, calc(100dvh - 24px - var(--mnav-sat) - var(--mnav-sab))) !important;\n flex-direction: column !important;\n border-radius: 14px !important;\n animation: dsh-mobile-nav-sheet-in .22s var(--ds-ease-out, ease-in-out);\n }\n /* The settings sheet's dimmed mask fades in with the panel (the mask is\n the first child of the overlay that directly contains the sheet). */\n :has(> [aria-modal=\"true\"]:has(> :first-child > :last-child > button):not(:has([role=\"navigation\"])):not(:has([class*=\"ZuhsRW\"]))) > :first-child {\n animation: dsh-mobile-nav-fade .18s var(--ds-ease-out, ease-in-out);\n }\n @media (prefers-reduced-motion: reduce) {\n [aria-modal=\"true\"]:has(> :first-child > :last-child > button):not(:has([role=\"navigation\"])):not(:has([class*=\"ZuhsRW\"])),\n :has(> [aria-modal=\"true\"]:has(> :first-child > :last-child > button):not(:has([role=\"navigation\"])):not(:has([class*=\"ZuhsRW\"]))) > :first-child {\n animation: none !important;\n }\n }\n /* The export dialog (not the settings sheet) must never overflow the\n viewport: the official centered card can be wider than 390px.\n :not([data-mobile-nav=\"info-sheet\"]) (S4, 2026-08-17): the session-info\n sheet also carries role=\"dialog\" aria-modal=\"true\" (correct a11y\n semantics for a bottom sheet with a scrim) and has no button as its\n first-child's last-child, so without this exclusion it silently matched\n this generic selector too \u2014 measured 358px (100vw-32px) instead of the\n 374px its own left:8px/right:8px margins specify. Same category of bug\n as the ZuhsRW directory-picker collision below; same fix shape.\n :not([data-mobile-nav=\"share-range-sheet\"]) (share-image, 2026-09-10):\n the share range picker rides the same role=\"dialog\" aria-modal bottom\n -sheet shape and the same margins, so it hit the identical clamp. */\n [aria-modal=\"true\"]:not(:has(> :first-child > :last-child > button)):not([data-mobile-nav=\"info-sheet\"]):not([data-mobile-nav=\"share-range-sheet\"]) {\n max-width: calc(100vw - 32px) !important;\n }\n /* Nav bar: hide the \"Settings\" caption (redundant on a full-width sheet)\n and wrap the tab list so every tab is visible \u2014 a horizontal scroll cut\n the last tab (\"Plugins\") off with no affordance to scroll. */\n [aria-modal=\"true\"]:has(> :first-child > :last-child > button):not(:has([role=\"navigation\"])):not(:has([class*=\"ZuhsRW\"])) > :first-child {\n width: 100% !important;\n flex-direction: row !important;\n align-items: center !important;\n gap: 6px !important;\n padding: 10px 12px 8px !important;\n }\n [aria-modal=\"true\"]:has(> :first-child > :last-child > button):not(:has([role=\"navigation\"])):not(:has([class*=\"ZuhsRW\"])) > :first-child > :first-child {\n display: none !important;\n }\n /* The tab list scrolls in the space left by the toolbar: the toolbar\n (config file + close) is reparented INTO this nav row by a client\n effect (MobileNavOverlay), so the tab list must be anchored by its\n class, NOT by :last-child (the reparented toolbar becomes the nav's\n new last child).\n\n 2026-10-21 (DSH 0.2.1-rc.2): this rule used to declare\n \"flex-wrap: wrap; overflow: visible\" on top of the flex/min-width/gap\n above. Because it is one class-anchored compound selector with a much\n higher specificity than compat.css.ts's portal-scoped navList rule, it\n silently won the tie and the tab list wrapped into two rows \u2014 with the\n reparented \u2715 vertically centred across both of them. Measured on a\n phone shell: the list was 86px tall (two rows) instead of one 40px row,\n and it scrolled nowhere. The wrap was a 2026-08-16 trade-off (show every\n tab, no hidden scroll cut-off); with the thin scrollbar affordance now\n in compat.css.ts the single scrolling row is the better trade, so the\n two declarations live there and this rule no longer contradicts them. */\n [aria-modal=\"true\"]:has(> :first-child > :last-child > button):not(:has([role=\"navigation\"])):not(:has([class*=\"ZuhsRW\"])) > :first-child [class$=\"_navList\"] {\n flex: 1 1 auto !important;\n min-width: 0 !important;\n flex-direction: row !important;\n gap: 6px !important;\n }\n /* Content toolbar (Open configuration file + close): grouped flush to\n the right edge, and reparented INTO the nav row on mobile so it shares\n one line with the tabs (user feedback 2026-08-16 \u2014 the toolbar's own\n row left a full-width dead gap under the tabs). Anchored by class: the\n header leaves the content subtree, so :first-child/:last-child anchors\n would now hit the options area. Children carry official auto-margins\n that would defeat flex-end, so neutralize them. The close button gets\n a round tappable base so it reads as its own control, not part of the\n outline button. */\n [aria-modal=\"true\"]:has(> :first-child > :last-child > button):not(:has([role=\"navigation\"])):not(:has([class*=\"ZuhsRW\"])) [class$=\"_header\"] {\n flex: 0 0 auto !important;\n justify-content: flex-end !important;\n align-items: center !important;\n gap: 8px !important;\n padding: 0 0 0 4px !important;\n min-height: 40px !important;\n }\n [aria-modal=\"true\"]:has(> :first-child > :last-child > button):not(:has([role=\"navigation\"])):not(:has([class*=\"ZuhsRW\"])) [class$=\"_header\"] > * {\n margin-left: 0 !important;\n margin-right: 0 !important;\n }\n [aria-modal=\"true\"]:has(> :first-child > :last-child > button):not(:has([role=\"navigation\"])):not(:has([class*=\"ZuhsRW\"])) [class$=\"_header\"] > :last-child {\n width: 32px !important;\n height: 32px !important;\n border-radius: 50% !important;\n display: inline-flex !important;\n align-items: center !important;\n justify-content: center !important;\n background: var(--dsw-alias-interactive-bg-hover, rgba(0, 0, 0, .06)) !important;\n }\n /* Appearance mode cards: the official cube row renders three tall\n vertical cards (~268px) that eat half the sheet. Turn them into a\n compact horizontal trio (icon + label inline, equal widths).\n Relies on the official cube-row class name of this version. */\n [aria-modal=\"true\"] [class$=\"_cubeRow\"] {\n gap: 6px !important;\n }\n [aria-modal=\"true\"] [class$=\"_cubeRow\"] > * {\n flex: 1 1 0 !important;\n flex-direction: row !important;\n align-items: center !important;\n justify-content: center !important;\n gap: 6px !important;\n padding: 10px 8px !important;\n min-height: 0 !important;\n }\n /* Content: the options scroll area gets bottom breathing room so the last\n row never sits flush against the sheet's rounded corner. */\n [aria-modal=\"true\"]:has(> :first-child > :last-child > button):not(:has([role=\"navigation\"])):not(:has([class*=\"ZuhsRW\"])) > :last-child {\n flex: 1 1 auto !important;\n min-height: 0 !important;\n }\n [aria-modal=\"true\"]:has(> :first-child > :last-child > button):not(:has([role=\"navigation\"])):not(:has([class*=\"ZuhsRW\"])) > :last-child > :last-child {\n padding: 0 12px 24px !important;\n }\n";
2
2
  //# sourceMappingURL=layout.css.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"layout.css.d.ts","sourceRoot":"","sources":["../../../../src/client/styles/layout.css.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,UAAU,y51BAwgBtB,CAAA"}
1
+ {"version":3,"file":"layout.css.d.ts","sourceRoot":"","sources":["../../../../src/client/styles/layout.css.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,UAAU,mu4BAyhBtB,CAAA"}
@@ -1,2 +1,2 @@
1
- export declare const REMOTE_SESSION_CSS = "/* ---------- remote session: hide the open-on-the-server-machine entries ----------\n A remote session's files live on the relay SERVER; every \"open\" control here\n would act on the machine the DSH process runs on, not the one the browser is\n on. Hidden while the current session is remote (html[data-zr-remote-session]):\n - [data-open-target] is dsh-client-ui-open-in-app's own mount marker (RT\n dsh-client-ui-open-in-app lib/client.js ~325: the split-button anchor\n React renders with data-open-target={kind}) \u2014 one selector covers the\n session-header \"Open In...\" button, the document-preview actions, AND the\n \"Open / Show in Finder / Choose an application\" buttons of the changes\n panel and the deliverable cards (RT dsh-client-ui-deliverables\n lib/client.js ~1702, ~1963: those cards render the open-in-app package's\n FileRouteAction through the deliverables.file.actions and\n deliverables.review.file.actions slots, the same OpenTargetButton anchor).\n The attribute is the component's own contract, not a generated class. */\nhtml[data-zr-remote-session=\"1\"] [data-open-target] {\n display: none !important;\n}\n\n/* ---------- remote session: hide dsh-better-sidebar's file surfaces (T53, two regimes since PB-14) ----------\n dsh-better-sidebar 0.25.0 is the second big \"open the machine's files\" UI\n AND, since PB-12/13, the first ADAPTER-BRIDGED one: at exactly 0.25.0 its\n /sidebar/api routes, its two WebSockets and its side chat cross the byte\n tunnel and read/write the SERVER's data, gated on the whole-machine-data\n consent. The hiding below therefore applies ONLY while the plugin is NOT\n bridged \u2014 the :not([data-zr-bridge-dsh-better-sidebar=\"1\"]) stamp the\n remote-status poll writes; see the PB-14 note above): bridged, the panels\n are remote-aware and stay visible; unbridged (a different version, the\n server without the adapter's consent), every tab it registers (files/\n editor, git changes, subagent/tasks, side chat, the markdown/html/code\n file viewers) builds its requests from a {sessionId, cwd} scope and POSTs\n them to the plugin's own /sidebar/api/* routes on whichever machine\n answers \u2014 in a remote session that is the SUB-CLIENT's machine (client.js\n call() ~3111, fetchUpload ~3162, encodeHtmlUrl /sidebar/html/ ~3069-3414),\n so the tree would show same-named LOCAL files as if they were the\n session's and an edit would WRITE locally.\n\n Anchors, all the plugin's or the host's own rendered contracts (no hashed\n class names; the one suffix selector, _chipIcon, is unique among the\n profile's packages \u2014 checked dsh-vision-router / dsh-auto-approve /\n dsh-mem0 / dsh-llm-verifier / dsh-plugin-subscriptions /\n @liustack/modsearch / @wxg-prc-cpg/browser-skill-dsh-plugin (modsearch /\n browser-skill) / dshmarket and every @deepseek-ai sidebar package for it):\n\n HONEST LIMITS (T53-fix, adjusted PB-14): unbridged, the plugin's\n components stay mounted and keep silently POSTing READ-ONLY /sidebar/api\n requests to the local machine (session.cwd, changes.ops, the tree reads a\n mounted tab refreshes with) \u2014 the data never leaves that machine, and no\n write can happen because every write control is inside the hidden\n surfaces (the tab body hides its CHILDREN and spends the note copy as a\n ::before, so an already-open tab reads WHY it is empty instead of\n sitting blank). Known boundary: a dsh-resource://file/** address opened\n through sidebarRight.openResource in a remote session (file links in\n chat, deliverables, @-references, skills) is CLAIMED by the plugin's\n editor registration (client.js ~21377: patterns [\"dsh-resource://file/**\"])\n before the host preview sees it \u2014 the right sidebar expands, the rules\n below hide the tab's body content and chip, and the note fills the panel.\n Bridged (0.25.0 + consent), none of this applies: the tab reads the\n server's data through the adapter and stays visible whole.\n\n - [data-dsh-bottom-toggle] \u2014 the header-utilities button that expands the\n bottom workbench (client.js BottomDockToggle ~20863; slot registration\n ~21492-21498, id dsh-better-sidebar:bottom-toggle). Our own phone header\n button drives the OFFICIAL right sidebar (MobileSessionHeader.tsx), so\n hiding this does not strand the phone.\n - [data-dsh-panel-host] \u2014 the fixed viewport layer the plugin appends to\n document.body (client.js ~20763); the bottom workbench panel\n ([data-dsh-bottom-panel]) is its only child, so hiding the layer hides\n the workbench whole (tab strip, + menu, tree, editor and all).\n - --dsh-sidebar-height \u2014 the plugin's layout push: written INLINE on <html>\n while the workbench is open (client.js writeGeometry ~20482-20488) and\n spent by its own layout.css as the center column's margin-bottom\n (client.js layout css ~23009: #root [data-dsh-center-col] { margin-bottom:\n var(--dsh-sidebar-height, 0px) }). Hiding the panel alone would leave\n that reserved band as a blank strip under the conversation, so the remote\n html zeroes the variable. A stylesheet !important beats a non-important\n inline style, and the plugin's JS state is never touched: the moment the\n attribute is removed (back on a local session) its own value applies\n again, transitions included.\n - [data-dsh-native-tab-host] \u2014 the wrapper the plugin renders around EVERY\n tab body it contributes to the host's native right Sidebar\n (client.js NativeTabBody ~21074, marker ~21110/21120). The host's pane\n chrome is untouched: the strip keeps the \"+\" (guide) button and the\n collapse/fullscreen controls, so a tab that was already open leaves no\n dead panel \u2014 an empty body behind a strip that still collapses, and the\n \"+\" re-opens the guide page (whose plugin capsules these rules hide, see\n below). React keeps mounting into the display:none node: no errors, and\n the restore on returning to a local session is instant.\n - [data-dockkit-tab]:has([class$=\"_chipIcon\"]) \u2014 the native tab STRIP's\n chips for plugin tabs, so an already-open tab does not survive as a\n clickable ghost. The chip button is dockkit's ([data-dockkit-tab], dsh-web\n frontend bundle: role=tab, renderTabTitle inside a\n span[data-dockkit-tab-title]); its content is the plugin's\n NativeTabTitle (~21172-21197), which always leads with a\n [class$=\"_chipIcon\"] glyph span because every built-in descriptor ships an\n icon \u2014 a chip with no glyph (an external tab registered through the\n plugin's viewer service without an icon) keeps its chip; its body is\n still hidden by the rule above. Host tabs' chips never contain a\n _chipIcon (checked all four @deepseek-ai sidebar packages), so the\n remote-aware host files page survives alongside.\n - [data-floating-window]:has([data-window-body]) \u2014 the plugin's\n body-PORTALED floating windows (client.js FloatingWindow ~15078-15120):\n the task edit window (teams.taskCreate/Update with rootSessionId via\n /sidebar/api, writeTask ~3124-3140) and the job-output window (host jobs\n kill). Both open from the subagent/tasks tab; portal escapes the tab\n body's display:none, so they need their own rule. Anchored on the\n window's own root attribute plus its own inner body marker, so a foreign\n [data-floating-window] without that shape never matches.\n - guide capsules \u2014 the empty-sidebar doorway buttons the HOST renders from\n the plugin's registrations ([data-sidebar-right-guide-entry=\"<kind>\"], RT\n dsh-client-ui-sidebar-right lib/client.js:466): kinds git / subagent /\n sidechat exist only while this plugin registers them, so those selectors\n are inert without it. The \"files\" capsule is the one ambiguous kind:\n dsh-client-ui-sidebar-files registers the SAME kind (its filesDefinition,\n lib/client.js:14-31) and that page is REMOTE-AWARE (it injects the host's\n remote.workspaceFiles service). T53-fix discriminates on the capsule's\n own rendered contract instead of plugin presence: the host's EntryBox\n renders aria-keyshortcuts from the shortcut matching entry.commandId (RT\n sidebar-right lib/client.js:461-467) \u2014 the host files guide row carries\n commandId \"workspace.files\" (dsh-client-ui-sidebar-files\n lib/client.js:30), while better-sidebar's guide rows carry NO commandId\n (client.js registerNativeSurface ~21385-21400), so its capsule never\n renders the attribute. :not([aria-keyshortcuts]) therefore hides the\n plugin's takeover capsule and spares the host's wherever the host has a\n default binding. Boundary: that \"wherever\" is not everywhere \u2014 the host\n registers workspace.files defaults for desktop:macos/windows/linux and\n web:macos/windows only (dsh-client-ui-sidebar-files lib/client.js:949-977),\n so on any other platform the OFFICIAL capsule also renders without the\n attribute and this rule hides it too (cosmetic; the page stays reachable\n through its shortcut command path and the plugin's takeover is the\n \"files\" implementation on every deployment this plugin pairs with\n better-sidebar anyway).\n\n /* PB-14: every T53 rule below carries\n :not([data-zr-bridge-dsh-better-sidebar=\"1\"]) \u2014 when the adapter\n (PB-12) bridges the plugin, the panels read the SERVER's data through\n the byte tunnel and MUST stay visible; the hiding applies only to the\n unbridged combination, and the empty tab body then carries a note\n instead of blankness. The stamp is written by\n effects/remote-session.ts off the remote-status poll's bridgedPlugins\n list (client-data/remote-status.ts shouldStampBridgeAttribute). */\nhtml[data-zr-remote-session=\"1\"]:not([data-zr-bridge-dsh-better-sidebar=\"1\"]) [data-dsh-bottom-toggle] {\n display: none !important;\n}\nhtml[data-zr-remote-session=\"1\"]:not([data-zr-bridge-dsh-better-sidebar=\"1\"]) [data-dsh-panel-host] {\n display: none !important;\n}\nhtml[data-zr-remote-session=\"1\"]:not([data-zr-bridge-dsh-better-sidebar=\"1\"]) {\n --dsh-sidebar-height: 0px !important;\n}\n/* The unbridged tab body: hide the plugin's own content and spend the\n note copy as a ::before \u2014 an already-open tab reads WHY it is empty\n (0.25.0 keeps tabs mounted, so a stale body would otherwise sit blank).\n --zr-bridge-note is set on <html> by the stamp effect, in the\n browser's language; unset (effect not running yet) the content falls\n through and nothing renders. */\nhtml[data-zr-remote-session=\"1\"]:not([data-zr-bridge-dsh-better-sidebar=\"1\"]) [data-dsh-native-tab-host] > * {\n display: none !important;\n}\nhtml[data-zr-remote-session=\"1\"]:not([data-zr-bridge-dsh-better-sidebar=\"1\"]) [data-dsh-native-tab-host]::before {\n content: var(--zr-bridge-note);\n display: block;\n padding: 24px 16px;\n font-size: 13px;\n line-height: 1.7;\n color: var(--dsh-fg-muted, #6b7280);\n word-break: break-word;\n}\nhtml[data-zr-remote-session=\"1\"]:not([data-zr-bridge-dsh-better-sidebar=\"1\"]) [data-dockkit-tab]:has([class$=\"_chipIcon\"]) {\n display: none !important;\n}\nhtml[data-zr-remote-session=\"1\"]:not([data-zr-bridge-dsh-better-sidebar=\"1\"]) [data-floating-window]:has([data-window-body]) {\n display: none !important;\n}\nhtml[data-zr-remote-session=\"1\"]:not([data-zr-bridge-dsh-better-sidebar=\"1\"]) [data-sidebar-right-guide-entry=\"git\"],\nhtml[data-zr-remote-session=\"1\"]:not([data-zr-bridge-dsh-better-sidebar=\"1\"]) [data-sidebar-right-guide-entry=\"subagent\"],\nhtml[data-zr-remote-session=\"1\"]:not([data-zr-bridge-dsh-better-sidebar=\"1\"]) [data-sidebar-right-guide-entry=\"sidechat\"] {\n display: none !important;\n}\nhtml[data-zr-remote-session=\"1\"]:not([data-zr-bridge-dsh-better-sidebar=\"1\"]) [data-sidebar-right-guide-entry=\"files\"]:not([aria-keyshortcuts]) {\n display: none !important;\n}\n/* 0.25.0's dock fallback \u2014 the floating quick-open button the plugin pins\n for empty workspaces. Same treatment as every other open-the-machine's-\n files control: hidden while unbridged, untouched when bridged. */\nhtml[data-zr-remote-session=\"1\"]:not([data-zr-bridge-dsh-better-sidebar=\"1\"]) [data-dsh-dock-fallback] {\n display: none !important;\n}\n\n/* ---------- T52/T74: model-menu groups follow the session's side ----------\n The model catalog is GLOBAL (one shared load per page), so the merged\n catalog shows the server's groups everywhere; but a selection is only\n runnable on the side the open session lives on \u2014 the interceptor refuses\n the other side with a clear message. Hide what cannot run.\n\n What changed and why the mechanism is a STAMP now (T74): through 0.1.7\n each menu group rendered aria-labelledby=\"<useId>-<group.id>\" (RT017\n dsh-client-ui-model-selection lib/client.js ~824-830) \u2014 the group id was\n IN the attribute, and rules could key on a virtual group's \"zr~\" prefix\n directly. 0.2.0 renders the groups with the primitives' MenuGroup\n instead (RT dsh-client-ui-primitives lib/index.js ~4283-4304): the\n section's aria-labelledby carries ONLY the useId, the heading is a child\n div[data-menu-group-heading], and the menu container is a div whose id\n ends in \"-models\" with role=\"menu\" (RT dsh-client-ui-model-selection\n lib/client.js ~974-980). Two consequences killed the old rules: a group\n section no longer says anywhere in its markup which group it is, and the\n same MenuGroup renders OTHER menus' groups too \u2014 the old\n [role=\"menu\"] section[role=\"group\"] scope alone was too wide and would\n have hidden every unmarked group of every menu in a remote session\n (leaving just the search box), while missing the server's groups in\n local ones.\n\n The new keys on what EVERY version actually renders, the heading text:\n each virtual group's name is prefixed with the invisible WORD JOINER\n (VIRTUAL_GROUP_NAME_MARK, virtual-id.ts; written by mergeModelCatalogs).\n The browser effect (effects/model-group-side.ts) reads each group's\n heading and stamps data-zr-group=\"remote|local\" on the section \u2014 but\n only inside a CONTAINER (the sections' shared parent element) that holds\n at least one marked heading. That container rule is what scopes these\n rules to the model menu alone WITHOUT assuming menu structure: an\n unpaired client's model menu, every other menu, and the whole rest of\n the page hold no marked heading, receive no stamp, and match neither\n rule. And since the merged catalog only ever APPENDS virtual groups to\n the local list, within a decided container the unmarked groups are\n exactly the local ones \u2014 mixed containers (the norm) decide each group\n separately. The menu is a portal under <body>, but <html> is still its\n ancestor, so the html-level session attribute scopes both rules. If the\n effect is not running (uninstalled, or a host-role page that never had\n it), no stamp exists and both rules go inert \u2014 nothing stays hidden.\n\n KNOWN BOUNDARY (accepted, not fixed): in a remote session, searching the\n model menu and pressing Enter can commit a HIDDEN local model \u2014 the\n interceptor refuses it with its usual message. */\nhtml[data-zr-remote-session=\"1\"] section[role=\"group\"][data-zr-group=\"local\"] {\n display: none !important;\n}\nhtml:not([data-zr-remote-session]) section[role=\"group\"][data-zr-group=\"remote\"] {\n display: none !important;\n}\n\n/* ---------- T52-fix: hide the virtual groups in NATIVE <option> pickers ----\n The model menu above is React DOM, but dsh-vision-router's settings render\n its vision-backend picker as a native <select> of <option value={group.id}>\n rows, and its filter (dsh-vision-router lib/client.js:661-670\n filterVisionBackendGroups) drops only vision-http / vision-chain / *-vision\n \u2014 a merged virtual group (\"zr~<id>~\u2026\") survives into that picker even\n though a server model can never be a LOCAL vision backend (the router calls\n providers from the machine it runs on). Native <option> rows honor\n display:none in the dropdown list, so this hides them wherever they appear:\n - no scoping attribute on purpose: a virtual group is not a runnable\n backend in ANY local context, and the option element itself carries the\n value \u2014 no host-depth assumption, no :has();\n - when the vision router (or any other <option>-rendering surface) is not\n installed, nothing matches \u2014 dead rule, zero cost;\n - zen-remote's own surfaces are checked: our settings forms render fixed\n enum options (\"web\" / \"desktop-client\" / role kinds /\n configForm enum strings, src/client/settings/SettingsSection.tsx:641,690-701)\n and none can start with \"zr~\" (virtual group ids only ever exist inside\n model-catalog payloads and model-selection arguments). */\noption[value^=\"zr~\"] {\n display: none !important;\n}\n\n/* ---------- remote session: hide the session-export menu item (T51, T51-fix) ----------\n A remote session's log lives on the relay server and the backend refuses\n /api/session.export for a virtual id with 403 remote-unsupported\n (fetch-route-intercept.ts) \u2014 the item would only ever end in the \"Export\n failed\" modal, so it is hidden IN THE MENU (T51-fix: the anchor button\n stays, because it also opens the \u53CD\u9988 entry, which a remote session can\n still use). The DOM, verified against RT:\n - the Menu renders its anchor and its list as SIBLINGS inside its own\n span root (RT dsh-client-ui-primitives lib/index.js ~4265-4273:\n children = [anchor, portal ? createPortal(list) : list]), and the\n export Menu passes no portal flag (default false, ~3923) \u2014 so the list\n is the anchor's next sibling, matched by the general-sibling\n combinator below;\n - the list surface carries role=\"menu\" (Menu passes it at ~4243;\n MenuSurface spreads ...props onto its root div, ~3778-3795) and the\n items viewport inside it is div[role=\"presentation\"] (~4249-4252);\n - every data item is ONE div (the itemWrap wrapper, ~4143), so\n :first-child of the viewport is the FIRST item \u2014 and the export\n package puts \u4E0B\u8F7D/\u5BFC\u51FA first by construction (RT dsh-session-log-export\n lib/client.js 202-206, the optional feedback entry appended after at\n 207-211).\n The anchor button class suffix is matched the way compat.css.ts matches\n module classes (the hash prefix is build-local, \"_moreButton\" is the\n source name; unique in this slot \u2014 the only other moreButton in the RT\n tree, dsh-client-ui-sidebar-documentpreview lib/client.excel.js, lives in\n the sidebar, never under conversation.session.header.utilities).\n Known costs, accepted: with the feedback UI absent the menu's only item\n is the export, so the opened menu is EMPTY; and keyboard navigation still\n steps into the hidden item (focusable but invisible) until activated or\n escaped \u2014 it cannot be triggered through the visibility, only tabbed\n past blindly. */\nhtml[data-zr-remote-session=\"1\"] [data-slot=\"conversation.session.header.utilities\"] [class$=\"_moreButton\"] ~ [role=\"menu\"] > [role=\"presentation\"] > :first-child {\n display: none !important;\n}\n";
1
+ export declare const REMOTE_SESSION_CSS = "/* ---------- remote session: hide the open-on-the-server-machine entries ----------\n A remote session's files live on the relay SERVER; every \"open\" control here\n would act on the machine the DSH process runs on, not the one the browser is\n on. Hidden while the current session is remote (html[data-zr-remote-session]):\n - [data-open-target] is dsh-client-ui-open-in-app's own mount marker (RT\n dsh-client-ui-open-in-app lib/client.js ~325: the split-button anchor\n React renders with data-open-target={kind}) \u2014 one selector covers the\n session-header \"Open In...\" button, the document-preview actions, AND the\n \"Open / Show in Finder / Choose an application\" buttons of the changes\n panel and the deliverable cards (RT dsh-client-ui-deliverables\n lib/client.js ~1702, ~1963: those cards render the open-in-app package's\n FileRouteAction through the deliverables.file.actions and\n deliverables.review.file.actions slots, the same OpenTargetButton anchor).\n The attribute is the component's own contract, not a generated class. */\nhtml[data-zr-remote-session=\"1\"] [data-open-target] {\n display: none !important;\n}\n\n/* ---------- remote session: hide dsh-better-sidebar's file surfaces (T53, two regimes since PB-14) ----------\n dsh-better-sidebar 0.25.0 is the second big \"open the machine's files\" UI\n AND, since PB-12/13, the first ADAPTER-BRIDGED one: at exactly 0.25.0 its\n /sidebar/api routes, its two WebSockets and its side chat cross the byte\n tunnel and read/write the SERVER's data, gated on the whole-machine-data\n consent. The hiding below therefore applies ONLY while the plugin is NOT\n bridged \u2014 the :not([data-zr-bridge-dsh-better-sidebar=\"1\"]) stamp the\n remote-status poll writes; see the PB-14 note above): bridged, the panels\n are remote-aware and stay visible; unbridged (a different version, the\n server without the adapter's consent), every tab it registers (files/\n editor, git changes, subagent/tasks, side chat, the markdown/html/code\n file viewers) builds its requests from a {sessionId, cwd} scope and POSTs\n them to the plugin's own /sidebar/api/* routes on whichever machine\n answers \u2014 in a remote session that is the SUB-CLIENT's machine (client.js\n call() ~3111, fetchUpload ~3162, encodeHtmlUrl /sidebar/html/ ~3069-3414),\n so the tree would show same-named LOCAL files as if they were the\n session's and an edit would WRITE locally.\n\n Anchors, all the plugin's or the host's own rendered contracts (no hashed\n class names; the one suffix selector, _chipIcon, is unique among the\n profile's packages \u2014 checked dsh-vision-router / dsh-auto-approve /\n dsh-mem0 / dsh-llm-verifier / dsh-plugin-subscriptions /\n @liustack/modsearch / @wxg-prc-cpg/browser-skill-dsh-plugin (modsearch /\n browser-skill) / dshmarket and every @deepseek-ai sidebar package for it):\n\n HONEST LIMITS (T53-fix, adjusted PB-14): unbridged, the plugin's\n components stay mounted and keep silently POSTing READ-ONLY /sidebar/api\n requests to the local machine (session.cwd, changes.ops, the tree reads a\n mounted tab refreshes with) \u2014 the data never leaves that machine, and no\n write can happen because every write control is inside the hidden\n surfaces (the tab body hides its CHILDREN and spends the note copy as a\n ::before, so an already-open tab reads WHY it is empty instead of\n sitting blank). Known boundary: a dsh-resource://file/** address opened\n through sidebarRight.openResource in a remote session (file links in\n chat, deliverables, @-references, skills) is CLAIMED by the plugin's\n editor registration (client.js ~21377: patterns [\"dsh-resource://file/**\"])\n before the host preview sees it \u2014 the right sidebar expands, the rules\n below hide the tab's body content and chip, and the note fills the panel.\n Bridged (0.25.0 + consent), none of this applies: the tab reads the\n server's data through the adapter and stays visible whole.\n\n - [data-dsh-bottom-toggle] \u2014 the header-utilities button that expands the\n bottom workbench (client.js BottomDockToggle ~20863; slot registration\n ~21492-21498, id dsh-better-sidebar:bottom-toggle). Our own phone header\n button drives the OFFICIAL right sidebar (MobileSessionHeader.tsx), so\n hiding this does not strand the phone.\n - [data-dsh-panel-host] \u2014 the fixed viewport layer the plugin appends to\n document.body (client.js ~20763); the bottom workbench panel\n ([data-dsh-bottom-panel]) is its only child, so hiding the layer hides\n the workbench whole (tab strip, + menu, tree, editor and all).\n - --dsh-sidebar-height \u2014 the plugin's layout push: written INLINE on <html>\n while the workbench is open (client.js writeGeometry ~20482-20488) and\n spent by its own layout.css as the center column's margin-bottom\n (client.js layout css ~23009: #root [data-dsh-center-col] { margin-bottom:\n var(--dsh-sidebar-height, 0px) }). Hiding the panel alone would leave\n that reserved band as a blank strip under the conversation, so the remote\n html zeroes the variable. A stylesheet !important beats a non-important\n inline style, and the plugin's JS state is never touched: the moment the\n attribute is removed (back on a local session) its own value applies\n again, transitions included.\n - [data-dsh-native-tab-host] \u2014 the wrapper the plugin renders around EVERY\n tab body it contributes to the host's native right Sidebar\n (client.js NativeTabBody ~21074, marker ~21110/21120). The host's pane\n chrome is untouched: the strip keeps the \"+\" (guide) button and the\n collapse/fullscreen controls, so a tab that was already open leaves no\n dead panel \u2014 an empty body behind a strip that still collapses, and the\n \"+\" re-opens the guide page (whose plugin capsules these rules hide, see\n below). React keeps mounting into the display:none node: no errors, and\n the restore on returning to a local session is instant.\n - [data-dockkit-tab]:has([class$=\"_chipIcon\"]) \u2014 the native tab STRIP's\n chips for plugin tabs, so an already-open tab does not survive as a\n clickable ghost. The chip button is dockkit's ([data-dockkit-tab], dsh-web\n frontend bundle: role=tab, renderTabTitle inside a\n span[data-dockkit-tab-title]); its content is the plugin's\n NativeTabTitle (~21172-21197), which always leads with a\n [class$=\"_chipIcon\"] glyph span because every built-in descriptor ships an\n icon \u2014 a chip with no glyph (an external tab registered through the\n plugin's viewer service without an icon) keeps its chip; its body is\n still hidden by the rule above. Host tabs' chips never contain a\n _chipIcon (checked all four @deepseek-ai sidebar packages), so the\n remote-aware host files page survives alongside.\n - [data-floating-window]:has([data-window-body]) \u2014 the plugin's\n body-PORTALED floating windows (client.js FloatingWindow ~15078-15120):\n the task edit window (teams.taskCreate/Update with rootSessionId via\n /sidebar/api, writeTask ~3124-3140) and the job-output window (host jobs\n kill). Both open from the subagent/tasks tab; portal escapes the tab\n body's display:none, so they need their own rule. Anchored on the\n window's own root attribute plus its own inner body marker, so a foreign\n [data-floating-window] without that shape never matches.\n - guide capsules \u2014 the empty-sidebar doorway buttons the HOST renders from\n the plugin's registrations ([data-sidebar-right-guide-entry=\"<kind>\"], RT\n dsh-client-ui-sidebar-right lib/client.js:466): kinds git / subagent /\n sidechat exist only while this plugin registers them, so those selectors\n are inert without it. The \"files\" capsule is the one ambiguous kind:\n dsh-client-ui-sidebar-files registers the SAME kind (its filesDefinition,\n lib/client.js:14-31) and that page is REMOTE-AWARE (it injects the host's\n remote.workspaceFiles service). T53-fix discriminates on the capsule's\n own rendered contract instead of plugin presence: the host's EntryBox\n renders aria-keyshortcuts from the shortcut matching entry.commandId (RT\n sidebar-right lib/client.js:461-467) \u2014 the host files guide row carries\n commandId \"workspace.files\" (dsh-client-ui-sidebar-files\n lib/client.js:30), while better-sidebar's guide rows carry NO commandId\n (client.js registerNativeSurface ~21385-21400), so its capsule never\n renders the attribute. :not([aria-keyshortcuts]) therefore hides the\n plugin's takeover capsule and spares the host's wherever the host has a\n default binding. Boundary: that \"wherever\" is not everywhere \u2014 the host\n registers workspace.files defaults for desktop:macos/windows/linux and\n web:macos/windows only (dsh-client-ui-sidebar-files lib/client.js:949-977),\n so on any other platform the OFFICIAL capsule also renders without the\n attribute and this rule hides it too (cosmetic; the page stays reachable\n through its shortcut command path and the plugin's takeover is the\n \"files\" implementation on every deployment this plugin pairs with\n better-sidebar anyway).\n\n /* PB-14: every T53 rule below carries\n :not([data-zr-bridge-dsh-better-sidebar=\"1\"]) \u2014 when the adapter\n (PB-12) bridges the plugin, the panels read the SERVER's data through\n the byte tunnel and MUST stay visible; the hiding applies only to the\n unbridged combination, and the empty tab body then carries a note\n instead of blankness. The stamp is written by\n effects/remote-session.ts off the remote-status poll's bridgedPlugins\n list (client-data/remote-status.ts shouldStampBridgeAttribute). */\nhtml[data-zr-remote-session=\"1\"]:not([data-zr-bridge-dsh-better-sidebar=\"1\"]) [data-dsh-bottom-toggle] {\n display: none !important;\n}\nhtml[data-zr-remote-session=\"1\"]:not([data-zr-bridge-dsh-better-sidebar=\"1\"]) [data-dsh-panel-host] {\n display: none !important;\n}\nhtml[data-zr-remote-session=\"1\"]:not([data-zr-bridge-dsh-better-sidebar=\"1\"]) {\n --dsh-sidebar-height: 0px !important;\n}\n/* The unbridged tab body: hide the plugin's own content and spend the\n note copy as a ::before \u2014 an already-open tab reads WHY it is empty\n (0.25.0 keeps tabs mounted, so a stale body would otherwise sit blank).\n --zr-bridge-note is set on <html> by the stamp effect, in the\n browser's language; unset (effect not running yet) the content falls\n through and nothing renders. */\nhtml[data-zr-remote-session=\"1\"]:not([data-zr-bridge-dsh-better-sidebar=\"1\"]) [data-dsh-native-tab-host] > * {\n display: none !important;\n}\nhtml[data-zr-remote-session=\"1\"]:not([data-zr-bridge-dsh-better-sidebar=\"1\"]) [data-dsh-native-tab-host]::before {\n content: var(--zr-bridge-note);\n display: block;\n padding: 24px 16px;\n font-size: 13px;\n line-height: 1.7;\n color: var(--dsh-fg-muted, #6b7280);\n word-break: break-word;\n}\nhtml[data-zr-remote-session=\"1\"]:not([data-zr-bridge-dsh-better-sidebar=\"1\"]) [data-dockkit-tab]:has([class$=\"_chipIcon\"]) {\n display: none !important;\n}\nhtml[data-zr-remote-session=\"1\"]:not([data-zr-bridge-dsh-better-sidebar=\"1\"]) [data-floating-window]:has([data-window-body]) {\n display: none !important;\n}\nhtml[data-zr-remote-session=\"1\"]:not([data-zr-bridge-dsh-better-sidebar=\"1\"]) [data-sidebar-right-guide-entry=\"git\"],\nhtml[data-zr-remote-session=\"1\"]:not([data-zr-bridge-dsh-better-sidebar=\"1\"]) [data-sidebar-right-guide-entry=\"subagent\"],\nhtml[data-zr-remote-session=\"1\"]:not([data-zr-bridge-dsh-better-sidebar=\"1\"]) [data-sidebar-right-guide-entry=\"sidechat\"] {\n display: none !important;\n}\nhtml[data-zr-remote-session=\"1\"]:not([data-zr-bridge-dsh-better-sidebar=\"1\"]) [data-sidebar-right-guide-entry=\"files\"]:not([aria-keyshortcuts]) {\n display: none !important;\n}\n/* 0.25.0's dock fallback \u2014 the floating quick-open button the plugin pins\n for empty workspaces. Same treatment as every other open-the-machine's-\n files control: hidden while unbridged, untouched when bridged. */\nhtml[data-zr-remote-session=\"1\"]:not([data-zr-bridge-dsh-better-sidebar=\"1\"]) [data-dsh-dock-fallback] {\n display: none !important;\n}\n\n/* ---------- T52/T74: model-menu groups follow the session's side ----------\n The model catalog is GLOBAL (one shared load per page), so the merged\n catalog shows the server's groups everywhere; but a selection is only\n runnable on the side the open session lives on \u2014 the interceptor refuses\n the other side with a clear message. Hide what cannot run.\n\n What changed and why the mechanism is a STAMP now (T74): through 0.1.7\n each menu group rendered aria-labelledby=\"<useId>-<group.id>\" (RT017\n dsh-client-ui-model-selection lib/client.js ~824-830) \u2014 the group id was\n IN the attribute, and rules could key on a virtual group's \"zr~\" prefix\n directly. 0.2.0 renders the groups with the primitives' MenuGroup\n instead (RT dsh-client-ui-primitives lib/index.js ~4283-4304): the\n section's aria-labelledby carries ONLY the useId, the heading is a child\n div[data-menu-group-heading], and the menu container is a div whose id\n ends in \"-models\" with role=\"menu\" (RT dsh-client-ui-model-selection\n lib/client.js ~974-980). Two consequences killed the old rules: a group\n section no longer says anywhere in its markup which group it is, and the\n same MenuGroup renders OTHER menus' groups too \u2014 the old\n [role=\"menu\"] section[role=\"group\"] scope alone was too wide and would\n have hidden every unmarked group of every menu in a remote session\n (leaving just the search box), while missing the server's groups in\n local ones.\n\n The new keys on what EVERY version actually renders, the heading text:\n each virtual group's name is prefixed with the invisible WORD JOINER\n (VIRTUAL_GROUP_NAME_MARK, virtual-id.ts; written by mergeModelCatalogs).\n The browser effect (effects/model-group-side.ts) reads each group's\n heading and stamps data-zr-group=\"remote|local\" on the section \u2014 but\n only inside a CONTAINER (the sections' shared parent element) that holds\n at least one marked heading. That container rule is what scopes these\n rules to the model menu alone WITHOUT assuming menu structure: an\n unpaired client's model menu, every other menu, and the whole rest of\n the page hold no marked heading, receive no stamp, and match neither\n rule. And since the merged catalog only ever APPENDS virtual groups to\n the local list, within a decided container the unmarked groups are\n exactly the local ones \u2014 mixed containers (the norm) decide each group\n separately. The menu is a portal under <body>, but <html> is still its\n ancestor, so the html-level session attribute scopes both rules. If the\n effect is not running (uninstalled, or a host-role page that never had\n it), no stamp exists and both rules go inert \u2014 nothing stays hidden.\n\n KNOWN BOUNDARY (accepted, not fixed): in a remote session, searching the\n model menu and pressing Enter can commit a HIDDEN local model \u2014 the\n interceptor refuses it with its usual message. */\nhtml[data-zr-remote-session=\"1\"] section[role=\"group\"][data-zr-group=\"local\"] {\n display: none !important;\n}\nhtml:not([data-zr-remote-session]) section[role=\"group\"][data-zr-group=\"remote\"] {\n display: none !important;\n}\n\n/* ---------- T52-fix: hide the virtual groups in NATIVE <option> pickers ----\n The model menu above is React DOM, but dsh-vision-router's settings render\n its vision-backend picker as a native <select> of <option value={group.id}>\n rows, and its filter (dsh-vision-router lib/client.js:661-670\n filterVisionBackendGroups) drops only vision-http / vision-chain / *-vision\n \u2014 a merged virtual group (\"zr~<id>~\u2026\") survives into that picker even\n though a server model can never be a LOCAL vision backend (the router calls\n providers from the machine it runs on). Native <option> rows honor\n display:none in the dropdown list, so this hides them wherever they appear:\n - no scoping attribute on purpose: a virtual group is not a runnable\n backend in ANY local context, and the option element itself carries the\n value \u2014 no host-depth assumption, no :has();\n - when the vision router (or any other <option>-rendering surface) is not\n installed, nothing matches \u2014 dead rule, zero cost;\n - zen-remote's own surfaces are checked: our settings forms render fixed\n enum options (\"web\" / \"desktop-client\" / role kinds /\n configForm enum strings, src/client/settings/SettingsSection.tsx:641,690-701)\n and none can start with \"zr~\" (virtual group ids only ever exist inside\n model-catalog payloads and model-selection arguments). */\noption[value^=\"zr~\"] {\n display: none !important;\n}\n\n/* ---------- remote session: hide the session-export menu item (T51, T51-fix) ----------\n A remote session's log lives on the relay server and the backend refuses\n /api/session.export for a virtual id with 403 remote-unsupported\n (fetch-route-intercept.ts) \u2014 the item would only ever end in the \"Export\n failed\" modal, so it is hidden IN THE MENU (T51-fix: the anchor button\n stays, because it also opens the \u53CD\u9988 entry, which a remote session can\n still use). The DOM, verified against RT:\n - the Menu renders its anchor and its list as SIBLINGS inside its own\n span root (RT dsh-client-ui-primitives lib/index.js ~4265-4273:\n children = [anchor, portal ? createPortal(list) : list]), and the\n export Menu passes no portal flag (default false, ~3923) \u2014 so the list\n is the anchor's next sibling, matched by the general-sibling\n combinator below;\n - the list surface carries role=\"menu\" (Menu passes it at ~4243;\n MenuSurface spreads ...props onto its root div, ~3778-3795) and the\n items viewport inside it is div[role=\"presentation\"] (~4249-4252);\n - every data item is ONE div (the itemWrap wrapper, ~4143), so\n :first-child of the viewport is the FIRST item \u2014 and the export\n package puts \u4E0B\u8F7D/\u5BFC\u51FA first by construction (RT dsh-session-log-export\n lib/client.js 202-206, the optional feedback entry appended after at\n 207-211).\n The anchor button class suffix is matched the way compat.css.ts matches\n module classes (the hash prefix is build-local, \"_moreButton\" is the\n source name; unique in this slot \u2014 the only other moreButton in the RT\n tree, dsh-client-ui-sidebar-documentpreview lib/client.excel.js, lives in\n the sidebar, never under conversation.session.header.utilities).\n Known costs, accepted: with the feedback UI absent the menu's only item\n is the export, so the opened menu is EMPTY; and keyboard navigation still\n steps into the hidden item (focusable but invisible) until activated or\n escaped \u2014 it cannot be triggered through the visibility, only tabbed\n past blindly. */\nhtml[data-zr-remote-session=\"1\"] [data-slot=\"conversation.session.header.utilities\"] [class$=\"_moreButton\"] ~ [role=\"menu\"] > [role=\"presentation\"] > :first-child {\n display: none !important;\n}\n\n/* ---------- remote session: the \"save to this machine\" action (2.2.6) ----------\n One class, owned by this plugin (no host module class, no hash): the\n deliverable-card entry renders it in the card's own actions cell, the\n document-preview entry in the preview header where open-in-app's control\n sits (that one is hidden remotely by the [data-open-target] rule above,\n so this is the only action left there). Both entries only MOUNT for a\n virtual session, so the html attribute gate is belt-and-braces, not the\n decision.\n The palette variables are the host's own (label-secondary / border-l1 /\n interactive-bg-hover / state-error), which keeps light/dark identical to\n the cards around it without copying a theme. */\nhtml[data-zr-remote-session=\"1\"] .zr-download-action {\n box-sizing: border-box;\n flex: none;\n font: inherit;\n font-size: 12px;\n line-height: 18px;\n color: var(--dsw-alias-label-secondary, #6b7280);\n background: transparent;\n border: 0.5px solid var(--dsw-alias-border-l1, #d9dde3);\n border-radius: var(--dsw-radius-sm, 4px);\n padding: 1px 8px;\n cursor: pointer;\n white-space: nowrap;\n}\nhtml[data-zr-remote-session=\"1\"] .zr-download-action:hover {\n color: var(--dsw-alias-label-primary, #111827);\n background: var(--dsw-alias-interactive-bg-hover, rgba(0, 0, 0, 0.05));\n}\nhtml[data-zr-remote-session=\"1\"] .zr-download-action[data-phase=\"busy\"] {\n cursor: progress;\n opacity: 0.7;\n}\nhtml[data-zr-remote-session=\"1\"] .zr-download-action[data-phase=\"error\"] {\n color: var(--dsw-alias-state-error-primary, #dc2626);\n border-color: var(--dsw-alias-state-error-primary, #dc2626);\n}\n";
2
2
  //# sourceMappingURL=remote-session.css.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"remote-session.css.d.ts","sourceRoot":"","sources":["../../../../src/client/styles/remote-session.css.ts"],"names":[],"mappings":"AAgBA,eAAO,MAAM,kBAAkB,2qmBAwS9B,CAAA"}
1
+ {"version":3,"file":"remote-session.css.d.ts","sourceRoot":"","sources":["../../../../src/client/styles/remote-session.css.ts"],"names":[],"mappings":"AAgBA,eAAO,MAAM,kBAAkB,m0pBA8U9B,CAAA"}
@@ -0,0 +1,99 @@
1
+ /**
2
+ * Remote-session drag-and-drop decision core (RD-1): the DOM-free, readable
3
+ * half of the document-level drop guard (src/client/effects/remote-drop.ts).
4
+ *
5
+ * Why this exists: the desktop app's attachment pipeline has a same-machine
6
+ * zero-copy fast path — the Electron preload exposes `__DSH_HOST_PATHS__`,
7
+ * and the host's `addFiles` turns a File that still carries a real disk path
8
+ * into an `@/absolute/path` mention chip WITHOUT uploading any bytes. In a
9
+ * remote session (`zr~<serverId>~<id>`) that path names a file on the
10
+ * SUB-CLIENT's machine; the server-side session can never read it, so the
11
+ * mention lands broken. The fix re-shapes the drop before the host sees it:
12
+ * strip the internal path by re-wrapping each File (`new File([f], ...)`) and
13
+ * redispatch a synthetic, untrusted DragEvent carrying them in a fresh
14
+ * DataTransfer. The host's own drop handler then treats it as an ordinary
15
+ * browser drag — the byte-upload branch — which the T51 fetch-route
16
+ * interception already relays to the server for staging.
17
+ *
18
+ * This module only DECIDES; it never touches the DOM:
19
+ * - `isRemoteSessionId` — the current-session gate, judged by the same
20
+ * `zr~` skeleton (virtual-id.ts) every other remote gate in this plugin
21
+ * keys on, so the two ends cannot drift;
22
+ * - `decideRemoteDrop` — the three trigger gates plus the directory rule,
23
+ * as a pure function over injectable data so the whole truth table is
24
+ * assertable in Node (scripts/check-remote-drop.mjs);
25
+ * - `rewrapFiles` — the File re-wrap itself (Node >= 20 has File).
26
+ *
27
+ * Misjudgement direction is safe by construction: every gate failing open
28
+ * lands on `passthrough` = today's behavior. The only wrong action a stale
29
+ * current-session signal can produce is re-shaping a LOCAL session's drop
30
+ * into an upload — bytes travel that did not have to, but nothing is lost.
31
+ * The reverse (a remote drop reaching the host untouched) is what loses the
32
+ * attachment, which is why all three gates must affirmatively pass.
33
+ */
34
+ /** True when the id is one of this plugin's virtual (relay) session ids —
35
+ * the `zr~<serverId>~<id>` form. `undefined` (no readable current-session
36
+ * signal) is deliberately NOT remote: the conservative gate reads a missing
37
+ * signal as a local session and never intervenes. */
38
+ export declare function isRemoteSessionId(id: string | undefined): boolean;
39
+ /** One drag item, reduced to what the decision needs. `kind` mirrors the
40
+ * DataTransferItem kind — only `file` items can carry attachment bytes.
41
+ * `isDirectory` comes from `webkitGetAsEntry().isDirectory`; a file item
42
+ * whose entry cannot be read counts as NOT a directory (the host applies
43
+ * the same default). */
44
+ export interface RemoteDropItemDescriptor {
45
+ kind: 'file' | 'other';
46
+ isDirectory: boolean;
47
+ }
48
+ /** Everything the decision may look at, injectable so no DOM is needed. */
49
+ export interface RemoteDropInput {
50
+ /** `__DSH_HOST_PATHS__` exists — the Electron preload's zero-copy bridge.
51
+ * False on phone / plain-browser hosts, which already upload bytes. */
52
+ hasHostPaths: boolean;
53
+ /** The currently open session id, or `undefined` when no signal. */
54
+ currentSessionId: string | undefined;
55
+ /** `event.isTrusted` — our own redispatched events are untrusted; this
56
+ * gate is the re-entry guard. */
57
+ trusted: boolean;
58
+ /** Descriptor per file-kind drag item. `undefined` means the entry API
59
+ * (`webkitGetAsEntry`) is unavailable, so directories cannot be detected —
60
+ * the host's own semantics treat that as "no directories". */
61
+ items: readonly RemoteDropItemDescriptor[] | undefined;
62
+ }
63
+ export type RemoteDropAction = 'passthrough' | 'redispatch' | 'block-directories';
64
+ /** Stable machine-readable why, one per action branch. Ordered by the gate
65
+ * sequence below. */
66
+ export type RemoteDropReason = 'untrusted-event' | 'no-host-paths' | 'not-remote-session' | 'no-entry-api' | 'contains-directory' | 'no-files' | 'remote-files';
67
+ export interface RemoteDropDecision {
68
+ action: RemoteDropAction;
69
+ reason: RemoteDropReason;
70
+ }
71
+ /**
72
+ * The three trigger gates, then the directory rule. Every gate must
73
+ * affirmatively pass before anything is intervened on:
74
+ * 1. `trusted` — synthetic (our own) events pass straight through, which is
75
+ * what makes the redispatch loop-free;
76
+ * 2. `hasHostPaths` — without the Electron bridge the host is already on
77
+ * the byte-upload branch and there is nothing to fix;
78
+ * 3. remote session — a missing/failed current-session read counts as local
79
+ * (conservative: passthrough keeps today's behavior);
80
+ * 4. no entry API — redispatch (no directory knowledge, same default as the
81
+ * host);
82
+ * 5. any directory — `block-directories`, which takes precedence over
83
+ * redispatch: a folder cannot be fixed by single-file upload, so the
84
+ * whole drop is stopped with a toast rather than silently reduced;
85
+ * 6. no file items at all — passthrough (the host's own `Files`-in-types
86
+ * gate would ignore the drop; there is nothing to re-shape);
87
+ * 7. otherwise — `redispatch`.
88
+ */
89
+ export declare function decideRemoteDrop(input: RemoteDropInput): RemoteDropDecision;
90
+ /**
91
+ * Re-wrap files so they stop carrying their disk paths. A File the browser
92
+ * constructed from an OS drop keeps a hidden reference the Electron
93
+ * `getPathForFile` can read; `new File([f], ...)` builds a JS-constructed
94
+ * File with no such backing — `getPathForFile` returns "" for it, which
95
+ * sends the host's `addFiles` down the byte-upload branch. name / type /
96
+ * lastModified are preserved so the staged upload keeps its filename.
97
+ */
98
+ export declare function rewrapFiles(files: Iterable<File>): File[];
99
+ //# sourceMappingURL=remote-drop.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"remote-drop.d.ts","sourceRoot":"","sources":["../../../src/client-data/remote-drop.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AAIH;;;qDAGqD;AACrD,wBAAgB,iBAAiB,CAAC,EAAE,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAEjE;AAED;;;;wBAIwB;AACxB,MAAM,WAAW,wBAAwB;IACvC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAA;IACtB,WAAW,EAAE,OAAO,CAAA;CACrB;AAED,2EAA2E;AAC3E,MAAM,WAAW,eAAe;IAC9B;2EACuE;IACvE,YAAY,EAAE,OAAO,CAAA;IACrB,oEAAoE;IACpE,gBAAgB,EAAE,MAAM,GAAG,SAAS,CAAA;IACpC;qCACiC;IACjC,OAAO,EAAE,OAAO,CAAA;IAChB;;kEAE8D;IAC9D,KAAK,EAAE,SAAS,wBAAwB,EAAE,GAAG,SAAS,CAAA;CACvD;AAED,MAAM,MAAM,gBAAgB,GAAG,aAAa,GAAG,YAAY,GAAG,mBAAmB,CAAA;AAEjF;qBACqB;AACrB,MAAM,MAAM,gBAAgB,GACxB,iBAAiB,GACjB,eAAe,GACf,oBAAoB,GACpB,cAAc,GACd,oBAAoB,GACpB,UAAU,GACV,cAAc,CAAA;AAElB,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,gBAAgB,CAAA;IACxB,MAAM,EAAE,gBAAgB,CAAA;CACzB;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,eAAe,GAAG,kBAAkB,CAQ3E;AAED;;;;;;;GAOG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,QAAQ,CAAC,IAAI,CAAC,GAAG,IAAI,EAAE,CAEzD"}
@@ -146,6 +146,9 @@ export interface ClientStatusBody {
146
146
  * a host role or a refused install may still answer it; a server without
147
147
  * the field never does). */
148
148
  pluginRouteIntercept?: unknown;
149
+ /** RD-6: the upload-redirect service probe (presence-gated — an older
150
+ * plugin answers without it). */
151
+ serviceProbe?: unknown;
149
152
  }
150
153
  /** One remote-call failure line in the diagnostics lists. `time` is epoch
151
154
  * milliseconds — ISO-stamped rings are parsed at derive time; `method`
@@ -199,6 +202,10 @@ export interface ClientConnectionView {
199
202
  installed: boolean;
200
203
  reasons: string[];
201
204
  } | undefined;
205
+ /** RD-6: the upload-redirect service probe from the same body, passed
206
+ * through tolerantly (undefined when the body carried none — an older
207
+ * plugin — and the diagnostics row stays hidden). */
208
+ uploadProbe: Readonly<Record<string, unknown>> | undefined;
202
209
  }
203
210
  /**
204
211
  * Map one `client/status` body into the view the client group renders.
@@ -1 +1 @@
1
- {"version":3,"file":"settings-form.d.ts","sourceRoot":"","sources":["../../../src/client-data/settings-form.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"settings-form.d.ts","sourceRoot":"","sources":["../../../src/client-data/settings-form.ts"],"names":[],"mappings":"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"}
@@ -72,6 +72,12 @@ export interface ClientHandlerOptions {
72
72
  getRowConfig: () => unknown;
73
73
  /** Outbound fetch, defaulting to the global one. */
74
74
  fetchImpl?: FetchLike;
75
+ /** Upload-redirect service probe (RD-6): lazily reflects `connection` /
76
+ * `fileUploads` from a context that already resolved, plus whether the
77
+ * fetch-route inject callback ever fired. Answers WHY the upload
78
+ * redirection is absent on compositions where one of the two services
79
+ * never becomes available (cordis keeps such injects silently PENDING). */
80
+ getServiceProbe?: () => Record<string, unknown>;
75
81
  /** The live relay client (T23a), once apply() built one. When it has LEFT
76
82
  * its initial `unpaired` state — a connection attempt ran — the status
77
83
  * route reports ITS verdict (state + handshake server name) and skips the
@@ -1 +1 @@
1
- {"version":3,"file":"client-routes.d.ts","sourceRoot":"","sources":["../../src/client-routes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,WAAW,CAAA;AAChE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAA;AAIvD,OAAO,KAAK,EAAE,8BAA8B,EAAE,MAAM,4BAA4B,CAAA;AAChF,OAAO,KAAK,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAA;AAC9E,OAAO,KAAK,EAAE,+BAA+B,EAAE,MAAM,6BAA6B,CAAA;AAElF,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AAGtD,OAAO,KAAK,EAAE,WAAW,EAAmB,MAAM,mBAAmB,CAAA;AAGrE,+EAA+E;AAC/E,eAAO,MAAM,mBAAmB,4BAA4B,CAAA;AAE5D,qEAAqE;AACrE,eAAO,MAAM,kBAAkB,kCAAiC,CAAA;AAEhE,mEAAmE;AACnE,eAAO,MAAM,mBAAmB,mCAAkC,CAAA;AAElE;kEACkE;AAClE,eAAO,MAAM,sBAAsB,sCAAqC,CAAA;AAExE;;;;;wEAKwE;AACxE,eAAO,MAAM,0BAA0B,0CAAyC,CAAA;AAEhF;;8EAE8E;AAC9E,eAAO,MAAM,oBAAoB,oCAAmC,CAAA;AAEpE;;;;4CAI4C;AAC5C,eAAO,MAAM,4BAA4B,4CAA2C,CAAA;AAOpF;;;uEAGuE;AACvE,eAAO,MAAM,wBAAwB,kCAAiC,CAAA;AAWtE,8DAA8D;AAC9D,MAAM,MAAM,SAAS,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,EAAE,IAAI,CAAC,EAAE,WAAW,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAA;AAEpF,MAAM,WAAW,oBAAoB;IACnC,0EAA0E;IAC1E,KAAK,EAAE,CAAC,GAAG,EAAE,eAAe,KAAK,cAAc,CAAA;IAC/C;;sCAEkC;IAClC,YAAY,EAAE,MAAM,OAAO,CAAA;IAC3B,oDAAoD;IACpD,SAAS,CAAC,EAAE,SAAS,CAAA;IACrB;;;;;oDAKgD;IAChD,cAAc,CAAC,EAAE,MAAM,WAAW,GAAG,SAAS,CAAA;IAC9C;;8EAE0E;IAC1E,YAAY,CAAC,EAAE,MAAM,oBAAoB,GAAG,SAAS,CAAA;IACrD;;;2EAGuE;IACvE,sBAAsB,CAAC,EAAE,MAAM,8BAA8B,GAAG,SAAS,CAAA;IACzE;;;uDAGmD;IACnD,uBAAuB,CAAC,EAAE,MAAM,+BAA+B,GAAG,SAAS,CAAA;IAC3E;;;;sEAIkE;IAClE,qBAAqB,CAAC,EAAE,MAAM,YAAY,EAAE,CAAA;IAC5C;;;;;;0CAMsC;IACtC,gBAAgB,CAAC,EAAE,OAAO,CAAA;IAC1B;;;;;iBAKa;IACb,gBAAgB,CAAC,EAAE,CAAC,IAAI,EAAE,kBAAkB,KAAK,IAAI,CAAA;CACtD;AAED,MAAM,MAAM,aAAa,GAAG,CAAC,GAAG,EAAE,eAAe,EAAE,GAAG,EAAE,cAAc,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;AA8NxF;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,oBAAoB,GAAG,aAAa,CA8XhF"}
1
+ {"version":3,"file":"client-routes.d.ts","sourceRoot":"","sources":["../../src/client-routes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,WAAW,CAAA;AAChE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAA;AAIvD,OAAO,KAAK,EAAE,8BAA8B,EAAE,MAAM,4BAA4B,CAAA;AAChF,OAAO,KAAK,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAA;AAC9E,OAAO,KAAK,EAAE,+BAA+B,EAAE,MAAM,6BAA6B,CAAA;AAElF,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AAGtD,OAAO,KAAK,EAAE,WAAW,EAAmB,MAAM,mBAAmB,CAAA;AAGrE,+EAA+E;AAC/E,eAAO,MAAM,mBAAmB,4BAA4B,CAAA;AAE5D,qEAAqE;AACrE,eAAO,MAAM,kBAAkB,kCAAiC,CAAA;AAEhE,mEAAmE;AACnE,eAAO,MAAM,mBAAmB,mCAAkC,CAAA;AAElE;kEACkE;AAClE,eAAO,MAAM,sBAAsB,sCAAqC,CAAA;AAExE;;;;;wEAKwE;AACxE,eAAO,MAAM,0BAA0B,0CAAyC,CAAA;AAEhF;;8EAE8E;AAC9E,eAAO,MAAM,oBAAoB,oCAAmC,CAAA;AAEpE;;;;4CAI4C;AAC5C,eAAO,MAAM,4BAA4B,4CAA2C,CAAA;AAOpF;;;uEAGuE;AACvE,eAAO,MAAM,wBAAwB,kCAAiC,CAAA;AAWtE,8DAA8D;AAC9D,MAAM,MAAM,SAAS,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,EAAE,IAAI,CAAC,EAAE,WAAW,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAA;AAEpF,MAAM,WAAW,oBAAoB;IACnC,0EAA0E;IAC1E,KAAK,EAAE,CAAC,GAAG,EAAE,eAAe,KAAK,cAAc,CAAA;IAC/C;;sCAEkC;IAClC,YAAY,EAAE,MAAM,OAAO,CAAA;IAC3B,oDAAoD;IACpD,SAAS,CAAC,EAAE,SAAS,CAAA;IACrB;;;;+EAI2E;IAC3E,eAAe,CAAC,EAAE,MAAM,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAC/C;;;;;oDAKgD;IAChD,cAAc,CAAC,EAAE,MAAM,WAAW,GAAG,SAAS,CAAA;IAC9C;;8EAE0E;IAC1E,YAAY,CAAC,EAAE,MAAM,oBAAoB,GAAG,SAAS,CAAA;IACrD;;;2EAGuE;IACvE,sBAAsB,CAAC,EAAE,MAAM,8BAA8B,GAAG,SAAS,CAAA;IACzE;;;uDAGmD;IACnD,uBAAuB,CAAC,EAAE,MAAM,+BAA+B,GAAG,SAAS,CAAA;IAC3E;;;;sEAIkE;IAClE,qBAAqB,CAAC,EAAE,MAAM,YAAY,EAAE,CAAA;IAC5C;;;;;;0CAMsC;IACtC,gBAAgB,CAAC,EAAE,OAAO,CAAA;IAC1B;;;;;iBAKa;IACb,gBAAgB,CAAC,EAAE,CAAC,IAAI,EAAE,kBAAkB,KAAK,IAAI,CAAA;CACtD;AAED,MAAM,MAAM,aAAa,GAAG,CAAC,GAAG,EAAE,eAAe,EAAE,GAAG,EAAE,cAAc,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;AA8NxF;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,oBAAoB,GAAG,aAAa,CAgYhF"}