export declare const COMPAT_CSS = "@media (max-width: 1023px) and (pointer: coarse) {\n /* ---------- dsh-web-ui family compatibility ----------\n The linxin666 plugin suite extends the shell frame directly:\n - aionui-panel appends two trailing grid columns (explorer / preview)\n plus absolute drag handles to [data-dsh-frame]; its 5-track inline\n grid is already overridden above, but the handles and columns would\n still float over the main UI. On mobile the columns leave the grid\n as floating bottom sheets and keep their own visibility state \u2014\n the suite's collapse chevron / preview tabs still work, so no\n feature is lost. The task-board / ssh plugins inject sidebar\n entries and center-column takeover panels; the entries need\n spacing and the kanban needs scrollable columns. */\n\n /* Touch devices: the drag handles are useless \u2014 the floating expand\n button is the opener. */\n .aionui-explorer-handle,\n .aionui-preview-handle {\n display: none !important;\n }\n\n /* Shared base: both columns leave the grid as floating panels. The\n explorer is gated shut by default (its own persisted expanded state\n must never cover the mobile UI on load); the header Files action opens\n it via the frame marker below, and the sheet's own collapse chevron\n clears it. Preview stays owned by the suite (hidden while no tab is\n open). The per-column rules below override the geometry. */\n [data-aionui-explorer-col],\n [data-aionui-preview-col] {\n position: fixed !important;\n z-index: 55 !important;\n background: var(--aion-bg-base, #ffffff) !important;\n border-left: none !important;\n }\n /* Explorer (file tree) bottom sheet: bottom edge aligned exactly with\n the composer card's bottom line \u2014 the card sits 36px above the\n viewport bottom (8px composer padding + the 28px stats strip below\n the card), so the sheet uses the same 36px bottom offset. */\n [data-aionui-explorer-col] {\n visibility: hidden !important;\n left: 8px !important;\n right: 8px !important;\n top: auto !important;\n bottom: 36px !important;\n width: auto !important;\n height: min(55dvh, 460px) !important;\n max-height: calc(100dvh - 44px) !important;\n border-radius: 14px !important;\n overflow: hidden !important;\n box-shadow: 0 -4px 28px rgba(0, 0, 0, .18) !important;\n animation: dsh-web-mobile-sheet-up .24s var(--ds-ease-out, ease-in-out) !important;\n }\n /* Preview (file content) bottom sheet. Gated shut by default: the suite\n persists open preview tabs in localStorage and restores them on load,\n which would pop the sheet over the fresh UI. The client only sets the\n frame marker after the user taps a file row in the explorer; the\n suite's own collapse chevron clears it via the visibility watcher. */\n [data-aionui-preview-col] {\n visibility: hidden !important;\n position: fixed !important;\n left: 8px !important;\n right: 8px !important;\n top: auto !important;\n bottom: 40px !important;\n width: auto !important;\n height: min(50dvh, 420px) !important;\n max-height: calc(100dvh - 48px) !important;\n border-radius: 14px !important;\n overflow: hidden !important;\n box-shadow: 0 -4px 28px rgba(0, 0, 0, .18) !important;\n z-index: 56 !important;\n animation: dsh-web-mobile-sheet-up .24s var(--ds-ease-out, ease-in-out) !important;\n /* Fullscreen toggle (issue #8): animate the geometry change instead of\n snapping. visibility is deliberately not listed, so opening/closing\n the sheet stays instant; the open/close keyframes own transform. */\n transition:\n left .24s var(--ds-ease-out, ease-in-out),\n right .24s var(--ds-ease-out, ease-in-out),\n top .24s var(--ds-ease-out, ease-in-out),\n bottom .24s var(--ds-ease-out, ease-in-out),\n width .24s var(--ds-ease-out, ease-in-out),\n height .24s var(--ds-ease-out, ease-in-out),\n border-radius .24s var(--ds-ease-out, ease-in-out),\n box-shadow .24s var(--ds-ease-out, ease-in-out),\n padding-top .24s var(--ds-ease-out, ease-in-out) !important;\n }\n /* User-opened preview sheet (frame marker, set on file-row tap). */\n [data-mobile-nav=\"frame\"][data-aionui-preview-open] [data-aionui-preview-col] {\n visibility: visible !important;\n }\n /* The Files action opens the explorer sheet (frame marker). */\n [data-mobile-nav=\"frame\"][data-aionui-explorer-open] [data-aionui-explorer-col] {\n visibility: visible !important;\n }\n /* While the preview sheet is up, the explorer sheet yields (two stacked\n bottom sheets would read as one broken overlay). Closing the preview\n via its collapse chevron / tab close clears the marker, and the\n explorer sheet returns. Same specificity as the explorer-open rule, so\n this must stay AFTER it. */\n [data-mobile-nav=\"frame\"][data-aionui-preview-open] [data-aionui-explorer-col] {\n visibility: hidden !important;\n }\n /* The open drawer must never sit under a sheet: while the frame is in the\n narrow-expanded state both sheets yield (later in the file than the\n open marker rule, so it wins at equal specificity). The fullscreen\n toggle is a descendant of this column, so it is hidden with the rest of\n the column \u2014 there is no separate drawer-open rule for it. */\n [data-mobile-nav=\"frame\"]:not([data-sidebar-collapsed]) [data-aionui-explorer-col],\n [data-mobile-nav=\"frame\"]:not([data-sidebar-collapsed]) [data-aionui-preview-col] {\n visibility: hidden !important;\n display: none !important;\n }\n /* The suite's own expand button reads the store state we bypass on\n mobile \u2014 hide it; the header Files action is the opener. */\n .aionui-floating-expand {\n display: none !important;\n }\n\n /* Preview sheet fullscreen toggle (issue #8): a fixed button parked in the\n sheet's titlebar row, just left of the suite's collapse chevron (24px at\n right:8px of the sheet, and the sheet spans 8px..(100vw-8px)). The top\n calc mirrors the sheet geometry above (bottom 40px + min(50dvh, 420px));\n when the frame carries \"data-mobile-preview-full\" the sheet goes\n fullscreen and the button moves to the viewport corner. */\n [data-mobile-nav=\"preview-full-toggle\"] {\n position: absolute !important;\n right: 36px !important;\n top: 8px !important;\n z-index: 57 !important;\n display: none !important;\n align-items: center;\n justify-content: center;\n width: 20px;\n height: 20px;\n padding: 0;\n border: none;\n border-radius: 4px;\n background: transparent;\n color: var(--aion-text-secondary, var(--dsw-alias-label-secondary, inherit));\n cursor: pointer;\n -webkit-tap-highlight-color: transparent;\n /* Native look: same size/radius/hover language as the suite's tab-bar\n icon buttons (the 20px panelCollapse next to it). The button lives\n INSIDE the preview column, so it rides the sheet's own open\n animation and geometry transition \u2014 no curve matching needed. */\n transition: background-color .15s, top .24s var(--ds-ease-out, ease-in-out);\n }\n [data-mobile-nav=\"preview-full-toggle\"]:hover {\n background: var(--aion-bg-3, rgba(0, 0, 0, .22));\n }\n [data-mobile-nav=\"preview-full-toggle\"]:active {\n background: var(--aion-bg-active, rgba(0, 0, 0, .28));\n }\n [data-mobile-nav=\"preview-full-toggle\"]:focus-visible {\n outline: 2px solid var(--dsw-alias-state-business-primary, #4f6ef7);\n outline-offset: 2px;\n }\n [data-mobile-nav=\"preview-full-toggle\"] svg {\n width: 14px;\n height: 14px;\n }\n /* Keep the last tab (and the \"+\" URL-tab trigger) from sliding under the\n fullscreen toggle: reserve the right end of the preview tab row. */\n [data-aionui-preview-col] [class*=\"_tabScroll\"] {\n padding-right: 34px !important;\n }\n /* Visible only while the preview sheet is open. Visibility itself is\n inherited from the column, so the sheet's own hide rules (collapse,\n drawer open) cover the button too. */\n [data-mobile-nav=\"frame\"][data-aionui-preview-open] [data-aionui-preview-col] [data-mobile-nav=\"preview-full-toggle\"] {\n display: inline-flex !important;\n }\n /* Icon swap on the frame fullscreen marker. */\n [data-mobile-nav=\"preview-full-toggle\"] .dsh-web-mobile-full-out {\n display: none !important;\n }\n [data-mobile-nav=\"frame\"][data-mobile-preview-full] [data-aionui-preview-col] [data-mobile-nav=\"preview-full-toggle\"] .dsh-web-mobile-full-in {\n display: none !important;\n }\n [data-mobile-nav=\"frame\"][data-mobile-preview-full] [data-aionui-preview-col] [data-mobile-nav=\"preview-full-toggle\"] .dsh-web-mobile-full-out {\n display: inline !important;\n }\n /* Fullscreen preview: the sheet fills the whole viewport (notch included);\n the safe-area padding drops the titlebar row below the status bar, and\n the toggle follows the titlebar into the top corner. */\n [data-mobile-nav=\"frame\"][data-aionui-preview-open][data-mobile-preview-full] [data-aionui-preview-col] {\n inset: 0 !important;\n left: 0 !important;\n right: 0 !important;\n top: 0 !important;\n bottom: 0 !important;\n width: 100% !important;\n height: 100dvh !important;\n max-height: none !important;\n box-sizing: border-box !important;\n padding-top: env(safe-area-inset-top, 0px) !important;\n border-radius: 0 !important;\n box-shadow: none !important;\n z-index: 57 !important;\n animation: none !important;\n }\n /* Fullscreen: the column fills the viewport, so the button follows the\n titlebar row down below the notch. */\n [data-mobile-nav=\"frame\"][data-mobile-preview-full] [data-aionui-preview-col] [data-mobile-nav=\"preview-full-toggle\"] {\n top: calc(env(safe-area-inset-top, 0px) + 8px) !important;\n }\n @media (prefers-reduced-motion: reduce) {\n [data-aionui-preview-col],\n [data-mobile-nav=\"preview-full-toggle\"] {\n transition: none !important;\n animation: none !important;\n }\n }\n\n /* dsh-web-ui sidebar entries (task board / ssh) sit flush against each\n other \u2014 give the injected rows breathing room. */\n button[data-dsh-taskboard-entry],\n button[data-dsh-ssh-entry] {\n margin-bottom: 8px !important;\n }\n\n /* Task board: five kanban columns at minmax(0,1fr) crush into ~78px phone\n strips. Give every column a usable minimum and let the row scroll. */\n [data-dsh-taskboard-board] > [class*=\"_columns\"] {\n grid-template-columns: repeat(5, minmax(240px, 1fr)) !important;\n overflow-x: auto !important;\n }\n /* The floating button must not float over a takeover panel (task board /\n ssh own the center column while active). */\n html[data-dsh-taskboard-active] [data-mobile-nav=\"fab\"],\n html[data-dsh-ssh-active] [data-mobile-nav=\"fab\"],\n html[data-dsh-taskboard-active] [data-mobile-nav=\"backdrop\"],\n html[data-dsh-ssh-active] [data-mobile-nav=\"backdrop\"] {\n display: none !important;\n }\n /* Board header: let the search field take the slack instead of squeezing\n the action buttons. */\n [data-dsh-taskboard-board] > [class*=\"_boardHeader\"] [class*=\"_search\"] {\n flex: 1 1 auto !important;\n min-width: 80px !important;\n }\n\n /* ---------- dsh-web-ui polish: plugin market search ----------\n The market tab row (Discover / Themes / Installed + the plugin search\n box) is a no-wrap flex: at 390px the tabs plus the ~218px search box\n (~475px total) overflow the ~334px sheet and the search box runs off\n the right edge of the screen (it also forces a horizontal scrollbar on\n the sheet's options area). Let the row wrap: the tabs keep the first\n line and the search box gets its own full-width second line. */\n\n [aria-modal=\"true\"] [class*=\"_tabs\"] {\n flex-wrap: wrap !important;\n row-gap: 8px !important;\n }\n [aria-modal=\"true\"] [class*=\"_searchInline\"] {\n flex: 1 1 100% !important;\n width: 100% !important;\n max-width: 100% !important;\n }\n /* iOS Safari auto-zooms a focused input whose computed font-size is below\n 16px. dshmarket's tab search uses the shared primitive Input at 13px;\n raise only this market-owned field on mobile so focusing it keeps the\n current viewport scale. Scoped to the market root to avoid changing\n unrelated settings/search fields; pinch zoom stays available. */\n [data-dsh-market-root] [class*=\"tabSearch\"] input,\n [data-dsh-market-root] input[class*=\"tabSearch\"] {\n font-size: 16px !important;\n }\n\n /* ---------- dshmarket polish: Tasks operations popup ----------\n Upstream .opPanel is a small dropdown pinned to the right edge of its\n ~54px trigger button; on a phone it reads as stuck to the sheet edge\n instead of centered. Promote it to a fixed, viewport-centered card:\n no ancestor between the popup and the viewport carries a transform,\n so position:fixed centers against the real viewport (a plain left:50%\n would resolve against the tiny relative trigger wrapper and land even\n further right). The upstream 86vw width cap, 70vh max-height and\n internal scroll all still apply; the close button stays inside.\n 2026-09-25: re-anchored from [data-mobile-nav=\"frame\"] [aria-modal]\n to the market's own root marker \u2014 since rc.2 the whole settings\n sheet (market included) is portaled to
and no longer matches a\n frame-descendant selector. */\n [data-dsh-market-root] [class*=\"_opPanel\"] {\n position: fixed !important;\n top: 50% !important;\n bottom: auto !important;\n left: 50% !important;\n right: auto !important;\n transform: translate(-50%, -50%) !important;\n }\n\n /* ---------- dshmarket polish: header title row ----------\n The title row (icon + title + repo link + version + optional\n \"Update market\" / \"Update all\" buttons) is a nowrap flex whose\n natural width (~450px with both update buttons) exceeds the ~334px\n sheet. Flex then crushes the flexible items below their content\n width and every label wraps word-by-word \u2014 the \"text turns\n vertical\" report. Trigger is state-dependent (the buttons only\n exist while plugin updates are pending), which explains the\n sometimes-horizontal/sometimes-vertical flapping. Let the row wrap\n instead: line 1 keeps icon + title + repo + version, the update\n buttons get their own full-width-feeling second line, and the title\n itself is locked to one ellipsized line no matter what follows it.\n 2026-09-25: re-anchored from [data-mobile-nav=\"frame\"] [aria-modal]\n to the market's own root marker \u2014 since rc.2 the whole settings\n sheet (market included) is portaled to and no longer matches a\n frame-descendant selector. Same day, second pass: the ported rule's\n flex:1 1 auto on the title GREW it to fill the row, which pushed the\n repo link and the version \"v1.65.1\" to the far right \u2014 exactly where\n the pinned toolbar's close \u2715 sits, crowding the corner the owner\n reported as \"\u5F88\u5BB9\u6613\u8BEF\u89E6\" (hit-test: the version box reached x\u2248378,\n the close \u2715 starts at x=350). flex:0 1 auto keeps the title at its\n natural width (repo + version pack left, as upstream intends) while\n still letting it shrink-and-ellipsize when the update buttons force a\n wrap \u2014 the wrap rule above, not flex-grow, is what makes room for\n them. */\n [data-dsh-market-root] [class*=\"_titleRow\"] {\n flex-wrap: wrap !important;\n row-gap: 6px !important;\n }\n [data-dsh-market-root] [class*=\"_titleRow\"] [class*=\"_title\"] {\n flex: 0 1 auto !important;\n min-width: 0 !important;\n white-space: nowrap !important;\n overflow: hidden !important;\n text-overflow: ellipsis !important;\n }\n [data-dsh-market-root] [class*=\"_titleRow\"] button {\n white-space: nowrap !important;\n }\n\n /* ---------- dshmarket polish: card byline stays on one line ----------\n The byline (avatar \u00B7 owner \u00B7 version \u00B7 \u2193downloads \u00B7 \u2605stars) is a\n wrapping flex row by upstream design \u2014 the market would rather drop\n the counts to a second line than over-shrink the owner name (its\n .owner carries flex:0 1 auto + ellipsis + min-width:44px exactly for\n that). At a phone's card width the break point lands mid-row though:\n everything but the star fits, so a lone \"\u00B7 \u2605 8k\" wraps onto its own\n line under the author \u2014 inconsistent with the cards that happen to\n fit, which reads as a rendering bug (owner report 2026-09-25,\n IMG_4208: dsh-remote-web-ui and dsh-skill-explorer both orphaned the\n star). Pin the row to one line instead: the owner is the market's own\n flexible item, so it absorbs the squeeze and the counts stay whole.\n Desktop cards are far wider than the row and never wrapped anyway. */\n [data-dsh-market-root] [class*=\"_byline\"] {\n flex-wrap: nowrap !important;\n }\n\n /* ---------- dshmarket polish: top inset ----------\n The sheet is pinned to the top of the screen (A': top = safe-area +\n 12px) and the market page started FLUSH against the sheet's top\n edge \u2014 measured 2026-09-25: the title row's gap from the sheet's top\n was 0px while the pinned close \u2715 sat 10px under it, so the whole\n page read as crushed against the boundary (owner report, IMG_4211:\n \"\u6700\u4E0A\u9762\u5FEB\u8981\u9876\u5230\u8FB9\u754C\u4E86... \u628A\u6574\u4F53\u5F80\u4E0B\u79FB\u4E00\u70B9\uFF0C\u6709\u70B9\u7559\u767D\u4F1A\u66F4\u7F8E\u89C2\").\n Give the page the same 12px inset its own horizontal padding already\n has (the root box was 12px from each side, 0px from the top), so the\n title lands ~12px under the sheet's rounded corner, level with the\n close \u2715. The market page is the sheet's CONTENT, so it moves; the\n pinned toolbar (close \u2715) belongs to the sheet and deliberately does\n NOT move (\"\u5173\u95ED\u6309\u94AE\u53EF\u4EE5\u4E0D\u52A8\"). Scrolls away naturally with the page.\n Desktop market is vertically centered with the host's own clearance\n and never had this read; the rule is mobile-only. */\n [data-dsh-market-root] {\n margin-top: 12px !important;\n }\n /* Below ~360px the fixed-width counts plus the owner's 44px min overrun\n the card, so the ellipsis eats most of the name (\"omds...\"). Trade text\n size for name length on the smallest phones: 11px \u2192 10px text and\n 6px \u2192 4px gaps buy the owner roughly a third more room while the row\n stays one line. Tablet/phone tiers above this width are unaffected. */\n @media (max-width: 360px) {\n [data-dsh-market-root] [class*=\"_byline\"] {\n gap: 4px !important;\n font-size: 10px !important;\n }\n [data-dsh-market-root] [class*=\"_byline\"] [class*=\"_dot\"] {\n margin-left: 3px !important;\n }\n }\n\n /* ---------- dshmarket 1.20+ compat: keep the settings nav visible ----------\n Upstream Market.module.css hides the host dialog's nav on phones\n ([role=dialog]:has([data-dsh-market-root]) > nav { display:none } at\n max-width:560px) so the market can take over the dialog; its comment\n assumes the host keeps \"its own close button in the content header\".\n Our host's only close \u2715 lives inside that very nav, so the market\n would leave no categories and no way back or out (dead-end UI,\n 2026-08-23). Mirror upstream's exact media condition and restore the\n nav: categories row + \u2715 stay above the inline market page.\n 2026-09-25 (rc.2 regression): 0.1.7-rc.2 renders this sheet through\n createPortal(..., document.body), so the frame-scoped selector matches\n nothing on rc.2+ hosts and the market takeover silently won \u2014 no\n categories row above the market page on every updated phone. The twin\n rule below carries the same declaration on a structural anchor\n ([role=dialog]:has(...) > nav, no frame prefix): on rc.1 hosts the\n frame-scoped rule does the work and the twin is inert (the sheet is a\n frame descendant there); on rc.2+ the twin carries it. Both stay\n inside this file's mobile media wrapper, so desktop never sees them.\n Premise note: this host generation keeps its close \u2715 in the CONTENT\n header (pinned top-right \u2014 see layout.css), so the dead-end half of\n the 2026-08-23 report no longer applies; the rule is kept and twinned\n for the categories row it restores (guarded by the test suite). */\n @media (max-width: 560px) {\n [data-mobile-nav=\"frame\"] [role=\"dialog\"]:has([data-dsh-market-root]) > nav {\n display: flex !important;\n }\n [role=\"dialog\"]:has([data-dsh-market-root]) > nav {\n display: flex !important;\n }\n }\n\n /* ---------- dsh-usage-stats polish: usage & balance panel ----------\n The panel's stats row shows three token counters side by side\n (today / month / total). The counters use tabular nowrap figures whose\n min-content width overflows the ~336px panel body on a phone: figures\n clip at the row's edges and the panel grows a horizontal scrollbar.\n Stack the three counters vertically \u2014 full-width rows, so the figures\n always fit. */\n\n [class*=\"usg_\"][class*=\"_statsRow\"] {\n flex-direction: column !important;\n }\n [class*=\"usg_\"][class*=\"_stat\"]:not([class*=\"_statsRow\"]) {\n flex: 0 0 auto !important;\n width: 100% !important;\n min-width: 0 !important;\n }\n\n /* ---------- dsh-web-ui polish: settings sheet ----------\n Keep the nav tabs on ONE horizontally scrolling row. Setting rows need\n no mobile rework: the host redesigned them into compact space-between\n rows (text left, control right \u2014 verified in\n dsh-client-ui-settings-general .Pt1bsG_row, 2026-09-24). The old\n \"stack each row\" rules, written for the previous two-column generation\n with its dead label/control gap, now fight that design and double every\n row's height; they were removed (see the tombstone below). */\n\n /* Nav tabs + toolbar: TOMBSTONE (2026-09-25). This whole family \u2014\n the single-row scroller, its hairline scrollbar, the compact cells and\n the hidden \"Open configuration file\" button \u2014 was scoped to\n [data-mobile-nav=\"frame\"] because rc.1 rendered the settings sheet in\n place, inside the app frame. rc.2 wraps the sheet in\n createPortal(..., document.body): the overlay is a direct body child,\n nothing inside it matches a frame-descendant selector, and every rule\n here went dead at once. The live symptoms were the nav cells wrapping\n into uneven rows that slid under the 138px toolbar and the config-file\n button reappearing in that toolbar (owner report 2026-09-25). The\n portal-aware replacements live in layout.css.ts, in the \"Settings\n dialog on mobile\" section, anchored on the same structural\n :has(> :first-child > :last-child > button) gate (settings sheet only;\n export dialog and directory picker stay excluded). Nothing to restore\n here \u2014 do not re-add behind a frame selector. */\n /* Setting rows: no mobile rework \u2014 the host renders compact space-between\n rows natively (.Pt1bsG_row: text left, control right, 16px vertical\n padding, .5px divider). The previous \"stack each row\" rule family\n (column + gap:8 + control width:100% + the 36\u00D720 switch cap that undid\n it) was written for the old two-column generation; on the redesigned\n host it doubled every row's height \u2014 the \"settings feel vertically\n empty\" report 2026-09-24 \u2014 and was removed in full. If an older host\n generation ever needs stacking again, reintroduce behind a generation\n guard, not as a blanket [class*=\"_row\"] override. */\n /* Models provider editor: a CLOSED (\"_customized\", the customized\n models section) must not paint its body. This engine paints the ~1500px\n model catalog of the closed details as a ghost layer anyway: it overlays\n the editor's own action rows (Fetch/Cancel/Apply/Add model) and the\n provider rows BEFORE the editor row in DOM order (those paint under the\n ghost and lose hit-testing), while rows after it paint above. Result\n (owner report 2026-09-19): providers cannot be deleted, \"fetch available\n models\" does nothing \u2014 every tap lands on whatever row overlaps the\n ghost. The host layout is computed for the collapsed details (editor\n 217px, rows 903px), so the fix is to restore what the browser should do\n on its own: hide the body while the details is closed. Tapping the\n summary then opens it for real (details 33 \u2192 1532px, rows re-flow,\n every button hittable \u2014 verified in place before this rule was written). */\n [aria-modal=\"true\"] details[class*=\"_customized\"]:not([open]) > [class*=\"_customizedBody\"] {\n display: none !important;\n }\n /* Owner dialog footers (_w1urq family: the provider delete confirm, the\n workspace rename dialog, ...): the footer buttons keep white-space\n normal, so any width squeeze \u2014 a narrow viewport, a long provider name,\n Android font scaling (owner report 2026-09-19, verified at 320px with a\n 1.3x font bump) \u2014 wraps the label inside the fixed 36px row where the\n second line clips. Keep each label on one line and let the footer wrap\n whole buttons to a second row instead. */\n [role=\"dialog\"][aria-modal=\"true\"] [class*=\"_footer\"] {\n flex-wrap: wrap !important;\n }\n [role=\"dialog\"][aria-modal=\"true\"] [class*=\"_footer\"] button[class*=\"_button\"] {\n white-space: nowrap !important;\n }\n /* Appearance mode group: give the cube row a consistent bordered\n segmented look (the official borders differ per state). */\n [aria-modal=\"true\"] [class*=\"_cubeRow\"] > * {\n border: 1px solid var(--dsw-alias-border-l1, rgba(0, 0, 0, .12)) !important;\n }\n\n /* ---------- dsh-web-ui polish: explorer sheet ----------\n The aionui explorer was designed for a desktop side column: compact the\n header, search box and tree rows so a phone shows more entries, and pad\n the scroll bottom so the last row never sits flush on the edge. */\n\n [data-aionui-explorer-col] [class*=\"_tabBar\"]:not([class*=\"_tabBarRight\"]) {\n height: 36px !important;\n }\n [data-aionui-explorer-col] [class*=\"_tabBtn\"],\n [data-aionui-explorer-col] [class*=\"_tabBtnActive\"] {\n padding: 0 12px !important;\n font-size: 13px !important;\n }\n [data-aionui-explorer-col] [class*=\"_searchBox\"] {\n height: 32px !important;\n font-size: 13px !important;\n }\n [data-aionui-explorer-col] [class*=\"_treeRow\"] {\n height: 30px !important;\n font-size: 13px !important;\n }\n [data-aionui-explorer-col] [class*=\"_treeRow\"] svg {\n width: 14px !important;\n height: 14px !important;\n }\n [data-aionui-explorer-col] [class*=\"_scrollArea\"] {\n padding-bottom: 28px !important;\n }\n\n /* ---------- dsh-web-ui polish: drawer footer ----------\n The official footerActions row also hosts the remote-web-ui entry row\n (two icon buttons) and the usage/balance badge; without wrapping the\n groups squeeze each other on one line. Wrap so each group gets its own\n row. (The plugin's own footer pill was removed on 2026-10-18 \u2014 the\n session-log entry now lives in the drawer brand row.) */\n [data-mobile-nav=\"frame\"] [class*=\"_footerActions\"] {\n flex-wrap: wrap !important;\n gap: 6px !important;\n }\n\n /* ---------- dsh-web-ui polish: floating pet ----------\n The whale-girl pet (dsh-pet) floats at the viewport corner with a\n persisted, draggable position. On phones the pet is scaled down so\n it does not dominate the screen; the plugin's own drag + persist\n still work (the position itself is left alone \u2014 the mobile default\n position is seeded via the pet API to just above the composer). */\n\n body > [class*=\"_float\"]:has([class*=\"_sprite\"][role=\"button\"]) {\n transform: scale(.66);\n transform-origin: bottom right;\n }\n /* While a modal dialog (settings sheet / export) owns the screen the pet\n floats ABOVE it and covers the dialog content; modal semantics say the\n background is inert, so hide the pet for the modal's lifetime. */\n body:has([aria-modal=\"true\"]) > [class*=\"_float\"]:has([class*=\"_sprite\"][role=\"button\"]) {\n display: none !important;\n }\n\n /* ---------- dsh-web-ui polish: conversation stats line ----------\n The official session-status row (turns / steps / LLM time / TTFT /\n cache) is long. The client marks the exact row with\n [data-mobile-nav=\"stats\"] (text-anchored, hashed classes can't be\n targeted). Layout: ONE fixed-height (28px) flex strip that scrolls\n horizontally \u2014 the full metrics stream stays reachable by swiping,\n the row never grows vertically, no ellipsis or fade, 12px gaps\n between metric groups, a 2px scrollbar as the swipe affordance.\n\n 2026-09-23 \u6539\u6863\uFF08\u5E97\u4E3B\uFF1A\"\u628A\u90A3\u4E2A\u6ED1\u52A8\u7684\u538B\u7F29\u4E00\u4E0B\uFF0C\u56FA\u5B9A\u4F4F\uFF0C\u4E0D\u518D\u6ED1\u52A8\"\uFF09\uFF1A\n \u771F\u673A\u63A2\u9488\u5B9E\u6D4B \u53EF\u89C1\u5BBD 251px\u3001\u5185\u5BB9 390px\uFF08\"10 \u8F6E 268 \u6B65\u00B7244 tok/s\" 178 +\n \"57.5M tok\u00B7\u7F13\u5B58\u547D\u4E2D 99%\" 187\uFF0Cgap 12\u3001font 12\uFF09\uFF0C\u53F3\u8FB9 ~75px \u88AB dock \u91CC\u7684\n \u4E0A\u4E0B\u6587\u767E\u5206\u6BD4\u90A3\u5757\u5360\u7740 \u21D2 \u4E00\u884C\u672C\u6765\u5C31\u653E\u4E0D\u4E0B\u3002\u6309\u5E97\u4E3B\u9009\u62E9\uFF1A**\u4FDD\u6301\u4E00\u884C + \u672B\u5C3E\n \u7701\u7565\u53F7**\u3002\u505A\u6CD5\uFF1A\u5B57\u53F7 12\u219210\uFF08\u22480.83\u00D7\uFF09\u3001\u7EC4\u95F4\u8DDD 12\u21926\u3001\u53BB\u6389\u4E3A\u6EDA\u52A8\u6761\u7559\u7684\n 4px \u4E0B\u5185\u8FB9\u8DDD\uFF1Boverflow \u6539 hidden\uFF08\u4E0D\u53EF\u6ED1\uFF09\u3001\u6EDA\u52A8\u6761\u663E\u5F0F\u5E72\u6389\uFF1B\u7B2C\u4E00\u7EC4\n flex:0 0 auto \u4FDD\u6301\u5B8C\u6574\uFF0C\u6700\u540E\u4E00\u7EC4 flex:0 1 auto + min-width:0 \u81EA\u5DF1\u5403\u6389\n \u5DEE\u989D\u5E76\u5728\u672B\u5C3E\u51FA\u7701\u7565\u53F7\uFF08\u5B9E\u6D4B\u622A\u5230\"\u2026\u7F13\u5B58\u547D\u2026\"\uFF0Ctok \u6570\u5B57\u4ECD\u5B8C\u6574\u53EF\u8BFB\uFF09\u3002\n \u9AD8\u5EA6\u4ECD\u662F 28px\uFF1Acomposer \u7684\u5E95\u90E8\u5360\u4F4D\uFF088px + 28px\uFF09\u4E0D\u53D8\uFF0C\u5176\u5B83\u51E0\u4F55\u4E0D\u8DDF\u7740\u52A8\u3002\n\n 2026-10-06 \u52A0\u6863\uFF08\u5E97\u4E3B\uFF1A\"\u8F93\u5165\u6846\u4E0B\u9762\u7684\u8F6E\u6B21\u8FD9\u4E00\u6761\u548C\u8F93\u5165\u6846\u5E95\u90E8\u7684\u8DDD\u79BB\u7F29\u51CF\u4E00\u4E0B\uFF0C\n \u4F46\u4E0D\u80FD\u6328\u5F97\u592A\u8FD1\uFF0C\u8FD8\u662F\u8981\u7559\u51FA\u4E00\u70B9\u7A7A\u95F4\"\uFF09\u3002**\u5B9E\u6D4B\uFF08\u771F\u673A\u540C\u6E90 headless\uFF0C\u5DE5\u5382\u7248\uFF09**\uFF1A\n \u5361\u7247 rect.bottom=808\u3001\u8F6E\u6B21\u6761 rect.top=812 \u2192 flex \u95F4\u9699\u53EA\u6709 4px\uFF0C\u89C6\u89C9\u95F4\u8DDD\n \u2248 4px + 28px \u884C\u9AD8\u91CC\u6587\u5B57\u4E0A\u65B9\u7684\u7EA6 5px \u2248 9px\u3002\u6240\u4EE5\u53EA\u4E0A\u63D0 2px\uFF08margin-top:-2px\uFF09\n \u2192 \u89C6\u89C9\u95F4\u8DDD\u7EA6 7px\uFF0C\u4ECD\u7559\u4F59\u91CF\uFF1B\u65E9\u524D\u7684 -4px \u4F1A\u628A\u95F4\u9699\u538B\u5230 0\uFF08\u5C31\u662F\"\u6328\u5F97\u592A\u8FD1\"\uFF09\uFF0C\n \u5DF2\u6309\u5B9E\u6D4B\u6539\u56DE\u3002\u4E0D\u6539 28px \u884C\u9AD8\u3001\u4E0D\u52A8 composer \u5E95\u90E8\u5360\u4F4D\uFF088px + 28px \u51E0\u4F55\u5951\u7EA6\uFF09\u3002 */\n\n [data-mobile-nav=\"stats\"] {\n margin-top: -2px !important;\n display: flex !important;\n flex-flow: row nowrap !important;\n align-items: center !important;\n width: 100% !important;\n max-width: 100% !important;\n min-width: 0 !important;\n height: 28px !important;\n min-height: 28px !important;\n max-height: 28px !important;\n box-sizing: border-box !important;\n white-space: nowrap !important;\n overflow: hidden !important;\n overscroll-behavior-x: none;\n scrollbar-width: none !important;\n padding: 0 !important;\n line-height: 18px !important;\n font-size: 10px !important;\n }\n [data-mobile-nav=\"stats\"]::-webkit-scrollbar {\n display: none !important;\n width: 0 !important;\n height: 0 !important;\n }\n [data-mobile-nav=\"stats\"] > * {\n display: flex !important;\n flex-flow: row nowrap !important;\n align-items: center !important;\n white-space: nowrap !important;\n margin-right: 6px !important;\n padding: 0 !important;\n }\n /* \u7B2C\u4E00\u7EC4\uFF08\u8F6E\u6B21\u00B7\u6B65\u6570\u00B7tok/s\uFF09\u4FDD\u6301\u5B8C\u6574\u3002 */\n [data-mobile-nav=\"stats\"] > *:first-child {\n flex: 0 0 auto !important;\n width: max-content !important;\n min-width: max-content !important;\n max-width: none !important;\n }\n /* \u6700\u540E\u4E00\u7EC4\uFF08tok \u603B\u91CF\u00B7\u7F13\u5B58\u547D\u4E2D\uFF09\u5403\u6389\u5269\u4F59\u5BBD\u5EA6\uFF0C\u672B\u5C3E\u7701\u7565\u53F7\u3002\n 2026-09-23 \u7B2C\u4E8C\u7248\u4FEE\u6B63\uFF1A\u7B2C\u4E00\u7248\u628A\u6574\u7EC4\u6539\u6210 display:block + \u5B50\u5143\u7D20 inline\uFF0C\n \u7ED3\u679C\u836F\u4E38\u91CC\u7684\u56FE\u6807\u53D8\u6210 inline\u3001\u57FA\u7EBF\u5BF9\u9F50\u9519\u4F4D\uFF08\u5E97\u4E3B\uFF1A\"\u56FE\u6807\u90FD\u51FA\u73B0\u4F4D\u79FB\"\uFF09\u3002\n \u8FD9\u7248\u4FDD\u6301 flex \u5BF9\u9F50\uFF0C\u53EA\u8BA9\u836F\u4E38**\u5185\u90E8\u7684\u6587\u5B57 span** \u6536\u7F29 + \u51FA\u7701\u7565\u53F7\uFF1B\n \u56FE\u6807 svg \u56FA\u5B9A\u4E0D\u7F29\u3002\u53E6\u5916\u628A\u4E24\u7EC4\u836F\u4E38\u7684\u5DE6\u53F3\u5185\u8FB9\u8DDD\u538B\u5230 6px\u3001\u7EC4\u95F4\u8DDD\u538B\u5230 4px\uFF0C\n \u62A0\u51FA\u6765\u7684\u5BBD\u5EA6\u5168\u90E8\u8BA9\u7ED9\u7B2C\u4E8C\u7EC4\uFF08\u5B9E\u6D4B\u5B83\u539F\u672C\u53EA\u5206\u5230 76px \u800C\u9700\u8981 156px\uFF09\u3002 */\n [data-mobile-nav=\"stats\"] > *:last-child {\n display: flex !important;\n align-items: center !important;\n flex: 0 1 auto !important;\n width: auto !important;\n min-width: 0 !important;\n max-width: none !important;\n overflow: hidden !important;\n margin-right: 0 !important;\n }\n [data-mobile-nav=\"stats\"] > *:last-child > * {\n display: flex !important;\n align-items: center !important;\n min-width: 0 !important;\n max-width: 100% !important;\n overflow: hidden !important;\n }\n [data-mobile-nav=\"stats\"] > *:last-child svg {\n flex: 0 0 auto !important;\n }\n [data-mobile-nav=\"stats\"] > *:last-child span {\n flex: 0 1 auto !important;\n min-width: 0 !important;\n overflow: hidden !important;\n text-overflow: ellipsis !important;\n }\n [data-mobile-nav=\"stats\"] button {\n padding: 0 3px !important;\n margin: 0 !important;\n min-width: 0 !important;\n max-width: 100% !important;\n }\n /* \u836F\u4E38\u5185\u90E8\u7684 span/svg \u6709\u81EA\u5DF1\u7684\u5B57\u53F7\uFF08\u5BBF\u4E3B .pill \u81EA\u5E26\uFF09\uFF0C\u53EA\u5728\u5916\u5C42\u8BBE 10px \u4E0D\u4F1A\u88AB\n \u7EE7\u627F\u8FDB\u53BB \u2014\u2014 \u771F\u673A\u4E0A\u7B2C\u4E8C\u7EC4\u4ECD\u5DEE ~20px \u88AB\u7701\u7565\u53F7\u5207\u6389\uFF0C\u6240\u4EE5\u8FD9\u91CC\u663E\u5F0F\u538B\u5230\u5185\u90E8\u3002 */\n [data-mobile-nav=\"stats\"] button,\n [data-mobile-nav=\"stats\"] button span,\n [data-mobile-nav=\"stats\"] button svg,\n [data-mobile-nav=\"stats\"] > * {\n font-size: 10px !important;\n line-height: 18px !important;\n }\n [data-mobile-nav=\"stats\"] > *:not(:last-child) {\n margin-right: 3px !important;\n }\n [data-mobile-nav=\"stats\"] * {\n white-space: nowrap !important;\n }\n /* \u300C\u4E0A\u4E0B\u6587\u73AF\u300D\u663E\u793A\u5728\u8F93\u5165\u6846\u884C\u7684\u53F3\u7C07\uFF08\u5E97\u4E3B 2026-09-23 \u786E\u8BA4\uFF1A\n \u73AF\u8981\u3001\u767E\u5206\u6BD4\u6570\u5B57\u4E0D\u8981\uFF09\u3002font-size:0 \u53EA\u584C\u6389\u6587\u672C\u3001\u73AF svg \u6709\u663E\u5F0F\u5C3A\u5BF8\u4E0D\u53D7\n \u5F71\u54CD\uFF1B\u7EDD\u5BF9\u5B9A\u4F4D\u76D6\u5728\u81EA\u5EFA\u5360\u4F4D\u4E0A\uFF08\u89C1\u4E0B\u65B9 #104 \u6CE8\u91CA\uFF09\uFF0C\u4E0D\u518D\u642C\u52A8\u8282\u70B9\u3002 */\n [data-mobile-nav=\"stats-ring\"] {\n position: absolute !important;\n flex: 0 0 auto !important;\n display: inline-flex !important;\n align-items: center !important;\n min-width: 0 !important;\n margin: 0 2px 0 0 !important;\n padding: 0 !important;\n background: transparent !important;\n box-shadow: none !important;\n border: 0 !important;\n }\n /* \u6587\u672C\u8981\u8FDE**\u836F\u4E38\u5185\u90E8**\u4E00\u8D77\u584C\u6389\uFF1A\u836F\u4E38\u81EA\u5E26\u5B57\u53F7\uFF0C\u53EA\u5728\u5916\u5C42\u8BBE 0 \u4E0D\u7EE7\u627F\u8FDB\u53BB\uFF0C\n \u771F\u673A\u4E0A\u4F1A\u7559\u4E0B\u534A\u4E2A \"46\"\u3002\u6574\u68F5\u5B50\u6811 font-size:0\uFF0C\u73AF svg \u7528\u663E\u5F0F px \u4E0D\u53D7\u5F71\u54CD\u3002 */\n [data-mobile-nav=\"stats-ring\"],\n [data-mobile-nav=\"stats-ring\"] * {\n font-size: 0 !important;\n }\n [data-mobile-nav=\"stats-ring\"] button {\n padding: 0 !important;\n margin: 0 !important;\n gap: 0 !important;\n min-width: 0 !important;\n width: auto !important;\n /* \u5BBF\u4E3B\u7ED9\u836F\u4E38\u753B\u7684\u7070\u5E95/\u63CF\u8FB9\u5728\u8F93\u5165\u6846\u884C\u91CC\u663E\u5F97\u6BD4\u73AF\u5927\u4E00\u500D\uFF08\u5E97\u4E3B\uFF1A\"\u5706\u5708\u5360\u4E86\u5F88\u591A\u7A7A\u95F4\"\uFF09\uFF0C\n \u5168\u53BB\u6389\uFF0C\u53EA\u7559\u73AF\u672C\u8EAB\u3002 */\n background: transparent !important;\n box-shadow: none !important;\n border: 0 !important;\n }\n [data-mobile-nav=\"stats-ring\"] svg {\n display: inline-block !important;\n /* 2026-09-29 \u9A8C\u6536\u5B9A\u7A3F\uFF08issue #140\uFF09\uFF1A16px \u96BE\u7784\u51C6\u300124px \u8FC7\u5927\u300120px \u4ECD\u504F\u5927\uFF0C\n \u5E97\u4E3B\u62CD\u677F 18px\uFF1B\u4E0E 26\u00D726 \u547D\u4E2D\u76D2\uFF08\u89C1 layout.css.ts \u7684\u73AF\u89C4\u5219\uFF09\u5339\u914D\u3002\n \u589E\u5BBD\u7531\u5C3E\u9053\u5DE6\u4FA7\u5BCC\u4F59\u5438\u6536\uFF0C\u6309\u952E\u95F4\u8DDD\u4E0D\u53D8\u3002 */\n width: 18px !important;\n height: 18px !important;\n flex: 0 0 auto !important;\n }\n /* \u8F68\u9053\u6DF1\u5316\uFF082026-09-29 \u9A8C\u6536\uFF0Cissue #140\uFF09\uFF1A\u5BBF\u4E3B\u8F68\u9053\u53EA\u6709 12% \u9ED1\uFF0C\u73AF\u653E\u5927\u5230\n 24px \u540E\u6DF1\u7070\u8FDB\u5EA6\u5F27\u663E\u5F97\u50CF\u6B8B\u7F3A\u7684\u52A0\u8F7D\u5708\uFF08\u5E97\u4E3B\u300C\u4EC0\u4E48\u73A9\u610F\u513F\u300D\uFF09\u3002\u52A0\u6DF1\u5230 25%\n \u8BA9 donut \u6210\u5B8C\u6574\u5706\u73AF\u2014\u2014\u662F\u300C\u7528\u91CF\u8868\u300D\u4E0D\u662F\u300Cspinner\u300D\u3002\u5B50\u4E32\u951A class*=_track\n \u4E0E\u4ED3\u5E93\u54C8\u5E0C\u951A\u60EF\u4F8B\u4E00\u81F4\uFF0C\u73AF\u6807\u8BB0\u5185\u4E0D\u4F1A\u8DE8\u5339\u914D\uFF08fill \u7C7B\u540D\u4E0D\u540C\uFF09\u3002\n #142\uFF1A25% \u9ED1\u6539\u6309\u4E3B\u9898\u53D6\u8272\u2014\u2014color-mix \u53D6 25% \u6807\u7B7E\u8272\uFF08label-primary \u6D45\u8272\n =\u8FD1\u9ED1\u3001\u6697\u8272=\u8FD1\u767D\uFF09\uFF0C\u6D45\u8272\u7EF4\u6301 #140 \u9A8C\u6536\u89C2\u611F\uFF0C\u6697\u8272\u81EA\u52A8\u7FFB\u6210 25% \u767D\uFF08\u88F8\n rgba(0,0,0,.25) \u5728\u6697\u8272\u4E0B\u4E0D\u53EF\u89C1\uFF0C\u73AF\u53C8\u9000\u56DE\u6B8B\u7F3A\u52A0\u8F7D\u5708\uFF09\uFF1Btoken \u7F3A\u5931\u65F6 var\n \u515C\u5E95 #000 \u4E0E\u539F\u503C\u7B49\u4EF7\u3002border \u65CF\u6CA1\u6709 25% \u7B49\u4EF7\u6863\uFF0C\u7EAF var \u515C\u5E95\u4F1A\u8BA9\u6D45\u8272\u56DE\n \u5F52\u5BBF\u4E3B 12%\uFF0C\u6545\u7528 color-mix\uFF1B\u5BBF\u4E3B CSS \u5DF2\u7528\u540C\u6B3E color-mix+var \u7EC4\u5408\u3002 */\n [data-mobile-nav=\"stats-ring\"] [class*=\"_track\"] {\n stroke: color-mix(in srgb, var(--dsw-alias-label-primary, #000) 25%, transparent) !important;\n }\n /* \u73AF\u4E0E TPS \u8BFB\u6570\u4E0D\u518D\u642C\u52A8\u5BBF\u4E3B React \u8282\u70B9\uFF08#104\uFF1A\u642C\u52A8\u540E\u5BBF\u4E3B\u5378\u8F7D\u8C03 removeChild\n \u5BF9\u4E0D\u4E0A\u7236\u8282\u70B9\u76F4\u63A5\u629B NotFoundError\uFF0CSlotErrorBoundary \u628A\u6574\u4E2A composer \u69FD\u4F4D\n \u6E05\u7A7A\uFF09\u3002\u8282\u70B9\u7559\u5728 React \u6E32\u67D3\u7684\u539F\u4F4D\uFF0C\u53EF\u89C1\u69FD\u4F4D\u7531\u63D2\u4EF6\u81EA\u5EFA\u5360\u4F4D\u9876\u4F4F\uFF0C\u5BBF\u4E3B\u8282\u70B9\n \u7EDD\u5BF9\u5B9A\u4F4D\u76D6\u5728\u5360\u4F4D\u4E0A\uFF1B\u5360\u4F4D\u662F\u63D2\u4EF6\u8282\u70B9\uFF0C\u5BBF\u4E3B\u91CD\u5EFA/\u5378\u8F7D\u90FD\u4E0D\u7ECF\u8FC7\u5B83\u3002 */\n [data-mobile-nav=\"stats-ring-reserve\"],\n [data-mobile-nav=\"stats-tps-reserve\"] {\n visibility: hidden !important;\n pointer-events: none !important;\n }\n [data-mobile-nav=\"stats-ring-reserve\"] {\n flex: 0 0 auto !important;\n display: inline-block !important;\n /* 18px \u4E0E\u5B9A\u7A3F\u7684\u73AF\uFF08\u4E0A\u65B9 svg \u89C4\u5219\uFF09\u540C\u5C3A\u5BF8\uFF1A\u5360\u4F4D\u9876\u4F4F\u7684\u69FD\u4F4D\u5373\u73AF\u7684\u843D\u70B9\uFF0C\n \u5C3E\u9053\u5DE6\u4FA7\u5BCC\u4F59\u5438\u6536\u589E\u5BBD\uFF0C\u6309\u952E\u95F4\u8DDD\u4E0D\u53D8\u3002 */\n width: 18px !important;\n height: 18px !important;\n margin: 0 2px 0 0 !important;\n padding: 0 !important;\n }\n [data-mobile-nav=\"stats-tps\"] {\n display: flex !important;\n flex-flow: row nowrap !important;\n align-items: center !important;\n margin: 0 !important;\n padding: 0 !important;\n font-size: 10px !important;\n line-height: 18px !important;\n white-space: nowrap !important;\n overflow: hidden !important;\n text-overflow: ellipsis !important;\n }\n [data-mobile-nav=\"stats-tps\"] * {\n white-space: nowrap !important;\n }\n [data-mobile-nav=\"stats-tps\"] span {\n overflow: hidden !important;\n text-overflow: ellipsis !important;\n min-width: 0 !important;\n }\n /* overlay \u7684\u5B9A\u4F4D\u4E0A\u4E0B\u6587\uFF1A\u5BBF\u4E3B\u81EA\u5DF1\u6CA1\u5B9A\u4F4D\u65F6\u624D\u751F\u6548\uFF08\u65E0 !important\uFF0C\u5BBF\u4E3B\u6837\u5F0F\u968F\u65F6\n \u53EF\u4EE5\u63A5\u7BA1\uFF1Bstats-line \u6BCF\u5E27\u6309\u771F\u5B9E positioned ancestor \u8BA1\u7B97\uFF0C\u4E0D\u53D7\u5F71\u54CD\uFF09\u3002 */\n [data-mobile-nav=\"stats-ring-dock\"],\n [data-mobile-nav=\"stats-tps-row\"] {\n position: relative;\n }\n\n /* ---------- dsh-genui panel dock ----------\n The genui panel docks above the composer (conversation.input.dock,\n id genui-panel). On a phone its business-blue outline, generous chrome\n and single-line ellipsis read as an unfinished artifact: long titles\n truncate mid-word (\"\u2026default b\u00B7\u00B7\u00B7\") with the chevron glued to the\n ellipsis, and the pill crowds the composer. Mobile treatment: neutral\n card border matching the composer, tighter chrome so the full title\n fits, chevron with breathing room. Scoped to the mobile frame marker \u2014\n desktop keeps genui's own styling untouched. */\n\n [data-mobile-nav=\"frame\"] [data-genui-panel] {\n margin: 6px 12px 4px !important;\n border-color: var(--dsw-alias-border-l1, rgba(0, 0, 0, .12)) !important;\n border-radius: 12px !important;\n }\n [data-mobile-nav=\"frame\"] [data-genui-panel] [class*=\"_panelToggle\"] {\n padding: 7px 12px !important;\n gap: 8px !important;\n }\n [data-mobile-nav=\"frame\"] [data-genui-panel] [class*=\"_panelBadge\"] {\n padding: 0 7px !important;\n border-radius: 5px !important;\n font-size: 10.5px !important;\n line-height: 1.7 !important;\n }\n [data-mobile-nav=\"frame\"] [data-genui-panel] [class*=\"_panelTitle\"] {\n flex: 1 1 auto !important;\n min-width: 0 !important;\n font-size: 12.5px !important;\n line-height: 1.45 !important;\n }\n [data-mobile-nav=\"frame\"] [data-genui-panel] [class*=\"_panelChevron\"] {\n flex: none !important;\n margin-left: 0 !important;\n padding-left: 4px !important;\n }\n\n /* ---------- git-graph branch chip: CSS re-anchor, no reparent (A\u2032) ----------\n The branch chip (conversation.input.dock) floats between the dock rows\n and the input card; on a phone it reads as a stray capsule crowding the\n composer. #105: the old fix reparented the chip INTO the composer card,\n and React's unmount removeChild then threw NotFoundError into the\n SlotErrorBoundary (same root cause as #104). A\u2032 re-anchors instead:\n the chip stays where React rendered it (inside the dock subtree) and\n the composerStack becomes the containing block, with the anchor\n constants = the card's static offset inside the stack + the original\n (12,12) corner offset. Constants measured 2026-09-24 (CDP, 393px):\n conversation phase card offset (16,0) \u2192 top 12 / left 28; hero phase\n card offset (16,122.9) \u2192 top 134.9 / left 28 (hero override below).\n The plugin's own sheet sets all four offsets on the anchor, so\n right/bottom must be neutralized too. Desktop untouched: the frame\n marker only exists below 1024px. Chip row geometry (2026-08-16, user\n feedback): 48px padding left a 16px dead gap and made the composer read\n too tall; 40px = chip (24px) at corner +12 + ~4px to the textarea; the\n chip has since grown to 28px (git-graph chip CSS), so the row is 44px\n (2026-09-06). The 44px clearance now keys off a STACK-level :has() \u2014\n the chip is no longer a card descendant, so a card-level :has() could\n never match; the card disambiguation keeps non-composer cards (e.g. a\n todo card sharing the stack) out of the chip row. */\n [data-mobile-nav=\"frame\"] [class*=\"_composerStack\"] {\n position: relative;\n }\n [data-mobile-nav=\"frame\"] [data-gitgraph-chip-anchor] {\n position: absolute !important;\n top: 12px !important;\n left: 28px !important;\n right: auto !important;\n bottom: auto !important;\n z-index: 1 !important;\n }\n [data-mobile-nav=\"frame\"] [data-phase=\"hero\"] [data-gitgraph-chip-anchor] {\n top: 134.9px !important;\n }\n [data-mobile-nav=\"frame\"] [class*=\"_composerStack\"]:has([data-gitgraph-chip-anchor]) [class*=\"_card\"]:has(textarea, [data-composer-input]) {\n padding-top: 44px !important;\n }\n\n /* ---------- dsh-meme \u8868\u60C5\u9009\u62E9\u5361\u7247\uFF1A\u53F3\u7F18\u5B89\u5168\u8DDD\u79BB ----------\n The meme picker (conversation.input.overlay, id meme-picker) is\n absolutely positioned left:0 inside the composer's overlay anchor with\n width:min(360px,90vw). That 90vw resolves against the VIEWPORT, not the\n anchor, and with the picker's own padding+border the border-box\n (377px on a 390px phone) exceeds the 356px anchor \u2014 the card's right\n edge then runs past the anchor and off the right screen edge, while the\n left edge keeps the anchor's 17px safe inset. Stretch the card to the\n anchor on both sides (left/right 0, width auto, border-box) so the\n right gap mirrors the left; cap at the card's original border-box size\n (360px content + 24px padding + 2px border) so tablets keep the\n intended card width instead of stretching. Desktop is untouched: the\n frame marker only exists below 1024px. */\n [data-mobile-nav=\"frame\"] .meme-picker {\n left: 0 !important;\n right: 0 !important;\n width: auto !important;\n box-sizing: border-box !important;\n max-width: 386px !important;\n }\n\n /* dsh-meme \u7F51\u683C\u7F29\u7565\u56FE\uFF1A\u81EA\u9002\u5E94\u94FA\u6EE1\u5361\u7247,\u4FDD\u7559 8px \u95F4\u9699\u3002\n dsh-meme \u7684 .mp-grid \u662F flex-wrap + \u56FA\u5B9A 76px \u7684 .mp-cell(\u884C\u5185 style \u518D\u538B\u5230 74px):\n 3 \u5217(390px \u624B\u673A)\u65F6\u6BCF\u884C\u53F3\u4FA7\u5269 ~78px \u7A7A\u767D,\u5361\u7247\u6CA1\u6709\u94FA\u6EE1\u3002\u6362\u6210\u54CD\u5E94\u5F0F grid:\n repeat(auto-fill, minmax(64px,1fr)) \u8BA9\u5217\u6570\u968F\u53EF\u7528\u5BBD\u5EA6\u4F38\u7F29\u3001\u5361\u7247 width:100% +\n aspect-ratio:1 \u968F\u8F68\u9053\u81EA\u9002\u5E94(\u65B9\u5F62,cover \u88C1\u5207\u4E0D\u53D8),gap \u4ECD\u662F dsh-meme \u7684 8px\u3002\n \u884C\u5185 width/height \u7528 !important \u8986\u76D6;\u624B\u673A\u7AEF\u7EA6 4 \u5217\u3001\u5E73\u677F\u7AEF\u7EA6 5 \u5217,\u5747\u6EE1\u5BBD\u3002 */\n [data-mobile-nav=\"frame\"] .meme-picker .mp-grid {\n display: grid !important;\n grid-template-columns: repeat(auto-fill, minmax(64px, 1fr)) !important;\n scrollbar-width: thin !important;\n scrollbar-color: var(--dsw-alias-label-tertiary, rgba(0, 0, 0, .3)) transparent !important;\n }\n [data-mobile-nav=\"frame\"] .meme-picker .mp-cell {\n width: 100% !important;\n height: auto !important;\n aspect-ratio: 1 !important;\n }\n /* dsh-meme \u7F51\u683C\u53F3\u4FA7\u6EDA\u52A8\u6761\uFF1A\u9ED8\u8BA4 WebKit \u6EDA\u52A8\u6761\u5728\u624B\u673A\u4E0A\u770B\u592A\u7C97,\u538B\u6210 4px\n \u7EC6\u6761\u2014\u2014\u4FDD\u7559\u6EDA\u52A8\u6307\u793A\u53C8\u4E0D\u5360\u6A2A\u5411\u7A7A\u95F4,thumb \u5706\u89D2\u6D45\u8272\u3001\u8F68\u9053\u900F\u660E\u3002 */\n [data-mobile-nav=\"frame\"] .meme-picker .mp-grid::-webkit-scrollbar {\n width: 4px !important;\n }\n [data-mobile-nav=\"frame\"] .meme-picker .mp-grid::-webkit-scrollbar-thumb {\n background: var(--dsw-alias-label-tertiary, rgba(0, 0, 0, .3)) !important;\n border-radius: 999px !important;\n }\n [data-mobile-nav=\"frame\"] .meme-picker .mp-grid::-webkit-scrollbar-track {\n background: transparent !important;\n }\n\n /* ---------- agent preset \u6A21\u5F0F\u9009\u62E9\u83DC\u5355\uFF1A\u624B\u673A\u7AEF\u7D27\u51D1\u5E95\u90E8\u5F39\u5C42 ----------\n The official agent-preset menu (role=menu, portal mounted on body) uses\n position:fixed + max-height:820px + bottom:12px, so on a phone it\n stretches from the trigger down to 12px above the screen bottom \u2014\n effectively filling the screen. Turn it into a polished bottom sheet:\n cap the height, center it horizontally (the official max-width 360px\n left-anchors at left:12px, leaving 12/18px asymmetric gaps), add a\n drag-handle affordance, breathing room, and softer top radius; the\n inner viewport keeps scrolling. Scoped to the agent-preset item class\n (cubgiG_*) so other role=menu dropdowns (model/access mode) are\n untouched. Desktop \u22651024px is outside the media query, so it keeps the\n official large dropdown. */\n /* agent-preset \u83DC\u5355\u4F9D\u8D56 @deepseek-ai/dsh-client-ui-agent-preset \u7684 CSS Module \u54C8\u5E0C (cubgiG_*)\uFF0C\u5347\u7EA7\u8BE5\u5305\u65F6\u9700\u9A8C\u8BC1\u6B64\u9009\u62E9\u5668\u662F\u5426\u4ECD\u6709\u6548 */\n [role=\"menu\"]:has([class*=\"cubgiG_item\"]) {\n top: auto !important;\n left: 50% !important;\n right: auto !important;\n bottom: 12px !important;\n transform: translateX(-50%) !important;\n width: min(100% - 24px, 360px) !important;\n max-width: 360px !important;\n max-height: min(55dvh, 440px) !important;\n padding: 30px 6px 10px !important;\n border-radius: 16px !important;\n }\n [role=\"menu\"]:has([class*=\"cubgiG_item\"])::before {\n content: '';\n position: absolute;\n top: 10px;\n left: 50%;\n transform: translateX(-50%);\n width: 36px;\n height: 4px;\n border-radius: 999px;\n background: var(--dsw-alias-border-l2, rgba(0, 0, 0, .22)) !important;\n pointer-events: none;\n }\n /* \u83DC\u5355\u5185\u90E8\u6EDA\u52A8\u6761\uFF1A\u9ED8\u8BA4 WebKit \u6EDA\u52A8\u6761\u5728\u7AD6\u5C4F\u592A\u7C97,\u4F1A\u5360 ~15px \u5BBD\u5EA6\u628A\u6587\u5B57\u63CF\u8FF0\n \u6324\u7A84,\u5BFC\u81F4\u63CF\u8FF0\u6362\u884C/\u622A\u65AD\u4E0D\u81EA\u7136\u3002\u538B\u6210 4px \u7EC6\u6761(\u4E0E\u8868\u60C5\u7F51\u683C\u4E00\u81F4),\u6587\u5B57\u533A\u57DF\n \u6062\u590D\u81EA\u9002\u5E94\u5BBD\u5EA6\u3002 */\n [role=\"menu\"]:has([class*=\"cubgiG_item\"]) [class*=\"_viewport_\"] {\n scrollbar-width: thin !important;\n scrollbar-color: var(--dsw-alias-label-tertiary, rgba(0, 0, 0, .3)) transparent !important;\n }\n [role=\"menu\"]:has([class*=\"cubgiG_item\"]) [class*=\"_viewport_\"]::-webkit-scrollbar {\n width: 4px !important;\n }\n [role=\"menu\"]:has([class*=\"cubgiG_item\"]) [class*=\"_viewport_\"]::-webkit-scrollbar-thumb {\n background: var(--dsw-alias-label-tertiary, rgba(0, 0, 0, .3)) !important;\n border-radius: 999px !important;\n }\n [role=\"menu\"]:has([class*=\"cubgiG_item\"]) [class*=\"_viewport_\"]::-webkit-scrollbar-track {\n background: transparent !important;\n }\n\n/* \u641C\u7D22\u6846\u5E95\u90E8\u95F4\u8DDD\u4FEE\u590D */\n [aria-modal=\"true\"] [class*=\"tabSearchRow\"] {\n padding: 2px 4px 16px !important;\n }\n\n\n /* ===== \u5DF2\u5B89\u88C5\u5217\u8868\uFF1A\u8DEF\u5F84\u5355\u884C\u622A\u65AD ===== */\n [class*=\"irow\"]:not([class*=\"irowActions\"]):not([class*=\"irowTrailing\"]) > div > [class*=\"spec\"] {\n white-space: nowrap !important;\n overflow: hidden !important;\n text-overflow: ellipsis !important;\n max-width: 100% !important;\n font-size: 12px !important;\n }\n [class*=\"irow\"]:not([class*=\"irowActions\"]):not([class*=\"irowTrailing\"]) > div > [class*=\"nm\"] {\n white-space: nowrap !important;\n overflow: hidden !important;\n text-overflow: ellipsis !important;\n max-width: 100% !important;\n }\n /* ===== \u5DF2\u5B89\u88C5\u5217\u8868\uFF1A\u624B\u673A\u7AEF\u7EB5\u5411\u91CD\u6392 ===== */\n [class*=\"irow\"]:not([class*=\"irowActions\"]):not([class*=\"irowTrailing\"]) {\n flex-wrap: wrap !important;\n align-items: center !important;\n gap: 4px 10px !important;\n }\n [class*=\"irow\"]:not([class*=\"irowActions\"]):not([class*=\"irowTrailing\"]) > div:first-child {\n flex: 1 1 100% !important;\n max-width: 100% !important;\n min-width: 0 !important;\n }\n [class*=\"irow\"]:not([class*=\"irowActions\"]):not([class*=\"irowTrailing\"]) > [class*=\"grow\"] {\n flex: 1 1 auto !important;\n }\n [class*=\"irow\"]:not([class*=\"irowActions\"]):not([class*=\"irowTrailing\"]) > button {\n flex: 0 0 auto !important;\n }\n [class*=\"irow\"]:not([class*=\"irowActions\"]):not([class*=\"irowTrailing\"]) > button[class*=\"switch\"] {\n order: 3 !important;\n }\n [class*=\"irow\"]:not([class*=\"irowActions\"]):not([class*=\"irowTrailing\"]) > button:not([class*=\"switch\"]) {\n order: 2 !important;\n }\n [class*=\"irow\"]:not([class*=\"irowActions\"]):not([class*=\"irowTrailing\"]) > [class*=\"owner\"] {\n order: 1 !important;\n }\n [class*=\"irow\"]:not([class*=\"irowActions\"]):not([class*=\"irowTrailing\"]) > [class*=\"grow\"] {\n order: 0 !important;\n }\n /* ===== \u5E02\u573A\u5361\u7247\u56FE\u7247\u5BB9\u5668\uFF1A\u6A2A\u5411\u6EDA\u52A8 ===== */\n [data-mobile-nav=\"frame\"] [class*=\"cardShots\"] {\n display: flex !important;\n flex-wrap: nowrap !important;\n overflow-x: auto !important;\n -webkit-overflow-scrolling: touch !important;\n scrollbar-width: thin !important;\n min-width: 0 !important;\n width: 100% !important;\n max-width: 100% !important;\n gap: 8px !important;\n padding: 4px 0 !important;\n }\n [data-mobile-nav=\"frame\"] [class*=\"cardShots\"] > [class*=\"cardShot\"] {\n flex: 0 0 min(100%, 420px) !important;\n width: min(100%, 420px) !important;\n max-width: 100% !important;\n height: auto !important;\n display: block !important;\n object-fit: contain !important;\n }\n [data-mobile-nav=\"frame\"] [class*=\"cardShots\"]::-webkit-scrollbar {\n height: 4px !important;\n }\n [data-mobile-nav=\"frame\"] [class*=\"cardShots\"]::-webkit-scrollbar-thumb {\n background: var(--ds-border-color, #ccc) !important;\n border-radius: 4px !important;\n}\n\n /* ---------- dsh-file-viewer (conversation.view tab\u300C\u6587\u4EF6\u67E5\u770B\u5668\u300D) ----------\n The plugin ships NO responsive CSS: its min-width:0 flex panels overflow\n on a phone \u2014 the titlebar caps the path at 520px beside a 5-button action\n row, and CSV/code headers row-stick inside content scrollers. It renders\n inline into the conversation view region (stable 'dsfv-*' prefix, injected\n