/* hoop.css — the ONE stylesheet of Hoop Matrix.
   Every app page links this file and carries zero inline styles: tokens, components
   and per-app sections all live here, so a visual change is a change in one place.
   Layout uses CSS LOGICAL properties throughout (inline-start/end, not left/right):
   that is what lets ar (RTL) flip the whole OS by flipping <html dir> alone.

   ═══ THE PAGE CODEX (V0.1.7 ② — law, not style) ═══════════════════════════════
   Every page declares ONE of three templates before it is built. No page may
   invent a fourth structure.
   T1 DOCUMENT   single 42rem column: h1.app + .lede + N × (.sect + .card);
                 inside cards only .kv/.opts/.row/.feed/form pieces.
                 (settings, vpn, memory, files, calendar, finance today)
   T2 WORKBENCH  sidebar + main working area, fixed header, 46rem reading column,
                 ≤900px the sidebar becomes a drawer. (chat, terminal, mail ④)
   T3 IMMERSIVE  a full-screen stage, ≤5 elements on it. (home / logged-out door)
   Codex articles: spacing only from the --sp-* scale; type only from the --fs-*
   scale (roles documented at the token block); ALL pictographs from icons.js —
   emoji are content, never interface; buttons ≤4 chars zh / ≤2 words en, long
   explanations go to .note; zh copy uses full-width punctuation, en half-width.

   ═══ CODEX ARTICLE 4 — THREE VOICES + THE WORDMARK (V0.2.0 ①) ═══════════════
   Serif = soul · Sans = body · Mono = machine. The body of the OS is Sans
   (--font-ui); Serif (--font-brand) is CLAIMED by role, never inherited; Mono
   (--mono) is for what a machine said. Serif ≤ 10–20% of any screen. The true
   HoopGram mark alone uses Marcellus (--font-wordmark): a seal, not a fourth
   content voice. Inline mentions of the name remain in their surrounding voice.
   ROLE TABLE (the only places Serif may appear):
     actual HoopGram wordmark ..................... Marcellus Regular  (.brand)
     the hoop sutra ............................... Serif Regular  (#hbrand)
     hero lines: home / public card / apex ........ Serif Regular, big, airy (.p-home)
     page title h1.app (T1), chat greeting .hi .... Serif Regular
     the PA's reply body, mail reading, the reader,
     researcher reports .rpt ...................... Serif Regular — the second voice
                                                    (.m.pa, .mw-body, .rd-col, .rpt)
   Everything else — nav, tabs, buttons, inputs, labels, captions, .sect, forms,
   card titles h3/h4, the OWNER's own messages — is Sans Regular/Medium(500).
   Numbers, money, timestamps, .tbl, addresses, hostnames, status, .steps —
   Mono or Sans tabular-nums.
   WEIGHT LAW: hierarchy = size + space + face + Regular/Medium, never a stair of
   bolds. 500 is the heaviest UI weight (buttons, small headings, active items);
   Serif headings are never bold; the only 600 is inline <strong> in prose.

   ═══ CODEX ARTICLE 5 — THE MATERIALS (V0.1.8 ②) ═════════════════════════════
   One grammar for every control, so they are visibly the work of one hand:
   PAPER  inputs, .chip, .opt, #cwrap: --surface + a half-strength
          line (--line-soft) + --shadow-1 — lifted 1mm off the page, never boxed.
          Focus = the --focus glow only; the border never thickens.
   KEY    Every action button is transparent in every state (owner, 2026-09-25; replaces the
          2026-09-23 filled primary). A button reads as a button by its line: .btn-primary is an
          amber line with amber-ink text and heavier weight, the one main action of an area;
          plain .btn / .btn-secondary is a visible hairline. Pressing = 1px down; hover darkens
          the line or the text, never paints a fill.
   GHOST  .btn-ghost / .btn-tonal: text only, the line appears on hover.
          .hbtn, .cbtn: icon only, hover = stronger ink. DANGER: red line, red text.
   LINES  --line is translucent ink (8% of --fg), so it melts into any theme;
          dividers are 1px var(--line) everywhere — never 2px, never a hex.
          --line-2 (16%) is the rail/track strength (blockquotes, switch track).
   CARDS  fill + 1px line, never fill + line + shadow.
   SHADOW two rungs only: --shadow-1 (paper) and --shadow-pop (floating layers);
          plus the two non-depth tokens --shadow-key (key material) and --focus.
          grep box-shadow → tokens only.
   SHAPE  standalone buttons use the website's quiet small corner (--r-xs);
          chips and options are CAPSULES (--r-pill); inputs --r-in 14px;
          cards --r-xl 24px; the composer, menus and sheets --r-2xl 28px; every icon
          button is a CIRCLE. Heights two rungs: --btn-h 34px, --btn-h-sm 28px.
          Sidebars share the page's --bg with at most a 1px --line at the edge.
   GLASS  (②b) floating layers — menus, modals, the palette, the capture, floats,
          the mobile dock, toasts — are .glass: --glass-bg + backdrop blur + the
          specular rim --glass-rim (light on top, a hair of shade below). Depth is
          rim + blur, never a border. prefers-reduced-transparency → solid.
   VOLUME (②b) --shadow-key now carries the key's own glow beneath it; --shadow-1
          carries a top-edge highlight, so paper reads as a slab, not a fill.

   ═══ CODEX ARTICLE 6 — THE NARROW LAW & THE PICK (V0.1.8 ⑥) ═══════════════════
   Born of three phone screenshots: a 15,883px settings page (two elements shared
   an id), a VPN table wider than the screen, a mail pane that stacked sideways.
   IDS     an id belongs to the script that targets it; anchors and groups use
           data-* attributes, never a second id. tools/lint-shell.mjs refuses a page
           with a duplicate id (update.sh runs it before every build).
   WIDTH   nothing is wider than its container. Tables and <pre> scroll INSIDE their
           own box (.tblw / .card pre / .p-vpn table); flex children carry min-width:0;
           ≤600px every form row is single-column and every input takes the row.
   CHOICE  ≤3 options with no hints may sit inline as .opt chips. Four or more, or
           any option that needs a hint, is a .pick: one row — label · current value
           · › — that opens the options as a .menu on desktop and as a bottom .sheet
           on a phone (HoopUI.pick). Never a wall of chips.
   POSTURE HoopUI.menu is the ONE popover; ≤720px it rises as a sheet by itself.
   AUDIT   after every deploy, the mobile audit (HANDOFF) loads every page in a 430px
           frame and reports any scrollWidth > viewport. Zero is the only pass.

   ═══ CODEX ARTICLE 7 — ONE DOOR, NO FLOOR (V0.1.9 ①②, owner's five screenshots) ═
   ONE DOOR   a setting or action has ONE landing place; everything else is an
              entrance to it. Settings = the settings surface (modal ≥900 / sheet on a
              phone / the page for deep links); the owner menu, the dock gear and every
              /settings link only open it. Never a second copy of a control.
   NO FLOOR   floating layers own no strip of page: the composer, the hoop button, the
              menus and sheets hover over content that flows beneath them (glass + blur).
              On a phone there is NO bottom bar: one hoop button → the App sheet.
   INPUTS     ≤720px every text input is 16px (iOS zooms the page on anything smaller);
              the chat frame follows the visual viewport (--vvh) so the composer rides
              on top of the keyboard.
   DENY       features of platforms (projects, libraries, plans, voice modes) are not
              organs of a Hoop. Ten apps, the dock, ⌘K — that is the whole body.

   ═══ CODEX ARTICLE 8 — LAYERS (V0.1.9 ④, the sheet that would not close) ═══════
   Every floating thing — menu, sheet, modal, palette, capture — is a LAYER on the one
   stack in hoop-ui.js (HoopUI.layerOpen). The stack owns the ways out: Esc and the
   phone's back gesture close the top layer; a scrim closes on CLICK, never on
   pointerdown (the tap that closes must be absorbed, or it lands on what was beneath
   — closing 语言 opened 主题); a scrimless popover closes on an outside press and
   swallows the click that follows; every sheet carries a × and a grabber; leaving a
   page goes through HoopUI.go(href), which unwinds the layers first. Pages never
   write their own pointerdown-to-close (tools/lint-shell.mjs forbids it outside
   hoop-ui.js / nav.js); tools/mobile-audit.js taps every scrim for real and expects
   zero layers afterwards.

   ═══ CODEX ARTICLE 9 — THE TOP BAR (V0.1.9 ⑤, the owner's phone) ═══════════════
   One bar on every page, one grammar: LEFT is where I came from (← on an app page,
   the sidebar toggle on chat), CENTRE the page's name (shown only once its own h1 has
   scrolled away — nothing is said twice), RIGHT at most two page actions as ghost
   circles. Glass, no floor: content flows beneath it. nav.js draws it (#hooptop) on
   every page but chat, where chat.html's own header wears the same class (.topbar).
   Also art. 6 tightened: a value with a finite set of choices is ALWAYS a .pick —
   long sets get a search box (timezone), never a text field with a save key.

   ═══ CODEX ARTICLE 10 — THE WINDOW CHROME (V0.2.3 C1, "a computer, not a website") ═
   Every window and every App page wears ONE .win-chrome, drawn by hoop-ui.js
   (windows) and nav.js (pages) — no App draws its own close, zoom or minimize.
   Three 12px lights, 8px apart, on the PHYSICAL LEFT in every locale, RTL included:
   this is the codex's single sanctioned non-logical position (macOS keeps them
   there in Arabic; muscle memory beats mirroring). Close = the layer stack's close;
   zoom = the page route ↔ the window; minimize = a capsule in the dock tray
   (#dock-tray) that restores on click. ≥900px up to four free windows (z-order by
   focus, drag by the title, resize at the end-bottom corner, positions kept per App
   in localStorage — interface state, never the owner's config); <900px one window;
   ≤800px the page; ≤720px the lights fold to a single × (art. 9's top bar).
   The lock screen (T3) owns the one display-size rung: --fs-display.

   ═══ CODEX ARTICLE 11 — ONE MATERIAL SOURCE (V0.2.4) ═══════════════════════
   Navigation surfaces — top bars, menu bars, dock sheets, drawers and window
   chrome — receive .bar-glass. That class is the single definition of their
   translucent material and lower hairline; pages and scripts may only attach it.
   A navigation selector must never paint background:var(--surface) for itself.

   ═══ CODEX ARTICLE 12 — ONE LANGUAGE, ONE TEXT (V0.2.4) ═════════════════════
   Public copy shows exactly the current HoopI18n language. Slogans, engravings
   and buttons have idiomatic zh-CN / en / ar strings; no English fallback is
   displayed beside a translation and no two language versions share a view.

   ═══ THE COMPONENT CONTRACT (V0.1.4) ══════════════════════════════════════════
   Pages may ONLY build UI from these pieces — never restyle them, never invent new
   one-off variants. If a page needs something new, it gets added HERE first.

   tokens     type scale --fs-*, space scale --sp-*, radius scale --r-*, shadows,
              colors: --brand/--brand-ink/--on-brand (amber), --accent (blue),
              --bg/--surface/--surface-2/--fg/--dim/--line/--lift/--ok/--bad/--warn.
              Rule: components reference tokens only; no magic hex, no magic px.
              Brand amber & blue are ACCENTS — never large filled areas.
   .btn       buttons. Variants: .btn-primary (filled amber, the card's main action),
              .btn-secondary (= plain .btn: paper + visible line), .btn-tonal / .btn-ghost
              (soft fill), .btn-danger (red line). Size: .btn-sm. Never style <button> ad hoc.
   inputs     input/select/textarea are styled GLOBALLY (border, radius, focus ring).
              Pages size them (width) but never re-skin them.
   .card      surface block; h3 title / h4 row-title / .meta / pre body.
   .sect      section label between cards (optional count badge .n).
   .tabs      underline tabs; active = .on (amber underline).
   .row       quiet link-action row under a card (a / a.primary / a.danger).
   .opt       choice chip (radio-like); active = .cur, staged = .stage.
   .onoff     toggle switch; on = .on.
   .chip      suggestion pill (chat hello).
   .perm      permission chip (label + level + adjust link).
   .empty     empty state (dashed box, .glyph icon line).
   icons      ALL UI pictographs come from icons.js (HoopIcons, nav.js-style 1.7px
              stroke SVG): <span data-icon="name"> fills itself. Emoji are content
              (chat, mail bodies) — NEVER interface. [data-icon] sizing lives here.
   .menu      floating context menu (a items, .danger).
   .tip       mac-style hover tooltip: the name floats in beside an icon. Never on
              touch. (nav.js's dock injects a token-riding copy of these rules so
              /trader — which has no hoop.css — keeps its tooltips too.)
   .modal     every modal window uses HoopUI.window + .ui-close. Confirm/prompt
              build on it; native confirm()/alert()/prompt() are banned.
   .toast     transient notice via HoopUI.toast().
   .kv        key/value grid. .feed/.evt audit stream. .list-box/.ent file rows.
   .tbl       data table (th dim labels, tabular-nums, .num end-aligned).
   .rpt       long-form report text (pre-wrap serif). .curve inline SVG sparkline.
   .capture   the ⌘J spark catcher: one input over a scrim, Enter saves, Esc goes.
   .timeline  journal timeline (.tl-day anchors, .tl-item time+text rows).
   .shelf     the library: .spine book cards. .rec* the 唱机. .mplayer/.mpcard the ONE
              player's bar and its chat receipt (gram-media.js).
   .reader    T3 immersive reading stage (epub/pdf/text), .night for lamplight.
   .skel      loading shimmer. .applybar password-confirm bar (the owner's pen).
   .float     (V0.1.8 ③) ANY floating control — scroll-to-latest, the record player,
              the compose card, progress — lives on the inline-END side in the dock's
              own column (--float-end keeps a 32px piece on the dock's axis; wide
              pieces hug the same edge). Never on the start side: one pillar, not two.
              ≤720px it drops to the centre above the bottom bar.
   .pick      (⑥) selector row: label (+ .pk-badge, .pk-n note) · value · ›. .picks
              stacks them with hairlines. Options open via HoopUI.pick → .menu/.sheet;
              rows inside are .mo (check · label · hint). .pk-v.staged = brand (pending).
   .sheet     (⑥) .menu's phone posture: bottom, full width, grabber, .sheet-scrim.
   .cdot      the conversation dot: rest = --line-2, busy = breathing brand, unread =
              solid brand. #owner the owner card at a sidebar's foot (avatar · name ·
              hoop name · status) → HoopUI.ownerMenu(). #mpick the model capsule.
   ══════════════════════════════════════════════════════════════════════════════ */

/* ── the HoopGram type identity (V0.1.5 serif + mono; V0.1.8 ① the sans body) ─
   Serif 思源宋体 + Source Serif 4 · Sans 思源黑体 + Inter + Noto Sans Arabic ·
   Mono Maple Mono — self-hosted slices, see fonts/README.md. The stacks keep full
   system fallbacks: offline or missing-slice never renders naked. @import must
   stay the first rule of this file. */
@import url("/fonts.css");
@import url("/tokens.css");   /* design tokens v1 (0.2.13): the ONE source of every number and colour */
@import url("/ui-kit.css");   /* UI-KIT v1: the ONE shared component layer */
@import url("/motion.css");   /* hoop-motion v1: reveal · draw · flip + the frame's transitions */
/* the metric-matched stand-in for Inter while its slice is still in flight:
   same x-height, so swap-in moves nothing (size-adjust, then overrides ÷ it) */
@font-face{font-family:"Inter Fallback"; src:local("Helvetica Neue"),local("Arial");
  size-adjust:105%; ascent-override:92.2%; descent-override:23%; line-gap-override:0%}

/* ── tokens: ALL in tokens.css (design tokens v1) — colours, the three themes, motion,
   shape, type, space, the WORK-FRAME sizes. This file only references them; a var() with
   no definition there is a red light (tools/test-design-tokens.mjs). ── */

/* ── V0.1.7 ①: cross-document view transitions — the shell never redraws ──
   MPA page loads become one soft cross-fade; the dock (view-transition-name:
   hoop-dock, set in nav.js) is matched across documents and stays motionless. */
@view-transition{navigation:auto}
::view-transition-group(hoop-dock){animation-duration:0s}
::view-transition-old(root), ::view-transition-new(root){animation-duration:var(--motion-base)}
@media (prefers-reduced-motion:reduce){
  ::view-transition-group(*), ::view-transition-old(*), ::view-transition-new(*){
    animation:none!important}
}

/* ── .glass: the floating material (②b) ─────────────────────────────────── */
.glass{background:var(--glass-bg); -webkit-backdrop-filter:var(--glass-blur);
  backdrop-filter:var(--glass-blur); box-shadow:var(--glass-rim), var(--shadow-pop); border:0}
.bar-glass{background:var(--glass-bg); -webkit-backdrop-filter:var(--glass-blur);
  backdrop-filter:var(--glass-blur); border-bottom:1px solid var(--line-soft)}
@media (prefers-reduced-transparency:reduce){
  .glass,.bar-glass{background:var(--surface); -webkit-backdrop-filter:none; backdrop-filter:none}
}

/* ── base ───────────────────────────────────────────────────────────────── */
*{box-sizing:border-box; -webkit-tap-highlight-color:transparent}
html.hoop-lock, html.hoop-lock body{overflow:hidden; overscroll-behavior:none}
[hidden]{display:none!important}
.foot{margin-top:3rem}
.dim{color:var(--dim)}
body{margin:0; background:var(--bg); color:var(--fg); min-height:100dvh;
  font:var(--fs-base)/1.7 var(--font)}
/* ── 法典第 13 条·滚动条（V0.2.7 C3，一处定义，处处继承）──────────────────────
   滚动条属于整个窗口：细、跟主题（--line-2）、轨道透明、RTL 由 direction 自然镜像，
   永远贴在可滚动区的 inline-end 最外侧；任何浮层（dock、float 列、菜单）不得压在它上面。
   导航层要让位时让「内容」让，不让「滚动容器」缩——见下面 .p-chat 的 T3 规则。
   根元素不留 stable gutter（T3 壳 100dvh 不滚，留了就是 11px 死槽）；内部滚动容器各自 stable。 */
html{scrollbar-width:thin; scrollbar-color:var(--line-2) transparent}
*{scrollbar-width:thin; scrollbar-color:var(--line-2) transparent}
::-webkit-scrollbar{width:8px; height:8px}
::-webkit-scrollbar-track{background:transparent}
::-webkit-scrollbar-thumb{background:var(--line-2); border-radius:var(--r-pill); border:2px solid transparent; background-clip:padding-box}
::-webkit-scrollbar-thumb:hover{background:var(--dim); background-clip:padding-box}
::selection{background:var(--selection)}
button{font:inherit; color:inherit}
a{color:var(--accent)}
@keyframes rise{from{opacity:0; transform:translateY(4px)}}
@keyframes fade{from{opacity:0}}
@keyframes breathe{50%{opacity:.25}}
@keyframes shimmer{to{background-position-x:-200%}}
/* U-08 (V0.2.10): a still OS reads as an empty one. One shared rule — every icon
   inside a real control (button/a, hoop-wide) gets a small perk under the pointer,
   not a per-component override, so the OS moves as one hand everywhere at once.
   prefers-reduced-motion is handled below (animation-duration -> .01ms), so this
   needs no separate guard; (hover:hover) keeps it off touch, where :hover sticks
   after a tap. */
@keyframes icon-perk{0%,100%{transform:rotate(0) scale(1)}30%{transform:rotate(-7deg) scale(1.08)}65%{transform:rotate(5deg) scale(1.08)}}
@media (hover:hover){
  button:not(:disabled):hover [data-icon] svg, a:hover [data-icon] svg{animation:icon-perk var(--motion-base) var(--ease)}
}
@media (prefers-reduced-motion:reduce){
  *,*::before,*::after{animation-duration:.01ms!important; transition-duration:.01ms!important}
  .p-chat #send:hover,.p-chat #send:active{transform:none!important}
}

/* ── the standard app page frame ────────────────────────────────────────── */
.page{padding:26px 18px 60px; padding-top:calc(26px + env(safe-area-inset-top))}
.page main{max-width:42rem; margin:0 auto}
h1.app{font-size:var(--fs-xl); font-weight:400; font-family:var(--font-brand); letter-spacing:-.01em; margin:0;
  display:flex; align-items:baseline; gap:10px; flex-wrap:wrap}
h1.app .sub{color:var(--dim); font-size:var(--fs-sm); font-weight:400}
.lede{color:var(--dim); font-size:var(--fs-md); margin:8px 0 0}
.sect{margin:28px 0 10px; color:var(--dim); font-size:var(--fs-sm); letter-spacing:.1em;
  font-weight:500; display:flex; align-items:center; gap:10px}
.sect .n{background:var(--code); border-radius:var(--r-pill); padding:1px 8px;
  font-size:var(--fs-2xs); letter-spacing:0}

/* ── cards: quiet surfaces, one rhythm everywhere ───────────────────────── */
.card{background:var(--surface); border:1px solid var(--line);
  border-radius:var(--r-lg); padding:14px 16px; margin-bottom:10px;
  animation:var(--rise)}
.card.off{opacity:.55}
.card h3{margin:0 0 10px; font-size:var(--fs-h); font-weight:500}
.card h4{margin:0 0 3px; font-size:var(--fs-h); font-weight:500; display:flex;
  align-items:center; gap:9px; flex-wrap:wrap}
.card .meta{color:var(--dim); font-size:var(--fs-sm); word-break:break-all}
.card pre{white-space:pre-wrap; word-break:break-word; margin:10px 0 0;
  font:var(--fs-md)/1.65 var(--mono); color:var(--fg)}
.advanced-card summary{cursor:pointer; color:var(--dim); font-size:var(--fs-sm); list-style-position:inside}
.advanced-card[open] summary{margin-bottom:14px}
.advanced-card-body{border-top:1px solid var(--line-soft); padding-top:14px}

/* ── rows of quiet link-actions under a card ────────────────────────────── */
.row{display:flex; gap:16px; margin-top:10px; align-items:center; flex-wrap:wrap}
/* a link-action in a row; an <a class="btn"> in a row stays a full button */
.row a:not(.btn){color:var(--dim); font-size:var(--fs-sm); text-decoration:none; cursor:pointer;
  padding:4px 0; transition:color var(--dur-1)}
.row a:not(.btn):hover{color:var(--fg)}
.row a.primary{color:var(--accent)}
.row a.danger:hover{color:var(--bad)}
.row .fine{color:var(--dim); font-size:var(--fs-sm)}

/* Settings: a status line is quiet small text, and an action row spaces its buttons (page and window alike) */
:is(.p-set, .modal-settings) .fine{color:var(--dim); font-size:var(--fs-sm)}
:is(.p-set, .modal-settings) .actions{display:flex; flex-wrap:wrap; align-items:center; gap:10px; margin-top:12px}
/* Settings › Get the apps: one card per app, name + one line + one download button */
.app-pending{display:none!important}
.app-get .app-get-head{display:grid;grid-template-columns:36px minmax(0,1fr);gap:12px;align-items:start;margin-bottom:12px}
.app-get .app-get-icon{display:grid;place-items:center;width:36px;height:36px;border-radius:var(--r-sm);background:var(--brand-soft);color:var(--brand-ink)}
.app-get .app-get-icon svg{width:20px;height:20px}
.app-get h3{margin:0 0 2px}
.app-get .fine{color:var(--dim);font-size:var(--fs-sm);overflow-wrap:anywhere}
.app-get .fine code{background:var(--code);border-radius:var(--r-xs);padding:.1em .4em}
.app-get .app-get-head .fine{margin:0}
.app-get > .btns{align-items:center}
.app-get > .fine{margin:10px 0 0}
.app-get > .fine + .btns,.app-get-line + .btns,.app-get > .btns + .btns{margin-top:10px}
.app-get > .fine:empty{display:none}
.app-get-line{margin-top:12px;border-top:1px solid var(--line);padding-top:10px}
.app-get-line > summary{cursor:pointer;color:var(--fg);font-size:var(--fs-sm);font-weight:500;padding:4px 0}
.app-get-line .picks{margin:8px 0}
.app-get-cmd{display:flex;align-items:center;gap:8px;margin-top:8px;min-width:0}
.app-get-cmd code{flex:1 1 auto;min-width:0;overflow-x:auto;white-space:nowrap;padding:8px 10px;border-radius:var(--r-xs);background:var(--code);font-size:var(--fs-sm)}
.app-get-cmd .btn{flex:none}

/* ── .btn: THE button. Variants only, no ad-hoc buttons anywhere ────────── */
.btn{display:inline-flex; align-items:center; justify-content:center; gap:7px;
  border:1px solid var(--line-2); border-radius:var(--r-xs); cursor:pointer;
  padding:0 14px; min-height:var(--btn-h); font:inherit; font-size:var(--fs-ui);
  font-weight:500; text-decoration:none; color:var(--fg); background:transparent;
  user-select:none; white-space:nowrap; line-height:1.2;
  transition:background var(--dur-1), border-color var(--dur-1), filter var(--dur-1),
    color var(--dur-1), transform var(--dur-1), box-shadow var(--dur-1), opacity var(--dur-1)}
.btn:hover:not(:disabled){background:transparent; border-color:color-mix(in oklab, var(--fg) 40%, transparent)}
.btn:active:not(:disabled){transform:translateY(1px); box-shadow:none}
.btn:disabled{opacity:.5; cursor:default; transform:none}
.btn:focus-visible{outline:none; box-shadow:var(--focus)}
/* Every button is transparent in every state (owner, 2026-09-25). Priority comes from place, weight and line:
   KEY = the one main action of an area: amber line, amber-ink text, heavier weight — never a filled slab. */
.btn-primary{color:var(--brand-ink); border-color:var(--brand); background:transparent; box-shadow:none; font-weight:600}
.btn-primary:hover:not(:disabled){background:transparent; border-color:var(--brand-600); color:var(--brand-600)}
/* SECONDARY: a visible hairline (the same as a plain .btn) */
.btn-secondary{background:transparent; border-color:var(--line-2); box-shadow:none}
/* TONAL / GHOST: text only; the line appears on hover */
.btn-tonal,.btn-ghost{background:transparent; border-color:transparent; color:var(--fg)}
.btn-tonal:hover:not(:disabled),.btn-ghost:hover:not(:disabled){background:transparent; border-color:var(--line-2)}
.btn-danger{color:var(--bad); background:transparent; border-color:color-mix(in oklab, var(--bad) 45%, transparent)}
.btn-danger:hover:not(:disabled){background:transparent; border-color:var(--bad)}
.btn-sm{padding:0 10px; min-height:var(--btn-h-sm); font-size:var(--fs-sm)}
.btn.big{margin:16px 0 20px}
.btns{display:flex; gap:10px; flex-wrap:wrap}
.saved{color:var(--ok); font-size:var(--fs-sm)}
.sent-ok{color:var(--ok); font-size:var(--fs-sm)}

/* ── inputs: styled globally, identical on every page ───────────────────── */
input, select, textarea{
  border:1px solid var(--line-soft); border-radius:var(--r-in); background:var(--paper);
  color:var(--fg); padding:7px 13px; min-height:var(--btn-h); outline:none; font:inherit;
  font-size:var(--fs-ui); box-shadow:var(--shadow-1);
  transition:border-color var(--dur-1), box-shadow var(--dur-1)}
input:focus, select:focus, textarea:focus{border-color:var(--line-soft);
  box-shadow:var(--focus), var(--shadow-1)}
input::placeholder, textarea::placeholder{color:var(--dim); opacity:.8}
input:disabled, select:disabled, textarea:disabled{opacity:.6}
input[type="checkbox"], input[type="radio"], input[type="file"]{border:0; box-shadow:none;
  background:none; padding:0}
textarea{min-height:0}
textarea{resize:vertical}

/* ── legacy form scaffolding (.f inline form, .compose) on the new base ─── */
.f{display:none}
.f.on{display:block}
.f .line{display:flex; gap:8px; margin-top:8px; flex-wrap:wrap; align-items:center}
.f .line input[type="number"]{width:6.5rem}
.f input.wide{width:100%; margin-top:8px}
.f textarea{width:100%; min-height:7rem; margin-top:8px; font-size:var(--fs-md)}
.f .lbl{color:var(--dim); font-size:var(--fs-sm)}
.f .line .grow{flex:1; min-width:9rem}
.f textarea.short{min-height:4rem}
.compose{display:none; margin-top:14px}
.compose.on{display:block; animation:var(--rise)}
.compose input, .compose textarea{width:100%; margin-bottom:8px}
.compose textarea{min-height:9rem}
.compose .duo{display:flex; gap:8px}
.compose .duo input{flex:1; min-width:0}
.note{color:var(--dim); font-size:var(--fs-sm); margin-top:8px}
.receipt p{margin:0 0 .55em; font-size:var(--fs-ui); line-height:1.55}   /* M3a privacy receipt: sentences, no meters */
.receipt p.fine{color:var(--dim); font-size:var(--fs-sm); margin:0 0 .3em; font-variant-numeric:tabular-nums}
.note code, .hint code{background:var(--code); border-radius:var(--r-xs); padding:.1em .4em;
  font:var(--fs-xs) var(--mono); user-select:all}
.hint{color:var(--dim); font-size:var(--fs-sm); margin-top:14px}

/* ── password confirm bar (the owner's pen) ─────────────────────────────── */
.applybar{display:none; margin-top:12px; gap:8px; flex-wrap:wrap; align-items:center}
.applybar.on{display:flex; animation:var(--rise)}
.applybar input{width:12rem}

/* ── tabs ───────────────────────────────────────────────────────────────── */
.tabs{display:flex; gap:6px; margin-top:16px; border-bottom:1px solid var(--line);
  overflow-x:auto; overflow-y:hidden; scrollbar-width:none}
.tabs button{border:0; background:none; color:var(--dim); cursor:pointer; font:inherit;
  font-size:var(--fs-ui); padding:10px 14px; border-bottom:2px solid transparent;
  margin-bottom:-1px; white-space:nowrap; min-height:var(--tap); border-radius:0;
  transition:color var(--dur-1), border-color var(--dur-1)}
.tabs button.on{color:var(--fg); font-weight:500; border-bottom-color:var(--brand)}

/* ── empty states: quiet, alive, honest ─────────────────────────────────── */
.empty{color:var(--dim); text-align:center; padding:2.2rem 1rem; font-size:var(--fs-md);
  line-height:2; border:1px dashed var(--line); border-radius:var(--r-lg);
  margin-top:12px; animation:fade var(--dur-3) var(--ease)}
.empty .glyph{display:block; line-height:1.6; opacity:.8}
.empty .glyph svg{width:26px; height:26px}

/* ── icons (icons.js): one hand, one size discipline ────────────────────── */
[data-icon]{display:inline-flex; align-items:center; vertical-align:-.18em}
[data-icon] svg{width:1.15em; height:1.15em}
.btn [data-icon] svg{width:1.05em; height:1.05em}
.ent .ic svg{width:18px; height:18px; color:var(--dim)}

/* ── toast ──────────────────────────────────────────────────────────────── */
.toast{position:fixed; inset-inline-start:50%; transform:translateX(-50%); bottom:92px;
  background:color-mix(in oklab, var(--fg) 88%, transparent); color:var(--bg);
  -webkit-backdrop-filter:var(--glass-blur); backdrop-filter:var(--glass-blur);
  border-radius:var(--r-pill); padding:9px 18px; box-shadow:var(--shadow-pop);
  font-size:var(--fs-md); z-index:99; animation:var(--rise); max-width:88vw}
[dir="rtl"] .toast{transform:translateX(50%)}

/* ── modal: the ONE confirm/prompt dialog (HoopUI.confirm / HoopUI.prompt) ─ */
.modal-scrim{position:fixed; inset:0; background:var(--scrim); z-index:9998;
  display:flex; align-items:center; justify-content:center; padding:20px;
  -webkit-backdrop-filter:blur(10px); backdrop-filter:blur(10px);
  animation:fade var(--dur-1) var(--ease)}
.modal{position:relative; background:var(--glass-bg); border:0; border-radius:var(--r-2xl);
  -webkit-backdrop-filter:var(--glass-blur); backdrop-filter:var(--glass-blur);
  box-shadow:var(--glass-rim), var(--shadow-pop); width:100%; max-width:24rem; padding:22px 22px 18px;
  animation:var(--rise)}
.modal:focus{outline:none}
@media (prefers-reduced-transparency:reduce){
  .modal, .menu, .cmenu, .pal-box, .cap-box, .mplayer, .mw-compose, .toast, .float.fbtn{
    background:var(--surface); -webkit-backdrop-filter:none; backdrop-filter:none}
  .modal-scrim, .palette, .capture{-webkit-backdrop-filter:none; backdrop-filter:none}
}
.modal h3{margin:0 0 6px; font-size:var(--fs-lg); font-weight:500}
.modal > h3{padding-inline-end:36px}
.ui-close:focus-visible{outline:none; box-shadow:var(--focus)}
.window-close,.modal-x{position:absolute; top:14px; inset-inline-end:14px; z-index:3}
.modal .m-body{color:var(--dim); font-size:var(--fs-ui); line-height:1.65;
  word-break:break-word}
.modal .m-body b{color:var(--fg)}
.modal .m-body.m-notes{white-space:pre-line; max-height:60vh; overflow:auto; color:var(--fg)}
.modal input{width:100%; margin-top:12px}
.modal .m-acts .btn{min-width:5.5rem}
.modal .m-acts{display:flex; gap:10px; justify-content:flex-end; margin-top:18px}

/* ── skeleton loading ───────────────────────────────────────────────────── */
.skel{border-radius:var(--r-sm); min-height:1em; color:transparent!important;
  background:linear-gradient(90deg,var(--code) 8%,var(--lift) 18%,var(--code) 33%);
  background-size:200% 100%; animation:shimmer var(--motion-shimmer) var(--ease-linear) infinite}

/* ── on/off switch ──────────────────────────────────────────────────────── */
.onoff{width:34px; height:20px; border-radius:var(--r-pill); background:var(--line-2);
  position:relative; cursor:pointer; flex:none; transition:background var(--dur-2)}
.onoff::after{content:""; position:absolute; top:2px; inset-inline-start:2px; width:16px;
  height:16px; border-radius:50%; background:var(--surface);
  transition:transform var(--dur-2) var(--ease); box-shadow:var(--shadow-1)}
.onoff.on{background:var(--brand)}
.onoff.on::after{transform:translateX(14px)}
[dir="rtl"] .onoff.on::after{transform:translateX(-14px)}

/* ── permission chip ────────────────────────────────────────────────────── */
.perm{display:inline-flex; align-items:center; gap:6px; margin-top:14px;
  border:1px solid var(--line-soft); border-radius:var(--r-btn); padding:5px 11px;
  font-size:var(--fs-sm); color:var(--dim); background:var(--surface)}
.perm b{color:var(--fg); font-weight:500}
.perm a{color:var(--accent); text-decoration:none}

/* ── tooltip: the floating name beside an icon (mac Dock style) ─────────── */
.tip{position:absolute; inset-inline-start:calc(100% + 12px); top:50%;
  transform:translateY(-50%) scale(.94); transform-origin:0 50%;
  background:var(--fg); color:var(--bg); font-size:var(--fs-xs); line-height:1;
  padding:6px 11px; border-radius:var(--r-xs); white-space:nowrap; pointer-events:none;
  opacity:0; transition:opacity var(--dur-1) var(--ease), transform var(--dur-1) var(--ease);
  z-index:2}
[dir="rtl"] .tip{transform-origin:100% 50%}
@media (hover:hover){
  :hover > .tip, :focus-visible > .tip{opacity:1; transform:translateY(-50%) scale(1);
    transition-delay:var(--motion-fast)}
}
@media (hover:none){ .tip{display:none} }

/* ── floating context menu ──────────────────────────────────────────────── */
.menu{position:fixed; z-index:9999; background:var(--glass-bg); border:0;
  -webkit-backdrop-filter:var(--glass-blur); backdrop-filter:var(--glass-blur);
  border-radius:var(--r-lg); box-shadow:var(--glass-rim), var(--shadow-pop); min-width:11rem; overflow:hidden;
  animation:var(--rise)}
.menu a{display:flex; align-items:center; gap:10px; padding:9px 14px; font-size:var(--fs-md);
  cursor:pointer; color:var(--fg); text-decoration:none; border-radius:var(--r-md)}
.menu a:hover{background:var(--lift)}
.menu a [data-icon]{color:var(--dim)}
.menu a.on{color:var(--brand-ink)}
.menu a.on [data-icon]{color:var(--brand-ink)}
.menu a .fine{margin-inline-start:auto; padding-inline-start:14px; color:var(--dim);
  font-size:var(--fs-2xs); font-variant-numeric:tabular-nums}
.menu{padding:6px}
.menu hr{border:0; border-top:1px solid var(--line); margin:4px 0}
.menu .mh{padding:8px 14px 4px; font-size:var(--fs-2xs); color:var(--dim); letter-spacing:.06em;
  user-select:none}
.menu .mh.mspace{user-select:text; letter-spacing:0; text-transform:none; overflow-wrap:anywhere; font-size:var(--fs-xs); padding:4px 14px}
.menu .mh.who{font:var(--fs-xs) var(--mono); letter-spacing:0; padding:10px 14px 8px; border-bottom:1px solid var(--line);
  margin-bottom:4px; color:var(--dim)}
.menu a.danger{color:var(--bad)}
.menu a.off{opacity:.55; cursor:default}
.menu a.off:hover{background:none}

/* ── .pick: the selector row (codex art. 6) — one row, tap, choose ──────── */
.picks{display:flex; flex-direction:column; margin:0 -4px}
.picks + .note{margin-top:10px}
.pick{display:flex; align-items:center; gap:12px; width:100%; min-height:46px; padding:8px 10px;
  border:0; background:none; border-radius:var(--r-md); cursor:pointer; text-align:start;
  font:inherit; color:var(--fg); transition:background var(--dur-1)}
.pick + .pick{border-top:1px solid var(--line)}
.pick:hover{background:var(--lift)}
.pick.on{background:var(--brand-soft)}
.pick:disabled{cursor:default; opacity:.6}
.pk-l{flex:1; min-width:0; display:flex; flex-direction:column; gap:1px}
.pk-t{font-size:var(--fs-ui); display:flex; align-items:center; gap:8px; flex-wrap:wrap}
.pk-n{font-size:var(--fs-xs); color:var(--dim); line-height:1.4}
.pk-badge{font-size:var(--fs-2xs); color:var(--dim); border:1px solid var(--line-2); border-radius:var(--r-pill);
  padding:0 8px; line-height:1.6}
.pk-badge.hard{color:var(--ok); border-color:var(--ok)}
.pk-v{flex:none; max-width:50%; color:var(--dim); font-size:var(--fs-md); white-space:nowrap; overflow:hidden;
  text-overflow:ellipsis; font-variant-numeric:tabular-nums}
.pk-v.staged{color:var(--brand-ink); font-weight:500}
.pk-c{flex:none; color:var(--dim); display:inline-flex}
.pk-c svg{width:14px; height:14px}
/* the search box of a long pick (timezones) */
.menu .mo-q{width:100%; min-height:34px; margin:4px 0 6px; font-size:var(--fs-md)}
.menu .mo-list{max-height:min(52vh, 420px); overflow-y:auto; overscroll-behavior:contain}
.menu.sheet .mo-list{max-height:52vh}
/* option rows inside a menu/sheet */
.menu .mo{display:flex; align-items:center; gap:10px; padding:9px 12px; border-radius:var(--r-md); cursor:pointer;
  color:var(--fg); font-size:var(--fs-md)}
.menu .mo:hover{background:var(--lift)}
.menu .mo-ck{width:16px; flex:none; color:var(--brand-ink); opacity:0}
.menu .mo.on .mo-ck{opacity:1}
.menu .mo-b{display:flex; flex-direction:column; min-width:0}
.menu .mo-h{font-size:var(--fs-xs); color:var(--dim)}
.menu .mo.on .mo-l{color:var(--brand-ink); font-weight:500}
/* .sheet: the menu's phone posture */
.sheet-scrim{position:fixed; inset:0; z-index:9998; background:var(--scrim);
  -webkit-backdrop-filter:blur(8px); backdrop-filter:blur(8px); animation:fade var(--dur-1) var(--ease)}
.menu.sheet{position:fixed; inset-inline:0; bottom:0; top:auto; left:0; right:0; z-index:9999; min-width:0;
  background:color-mix(in oklab, var(--surface) 92%, transparent);   /* dense text: nearly solid */
  border-radius:var(--r-2xl) var(--r-2xl) 0 0; padding:6px 12px calc(14px + env(safe-area-inset-bottom));
  max-height:72vh; overflow-y:auto; animation:sheetup var(--dur-2) var(--ease)}
.menu.sheet .grab{width:38px; height:5px; border-radius:var(--r-pill); background:var(--line-2); margin:4px auto 8px;
  cursor:pointer; padding:0; box-sizing:content-box; border-block:8px solid transparent; background-clip:padding-box}
.menu.sheet .sheet-x{position:absolute; top:10px; inset-inline-end:10px; width:32px; height:32px}
.menu.sheet .mh.big{padding-inline-end:48px}
.menu.sheet .mh.big{font-size:var(--fs-h); color:var(--fg); letter-spacing:0; padding:4px 12px 8px}
.menu.sheet a, .menu.sheet .mo{min-height:48px; font-size:var(--fs-ui)}
.menu.sheet .mrow .opt{min-height:34px; font-size:var(--fs-sm)}
@keyframes sheetup{from{transform:translateY(24px); opacity:0}}
/* ── date & time pickers (V0.2.7 C1, codex art. 13: no native popovers) ──
   .dp the month grid inside a .menu/.sheet (HoopUI.dateMenu / pickDate);
   .tp the hours list (HoopUI.timeMenu / pickTime) riding the pick's search list. */
.menu .dp{width:min(21rem, 92vw); padding:2px 4px 6px; user-select:none}
.menu.sheet .dp{width:auto}
.dp-head{display:flex; align-items:center; justify-content:space-between; gap:var(--sp-2); padding:2px 2px 6px}
.dp-m{flex:1; border:0; background:none; font:inherit; font-size:var(--fs-ui); font-weight:500; color:var(--fg);
  text-align:center; cursor:pointer; min-height:32px; border-radius:var(--r-md)}
.dp-m:hover{background:var(--lift)}
.dp-nav{flex:none; width:32px; height:32px; border:0; background:none; color:var(--dim); border-radius:var(--r-md);
  cursor:pointer; display:inline-flex; align-items:center; justify-content:center}
.dp-nav:hover{background:var(--lift); color:var(--fg)}
.dp-nav svg{width:16px; height:16px}
[dir="rtl"] .dp-nav svg{transform:scaleX(-1)}
.dp-grid{display:grid; grid-template-columns:repeat(7, 1fr); gap:2px}
.dp-wd{text-align:center; font-size:var(--fs-2xs); color:var(--dim); padding:4px 0; letter-spacing:.04em}
.dp-d{border:0; background:none; font:inherit; font-size:var(--fs-md); color:var(--fg); min-height:36px;
  border-radius:var(--r-md); cursor:pointer; font-variant-numeric:tabular-nums}
.dp-d:hover{background:var(--lift)}
.dp-d.off{color:var(--dim); opacity:.55}
.dp-d.today{color:var(--brand-ink); font-weight:600}
.dp-d.on{background:var(--brand); color:var(--on-brand); font-weight:600}
.dp-d:focus-visible{box-shadow:var(--focus); outline:0}
.dp-foot{display:flex; gap:var(--sp-2); padding:6px 2px 0; border-top:1px solid var(--line); margin-top:6px}
.dp-foot a{font-size:var(--fs-sm); color:var(--brand-ink); cursor:pointer; padding:6px 8px; border-radius:var(--r-md)}
.dp-foot a:hover{background:var(--lift)}
.dp-foot a.quiet{color:var(--dim); margin-inline-start:auto}
.menu.sheet .dp-d{min-height:var(--tap); font-size:var(--fs-ui)}
.menu .tp{min-width:11rem}
.menu .tp .mo-l{font-variant-numeric:tabular-nums}

/* ═══ home (p-home) ═════════════════════════════════════════════════════ */
.p-home{min-height:100dvh; overflow-x:hidden}
.p-home.home-pending{visibility:hidden}
.p-home .public-card{min-height:100dvh; display:flex; flex-direction:column; align-items:center;
  justify-content:center; text-align:center; padding:40px 24px; animation:rise var(--dur-3) var(--ease)}
.p-home .name{font-size:clamp(2.6rem,9vw,5rem); font-weight:400; font-family:var(--font-brand);
  letter-spacing:-.02em;
  display:flex; align-items:baseline; justify-content:center; gap:.18em}
.p-home .name .dot{width:.5em; height:.5em; align-self:center; display:block;
  animation:breathe var(--motion-breathe) var(--ease-loop) infinite}   /* the golden hoop mark, breathing */
.p-home .tag{color:var(--dim); margin-top:14px; font-size:clamp(.95rem,2.6vw,1.1rem);
  font-family:var(--font-brand)}
.p-home .go{display:inline-block; margin-top:38px; text-decoration:none;
  color:var(--brand-ink); background:transparent; border:1px solid var(--brand); font-weight:600;
  border-radius:var(--r-btn); padding:12px 30px; font-size:var(--fs-base); font-weight:500;
  box-shadow:var(--shadow-key); transition:filter var(--dur-2), transform var(--dur-1)}
.p-home .go:hover{filter:brightness(1.03)}
.p-home .go:active{transform:translateY(1px); box-shadow:none}
.p-home .hint{color:var(--dim); font-size:var(--fs-sm); margin-top:20px; opacity:0;
  transition:opacity var(--motion-slow)}
.p-home .hint.on{opacity:.8}
/* the public card (⑥): the logged-out face — quiet, serif, one column */
.p-home .bio{max-width:32rem; margin:22px auto 0; text-align:start;
  font-size:var(--fs-rd); line-height:1.85; font-family:var(--font-brand)}
.p-home .bio p{margin-top:10px}
.p-home .go.quiet{background:var(--paper); border:1px solid var(--line-soft); color:var(--dim);
  font-size:var(--fs-sm); padding:8px 22px; box-shadow:var(--shadow-1)}
.p-home .go.quiet:hover{color:var(--fg); border-color:var(--line-2)}
.p-home .hoopnote{color:var(--dim); font-size:var(--fs-xs); margin-top:26px;
  letter-spacing:.06em}
#pub-fields input,#pub-fields textarea{width:100%; margin-top:8px}
#pub-fields textarea{min-height:7rem}
/* V0.2.4 F4: Home is the owner's desktop/new-tab surface. Desktop and phone share
   one DOM; breakpoints only change grid columns and spacing. */
.sr-only{position:absolute!important;width:1px!important;height:1px!important;padding:0!important;margin:-1px!important;overflow:hidden!important;clip:rect(0,0,0,0)!important;white-space:nowrap!important;border:0!important}
/* ═══ CODEX ARTICLE 14 — THE THREE TEXT LAWS (V0.2.7 C2; law, not style) ═══════════
   1. A TITLE wraps two lines, then ellipsis, and carries its full text in `title`.    → .t2 + title
   2. A LIST NAME wraps two lines — never a one-line ellipsis.                         → .t2
   3. Any one-line ellipsis (.clip) must have a same-content FULL VIEW: `title`, an
      inspector, the thing it opens. `.clip-ok` marks text hidden on purpose (sr-only,
      decorative) — the only thing tools/mobile-audit.js's visible-rectangle audit
      waves through. A clipped .clip/.t2 without its full text in `title` fails the audit. */
.t2{display:-webkit-box; -webkit-line-clamp:2; -webkit-box-orient:vertical; overflow:hidden; white-space:normal; overflow-wrap:anywhere; min-width:0}
.clip{overflow:hidden; text-overflow:ellipsis; white-space:nowrap; min-width:0}
.p-home:not(.home-pending){background:var(--bg)}
html[data-wall="plain"] .p-home:not(.home-pending){background:var(--bg)}
html[data-wall="ink"] .p-home:not(.home-pending){background:var(--bg)}
html[data-wall="custom"] .p-home:not(.home-pending){background-image:linear-gradient(color-mix(in oklab,var(--bg) 18%,transparent),color-mix(in oklab,var(--bg) 18%,transparent)),var(--home-wallpaper);background-size:cover;background-position:center;background-attachment:fixed}
.p-home .pa-home{width:min(82rem,calc(100% - 64px));min-height:100dvh;margin:0 auto;padding:clamp(48px,7vw,88px) 0 72px;animation:rise var(--dur-3) var(--ease)}
.p-home .home-shortcuts{display:grid;grid-template-columns:repeat(12,minmax(0,1fr));gap:var(--sp-2)}
.p-home .home-shortcut{position:relative;min-width:0;border:0;background:none;color:var(--fg);font:inherit;text-align:center;border-radius:var(--r-lg)}
.p-home .home-shortcut-open,.p-home button.home-shortcut-add{width:100%;min-width:0;display:flex;flex-direction:column;align-items:center;gap:7px;border:0;background:none;color:var(--fg);font:inherit;font-size:var(--fs-xs);cursor:pointer;padding:8px 2px;border-radius:var(--r-lg);transition:transform var(--dur-1) var(--ease),background var(--dur-1)}
/* U-01: the mark was a 1.15em (~14px) glyph adrift in a 48px circle — visibly too
   small for its own frame. A bigger circle + an explicit glyph size (not the em-based
   default, sized off a caption-scale font) reads as one deliberate mark, not a speck. */
.p-home .home-shortcut-open>[data-icon],.p-home button.home-shortcut-add>[data-icon]{width:56px;height:56px;padding:14px;border-radius:var(--r-lg);color:var(--brand-ink);background:var(--glass-bg);box-shadow:var(--glass-rim)}
.p-home .home-shortcut-open>[data-icon] svg,.p-home button.home-shortcut-add>[data-icon] svg{width:26px;height:26px}
.p-home .home-shortcut-open:hover,.p-home button.home-shortcut-add:hover{background:var(--lift); transform:translateY(-1px)}
.p-home .home-shortcut-label,.p-home button.home-shortcut-add>span:last-child{width:100%;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;overflow-wrap:anywhere;line-height:1.25}
.p-home .home-shortcut-remove{position:absolute;inset-block-start:2px;inset-inline-end:2px;width:22px;height:22px;display:grid;place-items:center;border:0;border-radius:50%;background:var(--surface);color:var(--dim);box-shadow:var(--shadow-1);opacity:0;cursor:pointer}
.p-home .home-shortcut:hover .home-shortcut-remove,.p-home .home-shortcut:focus-within .home-shortcut-remove{opacity:1}
.p-home .home-shortcut-remove [data-icon]{width:12px;height:12px}.p-home .home-shortcut.dragging{opacity:.45}
.p-home .home-command{position:relative;width:min(46rem,100%);margin:clamp(60px,9vw,120px) auto clamp(52px,7vw,92px)}
.p-home .home-cards-toolbar{display:flex;justify-content:flex-end;gap:var(--sp-2);margin:clamp(40px,6vw,72px) 0 var(--sp-3)}
.p-home .home-cards .home-command{width:auto;margin:0;grid-column:1/-1}
.p-home .home-card{position:relative;min-width:0}
.p-home .home-card[hidden]{display:none}
.p-home .home-card-edit{display:none;position:absolute;z-index:2;inset-block-start:8px;inset-inline-end:8px;width:30px;height:30px;place-items:center;border:1px solid var(--line);border-radius:50%;background:var(--surface);color:var(--dim);cursor:pointer}
.p-home .home-card-edit [data-icon]{width:15px;height:15px}
.p-home .home-cards.editing .home-card-edit{display:grid}
.p-home .home-card.dragging{opacity:.45}
.p-home .home-owner{display:flex;justify-content:center;align-items:center;gap:10px;margin-bottom:14px}
.p-home .pa-owner-avatar{width:64px; height:64px; display:grid; place-items:center; overflow:hidden;
  border-radius:50%; background:var(--brand-soft); color:var(--brand-ink); font:400 var(--fs-2xl) var(--font-brand)}
.p-home .pa-owner-avatar img{width:100%; height:100%; object-fit:cover}
.p-home .home-owner .pa-owner-avatar{width:36px;height:36px;font-size:var(--fs-md)}
.p-home .pa-eyebrow{margin:0;color:var(--brand-ink);font-size:var(--fs-xs);letter-spacing:.08em;text-transform:uppercase}
.p-home .home-owner h2{margin:1px 0 0;font:400 var(--fs-md)/1.2 var(--font-brand)}
.p-home .home-ask{height:62px;display:grid;grid-template-columns:24px minmax(0,1fr) 38px;align-items:center;gap:12px;padding:0 12px 0 20px;border-radius:var(--r-2xl);box-shadow:var(--glass-rim),var(--shadow-pop)}
.p-home .home-ask>[data-icon]{width:21px;height:21px;color:var(--dim)}
.p-home .home-ask input{width:100%;height:100%;border:0;background:none;box-shadow:none;padding:0;font-size:var(--fs-lg);color:var(--fg)}
.p-home .home-ask input:focus{box-shadow:none;outline:0}
.p-home .home-ask button{width:38px;height:38px;display:grid;place-items:center;border:1px solid var(--brand);border-radius:50%;background:transparent;color:var(--brand-ink);box-shadow:none;cursor:pointer}
.p-home .home-ask button [data-icon]{width:18px;height:18px}.p-home .home-ask button:disabled{opacity:.5}
.p-home .home-ask-results{position:absolute;inset-inline:0;top:calc(100% + 8px);z-index:20;padding:6px;border-radius:var(--r-xl);box-shadow:var(--glass-rim),var(--shadow-pop);max-height:21rem;overflow:auto}
.p-home .home-result{width:100%;display:grid;grid-template-columns:22px minmax(0,1fr) minmax(0,1fr);align-items:center;gap:10px;border:0;background:none;color:var(--fg);font:inherit;text-align:start;padding:10px 12px;border-radius:var(--r-md);cursor:pointer}
.p-home .home-result:hover{background:var(--lift)}.p-home .home-result>[data-icon]{width:18px;height:18px;color:var(--brand-ink)}
.p-home .home-result .lb,.p-home .home-result .sub{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.p-home .home-result .sub{color:var(--dim);font-size:var(--fs-xs);text-align:end}
.p-home .home-cards{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:var(--sp-4);align-items:start}
/* C4: in-flow panels over the flat page keep the glass material but not the
   blur pass (each backdrop-filter is one compositor render pass per scrolled frame:
   9 passes = 15.5ms/frame in software compositing); a photo wallpaper earns it back */
.p-home .home-section.glass,.p-home .home-ask.glass{-webkit-backdrop-filter:none;backdrop-filter:none}
html[data-wall="custom"] .p-home .home-section.glass,html[data-wall="custom"] .p-home .home-ask.glass{-webkit-backdrop-filter:var(--glass-blur);backdrop-filter:var(--glass-blur)}
.p-home .home-section{min-width:0;padding:var(--sp-5);border-radius:var(--r-xl);box-shadow:var(--glass-rim)}
.p-home .home-section h2{font:500 var(--fs-h)/1.3 var(--font); margin:0 0 var(--sp-4)}
/* T3 os-dash: the dashboard strip — readings, not decoration */
.p-home .home-dash{margin:0 0 var(--sp-4)}
.p-home .home-dash-head{display:flex; align-items:baseline; justify-content:space-between; gap:var(--sp-2); margin:0 0 var(--sp-2)}
.p-home .home-dash-head h2{margin:0; font-size:var(--fs-2, 15px); font-weight:600}
.p-home .home-dash-when{font-size:var(--fs-xs); color:var(--dim)}
.p-home .home-dash-tiles{display:grid; gap:var(--sp-2); grid-template-columns:repeat(auto-fit, minmax(150px, 1fr))}
.p-home .dash-tile{display:flex; flex-direction:column; align-items:flex-start; gap:2px; text-align:start;
  min-height:86px; padding:12px 14px; border:1px solid var(--line); border-radius:var(--r-card);
  background:var(--glass-bg); color:var(--dim); transition:border-color var(--motion-fast), transform var(--motion-fast)}
.p-home button.dash-tile{cursor:pointer}
.p-home button.dash-tile:hover{border-color:var(--line-2); color:var(--fg); transform:translateY(-1px)}
.p-home .dash-tile .dash-k{display:flex; align-items:center; gap:6px; font-size:var(--fs-xs); color:var(--dim)}
.p-home .dash-tile .dash-k > [data-icon]{width:14px; height:14px; flex:none}
.p-home .dash-tile .dash-v{max-width:100%; font-size:var(--fs-5); line-height:1.15; font-weight:600; color:var(--fg); font-variant-numeric:tabular-nums}
.p-home .dash-tile .dash-s{font-size:var(--fs-xs); color:var(--dim)}
.p-home .dash-tile.ok .dash-k > [data-icon]{color:var(--ok)}
.p-home .dash-tile.live .dash-k > [data-icon]{color:var(--accent)}
.p-home .dash-tile.live .dash-v{color:var(--accent)}
.p-home .dash-tile.warn .dash-k > [data-icon]{color:var(--brand-ink)}
.p-home .dash-tile.warn .dash-v{color:var(--brand-ink)}
.p-home .dash-tile.unobserved .dash-v{color:var(--dim); font-size:var(--fs-base); font-weight:500}
@media (max-width:520px){.p-home .home-dash-tiles{grid-template-columns:repeat(2, 1fr)}}
.p-home .home-status{display:grid;grid-template-columns:1fr;gap:var(--sp-2)}
.p-home .home-status-item{display:flex; align-items:center; gap:10px; min-height:54px; padding:12px 14px;
  border:1px solid var(--line-soft); border-radius:var(--r-lg); color:var(--dim); background:color-mix(in oklab,var(--surface) 62%,transparent);
  font:inherit; font-size:var(--fs-sm); text-align:start; transition:transform var(--dur-1) var(--ease),border-color var(--dur-1),color var(--dur-1)}
.p-home button.home-status-item{cursor:pointer}
.p-home button.home-status-item:hover{border-color:var(--line-2); color:var(--fg); transform:translateY(-1px)}
.p-home .home-status-item > [data-icon]{width:18px; height:18px; flex:none}
.p-home .home-status-item.ok > [data-icon]{color:var(--ok)}
.p-home .home-status-item.live > [data-icon]{color:var(--accent)}
.p-home .home-status-item.warn > [data-icon]{color:var(--brand-ink)}
.p-home .home-actions{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:var(--sp-2)}
.p-home .home-action{display:grid; grid-template-columns:28px minmax(0,1fr); grid-template-rows:auto auto;
  column-gap:var(--sp-2); row-gap:4px; min-height:82px; padding:var(--sp-3); text-align:start;
  color:var(--fg); background:color-mix(in oklab,var(--surface) 62%,transparent); border:1px solid var(--line-soft); border-radius:var(--r-lg);
  text-decoration:none; font:inherit; cursor:pointer; transition:transform var(--dur-1) var(--ease),border-color var(--dur-1),background var(--dur-1)}
.p-home .home-action:hover{border-color:var(--line-2); background:var(--lift); transform:translateY(-1px)}
.p-home .home-action > [data-icon]{grid-row:1/3; width:24px; height:24px; color:var(--brand-ink)}
.p-home .home-action b{font-size:var(--fs-base); font-weight:500}
.p-home .home-action small{font-size:var(--fs-sm); color:var(--dim); line-height:1.45}
.p-home .home-section-head{display:flex; align-items:center; justify-content:space-between; gap:var(--sp-4)}
.p-home .home-guide-link{min-height:32px;padding-inline:8px;border:0;background:none;color:var(--dim);font:inherit;font-size:var(--fs-sm);cursor:pointer}
.p-home .home-guide-link:hover{color:var(--fg)}
.p-home .home-recents{display:grid; gap:8px}
.p-home .home-recent-hint{margin:0 0 var(--sp-1);color:var(--dim);font-size:var(--fs-sm);line-height:1.45}
.p-home .home-recent{display:flex; align-items:center; justify-content:space-between; gap:var(--sp-4);
  width:100%; padding:13px 0; border:0; border-bottom:1px solid var(--line-soft); background:none;
  color:var(--fg); font:inherit; text-align:start; cursor:pointer}
.p-home .home-recent b{font-weight:450; max-width:100%; display:-webkit-box; -webkit-line-clamp:2; -webkit-box-orient:vertical; overflow:hidden; overflow-wrap:anywhere}
.p-home .home-recent span{color:var(--dim); font-size:var(--fs-xs); white-space:nowrap}
.p-home .home-recent.empty{color:var(--dim); justify-content:flex-start}
@media (max-width:800px){
  .p-home .pa-home{width:calc(100% - 32px);padding:28px 0 92px}
  .p-home .home-shortcuts{grid-template-columns:repeat(6,minmax(0,1fr))}
  .p-home .home-cards{grid-template-columns:1fr}
}
@media (max-width:430px){
  .p-home .home-shortcuts{grid-template-columns:repeat(4,minmax(0,1fr))}
  .p-home .home-command{margin:48px auto 44px}.p-home .home-ask{height:56px}.p-home .home-ask input{font-size:16px}
  .p-home .home-actions{grid-template-columns:1fr}.p-home .home-action{min-height:76px}
  .p-home .home-recent{align-items:flex-start; flex-direction:column; gap:4px}
}

/* V0.2.1 onboarding uses the same surface and one short Hoop-light motion language. */
.p-home .onb{width:min(58rem, 100% - 48px); margin:0 auto; text-align:center;
  animation:rise var(--dur-3) var(--ease)}
.p-home.onb-on .wrap{display:none}
.p-home .onb-hi{font-family:var(--font-brand); font-weight:400; font-size:clamp(1.4rem,4vw,2rem);
  line-height:1.4; margin:0 0 var(--sp-6); letter-spacing:-.01em}
.p-home .onb-cards{display:grid; grid-template-columns:repeat(auto-fit, minmax(14rem, 1fr)); gap:var(--sp-4)}
.p-home .onb-card{position:relative; display:flex; flex-direction:column; align-items:flex-start; gap:var(--sp-2);
  padding:var(--sp-5); text-align:start; background:var(--surface); border:1px solid var(--line);
  border-radius:var(--r-xl); color:var(--fg); font:inherit; cursor:pointer; min-height:11rem;
  transition:border-color var(--dur-2), transform var(--dur-1)}
.p-home .onb-card:hover{border-color:var(--line-2)}
.p-home .onb-card:active{transform:translateY(1px)}
.p-home .onb-card > span[data-icon]{color:var(--brand-ink); width:24px; height:24px}
.p-home .onb-card b{font-weight:500; font-size:var(--fs-h)}
.p-home .onb-card small{color:var(--dim); font-size:var(--fs-sm); line-height:1.5}
.p-home .onb-card .onb-ck{position:absolute; inset-inline-end:var(--sp-4); inset-block-start:var(--sp-4);
  width:18px; height:18px; color:var(--line-2)}
.p-home .onb-card.done{border-color:var(--brand)}
.p-home .onb-card.done .onb-ck{color:var(--brand-ink)}
.p-home .onb-card.busy{opacity:.7; cursor:progress}
.p-home .onb-skip{margin-top:var(--sp-6); color:var(--dim)}
/* V0.2.12 home: the first-visit choice card (chat-first / classic) */
.p-home .home-mode{padding:var(--sp-4); border-radius:var(--r-xl); margin-block-end:var(--sp-3); display:flex; flex-direction:column; gap:var(--sp-2); max-width:46rem}
.p-home .home-mode h2{font-size:var(--fs-h); font-weight:500; margin:0}
.p-home .home-mode-acts{display:flex; gap:var(--sp-2); flex-wrap:wrap}
@media (max-width:600px){ .p-home .onb{width:calc(100% - 32px)} .p-home .onb-card{min-height:0} }
@media (prefers-reduced-motion:reduce){.p-home .pa-home,.p-home .public-card{animation:none}.p-home .pa-mark,.p-home .name .dot{animation:none}}

/* Hoop frame refinement: the rail is a margin and a signal, while the conversation
   owns the page.  Keep the visible marks small and let the active hairline do the
   orientation work. */
@media (min-width:721px){
  html.hoop-rail:not(.hoop-embedded) body{margin-inline-start:var(--rail-w)}
  html.hoop-rail:not(.hoop-session-embedded) .p-chat #side{background:var(--surface-2);border-inline-end-color:var(--line-soft)}
  html.hoop-rail:not(.hoop-session-embedded) .p-chat #main{background:var(--bg)}
}
.p-chat #cwrap{padding:var(--sp-2) var(--sp-3) var(--sp-2);border:1px solid var(--line);border-radius:var(--r-xl);background:var(--surface);box-shadow:var(--shadow-1);transition:border-color var(--motion-fast),transform var(--motion-fast)}
.p-chat #cwrap:focus-within{border-color:color-mix(in oklab,var(--brand) 48%,var(--line));box-shadow:var(--focus-chat-input),var(--shadow-1)}
.p-chat #inp{border:0;min-height:var(--control-h);padding:var(--sp-2) var(--sp-1);background:transparent}
.p-chat #send{width:var(--rail-hit);height:var(--rail-hit);border-color:var(--line-soft);background:transparent;border-radius:var(--r-md)}
.p-chat #send.ready{background:var(--brand-soft);color:var(--brand-ink);border-color:var(--brand-ink)}
.p-chat #send:hover{transform:translateY(-1px)}
.p-chat #send:active{transform:translateY(1px) scale(.96)}

/* AppWindow: one shared route shell on top of HoopUI.window. */
.modal-appwindow{width:min(70rem,calc(100vw - 72px)); height:min(48rem,calc(100dvh - 72px));
  max-width:none; padding:0; overflow:hidden; display:flex; flex-direction:column}
.appwindow-frame{width:100%; min-height:0; flex:1; border:0; background:var(--bg)}
html.hoop-embedded{background:var(--bg)}
@media (max-width:800px){.modal-appwindow{width:100vw;height:100dvh;border-radius:0}}

.guide-card{display:flex;align-items:center;justify-content:space-between;gap:var(--sp-5)}
.guide-card h3{margin:0 0 5px}.guide-card .btn{flex:none}
@media (max-width:600px){.guide-card{align-items:flex-start;flex-direction:column}}

/* ═══ chat (p-chat) ═════════════════════════════════════════════════════ */
.p-chat{font-size:var(--fs-rd); line-height:1.75; display:flex; height:var(--vvh, 100dvh); overflow:hidden}
/* the shell: the sidebar is the same sheet of paper as the page — one faint line */
.p-chat #side{width:264px; flex:none; display:flex; flex-direction:column;
  background:var(--bg); border-inline-end:1px solid var(--line);
  transition:margin-inline-start var(--dur-2) var(--ease)}
/* collapsed = no persistent rail: the header toggle is the single way to reveal history */
@media (min-width:901px){
  /* check-full (WORK-FRAME): the conversation's sidebar folds away with it — the strip is the chancellor's only face */
  body.work-check-full.stage-on #side{display:none}
  body.noside #side{width:0; overflow:hidden; border-inline-end:0}
  body.noside #side-head{padding:14px 10px 6px; padding-top:calc(14px + env(safe-area-inset-top))}
  body.noside .brand{justify-content:center; padding:2px 0 14px}
  body.noside .brand > span, body.noside .brand .sp{display:none}
  body.noside .brand #side-open{opacity:1; pointer-events:auto}
  body.noside #newconv, body.noside #tempconv, body.noside #csearch{width:var(--tap); height:var(--tap); min-height:0; padding:0;
    justify-content:center; margin:2px auto; border-radius:var(--r-md); gap:0}
  body.noside #newconv{background:none; border:0; box-shadow:none; color:var(--dim)}
  body.noside #newconv:hover, body.noside #tempconv:hover, body.noside #csearch:hover{background:var(--lift); color:var(--fg)}
  body.noside #newconv span, body.noside #tempconv span, body.noside #csearch span:not([data-icon]), body.noside #csearch kbd{display:none}
  body.noside #convlist{display:none}
  body.noside #owner{padding:8px 6px calc(10px + env(safe-area-inset-bottom))}
  body.noside #owner-btn{justify-content:center; padding:6px 0}
  body.noside #owner-btn .obody, body.noside #owner-btn > svg{display:none}
  body.noside #side-tg{display:grid}
}
@media (max-width:900px){ body.noside #side{margin-inline-start:0} }
/* the rail's permanent open-sidebar glyph; the expanded wordmark keeps it hidden */
#side-open{position:absolute; inset-inline-start:50%; top:50%; transform:translate(-50%,-50%); opacity:0;
  pointer-events:none; transition:opacity var(--dur-1)}
[dir="rtl"] #side-open{transform:translate(50%,-50%)}
.brand{position:relative}
/* the search row under 临时对话 (ChatGPT's "Search chats") */
#csearch{display:flex; align-items:center; gap:8px; width:100%; padding-block:0; min-height:var(--btn-h-sm);
  margin-top:2px; border:0; border-radius:var(--r-pill); background:none; cursor:pointer; font-size:var(--fs-md);
  color:var(--dim); transition:background var(--dur-1), color var(--dur-1); text-align:start; font:inherit; font-size:var(--fs-md)}
#csearch:hover{color:var(--fg); background:var(--lift)}
#csearch kbd{margin-inline-start:auto; font:var(--fs-2xs) var(--mono); color:var(--dim); opacity:.7}
#side-head{padding:14px 12px 8px; padding-top:calc(14px + env(safe-area-inset-top)); flex:none}
.brand{display:flex; align-items:center; gap:8px; font-weight:400; font-size:var(--fs-xl);
  font-family:var(--font-wordmark); font-synthesis:none; font-kerning:normal;
  letter-spacing:.01em; padding:2px 14px 12px; user-select:none}
.brand .sp{flex:1}
#newconv{display:flex; align-items:center; gap:8px; width:100%; padding-block:0;
  min-height:36px; border:1px solid var(--line-soft); border-radius:var(--r-pill);
  background:var(--paper); box-shadow:var(--shadow-1);
  cursor:pointer; font-size:var(--fs-md); font-weight:500;
  transition:background var(--dur-1), border-color var(--dur-1)}
#newconv:hover{border-color:var(--line-2)}
#newconv:active{transform:translateY(1px); box-shadow:none}
#tempconv{display:flex; align-items:center; gap:8px; width:100%; padding-block:0;
  min-height:var(--btn-h-sm); margin-top:6px; border:0; border-radius:var(--r-pill); background:none; cursor:pointer;
  font-size:var(--fs-md); color:var(--dim);
  transition:background var(--dur-1), color var(--dur-1)}
#tempconv:hover{color:var(--fg); background:var(--lift)}
#convlist{flex:1; overflow-y:auto; padding:4px 12px 20px; overscroll-behavior:contain}
/* the owner card: who this Hoop belongs to, at the foot of the sidebar */
#owner{flex:none; padding:8px 8px calc(10px + env(safe-area-inset-bottom)); border-top:1px solid var(--line)}
#owner-btn{display:flex; align-items:center; gap:10px; width:100%; padding:6px 8px; border:0;
  background:none; border-radius:var(--r-md); cursor:pointer; text-align:start; font:inherit;
  color:var(--fg); min-height:var(--tap)}
#owner-btn:hover, #owner-btn.on{background:transparent; color:var(--fg)}
.oava{width:28px; height:28px; border-radius:50%; flex:none; display:grid; place-items:center;
  border:1.5px solid var(--brand); color:var(--brand-ink); font-size:var(--fs-sm); font-weight:500;
  text-transform:uppercase; overflow:hidden}
.oava img{width:100%; height:100%; object-fit:cover}
.obody{flex:1; min-width:0; display:flex; flex-direction:column; line-height:1.3}
.oname{font-size:var(--fs-md); font-weight:500; display:flex; flex-wrap:wrap; align-items:baseline; gap:0 7px; min-width:0}
.oname > span:first-child{max-width:100%; white-space:nowrap; overflow:hidden; text-overflow:ellipsis}
.oname .ohoop{font:var(--fs-2xs) var(--mono); color:var(--dim); font-weight:400}
.ostat{font-size:var(--fs-2xs); color:var(--dim); white-space:nowrap; overflow:hidden;
  text-overflow:ellipsis; font-variant-numeric:tabular-nums}
#owner-btn > svg{width:14px; height:14px; color:var(--dim); flex:none}
.menu .mrow{display:flex; gap:4px; padding:4px 10px 6px}
.menu .mrow .opt{min-height:26px; padding:0 9px; font-size:var(--fs-xs); box-shadow:none}
/* ── the sidebar's ONE column law (0.2.23 T2) ──────────────────────────────────
   新对话 / 临时对话 / 搜索 and every conversation row are four rows of one list, so
   they get one icon column and one text column: the inline padding is written once
   here for all four, and each row's glyph sits in the SAME 15px slot — the
   conversation's dot is centred inside that slot (.cslot) instead of holding a
   narrower column of its own, which is what used to shift the titles left. */
#newconv, #tempconv, #csearch, .citem, .cgroup{padding-inline:14px}
/* 新对话 is the one row wearing a rim, and that 1px border would push its glyph off
   the shared axis — so it gives the pixel back out of its own padding */
#newconv{padding-inline:calc(14px - 1px)}
#newconv svg, #tempconv svg, #csearch [data-icon] svg, .citem .cslot{width:15px; height:15px; flex:none}
#csearch [data-icon], .citem .cslot{flex:none; display:flex; align-items:center; justify-content:center}
.cgroup{color:var(--dim); font-size:var(--fs-2xs); letter-spacing:.06em; padding-block:14px 4px;
  user-select:none}
.citem{display:flex; align-items:center; gap:8px; padding-block:8px;
  border-radius:var(--r-md); cursor:pointer; font-size:var(--fs-md); position:relative;
  color:var(--fg)}
/* the dot: a quiet hint at rest, the brand breathing while that conversation works,
   solid when a reply arrived while you were elsewhere (it goes out when you look) */
.cdot{width:6px; height:6px; border-radius:50%; background:var(--line-2); flex:none;
  transition:background var(--dur-2)}
.cdot.busy{background:var(--brand); animation:breathe var(--motion-pulse) var(--ease-loop) infinite}
.cdot.unread{background:var(--brand)}
@media (prefers-reduced-motion:reduce){ .cdot.busy{animation:none} }
.citem:hover{background:var(--lift)}
.citem.on{background:var(--brand-soft); font-weight:500}
.citem .ct{flex:1; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; min-width:0}
.citem .ct input{width:100%; border-radius:var(--r-xs); padding:1px 5px; font:inherit}
.citem .cm{flex:none; min-width:28px; min-height:28px; border:0; background:none; color:var(--dim); cursor:pointer;
  padding:2px 5px; border-radius:var(--r-xs); opacity:0; line-height:1; font-size:var(--fs-ui)}
.citem:hover .cm,.citem.menuon .cm{opacity:1}
.citem .cm:hover{color:var(--fg); background:var(--lift)}
@media (hover:none){ .citem .cm{opacity:.6} }
.cmenu{position:absolute; inset-inline-end:4px; top:calc(100% - 4px); z-index:30; min-width:110px;
  background:var(--glass-bg); -webkit-backdrop-filter:var(--glass-blur); backdrop-filter:var(--glass-blur);
  border:0; border-radius:var(--r-md); overflow:hidden; box-shadow:var(--glass-rim), var(--shadow-pop); padding:5px}
.cmenu button{display:block; width:100%; text-align:start; border:0; background:none;
  padding:7px 11px; font-size:var(--fs-sm); cursor:pointer; border-radius:var(--r-sm)}
.cmenu button:hover{background:var(--lift)}
.cmenu button.danger{color:var(--bad)}
#scrim{display:none}
.p-chat #main{flex:1; min-width:0; display:flex; flex-direction:column; height:var(--vvh, 100dvh);
  background:var(--bg); position:relative}
/* Subscription dialogs are independent of Chat's floating conversation toolbar. */
.chat-subscriptions-scrim{z-index:10002;padding:12px;backdrop-filter:blur(4px);-webkit-backdrop-filter:blur(4px)}
.modal.chat-subscriptions{inline-size:min(36rem,calc(100vw - 24px));block-size:auto;max-block-size:calc(100dvh - 24px);background:var(--surface);border-radius:var(--r-xl);font-size:var(--fs-ui);line-height:1.5}
.chat-subscriptions .ui-dialog-head{grid-template-columns:minmax(0,1fr) auto;padding:var(--sp-4) var(--sp-5);gap:var(--sp-3);background:var(--surface);z-index:2}
.chat-subscriptions .ui-dialog-head h2{margin:0;font-size:var(--fs-lg);font-weight:600}
.chat-subscriptions .sub-close{inline-size:44px;block-size:44px}
.chat-subscriptions .sub-body{padding:var(--sp-5);display:grid;gap:var(--sp-5);min-inline-size:0}
.chat-subscriptions p{margin:0;overflow-wrap:anywhere}
.chat-subscriptions .ui-help{color:var(--dim);font-size:var(--fs-sm);line-height:1.6}
.chat-subscriptions .sub-account{min-inline-size:0;padding:var(--sp-4);border:1px solid var(--line);border-radius:var(--r-lg);background:var(--surface)}
.chat-subscriptions .sub-account-head{display:flex;align-items:center;gap:var(--sp-3);flex-wrap:wrap}
.chat-subscriptions .sub-account-head h3{flex:1;min-inline-size:6rem;margin:0;font-size:var(--fs-ui);font-weight:600}
.chat-subscriptions .sub-mark{display:grid;place-items:center;inline-size:32px;block-size:32px;border-radius:var(--r-sm);background:var(--lift);color:var(--fg);font-weight:600}
.chat-subscriptions .sub-account-detail{margin-block:var(--sp-3);word-break:break-word}
.chat-subscriptions .ui-actions{margin:0;justify-content:flex-start;gap:var(--sp-2)}
.chat-subscriptions .btn{min-block-size:44px;white-space:normal;line-height:1.4;text-align:center}
.chat-subscriptions .sub-manage{font-size:var(--fs-sm);color:var(--dim)}
.chat-subscriptions .sub-manage summary{cursor:pointer;padding:12px 4px;min-block-size:44px;box-sizing:border-box}
.chat-subscriptions .sub-manage-actions{display:flex;gap:var(--sp-2);flex-wrap:wrap}
.chat-subscriptions .sub-flow{display:grid;gap:var(--sp-3);border-block-start:1px solid var(--line);padding-block-start:var(--sp-4);margin-block-start:var(--sp-4)}
.chat-subscriptions .sub-flow[hidden],.chat-subscriptions .sub-notice[hidden]{display:none}
.chat-subscriptions .sub-step{margin:0;font-size:var(--fs-sm);font-weight:600}
.chat-subscriptions .sub-code-form{display:flex;align-items:stretch;gap:var(--sp-2)}
.chat-subscriptions .sub-code-form input{min-inline-size:0;flex:1;inline-size:0;margin:0}
.chat-subscriptions .sub-device-code{display:flex;align-items:center;gap:var(--sp-3);flex-wrap:wrap}
.chat-subscriptions .sub-device-code code{font-size:var(--fs-lg);letter-spacing:.08em;user-select:all}
.chat-subscriptions .sub-success{color:var(--status-success);font-size:var(--fs-sm)}
.chat-subscriptions .sub-footer{display:flex;align-items:center;justify-content:space-between;gap:var(--sp-3)}
.chat-subscriptions .sub-footer>.btn{flex:none}
.chat-subscriptions .sub-notice{font-size:var(--fs-sm);overflow-wrap:anywhere}
.chat-subscriptions-scrim ~ .modal-scrim{z-index:10003}
.chat-model-menu{z-index:10002;max-block-size:calc(100dvh - 32px);overflow:auto}
@media(max-width:599px){.chat-subscriptions .sub-body{padding:var(--sp-4)}.chat-subscriptions .ui-dialog-head{padding:var(--sp-3) var(--sp-4)}.chat-subscriptions .sub-account{padding:var(--sp-3)}.chat-subscriptions .sub-account-head{gap:var(--sp-2)}.chat-subscriptions .sub-footer{align-items:flex-start}.chat-subscriptions .sub-code-form{flex-wrap:wrap}.chat-subscriptions .sub-code-form input{flex-basis:100%;inline-size:100%}}
.p-chat header{display:flex; align-items:center; gap:6px; padding:8px 12px;
  padding-top:calc(8px + env(safe-area-inset-top)); min-height:calc(50px + env(safe-area-inset-top));
  position:absolute; top:0; inset-inline:0; z-index:4;
  background:transparent; transition:background var(--dur-2)}
/* the bar itself stays fully transparent (the owner: nothing may veil the conversation);
   once the stream scrolls under it the buttons stay transparent too (no glass disc): a
   hairline ring marks each target — a state, never a fill (.on keeps its brand ring) */
/* (the shell layout, html.hoop-rail, keeps the stream under its own bar row, so there the buttons stay ghosts) */
html:not(.hoop-rail) .p-chat header.scrolled .hbtn:not(.on){background:transparent; box-shadow:var(--stroke-line)}
/* the title names the conversation while its top is in view; once the stream runs under the bar the
   title steps out (its place is kept, so no button moves) — in a narrow column the stream spans the
   bar, and a title left there would be written over the messages */
.p-chat header.scrolled #ctitle{visibility:hidden}
.p-chat header #ctitle{display:none}
.hbtn.on{color:var(--brand-ink); background:transparent; box-shadow:var(--stroke-on)}
/* GHOST icon button: 32px square, nothing until hover */
.hbtn{border:0; background:none; color:var(--dim); cursor:pointer; padding:0;
  border-radius:50%; line-height:0; flex:none; position:relative;
  width:32px; height:32px; display:inline-grid; place-items:center}
.hbtn:hover{color:var(--fg)}
.hbtn svg{width:18px;height:18px}
#ctitle{font-weight:500; font-size:var(--fs-h); padding:4px 9px; border-radius:var(--r-sm);
  cursor:pointer; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; min-width:0}
#ctitle:hover{background:var(--lift)}
#ctitle input{border-radius:var(--r-xs); padding:2px 6px; font:inherit; font-weight:500; width:14em}
#tempbadge{display:none; align-items:center; gap:6px; color:var(--dim);
  font-size:var(--fs-sm); border:1px dashed var(--line-2); border-radius:var(--r-btn);
  padding:3px 10px; white-space:nowrap}
body.tempmode #tempbadge{display:inline-flex}
body.tempmode #ctitle{display:none}
.p-chat header .sp{flex:1}
#nb{position:absolute; top:5px; inset-inline-end:5px; width:5px; height:5px; border-radius:50%;
  background:var(--accent); display:none}
#msgs{flex:1; overflow-y:auto; padding:calc(58px + env(safe-area-inset-top)) 18px calc(var(--composer-h, 96px) + 20px);
  overscroll-behavior:contain; scrollbar-gutter:stable}
html.hoop-top .p-chat #msgs{padding-top:calc(72px + env(safe-area-inset-top))}
/* T3 沉浸壳 + 桌面 dock：滚动容器伸到窗口最外侧（滚动条在窗口边），dock 的让位改由
   内容内边距承担——消息列、composer、顶栏各自退让 --dock-w，dock 只压在留白上，
   与滚动条带的交集为 0（C3 验收）。nav.js 给 body 的 padding-inline-end 在这里归零。 */
html.hoop-rail body.p-chat{padding-inline-end:0}
html.hoop-rail .p-chat #msgs{padding-inline-end:calc(18px + var(--dock-w))}
html.hoop-rail .p-chat #composer{padding-inline-end:calc(18px + var(--dock-w))}
html.hoop-rail .p-chat header{padding-inline-end:calc(12px + var(--dock-w))}
html.hoop-rail.hoop-folded body.p-chat{padding-inline-end:0}
html.hoop-rail.hoop-folded .p-chat #msgs, html.hoop-rail.hoop-folded .p-chat #composer{padding-inline-end:18px}
html.hoop-rail.hoop-folded .p-chat header{padding-inline-end:12px}
.m{max-width:46rem; margin:0 auto 16px; word-break:break-word; position:relative;
  animation:rise var(--motion-base) var(--ease)}
/* the owner's bubble stays INSIDE the centered reading column, aligned to its end —
   one shared visual midline with the PA (the ChatGPT harmony), never glued to the edge */
.m.own{background:var(--own); border-radius:var(--r-xl); border-end-end-radius:6px;
  padding:9px 15px; margin-inline-start:auto;
  margin-inline-end:max(0px, calc((100% - 46rem) / 2));
  max-width:34rem; width:fit-content; white-space:pre-wrap; margin-bottom:30px}
.m.own .ownimgs{display:flex; gap:6px; flex-wrap:wrap; margin:2px 0 6px}
.m.own .ownimgs img{max-width:150px; max-height:150px; min-width:40px; min-height:40px;
  object-fit:cover; background:var(--code); border-radius:var(--r-sm); display:block}
.m.own .ownimgs:last-child{margin-bottom:2px}
.m.pa{white-space:normal; font-family:var(--font-ui)}   /* prose follows the UI voice; headings retain the brand voice */
.m.pa strong, .m.pa b{font-weight:600}
.m.sys{color:var(--dim); text-align:center; font-size:var(--fs-xs); letter-spacing:.04em;
  margin-bottom:18px}
.m.day{color:var(--dim); text-align:center; font-size:var(--fs-xs); margin:26px auto 18px}
.mdbody > :first-child{margin-top:.2em}
.m p{margin:.45em 0}
.m h1{font-size:1.25em; font-weight:500; margin:1.2em 0 .35em}
.m h2{font-size:1.15em; font-weight:500; margin:1.2em 0 .3em}
.m h3,.m h4{font-size:1.05em; font-weight:500; margin:1.1em 0 .25em}
.m ul,.m ol{margin:.35em 0; padding-inline-start:1.5em}
.m li{margin:.18em 0}
.m li > ul,.m li > ol{margin:.1em 0}
.m li.task{list-style:none; margin-inline-start:-1.35em}
.m li.task input{margin-inline-end:.5em; accent-color:var(--accent); vertical-align:-.12em}
.m blockquote{margin:.6em 0; padding:.1em 0; padding-inline-start:1em;
  border-inline-start:1px solid var(--line-2); color:var(--dim)}
.m hr{border:0; border-top:1px solid var(--line); margin:1.2em 0}
.m code{background:var(--code); outline:1px solid var(--line-soft); outline-offset:-1px; border-radius:var(--r-xs); padding:.12em .38em; font-size:.88em;
  font-family:var(--mono)}
.m a{color:var(--link, var(--accent)); text-decoration:none}
.m a:hover{text-decoration:underline}
.m del{color:var(--dim)}
.m img{max-width:100%; border-radius:var(--r-sm)}
.tblw{overflow-x:auto; max-width:100%; margin:.7em 0; border:1px solid var(--line); border-radius:var(--r-md)}
.m table{border-collapse:collapse; width:max-content; min-width:100%; font-size:.93em;
  font-family:var(--font-ui); font-variant-numeric:tabular-nums}
.m th,.m td{padding:7px 13px; border-bottom:1px solid var(--line); text-align:start}
.m th{font-weight:500; background:var(--code); white-space:nowrap; font-family:var(--font-ui)}
.m tr:last-child td{border-bottom:0}
.cb{margin:.7em 0; border:1px solid var(--line); border-radius:var(--r-md); overflow:hidden;
  background:var(--code)}
.cb-h{display:flex; align-items:center; padding:5px 7px; padding-inline-start:13px;
  font-size:var(--fs-2xs); color:var(--dim); border-bottom:1px solid var(--line);
  font-family:var(--mono); letter-spacing:.03em}
.cb-h .sp{flex:1}
.cb-h button{border:0; background:none; color:var(--dim); cursor:pointer; font-size:var(--fs-2xs);
  padding:3px 8px; border-radius:var(--r-xs); font-family:inherit}
.cb-h button:hover{color:var(--fg); background:transparent}
.cb pre{margin:0; padding:11px 14px; overflow-x:auto; font:var(--fs-md)/1.6 var(--mono)}
.cb pre code{background:none; box-shadow:none; padding:0; font-size:1em; border-radius:0}
/* code speaks in the theme's syntax branch (tokens.css --hl-*); a ```diff block in its diff branch */
.hljs-keyword,.hljs-selector-tag,.hljs-literal,.hljs-doctag{color:var(--hl-key)}
.hljs-string,.hljs-regexp{color:var(--hl-str)}
.hljs-number,.hljs-symbol,.hljs-bullet,.hljs-meta{color:var(--hl-num)}
.hljs-comment,.hljs-quote{color:var(--hl-com); font-style:italic}
.hljs-title,.hljs-name,.hljs-section,.hljs-selector-id{color:var(--hl-fn)}
.hljs-built_in,.hljs-type,.hljs-title.class_,.hljs-attr,.hljs-attribute,.hljs-selector-class{color:var(--hl-type, var(--hl-fn))}
.hljs-punctuation,.hljs-operator{color:var(--hl-punc, inherit)}
.hljs-link{color:var(--link, var(--accent))}
.hljs-addition{color:var(--diff-add, var(--ok)); background:var(--diff-add-bg, transparent)}
.hljs-deletion{color:var(--diff-del, var(--bad)); background:var(--diff-del-bg, transparent)}
.hljs-addition,.hljs-deletion{display:inline-block; min-width:100%}   /* a diff line is washed edge to edge, as in a terminal */
.hljs-emphasis{font-style:italic}.hljs-strong{font-weight:500}
/* the actions under a message: one line of icon + word, transparent in every state, shown on hover
   (touch: quietly visible). The owner's bubble is narrow, so its row is sized by its own content,
   never by the bubble — a short message must not stack the words one character per line. */
.acts{display:flex; align-items:center; gap:2px; margin-top:2px; opacity:0; transition:opacity var(--dur-1);
  min-height:26px; white-space:nowrap; flex-wrap:nowrap}
.m:hover .acts,.acts:focus-within{opacity:1}
@media (hover:none){ .acts{opacity:.55} }
@media (max-width:720px){ .acts button{min-height:28px} }
.m.own .acts{justify-content:flex-end; position:absolute; inset-inline-end:0; top:100%; width:max-content;
  margin:2px 0 0; white-space:nowrap}
.acts button{flex:none; border:0; background:transparent; color:var(--dim); cursor:pointer; font:inherit; font-size:var(--fs-xs);
  line-height:1; padding:5px 6px; border-radius:var(--r-xs); display:inline-flex; align-items:center; gap:4px; white-space:nowrap}
.acts button:hover{color:var(--fg); background:transparent}
.acts button:active{color:var(--brand-ink)}
.acts button:focus-visible{outline:1px solid var(--line-2); outline-offset:1px}
.acts svg{width:13px; height:13px; flex:none}
.working{display:flex; align-items:center; gap:9px; color:var(--dim); font-size:var(--fs-ui)}
.working .orb{width:9px; height:9px; border-radius:50%; background:var(--spin, var(--brand));
  animation:orbit var(--motion-pulse) var(--ease-loop) infinite}
@keyframes orbit{0%,100%{transform:scale(.7);opacity:.4}50%{transform:scale(1);opacity:1}}
.m.typing > .mdbody > :last-child::after{content:"▍"; color:var(--spin, var(--brand)); animation:breathe var(--motion-pulse) var(--ease-loop) infinite}
.meta{margin:0 0 6px; font-size:var(--fs-xs); color:var(--dim)}
/* An AI task in Hoop for Terminal's shape (owner 2026-10-12). Every mark (• ● ✗ ▲ ✳) sits in one
   14px column on the reply's left edge, rows are 20px tall, spacing moves in 4px steps, colours are
   tokens only. Steps above the answer; the live / done line under it; the action buttons last. */
.m.pa > .stwrap{margin:0 0 8px; font-size:var(--fs-sm); color:var(--dim)}
/* the steps: ONE line in the done line's voice — • <newest step> · N 个操作 ▸ — opening the list below */
.m.pa .sline{display:flex; align-items:center; gap:8px; width:100%; min-width:0; min-height:28px; line-height:28px; padding:0; margin:0;
  border:0; background:transparent; font:inherit; color:inherit; text-align:start; white-space:nowrap; cursor:pointer;
  font-variant-numeric:tabular-nums}
.m.pa .sline:hover{color:var(--fg)}
.m.pa .sline:focus-visible{outline:1px solid var(--line-2); outline-offset:2px; border-radius:var(--r-xs)}
.m.pa .sline .sl-t{min-width:0; overflow:hidden; text-overflow:ellipsis}
.m.pa .sline .sl-n, .m.pa .sline .chev{flex:none}
.m.pa .sline .sl-n{margin-inline-start:-4px}
.m.pa .sline .chev{display:inline-block; transition:transform var(--dur-1)}
[dir=rtl] .m.pa .sline .chev{transform:scaleX(-1)}
.m.pa .sline[aria-expanded=true] .chev{transform:rotate(90deg)}
.m.pa .slist{margin:4px 0 0}
.m.pa .st{display:flex; align-items:center; gap:8px; min-height:20px; line-height:20px; white-space:nowrap; min-width:0}
.m.pa .st .dt{min-width:0; overflow:hidden; text-overflow:ellipsis}
.m.pa .st .mk, .m.pa .sline .mk, .meta-line .mk, .taskrow .mk{flex:none; width:14px; display:inline-flex; justify-content:center; align-self:center; line-height:20px}
.m.pa .sline .mk, .m.pa .st .mk{color:var(--ok)}
/* gradual reveal of a live turn (owner 2026-10-12): a new step, paragraph, done line or status row eases
   in over ~180ms; saved history (.still) appears as it is. Reduced motion zeroes the token. */
@keyframes rv-soft-in{from{opacity:0; transform:translateY(3px)}}
@keyframes fade-soft{from{opacity:0}}
.m.pa .rv{animation:rv-soft-in calc(var(--motion-fast) * 1.5) var(--ease) backwards}
.m.pa .sl-t.rv, .meta-line.rv{animation-name:fade-soft}
.m.still{animation:none}
.m.pa > .meta{margin:4px 0 0; font-size:var(--fs-sm); color:var(--dim)}
.meta-line{display:flex; align-items:center; gap:8px; min-height:20px; line-height:20px; min-width:0;
  font-variant-numeric:tabular-nums; white-space:nowrap}
.meta-line .mt{min-width:0; overflow:hidden; text-overflow:ellipsis}
.meta-line .tk{opacity:.7}
.meta-line .orb{display:none; width:7px; height:7px; border-radius:50%; background:var(--spin, var(--brand));
  animation:orbit var(--motion-breathe) var(--ease-loop) infinite}
.meta-line .star{color:var(--brand-ink); font-size:var(--fs-xs)}
.meta.live .meta-line .orb{display:block}
.meta.live .meta-line .star{display:none}
.meta.live .meta-line .mw{color:var(--fg); opacity:.8}
.m.pa > .acts{margin-top:4px}
/* the turn ended without finishing: ✗ 失败：<reason> (red) or ▲ 已停止 / 已中断 (warm yellow) */
.m.sys.taskrow{text-align:start; letter-spacing:0; font-size:var(--fs-sm); color:var(--fg); margin-top:-8px}
.taskrow .taskrow-head{display:flex; align-items:baseline; gap:8px; line-height:20px; min-width:0}
.taskrow .mk{color:var(--warn)}
.taskrow[data-state=failed] .mk{color:var(--bad)}
.taskrow .taskrow-why{min-width:0; overflow-wrap:anywhere}
.taskrow .taskrow-next{padding-inline-start:22px; line-height:20px; color:var(--dim); overflow-wrap:anywhere}
.taskrow .taskrow-acts{display:flex; flex-wrap:wrap; gap:8px; margin-top:4px; padding-inline-start:22px}
.taskrow .taskrow-acts:not(:has(> button:not([hidden]))){display:none}
#older{display:block; margin:4px auto 14px; border:0; background:none; color:var(--dim);
  font-size:var(--fs-sm); cursor:pointer; padding:5px 12px; border-radius:var(--r-pill)}
#older:hover{color:var(--fg); background:transparent}
#hello{max-width:46rem; margin:16vh auto 0; text-align:center; padding:0 8px}
#hello .hi{font-size:var(--fs-2xl); font-weight:400; font-family:var(--font-brand);
  letter-spacing:-.01em}
#hello .sub{color:var(--dim); margin-top:8px; font-size:var(--fs-h)}
#chips{display:flex; flex-wrap:wrap; gap:9px; justify-content:center; margin-top:26px}
.chip{border:1px solid var(--line-soft); border-radius:var(--r-btn); padding:0 13px;
  font-size:var(--fs-md); color:var(--dim); cursor:pointer; background:transparent;
  min-height:var(--btn-h); box-shadow:none; display:inline-flex; align-items:center;
  transition:color var(--dur-1), border-color var(--dur-1)}
.chip:hover{color:var(--fg); border-color:var(--line-2)}
.chip:active{transform:translateY(1px); box-shadow:none}
/* .float — the end-side column every floating control lives in (codex art. 5) */
.float{position:fixed; inset-inline-end:var(--float-end); z-index:50}
.float.fbtn{width:36px; height:36px; border-radius:50%; border:0;
  background:var(--glass-bg); -webkit-backdrop-filter:var(--glass-blur); backdrop-filter:var(--glass-blur);
  color:var(--dim); box-shadow:var(--glass-rim), var(--shadow-pop); cursor:pointer;
  display:grid; place-items:center; padding:0}
.float.fbtn:hover{color:var(--fg)}
.float.fbtn svg{width:16px; height:16px}
#tolatest{bottom:calc(var(--composer-h, 96px) + 18px + env(safe-area-inset-bottom)); display:none}
@media (max-width:720px){
  /* no bottom bar on a phone: the hoop button and scroll-to-latest stack in the end
     column above the composer (--float-base is written by gram-mind.js) */
  .p-chat #composer{padding:6px 12px calc(10px + env(safe-area-inset-bottom))}
  #tolatest{bottom:calc(var(--float-base, 16px) + 56px + env(safe-area-inset-bottom)); width:40px; height:40px}
  .float.fbtn{width:40px; height:40px}
}
/* the composer floats over the stream: no floor, the text flows beneath the glass card */
#composer{position:absolute; inset-inline:0; bottom:0; z-index:3; pointer-events:none;
  padding:8px 18px calc(14px + env(safe-area-inset-bottom))}
#composer > *{pointer-events:auto}
#upname{max-width:46rem; margin:0 auto 6px; font-size:var(--fs-sm); color:var(--dim); display:none}
/* image tray: thumbnails of images about to be sent, each deletable */
#imgtray{max-width:46rem; margin:0 auto 8px; display:none; gap:8px; flex-wrap:wrap}
#imgtray.on{display:flex}
/* the tasks this chat handed to the owner's computers, by the composer while they run: one row each —
   state dot · title over computer · state · minutes · Open · Stop; Stop all when there are two or more */
#subtasks{max-width:46rem; margin:0 auto 8px; padding:6px 10px; border:1px solid var(--line-soft); border-radius:var(--r-md); background:var(--paper); font-size:var(--fs-sm); color:var(--dim)}
#subtasks[hidden]{display:none}
.subtasks-head{display:flex; align-items:center; justify-content:space-between; gap:8px; padding:2px 0 6px; font-size:var(--fs-xs); letter-spacing:.02em}
.subtask{display:flex; align-items:center; gap:10px; padding:6px 0; border-top:1px solid var(--line-soft)}
.subtask-dot{flex:none; width:8px; height:8px; border-radius:50%; background:var(--ok)}
.subtask[data-state="waiting"] .subtask-dot{background:var(--warn)}
.subtask[data-state="stopping"] .subtask-dot{background:var(--bad)}
.subtask-text{flex:1; min-width:0; display:flex; flex-direction:column}
.subtask-text strong{color:var(--fg); font-weight:600; overflow:hidden; text-overflow:ellipsis; white-space:nowrap}
.subtask-text small{font-size:var(--fs-xs); overflow:hidden; text-overflow:ellipsis; white-space:nowrap}
.subtask-open,.subtask-stop{flex:none; min-height:32px; padding:0 12px; border:1px solid var(--line-soft); border-radius:var(--r-md); background:none; color:var(--fg); font:inherit; font-size:var(--fs-xs); cursor:pointer}
.subtask-stop{color:var(--bad)}
.subtask-open:hover,.subtask-stop:hover{background:var(--sheet)}
.subtask-stop:disabled{opacity:.6; cursor:default}
.remote-task-row button.subtask-stop{grid-column:3;color:var(--bad)}
.imgchip{position:relative; width:64px; height:64px; border-radius:var(--r-sm);
  overflow:hidden; animation:var(--rise); background:var(--code); box-shadow:var(--shadow-1)}
.imgchip img{width:100%; height:100%; object-fit:cover; display:block}
.imgchip .del{position:absolute; top:3px; inset-inline-end:3px; width:20px; height:20px;
  border:0; border-radius:50%; background:var(--scrim-strong); color:var(--on-scrim); cursor:pointer;
  font-size:var(--fs-xs); line-height:1; display:grid; place-items:center; padding:0}
.imgchip .del:hover{background:var(--scrim-stronger)}
.imgchip.pending::after{pointer-events:none; content:""; position:absolute; inset:0;
  background:linear-gradient(90deg,transparent 8%,var(--glint) 18%,transparent 33%);
  background-size:200% 100%; animation:shimmer var(--motion-shimmer) var(--ease-linear) infinite}
#cwrap{max-width:46rem; margin:0 auto; display:flex; flex-direction:column; gap:8px;
  border:0; border-radius:0; padding:0; background:transparent; box-shadow:none;
  transition:background var(--dur-2); position:relative}
#cwrap:focus-within{box-shadow:none}
#chat-drop-hint:not([hidden]){position:absolute; inset:12px; z-index:100; pointer-events:none;
  display:grid; place-items:center; border:1px dashed var(--brand-ink); border-radius:var(--r-md);
  background:var(--brand-soft); color:var(--brand-ink); font-size:var(--fs-lg)}
.imgchip.filechip{width:auto; max-width:240px; padding:12px 32px 12px 12px; display:flex; align-items:center}
.filechip span{overflow:hidden; text-overflow:ellipsis; white-space:nowrap}
#composer-context{display:flex; align-items:center; gap:18px; min-height:24px; padding:0 5px;
  color:var(--dim); font-size:var(--fs-sm); line-height:1.2}
#composer-context > button{display:inline-flex; align-items:center; gap:6px; min-width:0; white-space:nowrap;
  border:0; padding:3px 5px; border-radius:var(--r-xs); background:transparent; color:inherit; font:inherit; cursor:pointer}
#composer-context > button:hover{background:var(--lift); color:var(--fg)}
#composer-context [data-icon]{width:16px; height:16px; opacity:.85}
#composer-context .composer-context-owner [data-icon]{color:var(--brand-ink)}
.composer-context-agency{color:var(--brand-ink)}
/* the composer's bottom rail: tools at the start, model + send at the end */
#crail{display:flex; align-items:center; gap:2px; min-height:32px}
#crail .sp{flex:1}
#inp{flex:none; width:100%; box-sizing:border-box; border:1px solid var(--line-soft); outline:0;
  border-radius:var(--r-md); background:transparent; color:var(--fg); resize:none;
  font:inherit; font-size:var(--fs-lg); line-height:1.6; letter-spacing:.01em; max-height:40vh;
  min-height:48px; padding:10px 13px; overflow-x:hidden; overflow-y:hidden; overflow-wrap:anywhere;
  word-break:break-word; white-space:pre-wrap; box-shadow:none}
#inp:focus{border-color:var(--brand); box-shadow:none}
#inp::placeholder{color:var(--dim); opacity:.7}
#charn{position:absolute; inset-inline-end:14px; bottom:-19px; font-size:var(--fs-2xs); color:var(--dim);
  opacity:.8; display:none}
.cbtn{border:0; background:none; color:var(--dim); cursor:pointer;
  padding:0; border-radius:50%; line-height:0; flex:none; width:32px; height:32px;
  display:grid; place-items:center; transition:color var(--dur-1), background var(--dur-1)}
.cbtn:hover{color:var(--fg); background:transparent}
.cbtn svg{width:18px; height:18px}
#send{color:var(--dim); opacity:.65; border:1px solid var(--line-soft); box-shadow:none;
  background:transparent; margin-inline-start:4px; transition:opacity var(--dur-1), transform var(--dur-1), border-color var(--dur-1)}
#send.ready{opacity:1; color:var(--brand-ink); border-color:var(--brand)}
#send:active{transform:translateY(1px); box-shadow:none}
#send.stop{opacity:1; background:transparent; color:var(--fg); border-color:transparent; box-shadow:none}
#send:disabled, #send:not(.ready):not(.stop){filter:saturate(.6)}
#file{display:none}
#mic.rec{color:var(--bad); background:transparent; box-shadow:var(--stroke-bad); animation:breathe var(--motion-pulse) var(--ease-loop) infinite}
/* ── V0.2.7 H1: the composer while it listens (gram-mind.js voice section; chat.html #voice) ──
   wave = brand bars on a canvas (colour comes from `color`), timer in mono, a language tag
   that can be pinned, three actions: pause · cancel · done. Tokens only; no new colours. */
#voice{display:flex; align-items:center; gap:8px; flex:1 1 auto; min-width:0; min-height:36px; padding:0; animation:var(--rise)}
#voice[hidden]{display:none}
#vwave{flex:1 1 120px; min-width:56px; height:28px; color:var(--brand); display:block}
#voice .vtime{font:var(--fs-xs) var(--mono); color:var(--dim); min-width:2.8em; text-align:center; font-variant-numeric:tabular-nums}
#voice .vlang{border:1px solid var(--line); background:none; color:var(--dim); font:inherit; font-size:var(--fs-2xs);
  padding:0 8px; height:22px; border-radius:var(--r-pill); cursor:pointer; white-space:nowrap; transition:color var(--dur-1), background var(--dur-1)}
#voice .vlang:hover{color:var(--fg); background:transparent; border-color:var(--line-2)}
#voice .vlang.pinned{color:var(--brand-ink); background:transparent; border-color:var(--brand)}
#voice .vstat{font-size:var(--fs-xs); color:var(--dim); white-space:nowrap}
#voice .vbtn.on{color:var(--brand-ink); background:transparent}
#voice .vcancel{color:var(--dim)}
#voice .vcancel:hover{color:var(--fg)}
#voice .vpause{color:var(--dim)}
#voice .vstop{color:var(--brand-ink); background:transparent; box-shadow:var(--stroke-brand)}
#voice .vstop:hover{background:transparent; color:var(--brand-600)}
#mic.rec.paused{animation:none; opacity:.7}
#composer.voice-on #cwrap{border-color:color-mix(in oklab, var(--brand) 45%, var(--line-soft))}
.p-chat #composer.voice-on #compose-input #attach,
.p-chat #composer.voice-on #compose-input #inp,
.p-chat #composer.voice-on #compose-input #mic,
.p-chat #composer.voice-on #compose-input #csettings,
.p-chat #composer.voice-on #compose-input #send:not(.stop){display:none}
.p-chat #composer.voice-on #compose-input{align-items:center}
@media (max-width:720px){
  #voice .vstat{display:none}
  #voice .vbtn{width:36px; height:36px}
}
#attach svg{width:20px; height:20px}
#codebtn[hidden]{display:none}
.menu a .mo-sub{color:var(--dim); font-size:var(--fs-xs); margin-inline-start:auto; padding-inline-start:14px}
/* the model · thinking capsule on the rail (V0.1.8 ③): quiet sans, opens a .menu */
#mpick{border:0; background:none; color:var(--dim); cursor:pointer; font:inherit;
  font-size:var(--fs-xs); padding:0 10px; height:28px; border-radius:var(--r-pill);
  display:inline-flex; align-items:center; gap:5px; white-space:nowrap; max-width:14rem;
  overflow:hidden; text-overflow:ellipsis}
#mpick:hover{color:var(--fg); background:var(--lift)}
#mpick svg{width:12px; height:12px; flex:none; opacity:.8}
/* ── V0.2.7 D: the Code state of the conversation window (gram-code.js) ─────────
   Same window, second posture: #msgs steps aside, #codepane takes the column; the
   composer stays where it is. The third voice: everything the machine did is mono.
   Each event is one foldable .cev row (header button + body); the approval card is
   the only interactive thing inside. Busy = the Chat .working .orb, reused as is. */
#codepane{display:none; min-width:0; overflow:hidden}
body.codemode #msgs, body.codemode #tolatest{display:none}
body.codemode #compose-welcome{display:none}
body.codemode #codepane{display:flex; flex:1; min-height:0; max-height:calc(100vh - var(--composer-h, 96px) - 54px); flex-direction:column}
#codeusage{width:100%; max-width:46rem; margin:0 auto; padding-inline:18px; box-sizing:border-box; flex:none}
body.codemode.emptyconv #composer{position:absolute; margin:0}
#codebtn.on{color:var(--brand-ink); background:transparent; box-shadow:var(--stroke-on)}
#codebar{display:flex; align-items:center; gap:var(--sp-2); padding:calc(52px + env(safe-area-inset-top)) 18px 6px;
  max-width:46rem; width:100%; margin:0 auto; box-sizing:border-box}
#codepicks{flex:1; min-width:0; display:grid; grid-template-columns:minmax(0,1.4fr) minmax(0,1fr); gap:var(--sp-2)}
#codepicks .pick{min-height:var(--btn-h); padding:4px 10px; border:1px solid var(--line-soft); border-radius:var(--r-in);
  background:var(--paper); box-shadow:var(--shadow-1)}
#codepicks .pk-n{display:none}
#codeback{flex:none}
#codelog{flex:1; overflow-y:auto; padding:6px 18px calc(var(--composer-h, 96px) + 12px);
  font:var(--fs-md)/1.6 var(--mono)}
html.hoop-rail .p-chat #codelog, html.hoop-rail .p-chat #codebar{padding-inline-end:calc(18px + var(--dock-w))}
html.hoop-rail.hoop-folded .p-chat #codelog, html.hoop-rail.hoop-folded .p-chat #codebar{padding-inline-end:18px}
#codehello{max-width:46rem; margin:10vh auto 0; text-align:center; font-family:var(--font)}
#codehello .hi{font:400 var(--fs-h)/1.3 var(--font-brand)}
#codehello .sub{color:var(--dim); font-size:var(--fs-ui); margin-top:6px}
/* ── the work session list (0.2.23 T2): what this machine is running, standing under
   the greeting instead of an empty column. One row = state dot · title · one line of
   state · when it last moved · the way in; the whole row is the button. ── */
#codesessions{margin-top:var(--sp-6); text-align:start}
#codesessions:empty{display:none}
.remote-relation{display:flex;flex-direction:column;align-items:stretch;gap:8px;max-width:46rem;margin:8px auto;padding:10px 14px;border:1px solid var(--line-soft);border-radius:var(--r-md);background:var(--paper);font-size:var(--fs-sm);color:var(--dim)}.remote-relation>a{align-self:flex-start;color:var(--fg);font-weight:600;text-decoration:underline;text-underline-offset:3px}.remote-task-row{display:grid;grid-template-columns:minmax(0,1fr) auto auto;gap:3px 10px;padding-top:7px;border-top:1px solid var(--line-soft)}.remote-task-row strong,.remote-task-row span,.remote-task-row small{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.remote-task-row span,.remote-task-row small{grid-column:1;color:var(--dim);font-size:var(--fs-xs)}.remote-task-row button{grid-column:2;grid-row:1 / span 3;align-self:center;border:0;background:none;color:var(--fg);font:inherit;text-decoration:underline;text-underline-offset:3px;cursor:pointer}
.remote-desktop{width:min(46rem,100%);margin:0 auto 12px;padding:12px 18px;border-top:1px solid var(--line-soft);box-sizing:border-box;background:var(--sheet);font-family:var(--font);position:relative;z-index:1}
.remote-head{display:flex;align-items:center;justify-content:space-between;gap:12px}.remote-title{display:block;font-size:var(--fs-md)}.remote-sub{display:block;color:var(--dim);font-size:var(--fs-xs);margin-top:2px}.remote-state{font-size:var(--fs-xs);color:var(--dim);margin:8px 0}.remote-state.error{color:var(--bad)}
.remote-screen-wrap{position:relative;min-height:150px;display:grid;place-items:center;border:1px solid var(--line-soft);border-radius:var(--r-md);overflow:hidden;background:var(--paper);touch-action:none}.remote-screen{display:block;max-width:100%;max-height:48vh;width:auto;height:auto;object-fit:contain;user-select:none;cursor:crosshair}.remote-empty{padding:30px 12px;color:var(--dim);font-size:var(--fs-sm);text-align:center}.remote-controls{display:flex;align-items:center;gap:6px;flex-wrap:wrap;margin-top:8px}.remote-controls .remote-text{min-width:10rem;flex:1;height:30px;padding:0 9px;border:1px solid var(--line-soft);border-radius:var(--r-in);background:var(--paper);color:var(--fg);font:inherit}.remote-hint{color:var(--dim);font-size:var(--fs-2xs);margin:7px 0 0}.remote-desktop.is-busy{opacity:.75;pointer-events:none}
@media (max-width:600px){.remote-desktop{margin-top:-80px;padding-inline:12px}.remote-screen{max-height:38vh}.remote-controls .remote-text{min-width:8rem}}
.cses-h{color:var(--dim); font-size:var(--fs-2xs); letter-spacing:.06em; padding:0 var(--sp-3) var(--sp-2)}
.cses-empty{color:var(--dim); font-size:var(--fs-md); padding:var(--sp-3)}
.cses-row{display:flex; align-items:center; gap:var(--sp-3); width:100%; min-height:var(--tap);
  padding:var(--sp-2) var(--sp-3); border:0; border-radius:var(--r-md); background:none;
  cursor:pointer; text-align:start; font:inherit; color:var(--fg); transition:background var(--dur-1)}
.cses-row:hover{background:var(--lift)}
.cses-dot{flex:none; width:8px; height:8px; border-radius:50%; background:var(--line-2);
  transition:background var(--dur-2)}
.cses-row[data-state="running"] .cses-dot{background:var(--status-working);
  animation:breathe var(--motion-pulse) var(--ease-loop) infinite}
.cses-row[data-state="owner"] .cses-dot{background:var(--accent-gate)}
.cses-row[data-state="chancellor"] .cses-dot{background:var(--accent-agent)}
.cses-row[data-state="delivered"] .cses-dot{background:var(--status-success)}
@media (prefers-reduced-motion:reduce){ .cses-row[data-state="running"] .cses-dot{animation:none} }
.cses-main{flex:1; min-width:0; display:flex; align-items:baseline; gap:var(--sp-2)}
.cses-t{min-width:0; font-size:var(--fs-md); font-weight:500;
  white-space:nowrap; overflow:hidden; text-overflow:ellipsis}
.cses-s{flex:none; color:var(--dim); font-size:var(--fs-xs); white-space:nowrap}
.cses-when{flex:none; color:var(--dim); font-size:var(--fs-2xs); font-variant-numeric:tabular-nums; white-space:nowrap}
.cses-go{flex:none; display:inline-flex; color:var(--dim)}
.cses-go svg{width:15px; height:15px}
[dir="rtl"] .cses-go{transform:scaleX(-1)}
@media (max-width:520px){ .cses-when{display:none} }
#codelog .working{max-width:46rem; margin:6px auto 14px; font-family:var(--font)}
.cev{max-width:46rem; margin:0 auto 6px; border:1px solid var(--line-soft); border-radius:var(--r-md); background:var(--surface);
  box-shadow:var(--shadow-1); overflow:hidden}
.cev-h{display:flex; align-items:center; gap:8px; width:100%; min-height:var(--btn-h); padding:5px 10px; border:0;
  background:none; color:var(--fg); font:inherit; text-align:start; cursor:pointer; border-radius:0}
.cev-h:hover{background:var(--lift)}
.cev-i{flex:none; display:inline-flex; color:var(--brand-ink)}
.cev-i svg, .cev-c svg{width:15px; height:15px}
.cev-t{flex:1; min-width:0; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; font-size:var(--fs-sm)}
.cev-m{flex:none; display:inline-flex; gap:4px; align-items:center}
.cev-c{flex:none; display:inline-flex; color:var(--dim); transition:transform var(--dur-1)}
.cev.open .cev-c{transform:rotate(90deg)}
.cev-b{display:none; border-top:1px solid var(--line-soft); padding:8px 12px}
.cev.open .cev-b{display:block}
.cev-st{font-size:var(--fs-2xs); line-height:1; padding:3px 7px; border-radius:var(--r-pill); color:var(--dim); background:var(--surface-2); white-space:nowrap}
.cev-st.ok{color:var(--ok)} .cev-st.bad{color:var(--bad)} .cev-st.pend{color:var(--on-brand); background:var(--brand)} .cev-st.run{color:var(--brand-ink)}
.cev-st.risk.write, .cev-st.risk.network{color:var(--warn)} .cev-st.risk.destructive, .cev-st.risk.money, .cev-st.risk.identity{color:var(--bad)}
/* the two voices (owner / model) read as prose: open = body only, the fold control floats at the corner */
.cev-own, .cev-text{position:relative}
.cev-own.open .cev-h, .cev-text.open .cev-h{position:absolute; inset-inline-end:4px; top:3px; width:auto; min-height:26px; padding:2px 6px; border-radius:var(--r-pill)}
.cev-own.open .cev-t, .cev-text.open .cev-t, .cev-own.open .cev-m, .cev-text.open .cev-m{display:none}
.cev-own.open .cev-b, .cev-text.open .cev-b{border-top:0; padding-inline-end:64px}
.cev-own{background:var(--own); border-color:transparent}
.cev-own .cev-i{color:var(--dim)}
.cev-own .cev-pre{font-family:var(--font)}
.cev-text .cev-i{color:var(--accent)}
.cev-text .cev-pre{font-family:var(--font-brand); font-size:var(--fs-rd)}
.cev-text.typing .cev-b > :last-child::after{content:"▍"; color:var(--brand); animation:breathe var(--motion-pulse) var(--ease-loop) infinite}
.cev-turn, .cev-sys, .cev-end, .cev-err{border:0; box-shadow:none; background:none; margin-bottom:2px}
.cev-turn .cev-h, .cev-sys .cev-h, .cev-end .cev-h, .cev-err .cev-h{min-height:28px; padding:2px 10px; font-size:var(--fs-xs); color:var(--dim); cursor:default}
.cev-turn .cev-h:hover, .cev-sys .cev-h:hover, .cev-end .cev-h:hover{background:none}
.cev-turn{margin-top:14px}
.cev-end.ok .cev-i{color:var(--ok)} .cev-err .cev-i, .cev-err .cev-t{color:var(--bad)}
.cev-tool.st-pending{border-color:var(--brand)}
.cev-tool.st-denied .cev-t, .cev-tool.st-cancelled .cev-t{color:var(--dim); text-decoration:line-through}
.cev-pre{margin:0; white-space:pre-wrap; word-break:break-word; font:inherit; max-height:24rem; overflow:auto}
.cev-pre.path{color:var(--dim); font-size:var(--fs-xs); margin-bottom:4px}
.cev-pre.cmd::before{content:"$ "; color:var(--dim)}
.cev-pre.out{background:var(--code); border-radius:var(--r-sm); padding:6px 8px; font-size:var(--fs-xs)}
.cev-sec + .cev-sec{margin-top:8px}
.cev-sec-h{display:flex; align-items:center; gap:8px; margin-bottom:4px}
.cev-fine{color:var(--dim); font-size:var(--fs-xs)}
.cev-diff{display:flex; flex-direction:column; font-size:var(--fs-xs); border-radius:var(--r-sm); overflow:auto; max-height:24rem}
.cev-diff span{white-space:pre-wrap; word-break:break-word; padding:0 6px}
.cev-diff .del{color:var(--diff-del, var(--bad)); background:var(--diff-del-bg, color-mix(in oklab, var(--bad) 9%, transparent))}
.cev-diff .add{color:var(--diff-add, var(--ok)); background:var(--diff-add-bg, color-mix(in oklab, var(--ok) 10%, transparent))}
.cev-ask{display:flex; align-items:center; flex-wrap:wrap; gap:var(--sp-2); margin-top:10px; padding-top:10px; border-top:1px solid var(--line-soft); font-family:var(--font)}
.cev-ask-t{flex:1; min-width:8rem; color:var(--fg); font-size:var(--fs-ui)}
@media (max-width:900px){
  /* The agency badge and stop action are real controls, so let the header own
     their height on a phone instead of painting them over the first message. */
  .p-chat header{position:relative;flex-wrap:wrap;background:var(--bg);padding-inline:8px;}
  .p-chat #msgs{padding-top:12px;}
  #codebar{padding:calc(52px + env(safe-area-inset-top)) 12px 6px; flex-wrap:wrap}
  #codepicks{grid-template-columns:1fr; width:100%}
  #codeback{margin-inline-start:auto}
  #codelog{padding-inline:12px}
  .cev-m .cev-st.risk{display:none}
  .cev-ask .btn{flex:1 1 30%}
  .cev-ask-t{flex-basis:100%}
  .cev-pre, .cev-diff{max-height:14rem}
}
/* Replies use the conversation's scroll on every screen. Only code and tables
   scroll sideways; prose never becomes a second, short scrolling box. */
.cev-text .cev-reply{max-height:none; overflow:visible; white-space:normal; line-height:1.75; min-width:0}
.mdbody.reply-plain{white-space:pre-wrap}
.cev-reply > :first-child{margin-top:0}
.cev-reply > :last-child{margin-bottom:0}

/* ═══ Hoop Matrix chat surface · the connected welcome posture ════════════════ */
.p-chat #hello{max-width:52rem; margin-top:0; padding-inline:12px}
.p-chat #hello .hello-mark{display:flex; justify-content:center; align-items:center; gap:5px; height:18px; margin-bottom:19px}
.p-chat #hello .hello-mark span{display:block; width:7px; height:7px; border-radius:50%; background:var(--brand); opacity:.35}
.p-chat #hello .hello-mark span:first-child{transform:translateY(3px); opacity:.6}
.p-chat #hello .hello-mark span:nth-child(2){width:11px; height:11px; opacity:1; box-shadow:var(--shadow-brand-halo)}
.p-chat #hello .hello-mark span:last-child{transform:translateY(-3px); opacity:.6}
.p-chat #hello .hi{font-size:clamp(1.9rem,4vw,2.8rem); letter-spacing:-.025em; line-height:1.2}
.p-chat #hello .sub{max-width:35rem; margin:10px auto 0; font-size:var(--fs-md); line-height:1.55}
.p-chat #hello .hello-note{margin-top:7px; color:var(--brand-ink); font:var(--fs-xs)/1.4 var(--mono); letter-spacing:.04em}
.p-chat .hello-doors{display:grid; grid-template-columns:repeat(3,minmax(0,1fr)); gap:8px; margin:27px auto 20px; max-width:40rem; text-align:start}
/* a Matrix member sees only the doors granted to them: one or two, centered at the same width each */
.p-chat .hello-doors.doors-1{grid-template-columns:minmax(0,1fr); max-width:13.33rem}
.p-chat .hello-doors.doors-2{grid-template-columns:repeat(2,minmax(0,1fr)); max-width:26.66rem}
.p-chat .hello-door{display:flex; align-items:center; gap:9px; min-width:0; min-height:58px; padding:10px 11px; border:1px solid var(--line-soft);
  border-radius:var(--r-lg); color:var(--fg); background:color-mix(in oklab,var(--paper) 56%,transparent); text-decoration:none;
  box-shadow:var(--shadow-1); transition:transform var(--dur-1),border-color var(--dur-1),background var(--dur-1)}
.p-chat .hello-door:hover{transform:translateY(-2px); border-color:var(--line-2); background:var(--paper); box-shadow:var(--shadow-pop)}
.p-chat .door-icon{width:25px; height:25px; flex:none; display:grid; place-items:center; border-radius:var(--r-sm); color:var(--brand-ink);
  background:var(--brand-soft); font-size:var(--fs-lg); line-height:1}
.p-chat .hello-door:nth-child(2) .door-icon{color:var(--accent); background:color-mix(in oklab,var(--accent) 12%,transparent)}
.p-chat .hello-door:nth-child(3) .door-icon{color:var(--ok); background:color-mix(in oklab,var(--ok) 12%,transparent)}
.p-chat .hello-door > span:nth-child(2){display:flex; flex-direction:column; min-width:0; line-height:1.25}
.p-chat .hello-door b{font-size:var(--fs-sm); font-weight:500; white-space:nowrap; overflow:hidden; text-overflow:ellipsis}
.p-chat .hello-door small{margin-top:3px; color:var(--dim); font-size:var(--fs-2xs); white-space:nowrap; overflow:hidden; text-overflow:ellipsis}
.p-chat .door-arrow{margin-inline-start:auto; align-self:flex-start; color:var(--line-2); font-size:var(--fs-sm)}
.p-chat .door-arrow[data-icon]{width:14px; height:14px; flex:none; opacity:.55}
.p-chat .hello-door:hover .door-arrow{color:var(--brand-ink)}
.p-chat #chips-more{min-height:32px; padding-inline:14px; font-size:var(--fs-sm); box-shadow:none; background:transparent}
@media (max-width:650px){
  .p-chat .hello-doors, .p-chat .hello-doors.doors-2{grid-template-columns:1fr; max-width:22rem; margin-top:23px}
  .p-chat .hello-door{min-height:48px}
  .p-chat .hello-door small{display:none}
}
/* empty conversation: greeting + composer sit together at the page's center
   (the ChatGPT "ready when you are" posture); once a message exists the composer
   returns to its bottom dock. Toggled by body.emptyconv from gram-mind.js. */
/* First-frame stability: empty and populated conversations share one composer box.
   Only the greeting uses the spare space; async conversation truth never moves the
   owner's primary action between the centre and the bottom of the viewport. */
body.emptyconv #msgs{flex:1 1 auto; margin-block-start:0; overflow-y:auto; display:grid; align-content:center;
  padding-bottom:calc(var(--composer-h, 96px) + 12px)}
body.emptyconv #composer{position:absolute; margin-block-end:0}
body.emptyconv #hello{margin:0 auto 26px}
#panel{position:fixed; inset:0; background:var(--bg); display:none;
  flex-direction:column; z-index:40; animation:fade var(--dur-1) var(--ease)}
#panel.on{display:flex}
#phead{display:flex; align-items:center; gap:10px; padding:12px 18px;
  padding-top:calc(12px + env(safe-area-inset-top)); border-bottom:1px solid var(--line)}
#ptitle{font-weight:500}
#phead .sp{flex:1}
#phead a{color:var(--dim); text-decoration:none; font-size:var(--fs-md); padding:6px 10px;
  border-radius:var(--r-sm)}
#phead a:hover{color:var(--fg); background:var(--lift)}
#pbody{flex:1; overflow-y:auto; padding:16px 18px 40px}
#pbody .card{max-width:46rem; margin:0 auto 12px}
@media (max-width:900px){
  .p-chat #side{position:fixed; inset-inline-start:0; top:0; bottom:0; z-index:9996; width:280px;
    transform:translateX(-102%); transition:transform var(--dur-2) var(--ease); margin:0!important;
    background:var(--bg); border-radius:0; border-inline-end:0; box-shadow:none}
  [dir="rtl"] .p-chat #side{transform:translateX(102%)}
  body.sideopen #side{transform:none!important}
  .p-chat #main{transform-origin:left center; transition:transform var(--dur-2) var(--ease),border-radius var(--dur-2),box-shadow var(--dur-2); z-index:9997}
  [dir="rtl"] .p-chat #main{transform-origin:right center}
  /* The drawer should move the conversation aside without shrinking it. A scale here
     made text and the composer jump on touch screens and caused clipped history. */
  body.sideopen #main{transform:translateX(252px); border-radius:var(--r-xl); box-shadow:var(--shadow-pop); overflow:hidden}
  [dir="rtl"] body.sideopen #main{transform:translateX(-252px)}
  #scrim{position:fixed; inset-block:0; inset-inline-start:280px; inset-inline-end:0; background:var(--scrim); z-index:9998; opacity:0;
    pointer-events:none; transition:opacity var(--dur-2)}
  body.sideopen #scrim{display:block; opacity:1; pointer-events:auto}
  .m.own{max-width:88%}
}

/* ═══ WORK-FRAME v1 (0.2.13 design-v1 · OS-DESIGN §1/§3/§4 · contract: OWNER-DECISION-pa-chancellor) ═══
   The chancellor (the conversation: #msgs + #composer) + ONE check host (#stage) — every
   check entry comes from views.json (gram-stage.js). Three modes: split · check-full ·
   chancellor-only. The owner's PREFERRED mode is the mind's setting (workFrame.layout);
   the EFFECTIVE mode is derived from it and the frame's AVAILABLE WIDTH — #main's, read by
   a ResizeObserver, never the device's — and written as body.work-<mode> plus
   body[data-wf="compact|medium|expanded|large"] (the tiers = tokens.css --wf-*). Folding
   keeps the pane the owner is in. The split ratio (--wf-chancellor on #main; per body, in
   localStorage — interface state, never the owner's config) is clamped so the chancellor
   stays 288–440px and the check pane ≥480px. The chancellor is never a permanent narrow
   sidebar: in check-full it folds to a NAMED strip carrying the way back; on compact the
   check pane is an overlay on the one layer stack (Esc / the phone's Back close it).
   body.stagemode = chat is the home · body.stage-on = a view is up · body.check-drawer =
   an overlay check pane is open · body.stage-full mirrors check-full for the 0.2.12 rules.
   Motion (motion.css, one of the four places): a view reveals, a mode change FLIPs. */
#stage{display:none; flex:none; flex-direction:column; min-height:0; position:relative; z-index:var(--z-pane);
  background:var(--surface-pane); border-block-end:var(--wf-divider) solid var(--line);
  padding-top:calc(50px + var(--wf-safe-top))}
body.stage-on #stage{display:flex; flex:0 0 min(58%, calc(100% - 15rem))}   /* stacked: the no-script posture */
body.stage-on.stage-full #stage{flex:1 1 auto; padding-top:var(--wf-safe-top)}   /* no header to clear */
body.stage-on.stage-full #msgs,body.stage-on.stage-full #composer,body.stage-on.stage-full #hdr,body.stage-on.stage-full #tolatest{display:none}
#stage-bar{display:flex; align-items:center; gap:var(--sp-2); padding:var(--sp-1) var(--sp-3); min-height:40px; flex:none}
#stage-bar [data-icon]{width:18px; height:18px; color:var(--dim)}
#stage-name{font-size:var(--fs-ui); font-weight:500; min-width:0; outline:none; border-radius:var(--r-xs); padding:0 var(--sp-1)}
#stage-name:focus-visible{box-shadow:var(--focus)}
#stage-bar .sp{flex:1}
#stage-back[hidden]{display:none}
#stage-peek{display:none}
#stage-body{flex:1; min-height:0; position:relative}
#stage-frame{width:100%; height:100%; border:0; display:block; background:var(--bg)}
#stage-frame:focus-visible{outline:var(--focus-outline); outline-offset:calc(-1 * var(--focus-offset))}
#check-native{height:100%; overflow:auto; padding:var(--sp-2) var(--sp-3) var(--sp-5); background:var(--bg)}
#check-native.tk-native{display:block}
#stage-note{position:absolute; inset-inline:var(--sp-3); bottom:var(--sp-3); padding:10px 14px; border-radius:var(--r-in);
  font-size:var(--fs-sm); line-height:1.5; max-width:var(--reading-col); margin:0 auto; animation:var(--rise)}
/* the chancellor strip (check-full): name · unread · the way back; a real button, keyboard-reachable */
#chancellor-strip{display:none; position:fixed; z-index:var(--z-strip); inset-block:var(--sp-3); inset-inline-start:var(--sp-3); width:42px;
  border:var(--wf-divider) solid var(--line); border-radius:var(--r-xl); background:var(--surface-raised); color:var(--dim);
  box-shadow:var(--glass-rim),var(--shadow-card); align-items:center; justify-content:center; flex-direction:column; gap:var(--sp-2);
  writing-mode:vertical-rl; font:inherit; font-size:var(--fs-xs); cursor:pointer; padding:var(--sp-3) 0; animation:var(--rise)}
#chancellor-strip [data-icon]{width:18px; height:18px}
#chancellor-strip .strip-n{font-size:var(--fs-2xs); color:var(--on-brand); background:var(--brand); border-radius:var(--r-pill); padding:1px 6px; font-variant-numeric:tabular-nums}
#chancellor-strip .strip-n[hidden]{display:none}
#chancellor-strip:hover{color:var(--fg)}
#chancellor-strip:focus-visible{outline:none; box-shadow:var(--glass-rim),var(--focus)}
body.work-check-full.stage-on #chancellor-strip{display:flex}
body.work-chancellor-only.stage-on:not(.check-drawer) #stage{display:none}
/* the divider: a 1px line you see inside a 12px column you can grab; a keyboard separator too */
#wf-divider{display:none; position:relative; width:var(--wf-divider-hit); cursor:col-resize; touch-action:none; outline:none; border:0; background:none; padding:0; margin:0}
#wf-divider::before{content:""; position:absolute; inset-block:0; inset-inline-start:calc(50% - var(--wf-divider) / 2); width:var(--wf-divider); background:var(--line)}
#wf-divider:hover::before, #wf-divider.dragging::before{background:var(--line-2)}
#wf-divider:focus-visible::before{background:var(--accent); width:2px}
/* with a stage up the greeting posture yields: the stream scrolls, the composer docks */
body.stage-on.emptyconv #msgs{flex:1 1 auto; margin:0; overflow-y:auto; padding-top:var(--sp-3); padding-bottom:calc(var(--composer-h, 96px) + 12px)}
body.stage-on.emptyconv #composer{position:absolute; margin:0}
body.stage-on #msgs{padding-top:var(--sp-3)}
/* split (gram-stage.js only sets it where both panes fit): chancellor · divider · check */
body.work-split.stage-on:not(.stage-full) #main{display:grid; grid-template-rows:minmax(0,1fr);
  grid-template-columns:var(--wf-chancellor, var(--wf-chancellor-ideal)) var(--wf-divider-hit) minmax(var(--wf-check-min),1fr)}
body.work-split.stage-on:not(.stage-full) #wf-divider{display:block; grid-column:2; grid-row:1; z-index:var(--z-pane-raised)}
body.work-split.stage-on:not(.stage-full) #stage{grid-column:3; grid-row:1; height:100%; padding-top:0; border-block-end:0}
body.work-split.stage-on:not(.stage-full) #msgs{grid-column:1; grid-row:1; padding-top:calc(58px + var(--wf-safe-top))}
body.work-split.stage-on:not(.stage-full) #hdr, body.work-split.stage-on:not(.stage-full) #composer{inset-inline-end:auto; width:var(--wf-chancellor, var(--wf-chancellor-ideal))}
body.work-split.stage-on:not(.stage-full) #tolatest{inset-inline-end:calc(100% - var(--wf-chancellor, var(--wf-chancellor-ideal)) + 18px)}
/* large: beyond the page max the frame breathes, it does not grow a third pane */
body[data-wf="large"] #main{max-width:var(--wf-page-max); margin-inline:auto}
/* chancellor-only with a view up (medium and wider): the check pane is a side sheet from the end */
body:not([data-wf="compact"]).work-chancellor-only.check-drawer #stage{display:flex; position:fixed; z-index:var(--z-drawer); inset-block:0; inset-inline-end:0;
  width:min(70vw, 64rem); padding-top:0; border-block-end:0; border-inline-start:var(--wf-divider) solid var(--line); box-shadow:var(--shadow-pop)}
body:not([data-wf="compact"]).check-drawer #stage-peek{display:inline-grid}
/* compact: one focus. The check pane is a full overlay; the strip lies across the foot */
body[data-wf="compact"].stage-on:not(.check-drawer) #stage{display:none}
body[data-wf="compact"].stage-on.check-drawer #stage{display:flex; position:fixed; inset:0; z-index:var(--z-drawer); flex:none; padding-top:var(--wf-safe-top); border-block-end:0}
body[data-wf="compact"].stage-on.check-drawer #stage-peek{display:inline-grid}
body[data-wf="compact"].stage-on.check-drawer #msgs, body[data-wf="compact"].stage-on.check-drawer #composer, body[data-wf="compact"].stage-on.check-drawer #hdr, body[data-wf="compact"].stage-on.check-drawer #tolatest{display:none}
body[data-wf="compact"] #chancellor-strip{inset-block:auto 10px; inset-inline:10px; width:auto; height:var(--tap); writing-mode:horizontal-tb; flex-direction:row; padding:0 var(--sp-3)}
body[data-wf="compact"].stage-on #stage-note{bottom:calc(var(--sp-3) + var(--wf-safe-bottom))}
@media (prefers-reduced-motion:reduce){#chancellor-strip,#stage-note{animation:none}}

/* ═══ settings (p-set) ══════════════════════════════════════════════════ */
.form-grid{display:flex; flex-direction:column}
.form-row{display:grid; grid-template-columns:10rem minmax(0,1fr); gap:18px; align-items:center;
  padding:11px 0; color:var(--fg); text-decoration:none}
.form-row + .form-row{border-top:1px solid var(--line)}
.form-label{font-size:var(--fs-ui); min-width:0}
.form-label small{display:block; color:var(--dim); font-size:var(--fs-xs); line-height:1.5;
  margin-top:3px; font-weight:400}
.form-control{display:flex; align-items:center; justify-content:flex-end; gap:9px; min-width:0}
.form-control input,.form-control textarea{width:100%; margin:0}
.form-control textarea{min-height:8.5rem; line-height:1.55}
.update-source-form{margin-top:var(--sp-3)}
.profile-instructions-row{align-items:start}
.profile-avatar{width:48px; height:48px; position:relative; display:grid; place-items:center;
  border:1px solid var(--line-soft); border-radius:50%; overflow:hidden; padding:0; cursor:pointer;
  color:var(--fg); background:var(--surface-2); box-shadow:var(--shadow-1); font-weight:500}
.profile-avatar img{width:100%; height:100%; object-fit:cover}
.profile-avatar .avatar-edit{position:absolute; inset:0; display:grid; place-items:center;
  color:transparent; background:transparent; transition:color var(--dur-1),background var(--dur-1)}
.profile-avatar:hover .avatar-edit,.profile-avatar:focus-visible .avatar-edit{
  color:var(--surface); background:color-mix(in oklab,var(--fg) 56%,transparent)}
.profile-avatar:focus-visible{outline:none; box-shadow:var(--focus),var(--shadow-1)}
.avatar-control{justify-content:flex-start}
.profile-actions{display:flex; justify-content:flex-end; min-height:20px; margin-top:2px}
.profile-actions .fine{font-size:var(--fs-xs); color:var(--dim)}
.kv{display:grid; grid-template-columns:6.5rem 1fr; gap:6px 14px; font-size:var(--fs-ui)}
.card h3.kvh{margin-top:20px}
.kv .k{color:var(--dim)}
.kv .v{word-break:break-all; font-variant-numeric:tabular-nums}
.kv .v.na{color:var(--dim)}
.org{padding:10px 0; border-bottom:1px solid var(--line)}
.org:last-of-type{border-bottom:0}
.org .head{display:flex; align-items:baseline; gap:10px; margin-bottom:7px; flex-wrap:wrap}
.org .head b{font-size:var(--fs-ui)}
.org .head .enf{font-size:var(--fs-2xs); color:var(--dim); border:1px solid var(--line-2);
  border-radius:var(--r-pill); padding:1px 9px}
.org .head .enf.hard{color:var(--ok); border-color:var(--ok)}
.opts{display:flex; gap:8px; flex-wrap:wrap}
.opt{border:1px solid var(--line-soft); border-radius:var(--r-btn); padding:0 12px;
  font-size:var(--fs-sm); cursor:pointer; color:var(--dim); user-select:none; min-height:var(--btn-h-sm);
  display:inline-flex; align-items:center; gap:4px; background:transparent; box-shadow:none;
  transition:border-color var(--dur-1), color var(--dur-1), background var(--dur-1)}
.opt:hover{border-color:var(--line-2); color:var(--fg)}
.opt:active{transform:translateY(1px); box-shadow:none}
.opt.cur{background:transparent; color:var(--brand-ink); border-color:color-mix(in oklab, var(--brand) 45%, transparent);
  font-weight:500}
.opt.stage{color:var(--brand-ink); background:transparent; border-color:var(--brand);
  box-shadow:none; font-weight:600}
.opt .hint{font-weight:400; opacity:.75; margin:0; font-size:inherit; color:inherit}
.opt.reserved{opacity:.45; cursor:default}
.opt.reserved:hover{border-color:var(--line-soft); color:var(--dim)}
.feed{max-height:24rem; overflow:auto; margin:0 -6px}
.evt{display:flex; gap:10px; padding:7px 6px; font-size:var(--fs-sm); border-bottom:1px solid var(--line);
  align-items:baseline}
.evt:last-child{border-bottom:0}
.evt .t{color:var(--dim); font-size:var(--fs-xs); flex:none; width:7.2rem;
  font-variant-numeric:tabular-nums}
.evt .k{flex:none; font-size:var(--fs-xs); border-radius:var(--r-xs); padding:0 7px;
  background:var(--code); color:var(--dim)}
.evt .k.security{color:var(--warn)}
.evt .k.money{color:var(--ok)}
.evt .x{flex:1; min-width:0; word-break:break-word}
.svc{display:grid; grid-template-columns:1fr 1fr; gap:5px 18px}
.svc .s{display:flex; align-items:center; gap:8px; font-size:var(--fs-md)}
.svc .d{width:8px; height:8px; border-radius:50%; background:var(--line-2); flex:none;
  transition:background var(--dur-3)}
.svc .d.ok{background:var(--ok)}
.svc .d.bad{background:var(--bad)}
.svc .who{color:var(--dim); font-size:var(--fs-xs); margin-inline-start:auto}
.app-versions{display:grid; gap:0}
.app-version-row{display:flex; align-items:center; justify-content:space-between; gap:var(--sp-3); padding:10px 0; border-bottom:1px solid var(--line-soft)}
.app-version-row:last-child{border-bottom:0}
.app-version-name{font-size:var(--fs-sm); color:var(--fg)}
.app-version-meta{font-family:var(--mono); font-size:var(--fs-xs); color:var(--dim); text-align:end}
.update-panel{display:grid; gap:var(--sp-3); margin-top:var(--sp-3)}
.update-state{font-size:var(--fs-md); color:var(--fg)}
.update-detail{white-space:pre-line; font-size:var(--fs-sm); color:var(--dim); line-height:1.65}
/* V0.2.17 W1: an update the owner can see — a tone dot, a phase bar, a reason. */
.update-headline{display:flex; align-items:center; gap:var(--sp-2); margin:0}
.update-dot{inline-size:8px; block-size:8px; border-radius:50%; flex:none; background:var(--dim)}
.update-dot[data-tone="ok"]{background:var(--ok)}
.update-dot[data-tone="info"]{background:var(--accent)}
.update-dot[data-tone="busy"]{background:var(--accent); animation:breathe var(--motion-pulse) var(--ease-loop) infinite}
.update-dot[data-tone="warn"]{background:var(--warn)}
.update-dot[data-tone="bad"]{background:var(--bad)}
.update-progress{display:grid; gap:6px}
/* 0.2.92: the update reactor — hoopgram.com/upgrade's ring, charging with the gate's real phases. */
.update-reactor{display:grid; grid-template-columns:auto 1fr; align-items:center; gap:var(--sp-3)}
.update-reactor .reactor{inline-size:112px; block-size:auto; display:block; color:var(--accent)}
.reactor .rim{fill:none; stroke:var(--line); stroke-width:1}
.reactor .ticks{fill:none; stroke:var(--line); stroke-width:7; stroke-dasharray:1.2 7.8; transform-origin:100px 100px}
.reactor[data-state="busy"] .ticks{animation:reactor-turn calc(var(--motion-breathe) * 5) var(--ease-linear) infinite}
.reactor .track{fill:none; stroke:var(--line-soft); stroke-width:8}
.reactor .charge{fill:none; stroke:currentColor; stroke-width:8; stroke-linecap:round; transform:rotate(-90deg); transform-origin:100px 100px; transition:stroke-dashoffset var(--motion-base) var(--ease-linear)}
.reactor .seg{fill:none; stroke:var(--line-soft); stroke-width:9}
.reactor .seg.on{stroke:currentColor; opacity:.55}
.reactor .core{fill:currentColor}
.reactor[data-state="busy"] .core,.reactor[data-state="busy"] .halo{animation:reactor-breathe var(--motion-breathe) var(--ease-loop) infinite}
.reactor .num{fill:var(--fg); letter-spacing:-.02em; font-variant-numeric:tabular-nums; font-family:var(--font-ui)}
.reactor[data-state="done"]{color:var(--ok)}
.reactor[data-state="failed"]{color:var(--bad)}
[dir="rtl"] .reactor .charge{transform:rotate(-90deg) scale(1,-1)}
@keyframes reactor-turn{to{transform:rotate(360deg)}}
@keyframes reactor-breathe{50%{opacity:.65}}
.update-alert{display:grid; gap:6px; padding:10px 12px; border-radius:var(--r-sm);
  border:1px solid color-mix(in oklab, var(--bad) 35%, transparent);
  background:color-mix(in oklab, var(--bad) 8%, transparent); font-size:var(--fs-sm); color:var(--fg)}
.update-alert[data-tone="warn"]{border-color:color-mix(in oklab, var(--warn) 35%, transparent);
  background:color-mix(in oklab, var(--warn) 8%, transparent)}
.update-alert-detail,.update-history-why{display:block; font-family:var(--mono); font-size:var(--fs-xs);
  color:var(--dim); white-space:pre-wrap; overflow-wrap:anywhere}
.update-history-why{padding:0 0 8px}
.update-badge{border:1px solid color-mix(in oklab, var(--accent) 45%, transparent);
  background:color-mix(in oklab, var(--accent) 10%, transparent); color:var(--accent);
  border-radius:var(--r-pill); padding:4px 12px; font-size:var(--fs-sm); cursor:pointer;
  margin-inline-start:auto; white-space:nowrap}
.update-badge:hover{background:color-mix(in oklab, var(--accent) 18%, transparent)}
.update-badge:focus-visible{outline:none; box-shadow:var(--focus)}
.update-sheet{display:grid; gap:var(--sp-3); padding:var(--sp-4); border-radius:var(--r-lg);
  border:1px solid var(--line-soft); background:color-mix(in oklab, var(--fg) 3%, transparent)}
.update-sheet:focus-visible{outline:none; box-shadow:var(--focus)}
.update-sheet-head{display:flex; align-items:center; justify-content:space-between; gap:var(--sp-3)}
.update-sheet-head h4{margin:0; font-size:var(--fs-ui)}
.update-notes-title{margin:0; font-size:var(--fs-sm); color:var(--dim); font-weight:500}
.update-notes{white-space:pre-line; font-size:var(--fs-sm); line-height:1.65; color:var(--fg)}
.update-history{display:grid; gap:8px}
.whats-new-notes{white-space:pre-line; line-height:1.6; color:var(--fg); overflow-wrap:anywhere}
.modal .m-body.m-later{margin-top:var(--sp-2); font-size:var(--fs-sm); color:var(--dim)}
.update-history-row{display:grid; grid-template-columns:minmax(8rem,1fr) auto; gap:var(--sp-3); padding:8px 0; border-bottom:1px solid var(--line-soft); font-size:var(--fs-sm)}
.update-history-row:last-child{border-bottom:0}
.update-history-row span:last-child{font-family:var(--mono); color:var(--dim); text-align:end}
.facts{display:flex; gap:20px; flex-wrap:wrap; margin-top:12px; padding-top:10px;
  border-top:1px solid var(--line); color:var(--dim); font-size:var(--fs-sm)}
.facts b{color:var(--fg); font-weight:500}
.tzline{display:flex; gap:10px; align-items:center; flex-wrap:wrap; margin-top:12px}
.tzline .k{color:var(--dim); font-size:var(--fs-ui)}
.tzline input{width:13rem}
.langline{display:flex; gap:8px; flex-wrap:wrap; margin-top:12px; align-items:center}
.langline .k{color:var(--dim); font-size:var(--fs-ui)}
@media (max-width:600px){
  .form-row{grid-template-columns:1fr; gap:7px; padding:13px 0}
  .profile-avatar-row{grid-template-columns:minmax(0,1fr) auto}
  .profile-avatar-row .avatar-control{justify-content:flex-end}
}
@media (max-width:480px){ .svc{grid-template-columns:1fr} .kv{grid-template-columns:5.5rem 1fr} }

/* ═══ budget grid (finance + settings summary) ══════════════════════════ */
.bud{display:grid; grid-template-columns:1fr 6rem 6rem; gap:6px 12px; font-size:var(--fs-ui);
  align-items:center; font-variant-numeric:tabular-nums}
.bud .h{color:var(--dim); font-size:var(--fs-xs)}
.bud input{border-radius:var(--r-btn); padding:0 9px; min-height:var(--btn-h-sm); font-size:var(--fs-md); width:100%;
  text-align:end}
.bud input:disabled{border-color:transparent; background:none; color:var(--fg);
  opacity:1; box-shadow:none; padding-inline-start:0}
.citem .ct input, #ctitle input{min-height:0; box-shadow:none; padding:1px 5px}
.bud .nm{font-weight:500}
.bud .over{color:var(--bad); font-weight:500}
.budline{display:flex; gap:14px; flex-wrap:wrap; margin-top:12px; padding-top:10px;
  border-top:1px solid var(--line); color:var(--dim); font-size:var(--fs-sm);
  align-items:baseline}
.budline b{color:var(--fg)}
.fin-budget .ui-card-head+.set-hint{margin:0 0 var(--sp-4)}
.fin-budget .budline{align-items:center; justify-content:space-between}
.fin-budget .ui-pill:empty{display:none}
.fin-card-empty .ui-empty-hint{max-width:52ch}
@media (max-width:390px){ .bud{grid-template-columns:1fr 4.6rem 4.6rem} }

/* ═══ mail / comms (p-mail) ═════════════════════════════════════════════ */
.unread{color:var(--accent); font-size:var(--fs-2xs); margin-inline-start:8px; vertical-align:2px}
.numline{display:flex; align-items:baseline; gap:10px; flex-wrap:wrap; margin-top:16px;
  font-size:var(--fs-ui)}
.numline b{font-size:var(--fs-lg); letter-spacing:.02em; font-variant-numeric:tabular-nums}
.numline .off{color:var(--dim)}
.chan{display:inline-flex; align-items:center; gap:5px; margin:2px 0;
  margin-inline-end:10px; color:var(--dim); font-size:var(--fs-sm)}
.chan a{color:var(--accent); text-decoration:none; cursor:pointer}

/* ── the mail workbench (V0.1.7 ④: T2 — folders · thread list · reading) ── */
.p-mail main{max-width:78rem}
.mailwb{display:grid; grid-template-columns:11rem 21rem 1fr; margin-top:14px;
  border:1px solid var(--line); border-radius:var(--r-lg); overflow:hidden;
  background:var(--surface); height:calc(100dvh - 16rem); min-height:28rem}
.mw-side{border-inline-end:1px solid var(--line); padding:12px 10px; overflow-y:auto;
  display:flex; flex-direction:column; gap:2px}
.mw-side > .btn{margin-bottom:10px; flex:none}
.mail-accounts-bar{display:flex;align-items:center;gap:10px;flex-wrap:wrap;margin:16px 0}
.mail-accounts-bar .mail-account-picker{max-width:100%;min-width:220px;width:auto;flex:0 1 420px;justify-content:space-between;overflow-wrap:anywhere}
.mail-account-panel{border:1px solid var(--line);border-radius:var(--r-md);padding:20px;margin-bottom:16px;max-width:620px}
.mail-account-panel label,.mail-account-field{display:block;margin-bottom:12px}
.mail-account-panel input,.mail-account-field button{width:100%;margin-top:6px}
.mail-address-input{display:flex;align-items:center;gap:6px;flex-wrap:wrap}
.mail-address-input input{flex:1;min-width:100px;width:40%}
.mail-account-panel [role=status]{color:var(--dim)}
.mw-owner{margin-top:auto; padding:8px 0 0; border-top:1px solid var(--line)}
.mw-owner #owner-btn{padding:4px 6px; min-height:40px}
.mw-box{display:flex; align-items:center; gap:8px; padding:7px 10px;
  border-radius:var(--r-sm); cursor:pointer; color:var(--fg); font-size:var(--fs-sm);
  border:0; background:none; font:inherit; text-align:start; width:100%}
.mw-box:hover{background:var(--lift)}
.mw-box.on{background:var(--brand-soft); color:var(--brand-ink); font-weight:500}
.mw-box.quiet{color:var(--dim)}
.mw-box .n{margin-inline-start:auto; color:var(--dim); font-size:var(--fs-2xs)}
.mw-box.on .n{color:var(--brand-ink)}
.mw-list{border-inline-end:1px solid var(--line); overflow-y:auto; min-width:0}
.mw-tools{padding:10px; border-bottom:1px solid var(--line); position:sticky; top:0;
  background:var(--surface); z-index:1}
.mw-tools input{width:100%}
.mw-row{padding:10px 12px; border-bottom:1px solid var(--line); cursor:pointer; min-width:0}
.mw-row:hover{background:var(--lift)}
.mw-row.sel{background:var(--brand-soft)}
.mw-row .l1{display:flex; gap:8px; align-items:baseline; min-width:0}
.mw-unread-dot{width:7px; height:7px; border-radius:50%; background:var(--accent); flex:none; align-self:center}
.mw-row .who{font-size:var(--fs-sm); color:var(--dim); overflow:hidden;
  text-overflow:ellipsis; white-space:nowrap; flex:1; min-width:0}
.mw-row .when,.mw-row .nthr{color:var(--dim); font-size:var(--fs-2xs); flex:none}
.mw-row .subj{font-size:var(--fs-sm); overflow:hidden; text-overflow:ellipsis;
  white-space:nowrap; flex:1; min-width:0}
.mw-row.unseen .who,.mw-row.unseen .subj{color:var(--fg); font-weight:500}
.mw-row .prev{color:var(--dim); font-size:var(--fs-xs); overflow:hidden;
  text-overflow:ellipsis; white-space:nowrap}
.mw-read{overflow-y:auto; min-width:0; padding:14px 20px}
.mw-rtools{display:flex; gap:2px; align-items:center; flex-wrap:wrap;
  padding-bottom:8px; border-bottom:1px solid var(--line); margin-bottom:10px}
.mw-rtools .mw-move{margin-inline-start:auto; max-width:9rem}
.mw-backbtn{display:none}
.mw-msg{border-bottom:1px solid var(--line); padding:12px 0}
.mw-msg:last-child{border-bottom:0}
.mw-msg .mhead{display:flex; gap:10px; align-items:center}
.mw-msg .mcol{min-width:0; display:flex; flex-direction:column}
.mw-ava{flex:none; width:34px; height:34px; border-radius:50%;
  border:1px solid var(--brand); color:var(--brand-ink); display:grid;
  place-items:center; font-weight:500; font-size:var(--fs-ui)}
.mw-msg .mfrom{font-weight:500; font-size:var(--fs-sm)}
.mw-msg .mmeta{color:var(--dim); font-size:var(--fs-xs); overflow:hidden;
  text-overflow:ellipsis; white-space:nowrap}
.mw-body{margin-top:10px; font-size:var(--fs-rd); line-height:1.75;
  overflow-wrap:break-word; font-family:var(--font-brand)}   /* reading = serif */
.mw-body img{max-width:100%}
.mw-body blockquote{border-inline-start:1px solid var(--line-2); margin:8px 0;
  padding-inline-start:12px; color:var(--dim)}
.mw-att{display:inline-flex; align-items:center; gap:7px; border:1px solid var(--line-soft);
  border-radius:var(--r-btn); padding:5px 10px; margin:6px 6px 0 0; background:var(--paper);
  font-size:var(--fs-xs); color:var(--fg); text-decoration:none}
.mw-att:hover{background:var(--lift)}
.mw-att .rm{cursor:pointer; color:var(--dim)}
.mw-quick{margin-top:14px}
.mw-quick textarea{width:100%; min-height:5rem; margin-bottom:8px}
/* the floating compose card */
.mw-compose{position:fixed; inset-inline-end:var(--float-end); bottom:16px;
  width:min(34rem, calc(100vw - var(--dock-w) - 32px)); background:var(--glass-bg);
  -webkit-backdrop-filter:var(--glass-blur); backdrop-filter:var(--glass-blur);
  border:0; border-radius:var(--r-2xl);
  box-shadow:var(--glass-rim), var(--shadow-pop); padding:16px; z-index:9000}
.mw-compose input,.mw-compose textarea{width:100%; margin-bottom:8px}
.mw-compose textarea{min-height:9rem}
.mw-compose .duo{display:flex; gap:8px}
.mw-compose .duo input{flex:1; min-width:0}
.mwc-head{display:flex; justify-content:space-between; align-items:center;
  margin-bottom:8px}
.mwc-x{border:0; background:none; color:var(--dim); cursor:pointer;
  font-size:var(--fs-ui); padding:2px 6px}
@media (max-width:900px){
  .mailwb{grid-template-columns:1fr; height:auto; min-height:60dvh}
  .mw-owner{display:none}
  .mw-boxes{display:flex; gap:4px; overflow-x:auto; flex:1; min-width:0; scrollbar-width:none}
  .mw-boxes .mw-box{flex:none}
  .mw-side > .btn{padding:0 12px; min-height:30px; font-size:var(--fs-sm)}
  .mw-side{flex-direction:row; overflow-x:auto; border-inline-end:0;
    border-bottom:1px solid var(--line); align-items:center}
  .mw-side > .btn{margin:0 8px 0 0}
  .mw-box{width:auto; white-space:nowrap}
  .mw-list{border-inline-end:0}
  .mailwb.reading .mw-list,.mailwb.reading .mw-side{display:none}
  .mailwb:not(.reading) .mw-read{display:none}
  .mw-backbtn{display:inline-flex}
  /* U-02/U-06: the phone rail can now stack up to 3 doors (home + quick-chat +
     launcher), so the compose card's clearance grows with it — nav.js's own
     padding-bottom moved the same amount (72px -> 176px). */
  .mw-compose{inset-inline:10px; width:auto; bottom:calc(176px + env(safe-area-inset-bottom))}
}

/* ═══ calendar / time (p-cal) ═══════════════════════════════════════════ */
.card pre.clamp{max-height:5.2em; overflow:hidden; cursor:pointer; color:var(--dim);
  font-size:var(--fs-sm)}
.card pre.clamp.open{max-height:none; color:var(--fg)}
.when{color:var(--dim); font-size:var(--fs-sm); margin-top:2px}
.day{margin:22px 0 8px; color:var(--dim); font-size:var(--fs-sm); letter-spacing:.05em;
  display:flex; align-items:baseline; gap:8px}
.day b{color:var(--fg); font-weight:500; font-size:var(--fs-md); letter-spacing:0}
.day.today b{color:var(--brand-ink)}
.ev{display:flex; gap:12px; background:var(--surface); border:1px solid var(--line);
  border-radius:var(--r-lg); padding:11px 15px; margin-bottom:8px; align-items:baseline;
  animation:var(--rise); flex-wrap:wrap}
.ev.past{opacity:.5}
.ev .tm{flex:none; font:var(--fs-md) var(--mono); color:var(--brand-ink); width:6.8rem}
.ev .bd{flex:1; min-width:0}
.ev .bd b{font-size:var(--fs-h); font-weight:500}
.ev .bd .meta{color:var(--dim); font-size:var(--fs-sm); word-break:break-word}
.ev .ops{flex:none; display:flex; gap:var(--sp-1)}
.ev .ops .danger:hover:not(:disabled),.tl-meta .danger:hover:not(:disabled),.row .btn.danger:hover:not(:disabled){color:var(--bad)}
.pastbar{color:var(--dim); font-size:var(--fs-sm); cursor:pointer; margin:18px 0 4px;
  user-select:none}
.pastbar:hover{color:var(--fg)}

/* ═══ files (p-files) ═══════════════════════════════════════════════════ */
.crumbs{display:flex; align-items:center; gap:4px; flex-wrap:wrap; font-size:var(--fs-md);
  margin:14px 0 10px; min-height:28px}
.crumbs a{color:var(--accent); text-decoration:none; cursor:pointer; padding:4px 6px;
  border-radius:var(--r-sm)}
.crumbs a:hover{background:var(--lift)}
.crumbs .sep{color:var(--dim)}
.crumbs .here{font-weight:500; padding:4px 6px}

/* V0.2.3 C3 — the Finder: T2 workbench (sidebar · toolbar · content · info). In a window
   (html.hoop-embedded) it fills the frame; as a page it sits in the 78rem column. */
.p-files main{max-width:78rem}
.fd{display:grid; grid-template-columns:12rem 1fr; margin-top:14px; border:1px solid var(--line); border-radius:var(--r-lg);
  overflow:hidden; background:var(--surface); height:calc(100dvh - 12rem); min-height:26rem}
.fd.with-info{grid-template-columns:12rem 1fr 17rem}
html.hoop-embedded .p-files main{max-width:none; padding:0}
html.hoop-embedded .p-files h1.app{display:none}
html.hoop-embedded .fd{margin:0; border:0; border-radius:0; height:100dvh}
.fd-side{border-inline-end:1px solid var(--line); padding:12px 8px; overflow-y:auto; background:var(--bg)}
.fd-sect{color:var(--dim); font-size:var(--fs-2xs); letter-spacing:.08em; text-transform:uppercase; padding:8px 10px 4px}
.fd-place{display:flex; align-items:center; gap:8px; width:100%; padding:6px 10px; border:0; background:none; font:inherit;
  font-size:var(--fs-sm); color:var(--fg); border-radius:var(--r-sm); cursor:pointer; text-align:start; min-height:30px}
.fd-place:hover{background:var(--lift)} .fd-place.on{background:var(--brand-soft); color:var(--brand-ink); font-weight:500}
.fd-place [data-icon]{width:16px; height:16px; color:var(--dim); flex:none} .fd-place.on [data-icon]{color:var(--brand-ink)}
.fd-place.drop{outline:2px solid var(--accent); outline-offset:-2px}
.fd-main{display:flex; flex-direction:column; min-width:0; position:relative}
.fd-tools{display:flex; align-items:center; gap:2px; padding:6px 8px; flex:none; min-height:46px}
.fd-tools .hbtn{position:static; flex:none} .fd-tools .hbtn:disabled{opacity:.35; cursor:default}
.fd-sidebtn, #fd-sidebtn{display:none}
.fd-crumbs{margin:0 6px; min-width:0; flex-wrap:nowrap; overflow:hidden; white-space:nowrap}
.fd-sp{flex:1}
.fd-q{width:11rem; min-height:30px; font-size:var(--fs-sm); margin:0 6px}
@media (max-width:720px){.fd-q{font-size:16px}}   /* art. 7: no iOS zoom */
.fd-body{flex:1; overflow:auto; outline:none; padding:6px; position:relative}
.fd-body:focus-visible{outline:2px solid var(--ring); outline-offset:-2px}
.fd-body.grid{display:grid; grid-template-columns:repeat(auto-fill, minmax(112px, 1fr)); gap:4px; align-content:start}
.fd-body.rows{display:flex; flex-direction:column}
.fd-head{display:grid; grid-template-columns:minmax(0,1fr) 10rem 6rem 9rem; gap:12px; padding:4px 10px; position:sticky; top:-6px; z-index:1;
  background:var(--surface); border-bottom:1px solid var(--line)}
.fd-col{border:0; background:none; font:inherit; font-size:var(--fs-2xs); color:var(--dim); text-align:start; padding:4px 0; min-height:28px; cursor:pointer; letter-spacing:.04em}
.fd-col.on{color:var(--fg); font-weight:500}
.fd-item{display:flex; align-items:center; gap:10px; padding:6px 10px; border-radius:var(--r-sm); cursor:default; user-select:none; min-width:0}
.fd-body.rows .fd-item{display:grid; grid-template-columns:minmax(0,1fr) 10rem 6rem 9rem; gap:12px; min-height:32px}
.fd-body.rows .fd-item > .fd-cell{display:flex; align-items:center; gap:8px; min-width:0}   /* icon + name = one grid cell (C2) */
.fd-body.rows .fd-ic{display:inline-flex; flex:none; width:18px; height:18px}
.fd-body.rows .fd-nm{display:-webkit-box; -webkit-line-clamp:2; -webkit-box-orient:vertical; overflow:hidden; overflow-wrap:anywhere; min-width:0; font-size:var(--fs-md); line-height:1.3}   /* law 2 */
.fd-body.grid .fd-cell{display:contents}
.fd-body.grid .fd-item{flex-direction:column; gap:6px; padding:12px 6px 10px; text-align:center}
.fd-body.grid .fd-ic{width:48px; height:48px; display:grid; place-items:center}
.fd-body.grid .fd-ic svg{width:40px; height:40px; color:var(--dim)}
.fd-body.grid .fd-nm{font-size:var(--fs-sm); line-height:1.3; max-width:100%; overflow:hidden; text-overflow:ellipsis; display:-webkit-box;
  -webkit-line-clamp:2; -webkit-box-orient:vertical; word-break:break-word}
.fd-ic.thumb img{width:100%; height:100%; object-fit:cover; border-radius:var(--r-xs)}
.fd-body.rows .fd-ic.thumb img{width:18px; height:18px; border-radius:var(--r-2xs)}
.fd-ic svg{width:18px; height:18px; color:var(--dim)}
.fd-item:hover{background:var(--lift)}
.fd-item.sel{background:var(--brand-soft)} .fd-item.sel .fd-nm{color:var(--brand-ink)}
.fd-item.drop{outline:2px solid var(--accent); outline-offset:-2px}
.fd-meta{color:var(--dim); font-size:var(--fs-xs); overflow:hidden; text-overflow:ellipsis; white-space:nowrap; font-variant-numeric:tabular-nums}
.fd-meta.num{text-align:end}
.fd-status{flex:none; padding:4px 12px; border-top:1px solid var(--line); color:var(--dim); font-size:var(--fs-2xs); text-align:center}
.fd-drop{position:absolute; inset:46px 0 0 0; z-index:2; display:grid; place-items:center; pointer-events:none; color:var(--accent);
  font-size:var(--fs-lg); background:color-mix(in oklab, var(--accent) 8%, transparent); outline:2px dashed var(--accent); outline-offset:-8px}
.fd-marquee{position:fixed; z-index:9; border:1px solid var(--accent); background:color-mix(in oklab, var(--accent) 12%, transparent); pointer-events:none}
.fd-info{border-inline-start:1px solid var(--line); padding:14px; overflow-y:auto; background:var(--bg)}
.fd-info h3{margin:0 0 10px; font-size:var(--fs-h); font-weight:500}
.fd-info-ic{width:64px; height:64px; margin:6px auto} .fd-info-ic svg{width:64px; height:64px; color:var(--dim)}
.fd-info-name{text-align:center; font-size:var(--fs-md); font-weight:500; margin-bottom:12px; word-break:break-word}
.fd-info .kv{font-size:var(--fs-sm)}
/* quick look: a glass stage over everything, Esc / × / click-out */
.ql{position:fixed; inset:0; z-index:9997; background:var(--scrim); display:flex; flex-direction:column; align-items:center; justify-content:center; padding:24px;
  -webkit-backdrop-filter:blur(10px); backdrop-filter:blur(10px); animation:fade var(--dur-1) var(--ease)}
.ql-head{width:min(64rem,100%); display:flex; align-items:center; gap:6px; color:var(--bg); padding:0 4px 8px}
.ql-head b{flex:1; min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; font-weight:500; color:var(--on-scrim)}
.ql-head .hbtn, .ql-head .ql-x{position:static; color:var(--on-scrim)}
.ql-body{width:min(64rem,100%); height:min(80dvh,100%); background:var(--surface); border-radius:var(--r-xl); overflow:auto; display:grid; place-items:center; box-shadow:var(--shadow-pop)}
.ql-body img, .ql-body video{max-width:100%; max-height:80dvh; object-fit:contain}
.ql-body iframe{width:100%; height:80dvh; border:0}
.ql-body pre{align-self:start; justify-self:stretch; margin:0; padding:18px 22px; white-space:pre-wrap; word-break:break-word; font:var(--fs-md)/1.6 var(--mono)}
.ql-body .ql-md{align-self:start; justify-self:stretch; padding:22px 28px; max-width:46rem; margin:0 auto; font-family:var(--font-brand); font-size:var(--fs-rd); line-height:1.75}
.toast.undo{display:flex; align-items:center; gap:12px; padding-inline-end:6px}
@media (max-width:900px){
  .fd{grid-template-columns:1fr; height:calc(100dvh - 9rem)}
  .fd.with-info{grid-template-columns:1fr}
  .fd-side{position:absolute; inset-inline-start:0; top:0; bottom:0; z-index:3; width:13rem; transform:translateX(-102%); transition:transform var(--dur-2) var(--ease); box-shadow:var(--shadow-pop)}
  [dir="rtl"] .fd-side{transform:translateX(102%)}
  .fd.side-open .fd-side{transform:none}
  #fd-sidebtn{display:inline-grid}
  .fd-info{position:absolute; inset-inline-end:0; top:46px; bottom:0; z-index:3; width:min(17rem,80vw); box-shadow:var(--shadow-pop)}
  .fd-main{position:relative}
}
@media (max-width:720px){
  .fd{margin-top:8px; height:calc(100dvh - 7rem); border-radius:var(--r-md)}
  .fd-q{width:7rem}
  .fd-head, .fd-body.rows .fd-item{grid-template-columns:minmax(0,1fr) 7rem}   /* "22/08/2026 21:09" needs 7rem */
  .fd-head .fd-col:nth-child(3), .fd-head .fd-col:nth-child(4), .fd-body.rows .fd-meta:nth-child(3), .fd-body.rows .fd-meta:nth-child(4){display:none}
  .fd-body.rows .fd-item{min-height:40px}
  #fd-sort, #fd-infobtn{display:none}
}
/* Linux desktop stream stays inside its owner-authenticated AppWindow. */
.lx-stage{width:100%;aspect-ratio:4/3;max-height:calc(100dvh - 13rem);overflow:hidden;
  border-radius:var(--r-card);background:var(--ink-stage);box-shadow:var(--shadow-1)}
.lx-frame{display:block;width:100%;height:100%;border:0;background:var(--ink-stage)}
@media (max-width:720px){.lx-stage{border-radius:0;max-height:calc(100dvh - 10rem)}}
.list-box .empty,.list-box .ui-empty{border:0; margin:0}
.up{color:var(--dim); font-size:var(--fs-sm); margin-top:10px}

/* ═══ memory (p-mem) ════════════════════════════════════════════════════ */
.p-mem .card textarea, .p-mem .card input{width:100%; margin-top:8px}
.p-mem .card textarea{min-height:9rem; background:var(--code);
  font:var(--fs-md)/1.65 var(--mono)}
.p-mem .mem-card .ui-card-head{margin-block-end:var(--sp-2)}
.p-mem .mem-body{min-width:0; color:var(--fg); font-size:var(--fs-ui); line-height:var(--lh-body); overflow-wrap:anywhere}
.p-mem .mem-body>:first-child{margin-top:0}
.p-mem .mem-body>:last-child{margin-bottom:0}
.p-mem .mem-body :is(h1,h2,h3,h4){margin:var(--sp-3) 0 var(--sp-1); font-size:var(--fs-h); font-weight:500; line-height:var(--lh-tight)}
.p-mem .mem-body :is(p,ul,ol,blockquote,pre,table){margin:0 0 var(--sp-2)}
.p-mem .mem-body :is(ul,ol){padding-inline-start:1.3em}
.p-mem .mem-body li+li{margin-top:2px}
.p-mem .mem-body blockquote{padding-inline-start:var(--sp-3); border-inline-start:var(--sp-1) solid var(--line-2); color:var(--dim)}
.p-mem .mem-body code{background:var(--code); border-radius:var(--r-xs); padding:.1em .35em; font-size:.92em}
.p-mem .mem-body pre{overflow:auto; max-width:100%}
.p-mem .mem-body pre code{background:none; padding:0}
.p-mem .mem-body :is(table){display:block; overflow:auto; max-width:100%}
.p-mem .mem-body a{color:var(--accent)}
.p-mem .mem-body .mem-plain{white-space:pre-wrap}
.p-mem .mem-actions{display:flex; gap:var(--sp-2); flex-wrap:wrap; margin-top:var(--sp-3)}
.p-mem #hubcard .row{margin-top:var(--sp-3)}
.p-mem #newcard{display:none}
.p-mem #newcard.on{display:block}

/* ═══ vpn (p-vpn) ═══════════════════════════════════════════════════════ */
.p-vpn{font:var(--fs-base)/1.7 var(--mono)}
.p-vpn main{width:100%;}
.p-vpn h2{font-size:var(--fs-h); margin-top:2.6rem; border-bottom:1px solid var(--line);
  padding-bottom:.4rem; font-weight:500}
.p-vpn .dim{color:var(--dim)}
.p-vpn .ok{color:var(--ok)}
.p-vpn table{border-collapse:collapse; width:100%; margin:.6rem 0}
.p-vpn td{padding:.25rem 0; padding-inline-end:.8rem; vertical-align:top}
/* V0.1.9 ② the connect card: QR + links + a breathing badge that turns brand once the probe says "via_hoop" */
.p-vpn .vcard{font-family:var(--font-ui); font-size:var(--fs-ui); line-height:1.55}
.p-vpn .vcard h3{margin-bottom:var(--sp-2)}
.p-vpn .lede{font-family:var(--font-ui)}
.p-vpn .vcard .ui-card-head{margin-bottom:var(--sp-2)}
.p-vpn .vcard .ui-card-head h3{margin:0}
.p-vpn .vhint{margin:0 0 var(--sp-2)}
.p-vpn .vsteps{list-style:none; counter-reset:vstep; padding:0; margin:var(--sp-4) 0 var(--sp-3)}
.p-vpn .vsteps>li{counter-increment:vstep; position:relative; display:grid; gap:var(--sp-2); margin:0;
  padding:var(--sp-4) 0; padding-inline-start:calc(var(--sp-6) + var(--sp-3)); border-top:1px solid var(--line)}
.p-vpn .vsteps>li::before{content:counter(vstep); position:absolute; inset-inline-start:0; top:var(--sp-4);
  width:var(--sp-6); height:var(--sp-6); border-radius:50%; display:grid; place-items:center;
  background:var(--surface-2); border:1px solid var(--line-2); box-sizing:border-box; color:var(--fg); font-size:var(--fs-sm); font-weight:500}
.p-vpn .vsteps>li>h3{margin:0; font-size:var(--fs-ui); font-weight:500; line-height:var(--sp-6)}
.p-vpn .vsteps>li>.fine{margin:0; color:var(--dim); font-size:var(--fs-sm)}
.p-vpn .vacts{display:flex; align-items:center; gap:var(--sp-2); flex-wrap:wrap; min-width:0}
.p-vpn .vacts>[hidden]{display:none}
.p-vpn .vstate{width:fit-content; max-width:100%; padding:var(--sp-1) var(--sp-3); border-radius:var(--r-sm);
  background:var(--surface-2); border-inline-start:var(--sp-1) solid var(--line-2); color:var(--dim); font-size:var(--fs-sm)}
.p-vpn .vstate:empty{display:none}
.p-vpn .vstate[data-state="complete"]{border-inline-start-color:var(--ok); color:var(--fg)}
.p-vpn .vstate[data-state="failed"]{border-inline-start-color:var(--bad); color:var(--fg)}
.p-vpn .vstate.ok,.p-vpn .vstate.bad{color:var(--fg)}
.p-vpn #pw-state.vstate{display:inline-block; padding:0 var(--sp-2)}
.p-vpn .vcard>details{margin-top:var(--sp-2)}
.p-vpn .vcard>details>summary,.p-vpn .vadvanced>summary{width:fit-content; cursor:pointer; color:var(--dim); font-family:var(--font-ui); font-size:var(--fs-sm); letter-spacing:0}
.p-vpn .vcard>details>summary:hover,.p-vpn .vadvanced>summary:hover{color:var(--fg)}
.p-vpn .vgrid{display:grid; grid-template-columns:auto 1fr; gap:var(--sp-5); align-items:start; margin-top:var(--sp-4)}
.p-vpn .vqr{text-align:center}
.p-vpn .vqr img{display:block; width:168px; height:168px; border-radius:var(--r-md); background:var(--surface-white); padding:6px}
.p-vpn .vqr .fine{color:var(--dim); font-size:var(--fs-xs); margin-top:var(--sp-2)}
.p-vpn .vbadge{display:inline-flex; align-items:center; gap:var(--sp-2); color:var(--dim); font-size:var(--fs-sm);
  padding:4px 12px; border:1px solid var(--line); border-radius:var(--r-pill); margin-bottom:var(--sp-3)}
.p-vpn .vbadge .cdot{background:var(--line-2)}
.p-vpn .vbadge.on{color:var(--brand-ink); border-color:var(--brand)}
.p-vpn .vbadge.on .cdot{background:var(--brand); animation:breathe var(--motion-breathe) var(--ease-loop) infinite}
.p-vpn .vclients{margin-top:var(--sp-4); font-size:var(--fs-sm)}
.p-vpn .vclients > div{display:flex; justify-content:space-between; gap:var(--sp-3); padding:6px 0; border-top:1px solid var(--line)}
.p-vpn .vclients a{color:var(--fg)}
@media (max-width:600px){ .p-vpn .vgrid{grid-template-columns:1fr} .p-vpn .vqr img{margin:0 auto} }
.p-vpn td:first-child{color:var(--dim); white-space:nowrap; width:11rem}
.p-vpn code, .p-vpn pre{background:var(--code); border:1px solid var(--line);
  border-radius:var(--r-xs)}
.p-vpn code{padding:.1rem .4rem}
.p-vpn pre{padding:.9rem 1rem; overflow-x:auto; position:relative; white-space:pre-wrap;
  word-break:break-all}
.p-vpn button.copy{position:absolute; top:.5rem; inset-inline-end:.5rem;
  background:transparent; color:var(--dim); border:1px solid var(--line-2);
  border-radius:var(--r-btn); font:var(--fs-xs) inherit; padding:.3rem .7rem; cursor:pointer;
  box-shadow:none}
.p-vpn pre:has(> button.copy){padding-inline-end:5rem}
.p-vpn button.copy:hover{color:var(--fg)}
.p-vpn ol{padding-inline-start:1.3rem} .p-vpn li{margin:.35rem 0}
.p-vpn .locked{color:var(--dim); font-style:italic}
.p-vpn a{color:var(--accent)}

/* ═══ finance (p-fin) ═══════════════════════════════════════════════════ */
.p-fin main{max-width:68rem}
.wallet-head{display:flex; gap:18px; align-items:center; flex-wrap:wrap}
.wallet-head .qr{flex:none; width:132px; height:132px; border:1px solid var(--line);
  border-radius:var(--r-md); padding:8px; background:var(--surface-white); display:grid; place-items:center}
.wallet-head .qr canvas, .wallet-head .qr img{width:100%; height:100%; image-rendering:pixelated}
.wallet-bal{flex:1; min-width:12rem}
.wallet-bal .amt{font-size:var(--fs-3xl); font-weight:500; letter-spacing:-.01em;
  font-variant-numeric:tabular-nums;
  transition:opacity var(--dur-3)}
.wallet-bal .amt .cur{font-size:var(--fs-ui); color:var(--dim); font-weight:400;
  margin-inline-start:6px}
.wallet-bal .sub{color:var(--dim); font-size:var(--fs-sm); margin-top:2px}

/* ── .tbl / .rpt / .curve: the trading workbench's honest surfaces (V0.1.7 ③) ─ */
.tbl{width:100%; min-width:max-content; border-collapse:collapse; font-size:var(--fs-sm);
  font-variant-numeric:tabular-nums}
.tbl caption{padding:6px 8px; color:var(--dim); font-size:var(--fs-xs); text-align:start}
.tbl th{text-align:start; color:var(--dim); font-size:var(--fs-xs); font-weight:500;
  position:sticky;top:0;padding:var(--sp-2) var(--sp-3);border-bottom:1px solid var(--line);background:var(--surface);z-index:1}
.tbl td{padding:var(--sp-2) var(--sp-3);border-bottom:1px solid var(--line);vertical-align:top;text-align:start}
.tbl tr:last-child td{border-bottom:0}
.tbl .num{text-align:end}
.tbl time,.tbl .time{font-family:var(--mono);font-variant-numeric:tabular-nums}
.tbl .up{color:var(--ok)} .tbl .down{color:var(--bad)}
.rpt{white-space:pre-wrap; font-size:var(--fs-rd); line-height:1.85;
  word-break:break-word; font-family:var(--font-brand)}   /* the researcher's voice */
.curve{display:block; width:100%; height:110px; margin-top:12px}
.curve polyline{fill:none; stroke:var(--brand-ink); stroke-width:1.6}
.curve line.base{stroke:var(--line); stroke-width:1; stroke-dasharray:4 4}
.curve polyline.bench{stroke:var(--dim); stroke-width:1; stroke-dasharray:3 3}   /* V0.2.12: the BTC/USDT 50/50 yardstick */
.addr-line{display:flex; align-items:center; gap:8px; margin-top:10px; flex-wrap:wrap}
.addr-line code{background:var(--code); border-radius:var(--r-xs); padding:5px 10px;
  font:var(--fs-sm) var(--mono); word-break:break-all; user-select:all}
.netline{display:flex; gap:8px; align-items:center; flex-wrap:wrap; margin-top:14px;
  color:var(--dim); font-size:var(--fs-sm)}
.netline .opt{padding:0 10px; min-height:24px; font-size:var(--fs-xs)}
.pend{border-color:var(--warn)}
.pend .amt{font-weight:500}
/* The desk's cards say nothing until /trade/status answers, and the fills hide the ones that
   come back empty — which pulled every section below them up (~0.62 CLS in a single frame on
   /finance, the worst page). So the desk's body stays out of sight until the status render has
   painted the truth: it keeps its box (the equity chart still measures itself), and appearing
   content is not a layout shift while moving-then-hiding content is. */
#tab-trade[data-desk="wait"] > *{visibility:hidden}
.ritual{border-color:var(--brand)}
.ritual .words{display:grid; grid-template-columns:repeat(3,1fr); gap:6px 12px; margin:14px 0;
  font:var(--fs-h)/1.5 var(--mono); counter-reset:w}
.ritual .words span{counter-increment:w; padding:4px 8px; background:var(--code);
  border-radius:var(--r-xs)}
.ritual .words span::before{content:counter(w) " "; color:var(--dim); font-size:var(--fs-2xs)}
.ritual .keyhex{font:var(--fs-sm) var(--mono); background:var(--code); border-radius:var(--r-xs);
  padding:8px 10px; word-break:break-all; user-select:all; margin-top:8px}
@media (max-width:480px){ .ritual .words{grid-template-columns:repeat(2,1fr)} }

/* ═══ the narrow law (codex art. 6): ≤600px nothing is wider than its box ═ */
.card pre, .p-vpn pre{overflow-x:auto; max-width:100%}
.p-vpn .tblw{overflow:visible}
#tr-params.tblw{overflow-x:visible}
#tr-params .tbl{min-width:0;table-layout:fixed}
#tr-params .tbl td{min-width:0;overflow-wrap:anywhere;word-break:break-word}
.p-vpn table{display:table; width:100%; overflow:visible; max-width:100%; table-layout:fixed}
.p-vpn td{min-width:0; word-break:break-word; overflow-wrap:anywhere}
.card > table{display:block; overflow-x:auto; max-width:100%}
.row, .btns, .f .line, .tzline, .langline, .applybar, .wallet-head, .addr-line, .netline{min-width:0}
.row > *, .f .line > *, .tzline > *, .applybar > *{min-width:0}
@media (max-width:600px){
  .page{padding-inline:var(--sp-4)}
  .card{padding:12px 14px}
  .ev .tm{width:auto}
  .evt .t{width:5.6rem}
  .modal .m-acts{flex-direction:column-reverse}
  .modal .m-acts .btn{width:100%}
  .tzline input, .applybar input, .f .line input:not([type=number]){flex:1 1 10rem; width:auto}
  .p-vpn td:first-child{white-space:normal; width:auto}
  .kv{grid-template-columns:5.5rem 1fr}
  .pk-v{max-width:42%}
}

/* ═══ 书房 + 随手记 (V0.1.7 ⑤) ══════════════════════════════════════════ */
/* .capture — the ⌘J spark catcher: milliseconds to appear, Enter to keep */
.capture{position:fixed; inset:0; z-index:9500; background:var(--scrim);
  -webkit-backdrop-filter:blur(10px); backdrop-filter:blur(10px);
  display:grid; place-items:start center; padding-block-start:18vh;
  animation:fade var(--dur-1) var(--ease)}
.cap-box{width:min(34rem, calc(100vw - 32px)); background:var(--glass-bg); border:0;
  -webkit-backdrop-filter:var(--glass-blur); backdrop-filter:var(--glass-blur);
  border-radius:var(--r-2xl); box-shadow:var(--glass-rim), var(--shadow-pop); padding:16px 18px}
.cap-box textarea{width:100%; font:inherit; font-size:var(--fs-lg); line-height:1.6;
  border:0; outline:none; resize:none; background:none; color:var(--fg); padding:0;
  box-shadow:none; min-height:0}
.cap-box textarea:focus{box-shadow:none}
.cap-foot{display:flex; justify-content:space-between; color:var(--dim);
  font-size:var(--fs-xs); margin-top:6px}

/* ── .palette — ⌘K, the .capture's sibling (V0.1.8 ⑤) ───────────────────── */
.palette{position:fixed; inset:0; z-index:9600; background:var(--scrim);
  -webkit-backdrop-filter:blur(10px); backdrop-filter:blur(10px);
  display:grid; place-items:start center; padding-block-start:14vh;
  animation:fade var(--dur-1) var(--ease)}
.pal-box{width:min(38rem, calc(100vw - 32px)); background:var(--glass-bg); border:0;
  -webkit-backdrop-filter:var(--glass-blur); backdrop-filter:var(--glass-blur);
  border-radius:var(--r-2xl); box-shadow:var(--glass-rim), var(--shadow-pop);
  overflow:hidden; display:flex; flex-direction:column; max-height:72vh}
.pal-in{display:flex; align-items:center; gap:10px; padding:10px 14px; border-bottom:1px solid var(--line);
  color:var(--dim)}
.pal-in input{flex:1; border:0; background:none; box-shadow:none; padding:4px 0; min-height:0;
  font-size:var(--fs-lg); color:var(--fg)}
.pal-in input:focus{box-shadow:none}
.pal-res{overflow-y:auto; padding:6px; flex:1; min-height:3rem}
.pal-g{padding:10px 10px 3px; font-size:var(--fs-2xs); color:var(--dim); letter-spacing:.06em; user-select:none}
.pal-it{display:flex; align-items:center; gap:10px; padding:7px 12px; border-radius:var(--r-md);
  cursor:pointer; font-size:var(--fs-md); min-height:34px}
.pal-it [data-icon]{color:var(--dim); flex:none}
.pal-it .lb{white-space:nowrap; overflow:hidden; text-overflow:ellipsis; flex:none; max-width:60%}
.pal-it .sub{color:var(--dim); font-size:var(--fs-xs); margin-inline-start:auto; overflow:hidden;
  text-overflow:ellipsis; white-space:nowrap; min-width:0}
.pal-it.sel{background:var(--brand-soft)}
.pal-it.sel [data-icon]{color:var(--brand-ink)}
.pal-more{padding:4px 10px 8px; font-size:var(--fs-xs); color:var(--accent); cursor:pointer}
.pal-empty{padding:24px; text-align:center; color:var(--dim); font-size:var(--fs-md)}
/* the shortcuts page (?): a row is a fact, not a place to go — the keys sit at the end in mono */
.pal-it.pal-key{cursor:default}
.pal-it.pal-key .lb{flex:1; max-width:none; white-space:normal}
.pal-it.pal-key .sub{flex:none}
.pal-key kbd{font:var(--fs-xs) var(--mono); color:var(--fg)}
.pal-note{margin:8px 12px 4px; color:var(--dim); font-size:var(--fs-xs); line-height:1.5}
.pal-foot{display:flex; justify-content:space-between; padding:7px 14px; border-top:1px solid var(--line);
  color:var(--dim); font-size:var(--fs-2xs)}

/* ── S9 任务在场: the tasks overlay (gram-tasks.js) — same glass grammar as .palette ── */
.tasks-scrim{position:fixed; inset:0; z-index:9600; background:var(--scrim);
  -webkit-backdrop-filter:blur(10px); backdrop-filter:blur(10px);
  display:grid; place-items:start center; padding-block-start:8vh; padding-inline:16px;
  animation:fade var(--dur-1) var(--ease)}
.tasks-box{position:relative; width:min(34rem, 100%); max-height:80vh; background:var(--glass-bg);
  -webkit-backdrop-filter:var(--glass-blur); backdrop-filter:var(--glass-blur);
  border-radius:var(--r-2xl); box-shadow:var(--glass-rim), var(--shadow-pop);
  overflow:hidden; display:flex; flex-direction:column}
.tk-top{display:flex; align-items:center; padding:16px 52px 12px 20px; border-bottom:1px solid var(--line)}
.tk-top h3{margin:0; font-size:var(--fs-lg); font-weight:500}
.tk-body{overflow-y:auto; padding:8px}
.tk-empty,.tk-loadfail{padding:28px 16px; text-align:center; color:var(--dim); font-size:var(--fs-md)}
.tk-row{display:flex; gap:12px; align-items:flex-start; padding:12px 10px; border-radius:var(--r-lg)}
.tk-row + .tk-row{border-top:1px solid var(--line-soft)}
.tk-icon{flex:none; width:28px; height:28px; border-radius:50%; display:grid; place-items:center;
  color:var(--dim); background:var(--lift); margin-top:1px}
.tk-icon svg{width:16px; height:16px}
.tk-main{flex:1; min-width:0; display:flex; flex-direction:column; gap:3px}
.tk-head{display:flex; align-items:center; gap:8px; flex-wrap:wrap}
.tk-name{font-weight:500; max-width:12rem}
.tk-dir{color:var(--dim); font-size:var(--fs-xs); max-width:12rem}
.tk-pill{font-size:var(--fs-2xs); padding:1px 8px; border-radius:var(--r-pill); flex:none}
.tk-pill.tk-running{color:var(--ok); background:color-mix(in oklab, var(--ok) 14%, transparent)}
.tk-pill.tk-waiting{color:var(--warn); background:color-mix(in oklab, var(--warn) 16%, transparent)}
.tk-pill.tk-waiting.tk-wait-other{color:var(--dim); background:var(--lift)} /* waiting on another agent / a gate — not on you */
.tk-pill.tk-idle{color:var(--dim); background:var(--lift)}
.tk-meta{display:flex; gap:10px; color:var(--dim); font-size:var(--fs-2xs)}
.tk-title{color:var(--dim); font-size:var(--fs-xs)}
.tk-hint{color:var(--dim); font-size:var(--fs-xs)}
.tk-acts{flex:none; display:flex; flex-direction:column; gap:4px; align-items:stretch}
.tk-acts .btn{min-height:0; padding:4px 10px; font-size:var(--fs-xs)}
/* the one task record (gram-tasks.js recRow): 接手 / 停止 are full 44px tap targets on every screen */
.tk-rec .tk-acts .btn{min-height:44px; min-width:44px; padding:0 14px; font-size:var(--fs-sm)}
.tk-exec{color:var(--dim); font-size:var(--fs-xs)}
.tk-exec[data-alive="gone"]{color:var(--fg); font-weight:600}
@media (max-width:520px){
  .tasks-scrim{padding-block-start:0; place-items:end center}
  .tasks-box{width:100%; max-height:88vh; border-radius:var(--r-2xl) var(--r-2xl) 0 0}
  .tk-row{flex-wrap:wrap}
  .tk-acts{flex-direction:row; flex:1 0 100%}
  .tk-acts .btn{flex:1}
}

/* ── .modal-settings — one aligned settings window, desktop and phone ───── */
@media(min-width:721px){html.hoop-rail .settings-scrim{inset-inline-start:var(--matrix-w,248px)}}
.settings-page-grid{display:grid;grid-template-columns:minmax(12rem,15rem) minmax(0,1fr);gap:var(--sp-6)}
.settings-page-nav{position:sticky;top:var(--sp-5);align-self:start;display:grid;gap:var(--sp-2)}
.settings-page-nav input,.settings-page-group{width:100%;min-width:0}
.settings-page-group{display:grid;grid-template-columns:20px minmax(0,1fr);align-items:center;gap:var(--sp-2);text-align:start;border:0;background:none;color:var(--dim);padding:7px 9px;border-radius:var(--r-sm);font:inherit;cursor:pointer}
.settings-page-group [data-icon]{width:20px;display:grid;place-items:center;color:var(--dim)}
.settings-page-group [data-icon] svg{width:17px;height:17px}
.settings-page-group:hover,.settings-page-group:focus-visible{background:var(--lift);color:var(--fg)}
.settings-page-group.on{background:var(--brand-soft);color:var(--brand-ink);font-weight:500}
.settings-page-group.on [data-icon]{color:var(--brand-ink)}
.settings-search-hidden{display:none!important}
.set-card .ui-card-head{margin-block-end:var(--sp-3)}
.set-card .set-hint{margin:var(--sp-3) 0 0}
.set-card .ui-card-head+.set-hint{margin:0 0 var(--sp-3)}
.set-card .kv+.set-hint{margin-top:var(--sp-3)}
.set-card .set-status{margin-top:var(--sp-3)}
.set-card .ui-pill{vertical-align:middle}
.set-card .set-more{margin-top:var(--sp-3)}
.set-card .set-more>summary{cursor:pointer;width:fit-content;color:var(--dim);font-size:var(--fs-sm)}
.set-card .set-more>summary:hover{color:var(--fg)}
.set-card .set-more[open]>summary{margin-bottom:var(--sp-2)}
.set-card .set-actions{display:flex;align-items:center;gap:var(--sp-2) var(--sp-4);flex-wrap:wrap;margin-top:var(--sp-3)}
.set-card .set-actions .fine{flex:1 1 14rem;min-width:0;color:var(--dim);font-size:var(--fs-sm)}
.set-card .form-control .ui-file{justify-content:flex-end}
@media(max-width:800px){
  .settings-page-grid{display:block}
  .settings-page-nav{position:static;margin-bottom:var(--sp-5)}
  #settings-groups{display:flex;flex-wrap:wrap;gap:var(--sp-1);overflow:visible;overscroll-behavior-x:contain;scrollbar-width:none;margin-inline:calc(-1 * var(--sp-4));padding-inline:var(--sp-4)}
  #settings-groups::-webkit-scrollbar{display:none}
  .settings-page-group{flex:0 0 auto;width:auto;min-width:var(--tap);min-height:var(--tap);white-space:nowrap;border:1px solid var(--line-soft);border-radius:var(--r-pill);padding:0 var(--sp-3)}
  .settings-page-group.on{border-color:var(--brand)}
  .p-set a[href="/export.tar.gz"],.p-set #b-export,.p-set #update-rollback{min-height:var(--tap)}
}

.modal.modal-settings{max-width:960px; width:calc(100vw - 40px); height:min(84vh, 740px); padding:0;
  display:grid; grid-template-columns:14rem minmax(0,1fr); overflow:hidden; border-radius:var(--r-2xl)}
.ms-nav{border-inline-end:1px solid var(--line); padding:14px 10px; display:flex; flex-direction:column;
  gap:2px; background:none; min-height:0}
.ms-search{padding:0 2px; margin-bottom:10px}
.ms-search input,.ms-phone-search input{width:100%; min-width:0; min-height:32px; margin:0; padding:4px 10px;
  font-size:var(--fs-sm)}
.ms-g{display:grid; grid-template-columns:20px minmax(0,1fr) auto; align-items:center; gap:9px;
  min-height:38px; padding:7px 12px; border-radius:var(--r-md); cursor:pointer;
  font-size:var(--fs-md); color:var(--fg); border:0; background:none; text-align:start; font:inherit; width:100%}
.ms-g:hover{background:var(--lift)}
.ms-g.on{background:var(--brand-soft); color:var(--brand-ink); font-weight:500}
.ms-g.dim{opacity:.45}
.ms-g[data-tier="2"]{color:var(--dim)}
.ms-g[data-tier="2"].on{color:var(--brand-ink)}
.ms-g.tier-start{margin-top:8px; padding-top:12px; border-top:1px solid var(--line); border-radius:0 0 var(--r-sm) var(--r-sm)}
.ms-g [data-icon]{color:var(--dim); width:20px; display:grid; place-items:center}
.ms-g [data-icon] svg{width:17px; height:17px}
.ms-g.on [data-icon]{color:var(--brand-ink)}
.ms-g .n{margin-inline-start:auto; font-size:var(--fs-2xs); color:var(--brand-ink);
  background:var(--brand-soft); border-radius:var(--r-pill); padding:0 7px}
.ms-page{margin-top:auto; color:var(--dim); font-size:var(--fs-xs); text-decoration:none; padding:8px 10px}
.ms-page:hover{color:var(--fg)}
.ms-close{position:absolute; top:14px; inset-inline-end:14px; z-index:4}
.ms-body{overflow-y:auto; padding:20px 58px 32px 24px; padding-inline-start:24px;
  padding-inline-end:58px; min-width:0; background:color-mix(in oklab, var(--surface) 55%, transparent)}
.ms-body h2{font-size:var(--fs-lg); font-weight:500; margin:0 0 14px; min-height:32px;
  display:flex; align-items:center}
.ms-body .card{animation:none; border-color:var(--line)}
.ms-body .sect{margin-top:18px}
.ms-body .feed{max-height:none}
.modal-settings input{margin-top:0}
/* the phone posture of settings: a full-height sheet, every group stacked (V0.1.9 ①) */
.modal-scrim.ms-sheet{align-items:flex-end; padding:0}
.modal.modal-settings.ms-phone{width:100%; max-width:none; height:calc(100dvh - 24px - env(safe-area-inset-top));
  border-radius:var(--r-2xl) var(--r-2xl) 0 0; grid-template-columns:1fr; grid-template-rows:auto 1fr;
  animation:sheetup var(--dur-2) var(--ease); background:color-mix(in oklab, var(--surface) 94%, transparent)}
.ms-phone .ms-nav{display:none}
.ms-head{padding:6px 16px 12px; padding-top:calc(6px + env(safe-area-inset-top))}
.ms-head .grab{width:38px; height:5px; border-radius:var(--r-pill); background:var(--line-2); margin:4px auto 10px}
.ms-phone-title{min-height:36px; display:flex; align-items:center; padding-inline-end:44px}
.ms-head b{font-size:var(--fs-h); font-weight:500}
.ms-phone-search{margin-top:8px}
.ms-phone .ms-close{top:calc(17px + env(safe-area-inset-top)); inset-inline-end:16px}
.ms-phone .ms-body{padding:12px 16px calc(28px + env(safe-area-inset-bottom)); background:none}
.ms-phone .ms-body .sect{margin-top:20px}
.hit{box-shadow:var(--focus); border-radius:var(--r-sm)}
.sect.hit{box-shadow:none; color:var(--brand-ink)}

/* the journal timeline */
.jbar{display:flex; gap:8px; margin-top:14px}
.jbar input{flex:1; min-width:0}
.timeline{margin-top:10px}
.tl-day{color:var(--dim); font-size:var(--fs-xs); letter-spacing:.08em;
  margin:22px 0 6px; font-variant-numeric:tabular-nums}
.tl-item{display:flex; gap:12px; padding:8px 0; border-inline-start:1px solid var(--line-2);
  padding-inline-start:14px; margin-inline-start:4px}
.tl-t{flex:none; color:var(--dim); font-size:var(--fs-xs); width:2.8rem;
  font-variant-numeric:tabular-nums; padding-top:2px}
.tl-body{flex:1; min-width:0}
.tl-text{font-size:var(--fs-rd); line-height:1.75; white-space:pre-wrap;
  overflow-wrap:break-word}
.tl-meta{display:flex; align-items:center; flex-wrap:wrap; gap:var(--sp-1); margin-top:2px; font-size:var(--fs-xs); color:var(--dim)}
.tl-meta .tl-ctx{margin-inline-end:var(--sp-2)}
.tl-meta .tl-ctx:empty{display:none}
.tl-meta .tl-ctx:empty+.btn{margin-inline-start:-10px}
.tl-meta a{cursor:pointer; color:var(--dim)}
.tl-meta a:hover{color:var(--fg)}
.tl-meta a.danger:hover{color:var(--bad)}

/* the library shelf */
.shelf{display:grid; grid-template-columns:repeat(auto-fill, minmax(9rem, 1fr));
  gap:14px; margin-top:16px}
.spine{border:0; background:none; font:inherit; cursor:pointer; text-align:start;
  padding:0; color:var(--fg)}
.sp-cover{display:grid; place-items:center; position:relative; aspect-ratio:5/7;
  border-radius:var(--r-sm); background:linear-gradient(160deg, var(--surface-2), var(--code));
  box-shadow:var(--shadow-1); overflow:hidden;
  transition:transform var(--dur-1)}
.spine:hover .sp-cover{transform:translateY(-3px)}
.sp-cover img{position:absolute; inset:0; width:100%; height:100%; object-fit:cover}
.sp-title{padding:12px; font-size:var(--fs-h); font-weight:500; line-height:1.5;
  text-align:center; word-break:break-word}
.sp-title.over{position:absolute; inset-inline:0; bottom:0; background:var(--scrim);
  color:var(--on-scrim); font-size:var(--fs-xs); padding:6px 8px; text-align:start}
.sp-meta{display:block; color:var(--dim); font-size:var(--fs-xs); margin-top:6px}

/* ═══ 唱机 (Study → 音乐) + the mini player ═══════════════════════════════════════════════
   A record, not a file list. One disc — black shellac, a paper label with the year on it, the
   grooves a whisper apart — beside the title set in the brand serif, the band and the year under
   it, and the record's own progress line. The disc IS the key: press it to play or pause, and it
   turns only while sound is really coming out. gram-media.js is the ONLY player (this panel is its
   face, the mini bar is its corner, the chat card is its receipt), so a record the AI starts in the
   background lights up here too — and `blocked` (a browser that wants one tap) is said in place,
   with the tap right here, instead of opening a window for the owner to finish the machine's job. */
.rec{display:grid; grid-template-columns:clamp(7.5rem, 22vw, 11rem) minmax(0, 1fr);
  gap:var(--sp-6); align-items:center; margin-top:var(--sp-5)}
.rec-plate{position:relative; width:100%}
.rec-disc{position:relative; display:grid; place-items:center; width:100%; aspect-ratio:1;
  padding:0; border:0; border-radius:50%; cursor:pointer;
  background:radial-gradient(circle at 34% 26%, var(--vinyl-2), var(--vinyl) 74%);
  box-shadow:var(--shadow-pop), var(--stroke-vinyl)}
.rec-disc::before{content:""; position:absolute; inset:5%; border-radius:50%;
  background:repeating-radial-gradient(circle at 34% 26%,
    transparent 0 2px, var(--vinyl-groove) 2px 3.5px)}
/* the paper label: the spindle hole is pinned to the label's centre — the disc's turning axis — and
   the year is stamped in the band below it, so the hole can never sit on the text. Measured against
   a real render, and pinned by nixos/tools/test-appwindow-contract.mjs. */
.rec-label{position:relative; display:grid; align-items:end; justify-items:center;
  padding-block-end:7%; width:36%; aspect-ratio:1;
  border-radius:50%; background:var(--vinyl-label); color:var(--vinyl-label-ink);
  box-shadow:var(--stroke-vinyl-label);
  font-size:var(--fs-2xs); line-height:1; font-variant-numeric:tabular-nums; letter-spacing:.06em}
/* percentages here resolve against the disc's width, so the hole and the label stay in proportion at
   every size the record is drawn at */
.rec-label::after{content:""; position:absolute; inset-block-start:50%; inset-inline-start:50%;
  transform:translate(-50%, -50%); width:11%; aspect-ratio:1; border-radius:50%;
  background:var(--vinyl); box-shadow:var(--stroke-vinyl-label)}
.rec-sheen{position:absolute; inset:0; border-radius:50%; opacity:0;
  background:conic-gradient(from 0deg, transparent 0deg, var(--vinyl-sheen) 46deg, transparent 106deg)}
/* the arm: it pivots off the record's corner, the way a real one does, and its head reaches into
   the groove. It swings in ~10px when the record goes and out when it stops — the only motion on
   this page that is not air. */
.rec-arm{position:absolute; inset-block-start:1.5%; inset-inline-end:2%; width:3px; height:46%;
  border-radius:var(--r-pill); background:var(--line-2); transform-origin:top center;
  transform:rotate(10deg); transition:transform var(--dur-3) var(--ease)}
.rec-arm::before{content:""; position:absolute; inset-block-start:-7px; inset-inline-start:-5px;
  width:13px; height:13px; border-radius:50%; background:var(--surface-2);
  box-shadow:var(--stroke-line-2)}
.rec-arm::after{content:""; position:absolute; inset-block-end:-8px; inset-inline-start:-4px;
  width:11px; height:12px; border-radius:var(--r-2xs) var(--r-2xs) var(--r-xs) var(--r-xs); background:var(--line-2)}
.rec.on .rec-arm{transform:rotate(26deg)}
.rec.on .rec-sheen{opacity:1; animation:rec-turn var(--motion-breathe) var(--ease-loop) infinite}
@keyframes rec-turn{to{transform:rotate(1turn)}}
.rec-body{min-width:0; display:grid; gap:var(--sp-2)}
.rec-kick{color:var(--brand-ink); font-size:var(--fs-xs); letter-spacing:.08em; text-transform:uppercase}
.rec-title{margin:0; font-family:var(--font-brand); font-weight:400; font-size:var(--fs-2xl);
  line-height:1.25; overflow-wrap:break-word}
.rec-meta{margin:0; color:var(--dim); font-size:var(--fs-h); min-height:1.2em}
.rec-hint{margin:0; color:var(--warn); font-size:var(--fs-sm)}
.rec-keys{display:flex; align-items:center; gap:var(--sp-2); margin-top:var(--sp-1)}
.rec-key{display:grid; place-items:center; width:var(--tap); height:var(--tap); padding:0;
  border:0; border-radius:50%; background:none; color:var(--fg); cursor:pointer}
.rec-key:hover{background:var(--surface-2)}
.rec-key svg{width:20px; height:20px; fill:currentColor}
.rec-key.sm svg{width:15px; height:15px}
.rec-key.go{background:var(--brand); color:var(--on-brand); box-shadow:var(--shadow-key)}
.rec-key.go:hover{background:var(--brand-600)}
.rec-key[disabled]{opacity:.4; cursor:default; background:none}
.rec-seek{width:100%; min-width:0; margin:0; accent-color:var(--brand)}
.rec-time{display:flex; justify-content:space-between; color:var(--dim); font-size:var(--fs-xs);
  font-variant-numeric:tabular-nums}
.rec-vol{display:flex; align-items:center; gap:var(--sp-2); margin-inline-start:auto; color:var(--dim)}
.rec-vol input{width:6.5rem; min-width:0; accent-color:var(--brand)}
.rec-shelf{margin-top:var(--sp-6)}
.rec-list{margin-top:var(--sp-2); display:grid; gap:2px}
.rec-row{display:grid; grid-template-columns:auto minmax(0, 1fr); gap:0 var(--sp-3);
  align-items:center; padding:9px 12px; border:0; border-radius:var(--r-md); background:none;
  color:var(--fg); font:inherit; text-align:start; cursor:pointer}
.rec-row:hover{background:var(--surface-2)}
.rec-row.on{background:var(--brand-soft)}
.rec-n{grid-row:span 2; color:var(--dim); font-size:var(--fs-xs); font-variant-numeric:tabular-nums}
.rec-row.on .rec-n{color:var(--brand-ink)}
.rec-t{min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; font-size:var(--fs-rd)}
.rec-s{min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
  color:var(--dim); font-size:var(--fs-xs)}
@media(max-width:560px){
  .rec{grid-template-columns:1fr; justify-items:center; text-align:center; gap:var(--sp-5)}
  .rec-plate{width:min(13rem, 62vw)}
  .rec-keys{justify-content:center}
  .rec-vol{margin-inline-start:0}
  .rec-row{grid-template-columns:auto minmax(0, 1fr)}
}
/* the mini player: the record's own line, in the same corner on every page — what the AI's act
   leaves behind when the 唱机 itself is not on screen. One glass, like every other float. */
.mplayer{position:fixed; inset-inline-end:var(--float-end); bottom:16px; z-index:var(--z-float);
  display:flex; align-items:center; gap:var(--sp-3); padding:var(--sp-2) var(--sp-4);
  width:min(30rem, calc(100vw - var(--dock-w) - 32px));
  border-radius:var(--r-pill); background:var(--glass-bg);
  -webkit-backdrop-filter:var(--glass-blur); backdrop-filter:var(--glass-blur);
  box-shadow:var(--glass-rim), var(--shadow-pop)}
/* a folded dock parks its unfold button in the end corner: wide floats step above it */
html.hoop-folded .mplayer, html.hoop-folded .mw-compose{bottom:68px}

/* On Chat the bar belongs to the float column ABOVE the composer (--float-base, written by
   gram-mind.js) — never over the owner's own send button and never over his last line. */
body.p-chat .mplayer{bottom:calc(var(--float-base, 104px) + 8px)}
body.p-chat.has-media #msgs{padding-bottom:calc(var(--float-base, 104px) + 74px)}
.mp-disc{position:relative; flex:none; width:38px; height:38px; padding:0; border:0; cursor:pointer;
  border-radius:50%; background:radial-gradient(circle at 34% 26%, var(--vinyl-2), var(--vinyl) 74%);
  box-shadow:var(--stroke-vinyl)}
.mp-label{position:absolute; inset:0; margin:auto; width:38%; aspect-ratio:1; border-radius:50%;
  background:var(--vinyl-label)}
.mp-label::after{content:""; position:absolute; inset-block-start:16%; inset-inline-start:66%;
  width:17%; aspect-ratio:1; border-radius:50%; background:var(--vinyl-label-ink); opacity:.55}
.mplayer.on .mp-disc{animation:rec-turn var(--motion-breathe) var(--ease-loop) infinite}
.mp-txt{display:grid; flex:1; min-width:0}
.mp-title{overflow:hidden; text-overflow:ellipsis; white-space:nowrap; font-size:var(--fs-h)}
.mp-meta{overflow:hidden; text-overflow:ellipsis; white-space:nowrap; color:var(--dim); font-size:var(--fs-xs)}
.mp-meta.hint{color:var(--warn)}
.mp-act{flex:none; display:grid; place-items:center; width:34px; height:34px; padding:0; border:0;
  border-radius:50%; background:none; color:var(--fg); cursor:pointer}
.mp-act:hover{background:var(--surface-2)}
.mp-act svg{width:16px; height:16px; fill:currentColor}
.mp-open{flex:none; color:var(--dim); font-size:var(--fs-sm); text-decoration:none}
.mp-open:hover{color:var(--fg)}
.mp-prog{position:absolute; inset-inline:var(--sp-4); bottom:5px; height:2px; overflow:hidden;
  border-radius:var(--r-pill); background:var(--line)}
.mp-prog i{display:block; height:100%; background:var(--brand-ink)}
/* the chat card: the AI's record, right where it told the owner about it — the receipt, with the
   one tap that a browser may demand, and nothing to open a window for */
.mpcard{display:flex; align-items:center; gap:var(--sp-3); max-width:46rem; margin:0 auto 16px;
  padding:var(--sp-3) var(--sp-4); border-radius:var(--r-card); background:var(--surface);
  box-shadow:var(--shadow-card); position:relative; overflow:hidden}
.mpc-mark{flex:none; width:22px; height:22px; border-radius:50%;
  background:radial-gradient(circle at 34% 26%, var(--vinyl-2), var(--vinyl) 74%);
  box-shadow:var(--stroke-vinyl)}
.mpcard.on .mpc-mark{animation:rec-turn var(--motion-breathe) var(--ease-loop) infinite}
.mpc-title{min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
  font-family:var(--font-brand); font-size:var(--fs-rd); font-weight:400}
.mpc-meta{flex:1; min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
  color:var(--dim); font-size:var(--fs-xs)}
.mpc-play{flex:none}
.mpc-open{flex:none; color:var(--dim); font-size:var(--fs-sm); text-decoration:none}
.mpc-open:hover{color:var(--fg)}
.mpc-line{position:absolute; inset-inline:0; bottom:0; height:2px}
.mpc-line i{display:block; height:100%; width:0; background:var(--brand-ink)}
.ent.playing{background:var(--brand-soft)}
.ent.playing .ic{color:var(--brand-ink)}

/* the reader: a T3 stage over the OS; .night = lamplight */
.reader{position:fixed; inset:0; z-index:9400; background:var(--reader-paper); color:var(--reader-ink);
  display:flex; flex-direction:column}
.reader.night{background:var(--reader-night); color:var(--reader-night-ink)}
.rd-head,.rd-foot{flex:none; display:flex; align-items:center; gap:10px;
  padding:10px 16px}
.rd-head b{flex:1; text-align:center; overflow:hidden; text-overflow:ellipsis;
  white-space:nowrap; font-size:var(--fs-h)}
.rd-tools{display:flex; gap:2px}
.rd-foot{justify-content:center}
.reader .btn{color:inherit; opacity:.75}
.reader .btn:hover{opacity:1}
#rd-stage{flex:1; min-height:0; overflow-y:auto; position:relative}
.rd-pdf{border:0; width:100%; height:100%}
.rd-col{max-width:34rem; margin:0 auto; padding:24px 18px 12vh; line-height:1.9;
  font-size:var(--fs-reader); font-family:var(--font-brand)}
html.hoop-reading #hooprail{display:none}
@media (max-width:720px){
  /* the phone: the bar keeps the record's line and the two keys it needs, and drops the rest */
  .mplayer{inset-inline:12px; width:auto; gap:var(--sp-2);
    bottom:calc(16px + env(safe-area-inset-bottom))}
  .mplayer .mp-open{display:none}
  /* the scroll-to-latest button shares the end column: with a record up, it steps over the bar */
  body.p-chat.has-media #tolatest{bottom:calc(var(--float-base, 16px) + 122px + env(safe-area-inset-bottom))}
}

/* ═══ codex art. 7, last word: on a phone every text input is 16px (iOS zooms on less) ═ */
@media (max-width:720px){
  input, select, textarea, #inp, .cap-box textarea, .pal-in input, #ms-q, .citem .ct input, #ctitle input,
  .bud input, .f textarea, .modal input, .p-mem .card textarea{font-size:16px}
  html body.p-chat #compose-input textarea#inp{font-size:16px}
  .p-vpn .tbl{min-width:0;table-layout:fixed}
  .p-vpn .tbl td{overflow-wrap:anywhere}
  .p-vpn .tbl td:first-child{width:6.5rem}
}
@media (hover:none){ .citem .cm{min-width:30px; min-height:30px; opacity:.6} }

/* ═══ V0.2.3 C1 — THE WINDOW CHROME (codex art. 10) ═══════════════════════════
   One .win-chrome for every window and every App page, drawn by hoop-ui.js /
   nav.js only. The three controls sit on the PHYSICAL left in every locale — the
   single sanctioned non-logical position in this file (macOS keeps them there in
   Arabic too; muscle memory beats mirroring). Everything else stays logical.
   U-04 (V0.2.10): three RGB traffic-light dots read as macOS, not Hoop Matrix — and
   they hid their glyphs until hover, the one control in the whole shell that did.
   Redrawn in the OS's own GHOST material (nothing until hover — .hbtn/.tb-b/.hr-a's
   law) closer to GNOME/elementary's quiet monochrome symbol buttons: an always-legible
   line glyph, a lift on hover, red only for the one control that discards something. */
.win-chrome{height:var(--win-h); flex:none; display:flex; align-items:center; gap:8px; padding:0 10px;
  position:relative; user-select:none;
  touch-action:none}
.win-chrome .tl{position:absolute; left:8px; top:50%; transform:translateY(-50%); display:flex; gap:0;
  direction:ltr}  /* art. 10: physical left, always */
/* .tl-host: a bar that is not a .win-chrome but wears the same lights (the stage beside Chat) */
.tl-host .tl{display:flex; gap:0; direction:ltr; flex:none}
[dir="rtl"] .tl-host .tl{order:99}   /* art. 10: physical left in RTL too — last in an RTL row */
:is(.win-chrome, .tl-host) .tl-b{width:20px; height:24px; border-radius:50%; border:0; padding:0; cursor:pointer; display:grid;
  place-items:center; color:var(--dim); background:transparent; transition:color var(--dur-1)}
/* Keep the macOS hit target, but make the resting control a quiet 12px dot. */
:is(.win-chrome, .tl-host) .tl-b::before{content:"";width:12px;height:12px;border-radius:50%;background:var(--tl-idle);transition:background var(--dur-1),transform var(--dur-1)}
:is(.win-chrome, .tl-host) .tl-b::before,
:is(.win-chrome, .tl-host) .tl-b svg{grid-area:1 / 1;}
@media (pointer:coarse){:is(.win-chrome, .tl-host) .tl-b{width:24px}}
/* each light's own colour (--tl-color): tokens.css */
:is(.win-chrome, .tl-host) .tl:hover .tl-b::before,
:is(.win-chrome, .tl-host) .tl:focus-within .tl-b::before{background:var(--tl-color);transform:scale(1.08)}
:is(.win-chrome, .tl-host) .tl-b:hover,
:is(.win-chrome, .tl-host) .tl-b:focus-visible{color:var(--fg)}
:is(.win-chrome, .tl-host) .tl-b:hover::before,
:is(.win-chrome, .tl-host) .tl-b:focus-visible::before{transform:scale(1.16)}
:is(.win-chrome, .tl-host) .tl-b svg{opacity:0;transition:opacity var(--dur-1)}
:is(.win-chrome, .tl-host) .tl:hover .tl-b svg,
:is(.win-chrome, .tl-host) .tl:focus-within .tl-b svg{opacity:1}
:is(.win-chrome, .tl-host) .tl-b:disabled{color:var(--tl-idle); cursor:default}
:is(.win-chrome, .tl-host) .tl-b:disabled{opacity:.48;}
:is(.win-chrome, .tl-host) .tl-b:disabled:hover{background:transparent; color:inherit}
:is(.win-chrome, .tl-host) .tl-b svg{width:12px; height:12px; stroke-width:1.8}
:is(.win-chrome, .tl-host) .tl-b:focus-visible{outline:none; box-shadow:var(--focus)}
:is(.win-chrome, .tl-host) .tl-b:active{transform:translateY(1px)}
/* the lights took over the stage's own close and full/split buttons (they still answer by id) */
#stage-bar.tl-host #stage-close, #stage-bar.tl-host #stage-full{display:none}
.win.idle .win-chrome .tl-b, .win:not(.focused) .win-chrome .tl-b{color:var(--tl-idle)}
.win-chrome .wc-c{margin:0 auto; display:flex; align-items:center; gap:7px; min-width:0; padding:0 76px 0 100px}
.win-chrome .wc-i{width:17px; height:17px; color:var(--brand-ink); flex:none}
.win-chrome .wc-t{flex:0 1 auto; min-width:0; margin:0; padding:0; border:0; font-size:var(--fs-sm); font-weight:500; color:var(--fg);
  font-family:var(--font-ui); line-height:1.2; overflow:hidden; text-overflow:ellipsis; white-space:nowrap}
.win-chrome .wc-t[role="button"]{cursor:pointer}
.win-chrome .wc-r{position:absolute; inset-inline-end:10px; top:50%; transform:translateY(-50%); display:flex; gap:2px}
.win-chrome .wc-r .hbtn{position:static; width:30px; height:30px}
/* the page posture: the same bar, glass, pinned on top, content flows beneath (art. 7) */
.win-chrome.page{position:fixed; top:0; inset-inline:0; z-index:40}
html.hoop-chrome body{padding-top:var(--win-h)}
html.hoop-chrome.hoop-rail body{padding-top:var(--win-h)}
/* a phone is always one App, full screen: close and minimize stay, zoom has nothing to do there */
@media (max-width:720px){:is(.win-chrome, .tl-host) .tl-zoom{display:none}}

/* free windows (≥900px): a layer of .win boxes, no scrim, z-order by focus */
/* one stacking rule: the desk sits over every page (status bar 950, browser stage 1000) and under
   the shell's own layers (reader 9400 … launcher, tray, rail, modals); it starts below the top bar,
   so a title can never slide under it */
#hoop-windows{position:fixed; inset:0; inset-inline-end:calc(var(--dock-w) + var(--dock-clear-end)); z-index:9000; pointer-events:none}
html.hoop-rail:not(.hoop-embedded) #hoop-windows{top:var(--shell-top,0px)}
.win{position:fixed; pointer-events:auto; display:flex; flex-direction:column; overflow:hidden;
  background:var(--surface); border-radius:var(--r-lg); box-shadow:var(--glass-rim), var(--shadow-pop);
  min-width:320px; min-height:220px; outline:none; animation:var(--rise)}
.win.focused{box-shadow:var(--glass-rim), var(--shadow-win-focus), var(--shadow-pop)}
.win.min{display:none}
html.hoop-window-active{overflow:hidden;overscroll-behavior:none;scrollbar-gutter:stable}
.win{overscroll-behavior:contain}
html.hoop-embedded, html.hoop-embedded body{overscroll-behavior:contain}
/* a maximised window is the whole screen (owner 2026-10-13): no corners, no rim, no gap — over the
   top bar and over the dock, which step away (html.hoop-win-max) until the window gives its size back.
   The way out stays in the window's own lights (zoom), a double-click on its title, or Esc. */
.win.max{border-radius:0; box-shadow:none; min-width:0; min-height:0}
.win.max .win-resize{display:none}
html.hoop-win-max #hooprail, html.hoop-win-max #dock-tray{visibility:hidden; pointer-events:none}
.win.dragging, .win.dragging *{user-select:none}
html.hoop-dragging iframe{pointer-events:none}
/* hosts live under <html>, beside the page's body: they take the body's type, not the root's */
html > :not(body):not(head){font:var(--fs-base)/1.7 var(--font); color:var(--fg)}
/* full screen: the same box over the whole page beside the rail (the old Matrix route surface).
   The window's own geometry stays inline underneath, so zoom gives exactly that window back. */
.win.full{left:0!important; right:0!important; top:0!important; bottom:0!important; width:auto!important; height:auto!important;
  inset-inline-start:0!important; padding-top:var(--shell-top,44px); box-sizing:border-box;
  border-radius:var(--r-xl); box-shadow:var(--glass-rim),var(--shadow-pop); background:var(--bg); min-width:0; min-height:0; animation:none}
.win.full .win-resize{display:none}
@media (max-width:720px){.win.full{inset-inline-start:0!important}}
/* the page itself as an App (hoop-ui pageHostInit): its body becomes the window, or steps aside */
html.hoop-page-window{overflow:hidden}
html.hoop-page-window body{contain:layout paint; border-radius:var(--r-lg); box-shadow:var(--glass-rim), var(--shadow-pop); z-index:1}
html.hoop-page-window .win-chrome.page{inset-inline-start:0!important; padding-inline-end:10px!important}
html.hoop-page-window .page-resize{position:fixed; z-index:50}
html:not(.hoop-page-window) .page-resize{display:none}
html.hoop-page-hidden body{visibility:hidden}
html.hoop-page-hidden body *{pointer-events:none}
.win .win-body{flex:1; min-height:0; width:100%; border:0; background:var(--bg)}
/* eight grips, one for each edge and corner (owner 2026-10-11): any side resizes the box, not only
   the bottom-right corner, and each grip's cursor names the direction it grows in */
.win-resize{position:absolute; touch-action:none; z-index:3}
.wr-n,.wr-s{left:12px; right:12px; height:6px; cursor:ns-resize}
.wr-n{top:0}
.wr-s{bottom:0}
.wr-w,.wr-e{top:12px; bottom:12px; width:6px; cursor:ew-resize}
.wr-w{left:0}
.wr-e{right:0}
.wr-nw,.wr-ne,.wr-sw,.wr-se{width:16px; height:16px}
.wr-nw{top:0; left:0; cursor:nwse-resize}
.wr-se{bottom:0; right:0; cursor:nwse-resize}
.wr-ne{top:0; right:0; cursor:nesw-resize}
.wr-sw{bottom:0; left:0; cursor:nesw-resize}
.modal-appwindow .win-chrome{cursor:default}
/* the tray: minimized windows wait as capsules at the foot of the dock column */
#dock-tray{position:fixed; inset-inline-end:10px; bottom:60px; z-index:9989; display:flex; flex-direction:column; gap:4px;
  padding:6px; border-radius:var(--r-lg); box-shadow:var(--glass-rim), var(--shadow-pop); max-width:13rem}
.tray-cap{display:flex; align-items:center; gap:8px; border:0; background:none; color:var(--fg); font:inherit;
  font-size:var(--fs-sm); padding:6px 10px 6px 8px; border-radius:var(--r-pill); cursor:pointer; max-width:100%; min-height:30px}
.tray-cap:hover{background:var(--lift)}
.tray-cap [data-icon]{width:16px; height:16px; color:var(--brand-ink); flex:none}
.tray-t{overflow:hidden; text-overflow:ellipsis; white-space:nowrap}
@media (max-width:720px){#dock-tray{inset-inline-end:auto; left:50%; transform:translateX(-50%); bottom:calc(80px + env(safe-area-inset-bottom)); flex-direction:row; max-width:calc(100vw - 32px)}}

/* ═══ V0.2.3 C2 — THE LOCK SCREEN (T3: clock · date · name · hint · card) ═════ */
.p-home .lock{min-height:100dvh; display:flex; flex-direction:column; align-items:center; justify-content:center;
  text-align:center; padding:40px 24px; cursor:default; position:relative; overflow:hidden;
  background:var(--bg)}
.p-home .lock-clock{font-family:var(--font-brand); font-size:var(--fs-display); font-weight:400; line-height:1; letter-spacing:-.03em;
  font-variant-numeric:tabular-nums; color:var(--fg)}
.p-home .lock-date{margin-top:10px; font-size:var(--fs-lg); color:var(--dim)}
.p-home .lock-name{margin-top:28px; display:flex; align-items:center; gap:10px; font-family:var(--font-brand); font-size:var(--fs-xl); color:var(--fg)}
.p-home .lock-name img{width:.55em; height:.55em; animation:breathe var(--motion-breathe) var(--ease-loop) infinite}
.p-home .lock-ava{width:64px; height:64px; border-radius:50%; overflow:hidden; background:var(--surface-2); display:grid; place-items:center;
  font-family:var(--font-brand); font-size:var(--fs-2xl); color:var(--brand-ink); margin-top:28px}
.p-home .lock-ava img{width:100%; height:100%; object-fit:cover}
.p-home .lock-hint{position:absolute; bottom:40px; inset-inline:0; color:var(--dim); font-size:var(--fs-sm); opacity:.8; animation:lockhint var(--motion-breathe) var(--ease-loop) infinite}
@keyframes lockhint{0%,100%{opacity:.35}50%{opacity:.85}}
.p-home .lock.ready .lock-hint{display:none}
.p-home .lock-card{position:absolute; inset:0; display:flex; align-items:flex-end; justify-content:center; padding:20px 20px 12vh;
  background:color-mix(in oklab, var(--bg) 25%, transparent); -webkit-backdrop-filter:blur(6px); backdrop-filter:blur(6px);
  animation:fade var(--dur-2) var(--ease)}
.p-home .lock.ready .lock-clock{font-size:calc(var(--fs-display) * .6)}
.p-home .lock.ready .lock-clock, .p-home .lock.ready .lock-date, .p-home .lock.ready .lock-name{transform:translateY(-16vh)}
.p-home .lock-clock, .p-home .lock-date, .p-home .lock-name{transition:transform var(--dur-3) var(--ease), font-size var(--dur-3) var(--ease)}
.p-home .lock-name img{min-width:22px; min-height:22px}
.p-home .lock-card form{width:min(22rem, 100%); padding:26px 24px 20px; border-radius:var(--r-2xl); display:flex; flex-direction:column; gap:10px;
  box-shadow:var(--glass-rim), var(--shadow-pop); animation:var(--rise)}
.p-home .lock-card h2{margin:0 0 6px; font-size:var(--fs-lg); font-weight:500; text-align:center}
.p-home .lock-card input{width:100%}
.p-home .lock-card .btn{margin-top:6px}
.p-home .lock-err{min-height:1.2em; color:var(--bad); font-size:var(--fs-sm); text-align:center}
.p-home .lock-card .fine{color:var(--dim); font-size:var(--fs-xs); text-align:center; margin-top:4px}
@media (prefers-reduced-transparency:reduce){.p-home .lock-card{-webkit-backdrop-filter:none; backdrop-filter:none; background:var(--bg)}}
@media (prefers-reduced-motion:reduce){.p-home .lock-name img, .p-home .lock-hint, .p-home .lock-card, .p-home .lock-card form{animation:none}}
html.hoop-idle .p-home .lock-name img{animation-play-state:paused}

/* ═══ V0.2.3 C5 — THE DESKTOP (Home ≥900px): menu bar on top, widgets below ═══ */
.p-home .menubar{position:fixed; top:0; inset-inline:0; height:30px; z-index:950; display:none; align-items:center; gap:6px;
  padding:0 12px; font-size:var(--fs-sm); color:var(--fg)}
@media (min-width:900px){.p-home.desktop .menubar{display:flex} .p-home.desktop .pa-home{padding-top:clamp(56px,7vw,88px)}}

/* The classic home is a desktop: owner files stay in a quiet left column behind App windows. */
.home-files-desk{position:fixed;z-index:20;inset-block-start:calc(var(--shell-top,0px) + 72px);inset-inline-start:calc(var(--matrix-w,0px) + 18px);inline-size:188px;padding:10px;pointer-events:auto}
.home-files-head{display:flex;align-items:center;gap:7px;padding:2px 4px 8px;color:var(--fg)}.home-files-head svg{inline-size:17px}.home-files-head strong{font-size:var(--fs-md);flex:1}.home-files-head button{border:0;background:none;color:var(--dim);font-size:var(--fs-xl);line-height:1;cursor:pointer}
.home-files-list{display:grid;gap:2px;max-block-size:calc(100vh - 220px);overflow:auto}.home-file{display:flex;align-items:center;gap:8px;min-block-size:36px;padding:5px 7px;border:0;border-radius:var(--r-sm);background:transparent;color:var(--fg);text-align:start;cursor:pointer}.home-file:hover,.home-file:focus-visible{background:color-mix(in srgb,var(--own) 12%,transparent);outline:0}.home-file-icon{display:grid;place-items:center;inline-size:22px;flex:none;color:var(--own)}.home-file-icon svg{inline-size:20px;block-size:20px}.home-file-name{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:var(--fs-xs)}.home-files-empty{padding:8px 6px;color:var(--dim);font-size:var(--fs-xs)}.home-files-actions{display:flex;gap:5px;padding:8px 2px 0}.home-files-actions button{flex:1;min-block-size:30px;padding:4px 5px;border:1px solid color-mix(in srgb,var(--fg) 18%,transparent);border-radius:var(--r-xs);background:transparent;color:var(--dim);font-size:var(--fs-2xs);cursor:pointer}.home-files-actions button:hover,.home-files-actions button:focus-visible{color:var(--fg);border-color:var(--own);outline:0}
@media (max-width:899px){.home-files-desk{display:block;inset-block-start:auto;inset-block-end:var(--sp-3,12px);inset-inline-start:var(--sp-3,12px);inset-inline-end:var(--sp-3,12px);inline-size:auto;max-block-size:42vh}.home-files-list{display:flex;gap:4px;max-block-size:96px;overflow-x:auto;overflow-y:hidden}.home-file{flex:0 0 112px;min-block-size:44px}.home-files-actions{padding-top:6px}}
.p-home .mb-b{border:0; background:none; font:inherit; font-size:var(--fs-sm); color:var(--fg); padding:3px 9px; border-radius:var(--r-sm);
  cursor:pointer; display:inline-flex; align-items:center; gap:6px; min-height:24px}
.p-home .mb-b:hover, .p-home .mb-b.on{background:transparent; color:var(--fg)}
.p-home .menubar .hr-ava-menubar{display:inline-grid;width:24px;height:24px;place-items:center;margin-inline-start:-3px;margin-inline-end:calc(-1 * var(--sp-1));color:var(--brand-ink);border:0;background:transparent;cursor:pointer;padding:0}
.p-home .menubar .hr-ava-menubar svg{width:16px;height:16px}
.p-home .menubar .hr-ava-menubar:hover,.p-home .menubar .hr-ava-menubar:focus-visible{color:var(--fg);background:var(--lift);border-radius:var(--r-pill);outline:0}
.p-home .mb-app{font-weight:500}
/* the top bar on the terminal desktop (owner 2026-10-15): the name on the left, ONE changing fact on the
   right — version, how long it has run, VPN, backup, disk — so the bar never crowds the page */
.p-home .menubar{font-family:var(--mono)}
.p-home .mb-app{color:var(--tty-accent,var(--fg))}
.p-home .mb-facts{display:flex; align-items:center; justify-content:flex-end; gap:2.5ch; font-size:var(--fs-xs);
  min-inline-size:22ch; font-variant-numeric:tabular-nums}
/* the next fact eases in so the eye follows it; with less motion asked for the tokens turn it to no time */
.p-home .mb-facts.swap .tf{animation:var(--rise)}
.p-home .mb-sp{flex:1}
.p-home .mb-s{display:inline-flex; align-items:center; gap:5px; color:var(--dim); padding:3px 7px; border-radius:var(--r-sm); cursor:default}
.p-home .mb-s [data-icon]{width:15px; height:15px}
.p-home .mb-s.ok{color:var(--fg)} .p-home .mb-s.warn{color:var(--warn)}

/* ═══ V0.2.3 C4 — SYSTEM SETTINGS additions ═══════════════════════════════════ */
html.hoop-reduce-motion *, html.hoop-reduce-motion *::before, html.hoop-reduce-motion *::after{animation:none!important; transition:none!important}
html.hoop-reduce-transparency .glass, html.hoop-reduce-transparency .bar-glass, html.hoop-reduce-transparency .modal, html.hoop-reduce-transparency .menu,
html.hoop-reduce-transparency .toast, html.hoop-reduce-transparency #dock-tray{
  background:var(--surface); -webkit-backdrop-filter:none; backdrop-filter:none}
.about-mark{display:flex; align-items:center; gap:14px; margin-bottom:12px}
.about-mark img{width:var(--tap); height:var(--tap)}
.about-mark b{display:block; font-weight:500; font-size:var(--fs-lg); font-family:var(--font-brand)}
.kv .k.kbd{font-family:var(--mono); font-size:var(--fs-sm)}
.wall-upload{display:flex;align-items:center;gap:10px;flex-wrap:wrap;padding:12px 0 4px}.wall-upload .btn{display:inline-flex;align-items:center;gap:7px}.wall-upload [data-icon]{width:17px;height:17px}
html[data-wall="plain"] .p-home .lock{background:var(--bg)}
html[data-wall="ink"] .p-home .lock{background:var(--bg)}

/* V0.2.7 G: the three-step card's links and the VPN sheets use the UI voice, not the page's mono */
.p-fin #tr-howto ol a{color:var(--accent); text-decoration:none}
.p-vpn .menu{font-family:var(--font-ui)}

/* ═══ V0.2.12 — the owner's browser App (p-browser) ═══════════════════════════════════════ */
.p-browser main{max-width:78rem}
.br-stage{aspect-ratio:16/10; min-height:20rem; background:var(--ink-stage); border-radius:var(--r-md); overflow:hidden}
.br-stage.full{position:fixed; inset:0; z-index:1000; aspect-ratio:auto; border-radius:0; min-height:0}
.br-unfull{position:absolute; inset-block-start:8px; inset-inline-end:8px; z-index:2}
.br-stage{position:relative}
.br-video{object-fit:contain; touch-action:none; cursor:default; outline:none}
.br-keys{position:absolute; inset-block-start:0; inset-inline-start:0; width:1px; height:1px; opacity:0; border:0; padding:0; resize:none; pointer-events:none}
.br-tap{position:absolute; inset-block-start:50%; inset-inline-start:50%; transform:translate(-50%,-50%); z-index:2}
/* watching by default: the picture is not a remote mouse pad until 接手 */
.br-mode{position:absolute; inset-block-start:var(--sp-2, 8px); inset-inline-start:var(--sp-2, 8px); z-index:2; padding:2px 10px; border-radius:var(--r-pill); font-size:var(--fs-xs, 12px); line-height:20px; color:var(--fg); background:var(--surface); opacity:.85; pointer-events:none}
.br-mode:empty{display:none}
.br-mine .br-mode{color:var(--on-brand); background:var(--brand); opacity:1}
.br-mine{outline:2px solid var(--brand); outline-offset:-2px}
.br-ask{position:absolute; inset-inline:var(--sp-3, 12px); inset-block-end:var(--sp-3, 12px); z-index:3; display:flex; gap:var(--sp-2, 8px); align-items:center; justify-content:space-between; padding:var(--sp-2, 8px) var(--sp-3, 12px); border-radius:var(--r-md); background:var(--surface); color:var(--fg); box-shadow:var(--lift)}
.br-ask[hidden]{display:none}
.p-browser .br-stage:not(.br-mine) .br-video{cursor:default; touch-action:auto}
html.br-full{overflow:hidden}
.lx-frame{display:block;width:100%;height:100%;border:0;background:var(--ink-stage)}
.lx-stage{position:relative; min-height:24rem}
.lx-empty{position:absolute; inset:0; display:flex; flex-direction:column; align-items:center; justify-content:center; gap:10px; color:var(--dim); text-align:center; padding:24px}
.lx-empty [data-icon]{width:40px; height:40px}
.lx-empty p{max-width:30rem; margin:0; font-size:var(--fs-md)}
.lx-bar{display:flex; align-items:center; gap:8px; margin:12px 0 10px}
.lx-sp{flex:1}
.lx-state{display:inline-flex; align-items:center; gap:8px; color:var(--dim); font-size:var(--fs-sm)}
.lx-dot{width:8px; height:8px; border-radius:50%; background:var(--line-2)}
.lx-state.on .lx-dot{background:var(--ok)} .lx-state.busy .lx-dot{background:var(--brand); animation:breathe var(--motion-pulse) var(--ease-loop) infinite} .lx-state.bad .lx-dot{background:var(--bad)}
.lx-row{display:flex; align-items:center; gap:10px; padding:8px 0; border-bottom:1px solid var(--line)}
.lx-row:last-child{border-bottom:0}
.lx-row b{flex:1; min-width:0; display:-webkit-box; -webkit-line-clamp:2; -webkit-box-orient:vertical; overflow:hidden; overflow-wrap:anywhere; font-weight:500; font-size:var(--fs-md)}
html.hoop-embedded .p-browser main{max-width:none; padding:10px 12px}
html.hoop-embedded .p-browser h1.app, html.hoop-embedded .p-browser .lede{display:none}

/* ═══ P1-b — /handoff: the owner's own hands on the AI's browser (phone first) ═════════════ */
.p-handoff main{max-width:56rem}
.hd-list{display:flex; flex-wrap:wrap; gap:6px; margin-block-end:10px}
.hd-item{border:1px solid var(--line-2); background:transparent; color:var(--fg); border-radius:var(--r-pill);
  padding:5px 12px; font:inherit; font-size:var(--fs-sm); cursor:pointer; max-width:100%; text-align:start}
.hd-item.on{border-color:var(--accent); color:var(--accent); background:transparent}
.hd-card{margin-block-end:10px}
.hd-reason{display:flex; gap:8px; align-items:baseline; flex-wrap:wrap}
.hd-label{color:var(--dim); font-size:var(--fs-sm)}
.hd-reason b{font-weight:600; overflow-wrap:anywhere}
.hd-stage{position:relative; background:var(--ink-stage); border-radius:var(--r-md); overflow:hidden; min-height:12rem}
/* the picture is the viewport: touch-action none so a drag is a drag, and no long-press menu */
.hd-shot{display:block; width:100%; height:auto; touch-action:none; user-select:none; -webkit-user-drag:none; cursor:crosshair}
.hd-wait{position:absolute; inset:0; display:flex; align-items:center; justify-content:center; gap:8px;
  color:var(--on-scrim); background:var(--scrim); font-size:var(--fs-sm)}
.hd-spin{width:10px; height:10px; border-radius:50%; background:var(--brand); animation:breathe var(--motion-pulse) var(--ease-loop) infinite}
.hd-row{display:flex; gap:8px; align-items:center; margin-block:8px 0; flex-wrap:wrap}
.hd-input{flex:1 1 12rem; min-width:0; font-size:16px}
.hd-finish{margin-block-start:12px}
@media(max-width:720px){
  .p-handoff main{padding-inline:12px}
  .hd-stage{min-height:9rem}
  .hd-row .btn{flex:0 0 auto}
  .hd-input{flex:1 1 100%}
}

/* ── P1-b 交接提醒: 主人正在对话时，这里也要看得见"AI 在等你" ─────────────────────
   /handoff 是主人动手的那一页，这里只是提醒：一张 .card 挂在对话上方，滚动时钉在顶栏
   下面（顶栏 58px 透明，卡片因此压在它下沿、z-index 低于它的 4），没有等待的东西就消失。
   和 Full Agency 的确认卡同一个语法：左边一道 accent 竖线，一眼看出是"要你"的事。 */
#hn-card{display:none}
#hn-card:not([hidden]){display:flex; align-items:center; gap:12px; flex-wrap:wrap;
  position:sticky; top:calc(58px + env(safe-area-inset-top)); z-index:2;
  margin:0 0 12px; border-inline-start:1px solid var(--accent); box-shadow:var(--focus)}
body.stage-on #hn-card{position:static}   /* 台上开着应用时不钉住，免得压住消息 */
#hn-card .hn-say{flex:1 1 auto; min-width:0}
#hn-card .hn-reason{color:var(--fg); font-size:var(--fs-md); overflow-wrap:anywhere}
#hn-card .hn-more{color:var(--dim); font-size:var(--fs-sm); margin-block-start:3px}
#hn-card .hn-go{flex:none}

/* ── Full Agency (主人点击 = 同意；系统拦冒充不拦人): confirm-cards, badge, kill switch ── */
#cards{display:flex; flex-direction:column; gap:10px; margin:0 0 12px}
.fa-card{border-left:1px solid var(--accent); box-shadow:var(--focus)}
.fa-card .fa-lvl-note{margin-block:2px 6px}
.fa-card .fa-cmd-cap{margin-block-end:2px}
.fa-card .fa-audit .fa-audit-link{color:var(--accent)}
.fa-card.lvl-L3{border-left-color:var(--bad); box-shadow:none}
.fa-card.lvl-L1{border-left-color:var(--line-2); box-shadow:none}
.fa-card h4 .fa-lvl{font-size:var(--fs-sm); padding:.05em .5em; border-radius:var(--r-pill); background:var(--code); color:var(--dim); margin-inline-start:8px}
.fa-card.lvl-L3 h4 .fa-lvl{color:var(--bad)}
.fa-card pre{font-family:var(--mono, ui-monospace, monospace); user-select:all}
.fa-card .row input{flex:1 1 200px; min-width:0}
.fa-card.done{opacity:.7}
.fa-card.auto-pending{border-left-color:var(--brand)}.fa-card .fa-auto-note{color:var(--brand-ink)}
.hbtn.fa-badge{gap:6px; color:var(--accent); font-size:var(--fs-sm)}
.hbtn.fa-badge .fa-dot{width:8px; height:8px; border-radius:50%; background:var(--accent)}
.hbtn.fa-badge.paused{color:var(--bad)} .hbtn.fa-badge.paused .fa-dot{background:var(--bad)}
.hbtn.fa-stop{color:var(--bad); gap:4px; font-size:var(--fs-sm)}
/* the two text buttons in the chat header (Full Agency badge, 急停) size to their words instead of the icon-button box, so they never overlap */
.fa-box{margin-top:14px; padding-top:12px; border-top:1px solid var(--line)}
.fa-box input, .fa-box select{min-width:120px}
.agency-options{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:10px;margin-block:12px}
.agency-setup{margin:24px auto 8px;padding:16px;text-align:start;border:1px solid var(--line-soft);border-radius:var(--r-xl);background:var(--paper);box-shadow:var(--shadow-pop)}
.agency-setup h2{margin:0;font-size:var(--fs-h)}.agency-setup>p{margin:7px 0;color:var(--dim);font-size:var(--fs-sm);line-height:1.45}
.agency-option{display:flex;flex-direction:column;align-items:flex-start;gap:4px;min-height:64px;padding:12px 14px;border:1px solid var(--line-soft);border-radius:var(--r-md);background:var(--paper);color:var(--fg);text-align:start;cursor:pointer}
.agency-option strong{font-size:var(--fs-ui)}.agency-option span{color:var(--dim);font-size:var(--fs-sm);line-height:1.35}
.agency-option:hover,.agency-option.selected{border-color:var(--brand);box-shadow:var(--focus)}
.agency-option-primary{background:color-mix(in srgb,var(--brand) 9%,var(--paper))}
.agency-option:disabled{opacity:.6;cursor:wait}.agency-os-note{margin-block:10px 0;color:var(--dim);font-size:var(--fs-sm)}
@media (max-width:520px){.agency-options{grid-template-columns:1fr}}


/* ═══ 点将台 in the Sessions view (0.2.17 W3) ═══════════════════════════════
   One rail, top to bottom: the Commander gives the order → a general carries it →
   that general's run is what is actually happening. Nothing here invents a number:
   an unobserved rate says so. */
#check-native.tk-native .tk-commander{margin:0 0 10px}
.mc-card{border:1px solid var(--line); border-radius:var(--r-lg); background:var(--surface-2); padding:10px 12px}
.mc-card.mc-down{background:var(--lift)}
.mc-head{display:flex; align-items:center; gap:8px; flex-wrap:wrap}
.mc-title{margin:0; font-size:var(--fs-h); font-weight:600; letter-spacing:.06em}
.mc-sp{flex:1}
.mc-ico{flex:none; display:grid; place-items:center; width:22px; height:22px; color:var(--brand-ink)}
.mc-ico svg{width:16px; height:16px}
.mc-meta{color:var(--dim); font-size:var(--fs-2xs); white-space:nowrap}
.mc-note{color:var(--dim); font-size:var(--fs-xs); margin:2px 0}
.mc-scope{font-family:var(--mono, ui-monospace, monospace); overflow-wrap:anywhere; white-space:normal}
.mc-pill{font-size:var(--fs-2xs); padding:1px 8px; border-radius:var(--r-pill); flex:none; font-weight:500}
.mc-pill[data-band="observed"]{color:var(--ok); background:color-mix(in oklab, var(--ok) 14%, transparent)}
.mc-pill[data-band="working"],.mc-pill[data-band="command"]{color:var(--brand-ink); background:var(--brand-soft)}
.mc-pill[data-band="gate"]{color:var(--warn); background:color-mix(in oklab, var(--warn) 16%, transparent)}
.mc-pill[data-band="paused"],.mc-pill[data-band="done"]{color:var(--accent); background:color-mix(in oklab, var(--accent) 13%, transparent)}
.mc-pill[data-band="bad"]{color:var(--bad); background:color-mix(in oklab, var(--bad) 14%, transparent)}
.mc-pill[data-band="idle"]{color:var(--dim); background:var(--lift)}
/* the Commander node — everything below hangs off it */
.mc-commander{display:flex; gap:10px; align-items:flex-start; margin-top:10px; padding:8px 10px;
  border:1px solid var(--line-2); border-radius:var(--r-md); background:var(--surface)}
.mc-role{font-size:var(--fs-2xs); color:var(--brand-ink); background:var(--brand-soft); padding:1px 8px; border-radius:var(--r-pill)}
.mc-name{font-weight:600}
.mc-goal{font-size:var(--fs-xs)}
.mc-goal-full{font-size:var(--fs-md); margin:6px 0}
/* the rail down to the generals */
.mc-tree{list-style:none; margin:0; padding:0 0 0 20px; position:relative}
.mc-tree::before{content:""; position:absolute; inset-block:0 22px; inset-inline-start:10px; width:1px; background:var(--line-2)}
.mc-gen{position:relative}
.mc-gen::before{content:""; position:absolute; inset-inline-start:-10px; top:22px; width:10px; height:1px; background:var(--line-2)}
.mc-gen-row{display:flex; gap:10px; align-items:flex-start; padding:8px 0}
.mc-gen + .mc-gen .mc-gen-row{border-top:1px solid var(--line-soft)}
.mc-gen-main{flex:1; min-width:0; display:flex; flex-direction:column; gap:3px}
.mc-row-head{display:flex; align-items:center; gap:8px; flex-wrap:wrap}
.mc-run{display:flex; gap:8px; align-items:center; flex-wrap:wrap; text-align:start; margin-top:2px;
  padding:4px 8px; border:1px solid var(--line); border-radius:var(--r-sm); background:var(--surface); color:inherit; font:inherit; cursor:pointer}
.mc-run:hover{border-color:var(--line-2)}
.mc-run-id{font-family:var(--mono, ui-monospace, monospace); font-size:var(--fs-2xs); color:var(--dim)}
.mc-run-goal{font-size:var(--fs-xs); flex:1; min-width:0; text-align:start}
.mc-acts{flex:none; display:flex; flex-direction:column; gap:4px; align-items:stretch}
.mc-acts .btn{min-height:0; padding:4px 10px; font-size:var(--fs-xs)}
.mc-dialog-body{padding:12px 16px 16px; overflow-y:auto}
.mc-events{list-style:none; margin:8px 0 0; padding:0; display:flex; flex-direction:column; gap:2px}
.mc-event{display:flex; gap:8px; align-items:baseline}
.mc-event-k{font-family:var(--mono, ui-monospace, monospace); font-size:var(--fs-2xs)}
.mc-receipt{display:block; margin-top:6px; font-size:var(--fs-xs); color:var(--dim)}
@media (max-width:560px){
  .mc-gen-row{flex-wrap:wrap}
  .mc-acts{flex-direction:row; flex:1 0 100%}
  .mc-acts .btn{flex:1}
}

/* Hoop Matrix: native navigation and one conversation/work surface. */
.home-welcome a:focus-visible{outline:2px solid var(--brand);outline-offset:3px}
.p-chat #hdr{gap:10px}
.p-chat #ctitle{font-size:var(--fs-md);color:var(--dim);min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.p-chat #cwrap{border-radius:0;padding:0;box-shadow:none}
.p-chat #inp{line-height:1.6;min-height:48px}
.p-chat #codehello .hi{font-family:var(--font);font-size:clamp(24px,3vw,36px);letter-spacing:-.025em}
.p-chat #codehello .sub{max-width:34rem;margin:12px auto 24px;line-height:1.7}
.p-chat #codebar{border-bottom:1px solid var(--line-soft);padding-bottom:12px}
.home-welcome{display:flex;align-items:center;justify-content:space-between;gap:24px;margin:0 0 28px}
.home-welcome h1{font:400 clamp(28px,4vw,42px)/1.2 var(--font);letter-spacing:-.035em;margin:6px 0}
.home-welcome nav{display:flex;gap:10px}
.home-welcome a{display:flex;gap:28px;align-items:center;padding:13px 20px;border:1px solid var(--line);border-radius:var(--r-md);background:var(--surface);color:var(--fg);text-decoration:none;font:500 var(--fs-h) var(--font)}
.home-welcome a:hover{background:var(--surface-2)}
.home-welcome a span{color:var(--dim)}
.browser-address{display:flex;gap:8px;margin-bottom:8px}
.browser-address input{flex:1;min-width:0;font-size:16px}
.p-browser .br-stage{height:calc(100dvh - 250px);min-height:360px;aspect-ratio:auto}
.p-browser .br-stage.full{height:100dvh;min-height:0}
@media(max-width:720px){
  html.hoop-rail #hooprail{left:50%;right:auto;inset-inline-end:auto;transform:translateX(-50%);bottom:calc(10px + env(safe-area-inset-bottom));flex-direction:row;gap:4px;padding:4px 8px;border:1px solid var(--line);border-radius:var(--r-pill);background:var(--surface);box-shadow:var(--shadow-1)}
  html.hoop-rail #hooprail .hr-home{display:flex}
  html.hoop-rail body[class]{padding-bottom:calc(76px + env(safe-area-inset-bottom))}
  .p-chat #hdr{gap:5px}
  .p-chat #ctitle{max-width:24vw}
  .home-welcome{gap:12px;flex-wrap:wrap}
  .home-welcome nav{width:100%}
  .home-welcome a{flex:1;justify-content:space-between}
  .p-browser .br-stage{height:calc(100dvh - 300px);min-height:260px}
}
.p-chat #codebar{flex-wrap:wrap}
.p-chat #codepicks{flex:1 1 100%}
.p-chat #codeback{display:none}
.p-chat #codecoordbtn{margin-inline-start:auto}
.p-chat header #ctitle{display:block}
@media(max-width:720px){
  html.hoop-rail #hooprail{top:auto;min-width:204px;max-width:calc(100vw - 24px);height:54px;z-index:9990}
  html.hoop-rail .p-chat #composer{bottom:calc(76px + env(safe-area-inset-bottom));padding-inline:12px}
  html.hoop-rail .p-chat #msgs{padding-inline:12px}
  .p-chat #msgs{padding-bottom:calc(var(--composer-h, 128px) + 20px + env(safe-area-inset-bottom))}
  body.stage-on #msgs{padding-top:58px}
  .p-chat header #ctitle{display:none}
}
body.codemode.emptyconv #msgs{display:none}
body.codemode #codepane{overflow:hidden}
body.codemode #codehello{margin-top:clamp(32px,8vh,96px)}
body.codemode #codebar{padding-top:calc(64px + env(safe-area-inset-top))}
/* The mobile drawer used to place the entire app above its navigation. */
@media(max-width:900px){body.p-chat:not(.sideopen) #main{z-index:1}}
@media(min-width:901px){#newconv-top{display:none}}
@media(max-width:900px){#newconv-top{display:grid}}

.home-shortcut-open{text-decoration:none;color:inherit}
.phone-head,.phone-plan,.phone-list-head,.phone-actions,.phone-message-meta{display:flex;align-items:center;justify-content:space-between;gap:16px}.phone-head{margin-bottom:24px}.phone-head h1{margin-bottom:4px}.phone-plan{padding:20px 22px;margin-bottom:18px}.phone-plan>div:first-child{display:grid;gap:4px}.phone-plan .eyebrow,.phone-quote .eyebrow{font-size:var(--fs-xs);text-transform:uppercase;letter-spacing:.08em;color:var(--dim)}.phone-plan #phone-number{font:600 var(--fs-2xl)/1.2 var(--mono,monospace)}.phone-price{text-align:end;display:grid;gap:2px}.phone-price strong{font-size:var(--fs-3xl)}.phone-price span{font-size:var(--fs-xs);color:var(--dim)}.phone-empty{padding:28px;display:grid;gap:22px}.phone-empty-copy{display:flex;gap:14px;align-items:flex-start}.phone-empty h2{margin:0 0 6px}.phone-empty p{margin:0}.phone-step{display:grid;place-items:center;width:30px;height:30px;border-radius:50%;background:var(--brand);color:var(--brand-ink);font-weight:700;flex:none}.phone-country{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:8px;align-items:end}#phone-country{min-width:0}.phone-country .pick{border:1px solid var(--line-soft);border-radius:var(--r-in);background:var(--paper)}.phone-wait{display:flex;align-items:center;gap:12px;padding:18px 0}.phone-spinner{width:20px;height:20px;border:1px solid var(--line);border-top-color:var(--brand);border-radius:50%;animation:phone-spin var(--motion-pulse) var(--ease-linear) infinite}.phone-quote{padding:20px;display:grid;gap:18px}.phone-quote>div:first-child{display:grid;gap:5px}.phone-quote #phone-found-number{font:600 var(--fs-xl)/1.2 var(--mono,monospace)}.phone-quote dl{margin:0;display:grid;gap:8px}.phone-quote dl div{display:flex;justify-content:space-between;gap:18px}.phone-quote dt{color:var(--dim)}.phone-quote dd{margin:0;text-align:end}.phone-recover{display:grid;gap:10px}.phone-recover .btn{justify-self:start}.phone-compose{padding:20px;margin-bottom:24px}.phone-compose label{display:grid;gap:7px;margin-bottom:14px;font-weight:600}.phone-compose input,.phone-compose textarea{font:inherit}.phone-compose textarea{resize:vertical}.phone-list-head{margin:10px 0}.phone-list-head h2{margin:0}.phone-messages{display:grid;gap:10px}.phone-message{padding:16px 18px;border:1px solid var(--line);border-radius:var(--r-md);background:var(--surface)}.phone-message-meta{font-size:var(--fs-md)}.phone-message-meta time{color:var(--dim)}.phone-message p{white-space:pre-wrap;margin:9px 0 0;line-height:1.55}@keyframes phone-spin{to{transform:rotate(360deg)}}@media(prefers-reduced-motion:reduce){.phone-spinner{animation:none}}@media(max-width:620px){.phone-head,.phone-plan{align-items:flex-start}.phone-head{flex-direction:column}.phone-plan{flex-direction:column}.phone-price{text-align:start}.phone-country{grid-template-columns:1fr}.phone-country .btn{width:100%}.phone-compose{padding:16px}}

/* Hoop Matrix desktop: name · line · tree */
.p-home .home-welcome{display:flex;align-items:flex-end;justify-content:space-between;gap:16px}
.p-home .home-command{position:relative;margin:28px auto 20px;max-width:960px}
.p-home .home-ask-results{position:static;margin-top:10px;padding:12px 16px;white-space:pre-wrap;font:inherit;font-size:var(--fs-sm);color:var(--fg);max-height:14rem;overflow:auto}
.p-home .home-tree-wrap{max-width:960px;margin:0 auto}
.p-home .home-section-head{display:flex;align-items:baseline;justify-content:space-between;gap:12px;flex-wrap:wrap}
.p-home .home-trunk{display:inline-flex;align-items:center;gap:12px;font-size:var(--fs-sm);color:var(--dim)}
.p-home .home-trunk b{color:var(--fg);font-weight:600}
.p-home .home-trunk-update{border:1px solid var(--brand);background:transparent;color:var(--brand-ink);border-radius:var(--r-pill);padding:4px 12px;font-size:var(--fs-xs);cursor:pointer}
.p-home .home-tree{display:grid;gap:4px;margin-top:10px}
.p-home .home-branch{display:grid;grid-template-columns:20px minmax(8rem,1fr) 30px 4rem 4rem;align-items:center;gap:9px;padding:8px 10px;border-radius:var(--r-md);background:color-mix(in srgb,var(--bg) 60%,transparent)}
.p-home .home-branch-icon{width:20px;height:20px;color:var(--dim)}
.p-home .home-branch-state{display:inline-flex;align-items:center;justify-content:center;min-width:28px;color:var(--dim);font-size:var(--fs-sm);line-height:1;}
.p-home .home-branch-state[aria-label]{cursor:help}
.p-home .home-branch.grown .home-branch-icon,.p-home .home-branch.trunk .home-branch-icon{color:var(--brand-ink)}
.p-home .home-branch.grown .home-branch-state,.p-home .home-branch.trunk .home-branch-state{color:var(--ok)}
.p-home .home-branch.absent{opacity:.45}
.p-home .home-branch b{font-weight:600}
.p-home .home-branch-detail{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}
.p-home .home-branch-open{grid-column:4;justify-self:end;color:var(--brand-ink);text-decoration:none;font-size:var(--fs-sm)}
.p-home .home-branch-open:hover{text-decoration:underline}
.p-home .home-branch-cut{grid-column:5;justify-self:end;border:0;background:none;color:var(--dim);font-size:var(--fs-xs);cursor:pointer;padding:4px 6px}
.p-home .home-branch-cut:hover{color:var(--fg)}
.p-home .home-branch-grow{grid-column:4 / span 2;justify-self:end}
.p-home .home-tree-note{margin:0;color:var(--dim);font-size:var(--fs-sm)}
.p-home .home-apps-wrap{max-width:960px;margin:16px auto 0}
.p-home .home-apps{display:grid;gap:8px;margin-top:10px}
.p-home .home-app{display:grid;grid-template-columns:20px minmax(0,1fr) auto;align-items:center;gap:10px;padding:8px 10px;border-radius:var(--r-md);background:color-mix(in srgb,var(--bg) 60%,transparent)}
.p-home .home-app > [data-icon]{width:20px;height:20px;color:var(--brand-ink)}
.p-home .home-app .btn [data-icon] svg{width:15px;height:15px}
.p-home .home-app-text{display:grid;min-width:0}
.p-home .home-app-text b{font-weight:600}
.p-home .home-app-text span{color:var(--dim);font-size:var(--fs-xs)}
@media (max-width:640px){.p-home .home-branch{grid-template-columns:20px minmax(0,1fr) 28px 3rem 3rem;gap:7px;padding:8px}.p-home .home-branch-grow{grid-column:4 / span 2}}
.phone-forward{padding:20px;margin-top:24px;display:grid;gap:14px}
.phone-forward h2{margin:0 0 4px;font-size:var(--fs-xl)}
.phone-forward h3{font-size:var(--fs-md)}
.phone-forward p{margin:0}
.phone-forward-addr{display:grid;gap:6px}
.phone-forward-addr input{font:inherit}
.phone-forward-token{display:grid;gap:6px}
.phone-forward-token code{font-size:var(--fs-sm);word-break:break-all}
.phone-forward-actions{display:flex;flex-wrap:wrap;gap:8px}
.phone-forward-steps{margin:0;padding-inline-start:20px;display:grid;gap:6px;line-height:1.55}
.phone-tag{border:1px solid var(--line);border-radius:var(--r-in);padding:1px 7px;font-size:var(--fs-xs);color:var(--dim)}

/* Member administration: password-confirmed forms also fit a narrow phone. */
.p-members form{display:grid;gap:var(--sp-3);margin-block-start:var(--sp-4)}
.p-members label{display:flex;flex-direction:column;gap:var(--sp-2)}
.p-members input:not([type="checkbox"]),.p-members select{inline-size:100%;box-sizing:border-box}
.p-members fieldset{border:1px solid var(--line);padding:var(--sp-3);min-inline-size:0}
.p-members fieldset label{display:inline-flex;flex-direction:row;align-items:center;gap:var(--sp-2);margin-inline-end:var(--sp-3);margin-block:var(--sp-2)}
.p-members button{justify-self:start;min-block-size:var(--tap)}
.p-members code{overflow-wrap:anywhere}

/* A single-line input surface, with quiet session settings underneath. */
.p-chat #composer{background:var(--bg);padding-top:12px;padding-bottom:20px}
.p-chat #cwrap{padding:0;border:0;border-radius:0;background:var(--bg);box-shadow:none;gap:6px}
.p-chat #cwrap:focus-within{box-shadow:none}
.p-chat #compose-input{position:relative;display:flex;align-items:flex-end;gap:4px;padding:7px 8px;border:1px solid var(--line-2);border-radius:var(--r-lg);background:var(--surface);box-shadow:var(--shadow-1);transition:border-color var(--dur-2)}
.p-chat #compose-input::before{content:"";position:absolute;inset:-1px;border-radius:inherit;pointer-events:none;box-shadow:var(--focus-chat-input);opacity:0;transition:opacity var(--dur-2)}
.p-chat #compose-input:focus-within{border-color:color-mix(in oklab,var(--brand) 22%,var(--line-2))}
.p-chat #compose-input:focus-within::before{opacity:1}
.p-chat #compose-input .cbtn{width:36px;height:36px;margin:0;flex-shrink:0}
.p-chat #compose-input .cbtn:hover{background:var(--lift)}
.p-chat #inp{flex:1;min-width:0;width:0;border:0;border-radius:0;background:transparent;padding:6px 4px;min-height:36px;font-size:var(--fs-md);line-height:24px;box-shadow:none}
.p-chat #compose-settings{display:flex;align-items:center;gap:8px;min-width:0;padding:0 4px}
.p-chat #compose-settings #composer-context{flex:0 1 auto;min-width:0}
.p-chat #composer-context button>span:last-child{overflow:hidden;text-overflow:ellipsis}
.p-chat #compose-settings #crail{flex:1;min-width:0;justify-content:flex-end}
.p-chat #compose-settings #mpick{max-width:min(100%,24rem)}
.p-chat #charn{position:static;align-self:flex-end;padding-inline:8px}
.p-chat #session-controls{padding:0 4px 4px}
.p-chat #inp:focus{border:0;box-shadow:none}
.p-chat #composer-context{gap:10px;padding:0;font-size:var(--fs-sm)}
.p-chat #composer-context[hidden],#session-controls[hidden],#codeagency[hidden]{display:none}
.p-chat #session-controls #codebar{padding:0;border:0;gap:8px;flex-wrap:wrap}
.p-chat #session-controls #codepicks{display:flex;flex:1 1 auto;flex-wrap:wrap;gap:8px;min-width:0}
.p-chat #codepicks .pick{flex:0 1 auto;min-width:0;max-width:100%;width:auto;padding:7px 10px;gap:10px;border-radius:var(--r-sm);box-shadow:none;background:var(--lift);font-size:var(--fs-sm)}
.p-chat #codepicks .pick-btn{max-width:240px}
.p-chat #codedevcwd{flex:1 1 200px;min-width:0;width:auto;border:0;border-radius:var(--r-sm);background:var(--lift);color:var(--dim);font:inherit;font-size:var(--fs-sm);padding:7px 10px}
.p-chat #codecoordbtn{display:none}
.p-chat #crail{gap:6px;flex-wrap:wrap}
.p-chat #mode-state{display:none}
.p-chat #codebtn{display:inline-flex;gap:5px;width:auto;padding:6px 9px;border-radius:var(--r-sm);font:inherit;font-size:var(--fs-sm)}
.p-chat #codebtn[hidden]{display:none}
.p-chat #codebtn.on{background:transparent;color:var(--brand-ink)}
.p-chat #codeagency .pick{width:auto;padding:6px 8px;gap:8px;border-radius:var(--r-sm);box-shadow:none;background:none;font-size:var(--fs-sm)}
.p-chat #mpick{max-width:52%;min-width:0;font-size:var(--fs-sm)}
.p-chat #codelog{padding-top:calc(64px + env(safe-area-inset-top))}
.p-chat #code-usage-details{max-width:46rem;margin:0 auto 18px;color:var(--dim);font-size:var(--fs-xs)}
.p-chat #code-usage-details summary{cursor:pointer;list-style-position:inside}
.p-chat #codeusage{padding:12px 0 0}
#compose-welcome{display:none;max-width:46rem;margin:0 auto 26px;text-align:start}
#compose-welcome h1{font-size:var(--fs-3xl);font-weight:500;letter-spacing:-.025em;margin:0 0 10px}
#compose-welcome p{color:var(--dim);font-size:var(--fs-md);margin:0}
#chat-active{display:none;max-width:46rem;margin:24px auto 0;padding:0 6px}
#chat-active .active-heading{font-size:var(--fs-sm);color:var(--dim);margin-bottom:10px}
#chat-active .active-list{max-height:220px;overflow:auto;overscroll-behavior:contain}
.active-conversation{display:flex;align-items:center;justify-content:space-between;gap:18px;width:100%;padding:14px 4px;border:0;border-bottom:1px solid var(--line-soft);background:none;color:var(--fg);text-align:start;font:inherit;cursor:pointer}
.active-conversation>span:first-child{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.active-conversation .fine{flex-shrink:0;color:var(--dim)}
.active-conversation:hover{background:var(--lift)}
body.emptyconv:not(.stage-on) #compose-welcome{display:block}
body.emptyconv:not(.stage-on) #chat-active:not([hidden]){display:block}
/* V0.2.13 首页就是对话：输入框常驻底部（与正常对话同一位置），上面留白给「矩阵动态」。
   原来它吊在 22vh 处，中间空一大片，主人要往上找输入的地方。 */
body.emptyconv:not(.stage-on) #composer{top:auto;bottom:0;max-height:calc(100% - 100px);overflow:auto;background:var(--bg)}
body.emptyconv:not(.stage-on) #compose-welcome{max-width:40rem;text-align:center;margin:0 auto 6px}
body.emptyconv:not(.stage-on) #compose-welcome h1{font-size:var(--fs-h);font-weight:500;letter-spacing:-.01em;margin:0 0 4px}
body.emptyconv:not(.stage-on) #compose-welcome p{font-size:var(--fs-sm)}
body.emptyconv:not(.stage-on) #msgs #hello,body.emptyconv:not(.stage-on) #codehello{display:none}
/* 新对话像 ChatGPT（主人 2026-10-10）：宽屏上一句大招呼、输入框在页面中间、下面几条可以直接问的话；
   第一句发出去之后输入框回到底部。手机保持在底部，拇指够得着。 */
#compose-ideas{display:none}
@media (min-width:721px){
  body.emptyconv:not(.stage-on):not(.codemode) #composer{top:max(16px,calc(50% - 130px));bottom:auto;background:transparent}
  body.emptyconv:not(.stage-on):not(.codemode) #compose-welcome h1{font-size:var(--fs-3xl);font-weight:400;letter-spacing:-.015em;margin:0 0 22px}
  body.emptyconv:not(.stage-on):not(.codemode) #compose-welcome p{display:none}
  body.emptyconv:not(.stage-on):not(.codemode) #compose-ideas{display:flex;flex-direction:column;gap:2px;max-width:46rem;margin:18px auto 0;padding:0 6px}
  body.emptyconv:not(.stage-on):not(.codemode) #chat-active:not([hidden]){margin-top:28px}
}
#compose-ideas .idea{display:block;width:100%;padding:10px 14px;border:0;border-radius:var(--r-md);background:none;color:var(--dim);font:inherit;font-size:var(--fs-sm);text-align:start;cursor:pointer;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
#compose-ideas .idea:hover,#compose-ideas .idea:focus-visible{background:var(--lift);color:var(--fg);outline:none}
/* 空对话里 #compose-welcome（输入框上方那句招呼）已经承担了问候，#hello 只是不可见地
   占着 382px（手机上），把下面的矩阵动态挤到输入框底下。这块空间属于主人：让出来。 */
body.emptyconv #code-usage-details{display:none}

/* ── 矩阵动态 #pulse：空对话中间那块玻璃，读的是这台机器自己的真实状态 ────────────────
   每一格都是本机接口的读数（任务 / hoop work / 服务 / 磁盘 / 树 / 大脑用量），
   读不到就写读不到，不猜；折叠开关记在本机，谁都能改（gram-pulse.js，只读）。 */
#pulse{display:none;max-width:44rem;width:100%;margin:0 auto;padding:14px 16px;border-radius:var(--r-lg);
  background:var(--glass-bg);-webkit-backdrop-filter:var(--glass-blur);backdrop-filter:var(--glass-blur);
  box-shadow:var(--glass-rim),var(--shadow-pop);animation:pulse-in var(--motion-slow) var(--ease) both}
body.emptyconv:not(.stage-on) #pulse{display:block}
.pulse-head{display:flex;align-items:center;gap:8px;font-size:var(--fs-sm);color:var(--fg)}
.pulse-head b{font-weight:500}
.pulse-dot{flex:0 0 auto;width:7px;height:7px;border-radius:50%;background:var(--brand);box-shadow:var(--shadow-brand-halo);animation:breathe var(--motion-pulse) var(--ease-loop) infinite}
.pulse-when{color:var(--dim);font-family:var(--mono);font-size:var(--fs-2xs)}
#pulse-min{margin-inline-start:auto;width:26px;height:26px;display:grid;place-items:center;border:0;border-radius:50%;background:none;color:var(--dim);cursor:pointer}
#pulse-min:hover{color:var(--fg);background:var(--lift)}
#pulse-min svg{width:15px;height:15px;transition:transform var(--dur-1) var(--ease)}
#pulse.pulse-min #pulse-min svg{transform:rotate(180deg)}
#pulse.pulse-min #pulse-body{display:none}
#pulse-body{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:12px 20px;margin-top:12px}
.pulse-cell{display:flex;flex-direction:column;gap:5px;min-width:0}
.pulse-label{color:var(--dim);font-family:var(--mono);font-size:var(--fs-2xs);letter-spacing:.08em;text-transform:uppercase}
.pulse-value{font-size:var(--fs-sm);font-weight:500;overflow-wrap:anywhere}
.pulse-note{color:var(--dim);font-size:var(--fs-2xs)}
.pulse-cell.off .pulse-value,.pulse-value.off-t{color:var(--dim);font-weight:400}
.pulse-row{display:flex;align-items:center;gap:6px;min-width:0;font-size:var(--fs-xs);line-height:1.4}
.pulse-rdot{flex:0 0 auto;width:6px;height:6px;border-radius:50%;background:var(--brand)}
.pulse-rdot.s-wait{background:transparent;box-shadow:var(--shadow-win-focus)}
.pulse-agent{color:var(--dim);font-family:var(--mono)}
.pulse-work{font-family:var(--mono);font-size:var(--fs-2xs);color:var(--brand-ink)}
.pulse-title{flex:1;min-width:0;text-align:start}
.pulse-state{color:var(--dim);font-size:var(--fs-2xs);white-space:nowrap}
.pulse-more{color:var(--dim);font-size:var(--fs-2xs)}
@keyframes pulse-in{from{opacity:0;transform:translateY(6px)}to{opacity:1;transform:none}}
@media(prefers-reduced-motion:reduce){#pulse{animation:none}.pulse-dot{animation:none}}
@media(max-width:720px){
  .cev-h{min-height:28px}
  .p-talk .talk-myname,#talk-npub-copy{min-width:28px;min-height:28px;line-height:1.2}
  .cev-own.open .cev-h,.cev-text.open .cev-h{min-height:28px}
  .p-home .tf{min-height:28px}
  .p-home .tty-chips button,.p-home .tty-newchip,.p-home .tty-histchip{min-height:28px}
  #codestatus .cst-btn{min-height:28px}
  .p-chat #compose-input{padding:5px 6px}
  .p-chat #composer-context{gap:2px}
  .p-chat #composer-context .composer-context-owner>span:last-child{display:none}
  .p-chat #composer-files-context{max-width:90px}
  .p-chat #compose-settings{gap:4px;padding:0}
  .p-chat #composer{padding-bottom:12px}
  .p-chat #mpick{max-width:45%}
  body.emptyconv:not(.stage-on) #composer{top:auto;bottom:0;max-height:calc(100% - 100px)}
  #pulse{padding:12px 14px}
  #pulse-body{grid-template-columns:1fr}
  #compose-welcome{margin-bottom:20px}
  #chat-active .active-list{max-height:180px}
}

/* Session choices remain reachable below the input at narrow widths. */
.p-chat #cwrap #inp{background:transparent}
.p-chat #codeagency .pk-l{display:none}
.p-chat #codeagency .pk-v{max-width:none}
.p-chat #codepicks .pk-v{max-width:180px}
@media(max-width:720px){
  .p-chat #crail{gap:3px;flex-wrap:nowrap}
  .p-chat #codeagency .pick{padding:6px 4px;gap:4px}
  .p-chat #codebtn{padding:6px}
  .p-chat #crail .sp{min-width:0}
}

@media(max-width:720px){
  .p-chat #crail{flex-wrap:wrap}
  .p-chat #crail .sp{display:none}
  .p-chat #mpick{margin-inline-start:auto;max-width:65%}
  .p-chat #compose-settings #crail{flex-wrap:wrap}
  .p-chat #compose-settings #mpick{max-width:100%}
}

/* ═══ talk (p-talk): Hoop-to-Hoop text messages — work-app: contacts | thread ═══════════════
   Desktop: two panes, each scrolling inside itself. ≤720px: one pane at a time (the URL hash
   is the open thread, so Back returns to the list). No read receipts anywhere: a message
   says only queued / delivered / failed. The identity panel stays folded until opened. */
.p-talk{height:100dvh; display:flex; flex-direction:column; padding-bottom:calc(16px + env(safe-area-inset-bottom))}
.p-talk main{max-width:var(--wide-col); width:100%; flex:1; min-height:0; display:flex; flex-direction:column; gap:var(--sp-3)}
.talk-me{flex:none; display:flex; flex-wrap:wrap; align-items:flex-start; justify-content:space-between; gap:8px var(--sp-4); min-width:0}
.talk-me-text{min-width:0}
.talk-me-acts{flex:none; display:flex; gap:8px}
.talk-me-line{margin:6px 0 0; display:flex; flex-wrap:wrap; align-items:baseline; gap:2px 10px; min-width:0}
.talk-myname{border:0; background:none; padding:0; cursor:pointer; color:var(--fg); font:inherit; font-size:var(--fs-lg);
  font-weight:500; border-bottom:1px dashed var(--line-2); min-height:24px}
.talk-myname:focus-visible{outline:none; box-shadow:var(--focus)}
.talk-addr{font-family:var(--mono); font-size:var(--fs-sm); color:var(--dim); overflow-wrap:anywhere; min-width:0}
.talk-fp-inline{font-family:var(--mono); letter-spacing:.02em}
/* identity: a folded line; open, it scrolls inside itself so the conversation keeps its room */
.talk-id{flex:none; min-width:0; border:1px solid var(--line); border-radius:var(--r-md); background:var(--surface)}
.talk-id summary{display:flex; align-items:center; gap:10px; min-height:var(--tap); padding:0 14px; cursor:pointer;
  color:var(--dim); font-size:var(--fs-sm); list-style:none; border-radius:var(--r-md)}
.talk-id summary::-webkit-details-marker{display:none}
.talk-id summary::after{content:""; margin-inline-start:auto; width:7px; height:7px; border:solid currentColor;
  border-width:0 1.5px 1.5px 0; transform:rotate(45deg); transition:transform var(--dur-1)}
.talk-id[open] summary::after{transform:rotate(-135deg)}
.talk-id summary:focus-visible{outline:none; box-shadow:var(--focus)}
.talk-id-flag{font-size:var(--fs-xs); color:var(--warn); padding:1px 8px; border-radius:var(--r-pill);
  border:1px solid color-mix(in oklab, currentColor 40%, transparent)}
.talk-id-body{display:grid; gap:12px; padding:4px 14px 14px; max-height:min(52dvh, 30rem); overflow-y:auto; overscroll-behavior:contain}
.talk-id-body .fine{margin:0; color:var(--dim); font-size:var(--fs-sm); line-height:1.55; max-width:68ch}
.talk-kv{margin:0; display:grid; gap:8px}
.talk-kv > div{display:grid; grid-template-columns:5.5rem minmax(0,1fr); gap:10px; align-items:baseline}
.talk-kv dt{color:var(--dim); font-size:var(--fs-sm)}
.talk-kv dd{margin:0; display:flex; flex-wrap:wrap; align-items:baseline; gap:4px 12px; min-width:0}
.talk-kv code{font-family:var(--mono); font-size:var(--fs-sm); overflow-wrap:anywhere; min-width:0}
.talk-rec{display:grid; gap:8px; max-width:68ch}
.talk-rec h2{margin:0; font-size:var(--fs-md); font-weight:500}
.talk-rec p{margin:0; color:var(--dim); font-size:var(--fs-sm); line-height:1.6}
.talk-id-acts{display:flex; flex-wrap:wrap; gap:4px 18px}
.talk-link{border:0; background:none; padding:0; min-height:var(--tap); color:var(--dim); font:inherit; font-size:var(--fs-sm);
  cursor:pointer; text-decoration:underline; text-underline-offset:3px}
.talk-link:hover{color:var(--fg)}
.talk-link:disabled{opacity:.5; cursor:default}
.talk-link:focus-visible{outline:none; box-shadow:var(--focus)}
/* the recovery code / a new conversation link: shown once, selectable, never cut off */
.talk-code{display:block; margin-top:14px; padding:12px 14px; border-radius:var(--r-sm); background:var(--code);
  font-family:var(--mono); font-size:var(--fs-sm); line-height:1.6; overflow-wrap:anywhere; word-break:break-all; user-select:all; -webkit-user-select:all}
.talk-body{flex:1; min-height:0; display:grid; grid-template-columns:minmax(260px,340px) minmax(0,1fr); gap:var(--sp-4)}
.talk-side{min-height:0; min-width:0; overflow-y:auto; overscroll-behavior:contain; padding-inline-end:2px}
.talk-side .sect{margin:18px 0 6px}
.talk-req-lede{margin:0 0 6px; color:var(--dim); font-size:var(--fs-xs); line-height:1.5}
.talk-add-row{display:flex; flex-wrap:wrap; gap:8px; margin-bottom:10px}
.talk-form{display:grid; gap:10px; margin-bottom:10px}
.talk-form label{display:grid; gap:5px; font-size:var(--fs-sm); color:var(--dim)}
.talk-form input,.talk-form textarea{width:100%; min-width:0}
.talk-form textarea{resize:vertical; min-height:3.2em; line-height:1.45}
.talk-form-lede{margin:0; font-size:var(--fs-sm); color:var(--dim); line-height:1.55}
.talk-form-acts{display:flex; flex-wrap:wrap; justify-content:flex-end; gap:8px}
.talk-err{margin:0; color:var(--bad); font-size:var(--fs-sm); line-height:1.5}
.talk-list{display:grid; gap:2px}
.talk-row{display:flex; flex-wrap:wrap; align-items:center; gap:4px 8px; border-radius:var(--r-md); min-width:0}
.talk-row.on{background:var(--brand-soft)}
.talk-row-hit{flex:1 1 12rem; display:flex; align-items:center; gap:10px; min-width:0; min-height:var(--row-h); padding:8px 10px;
  border:0; border-radius:var(--r-md); background:transparent; color:var(--fg); text-align:start; font:inherit; cursor:pointer;
  transition:background var(--dur-1)}
.talk-row-hit:hover{background:var(--lift)}
.talk-row.on .talk-row-hit:hover{background:transparent}
.talk-row-hit:focus-visible{outline:none; box-shadow:var(--focus)}
.talk-row-acts{flex:none; display:flex; gap:6px; padding:0 8px 8px 56px}
.talk-av{flex:none; width:36px; height:36px; border-radius:50%; display:grid; place-items:center; background:var(--surface-2);
  border:1px solid var(--line); color:var(--fg); font-size:var(--fs-ui); font-weight:500}
.talk-av.guest{border-style:dashed; border-color:var(--line-2)}
.talk-row-main{flex:1; min-width:0; display:grid; gap:1px}
.talk-row-name{font-weight:500; overflow:hidden; text-overflow:ellipsis; white-space:nowrap}
.talk-row-sub{font-size:var(--fs-xs); color:var(--dim); overflow:hidden; text-overflow:ellipsis; white-space:nowrap}
.talk-row-end{flex:none; display:flex; flex-direction:column; align-items:flex-end; gap:4px; font-size:var(--fs-2xs); color:var(--dim)}
.talk-unread{min-width:18px; height:18px; padding:0 5px; border-radius:var(--r-pill); background:var(--accent); color:var(--on-scrim);
  font-size:var(--fs-2xs); font-weight:500; display:grid; place-items:center; font-variant-numeric:tabular-nums}
.talk-thread{min-height:0; min-width:0; display:flex; flex-direction:column; border:1px solid var(--line);
  border-radius:var(--r-lg); background:var(--surface); overflow:hidden}
.talk-none{flex:1; display:grid; place-items:center; padding:var(--sp-5)}
.talk-pane{flex:1; min-height:0; display:flex; flex-direction:column}
.talk-thread-head{flex:none; display:flex; align-items:center; gap:4px; padding:8px 10px 8px 14px; border-bottom:1px solid var(--line)}
.talk-thread-head .hbtn{width:var(--tap); height:var(--tap)}
.talk-back{display:none}
.talk-peer{flex:1; min-width:0; display:grid}
.talk-peer strong{font-weight:500; overflow:hidden; text-overflow:ellipsis; white-space:nowrap}
.talk-peer-sub{font-size:var(--fs-xs); color:var(--dim); overflow:hidden; text-overflow:ellipsis; white-space:nowrap}
.talk-msgs{flex:1; min-height:0; overflow-y:auto; overscroll-behavior:contain; padding:16px 14px 10px;
  display:flex; flex-direction:column; gap:10px; scrollbar-gutter:stable}
.talk-day{align-self:center; font-size:var(--fs-2xs); color:var(--dim); letter-spacing:.04em; margin:8px 0 2px}
.talk-earlier{align-self:center}
.talk-thread-empty{margin:auto; color:var(--dim); font-size:var(--fs-md); text-align:center; max-width:30ch; line-height:1.6}
.talk-msg{display:flex; flex-direction:column; gap:3px; max-width:min(80%, 34rem); min-width:0}
.talk-msg.in{align-self:flex-start; align-items:flex-start}
.talk-msg.out{align-self:flex-end; align-items:flex-end}
.talk-bubble{display:grid; gap:6px; min-width:0; max-width:100%; padding:8px 13px; border-radius:var(--r-lg);
  background:var(--surface-2); border:1px solid var(--line-soft); overflow-wrap:anywhere}
.talk-msg.in .talk-bubble{border-end-start-radius:var(--r-xs)}
.talk-msg.out .talk-bubble{background:var(--own); border-end-end-radius:var(--r-xs)}
.talk-text{white-space:pre-wrap; line-height:1.55}
.talk-ai{justify-self:start; font-size:var(--fs-2xs); font-weight:500; letter-spacing:.06em; line-height:1.6; padding:0 7px;
  color:var(--accent); border:1px solid color-mix(in oklab, var(--accent) 45%, transparent); border-radius:var(--r-pill)}
.talk-meta{display:flex; align-items:center; gap:6px; padding:0 4px; font-size:var(--fs-2xs); color:var(--dim); font-variant-numeric:tabular-nums}
.talk-st[data-status="failed"]{color:var(--bad)}
.talk-retry{border:0; background:none; padding:0; min-height:24px; color:var(--accent); font:inherit; cursor:pointer; text-decoration:underline}
.talk-retry:focus-visible{outline:none; box-shadow:var(--focus)}
.talk-note{flex:none; display:flex; flex-wrap:wrap; align-items:center; gap:8px; padding:10px 14px;
  border-top:1px solid var(--line); color:var(--dim); font-size:var(--fs-sm)}
.talk-note-text{flex:1 1 16rem; min-width:0; line-height:1.5}
.talk-compose{flex:none; display:flex; align-items:flex-end; gap:4px; padding:8px 8px 8px 10px; border-top:1px solid var(--line)}
.talk-compose .cbtn{width:var(--tap); height:var(--tap)}
.talk-compose textarea{flex:1; min-width:0; resize:none; max-height:180px; line-height:1.45; padding:9px 13px}
.talk-send{opacity:.65}
.talk-send.ready{opacity:1; color:var(--brand-ink)}
/* 约时间 (M8): negotiations pinned above the conversation; a step waiting for the owner is marked,
   finished ones older than a day fold into one line. Options are the owner's local times. */
.talk-sch{flex:none; display:grid; gap:8px; padding:10px 14px; border-bottom:1px solid var(--line);
  max-height:min(42%, 22rem); overflow-y:auto; overscroll-behavior:contain}
.talk-sch-card{display:grid; gap:6px; min-width:0; padding:10px 12px; border:1px solid var(--line); border-radius:var(--r-md);
  background:var(--surface-2)}
.talk-sch-card.wait{border-color:color-mix(in oklab, var(--accent) 45%, var(--line))}
.talk-sch-head{display:flex; align-items:flex-start; gap:10px; min-width:0}
.talk-sch-ico{flex:none; color:var(--dim); margin-top:2px}
.talk-sch-txt{flex:1; min-width:0; display:grid; gap:1px}
.talk-sch-title{font-weight:500; overflow-wrap:anywhere}
.talk-sch-meta{font-size:var(--fs-xs); color:var(--dim); font-variant-numeric:tabular-nums}
.talk-sch-note{margin:0; font-size:var(--fs-sm); color:var(--dim); line-height:1.5; overflow-wrap:anywhere}
.talk-sch-state{margin:0; font-size:var(--fs-sm); line-height:1.5}
.talk-sch-card[data-state="declined"] .talk-sch-state,.talk-sch-card[data-state="no_overlap"] .talk-sch-state,
.talk-sch-card[data-state="expired"] .talk-sch-state{color:var(--dim)}
.talk-sch-cal{color:var(--dim)}
.talk-sch-cal[data-on]{color:var(--ok)}
.talk-sch-acts{display:flex; flex-wrap:wrap; gap:6px}
.talk-sch-acts .btn{max-width:100%; white-space:normal; text-align:center}
.talk-sch-opt{font-variant-numeric:tabular-nums}
.talk-sch-old summary{cursor:pointer; min-height:32px; display:flex; align-items:center; color:var(--dim); font-size:var(--fs-sm); border-radius:var(--r-sm)}
.talk-sch-old summary:focus-visible{outline:none; box-shadow:var(--focus)}
.talk-sch-old[open]{display:grid; gap:8px}
.talk-sch-form{display:grid; gap:12px; margin-top:12px}
.talk-sch-form label{display:grid; gap:5px; font-size:var(--fs-sm); color:var(--dim)}
.talk-sch-form input,.talk-sch-form textarea{width:100%; min-width:0; margin-top:0}
.talk-sch-form textarea{resize:vertical; min-height:3.2em; line-height:1.45}
.talk-sch-form .m-acts{margin-top:6px}
@media (max-width:720px){
  .talk-sch{max-height:40dvh; padding:8px 10px}
  .talk-sch-form input,.talk-sch-form textarea{font-size:16px}
}
/* 聊天 | 动态 tabs (the shared .tabs, without its page-top margin) */
.p-talk .talk-tabs{flex:none; margin-top:0}
.talk-form-hint{margin:0; color:var(--dim); font-size:var(--fs-xs); line-height:1.5}
/* 新建群聊: pick at least two friends */
.talk-pick{margin:0; padding:0; border:0; min-width:0; display:grid; gap:5px}
.talk-pick legend{padding:0; margin-bottom:5px; font-size:var(--fs-sm); color:var(--dim)}
.talk-pick-list{display:grid; gap:2px; max-height:15rem; overflow-y:auto; overscroll-behavior:contain}
.talk-form .talk-pick-row{display:flex; align-items:center; gap:10px; min-height:var(--tap); padding:4px 6px; border-radius:var(--r-md);
  color:var(--fg); font-size:var(--fs-ui); cursor:pointer; min-width:0}
.talk-pick-row:hover{background:var(--lift)}
.talk-pick-row input{flex:none; width:18px; height:18px; margin:0; accent-color:var(--brand)}
.talk-pick-row .talk-av{width:28px; height:28px; font-size:var(--fs-sm)}
.talk-pick-name{flex:1; min-width:0; overflow-wrap:anywhere}
.talk-av.group{border-radius:var(--r-md)}
/* a group: who said it, above their bubble */
.talk-from{padding:0 4px; font-size:var(--fs-xs); color:var(--dim); overflow-wrap:anywhere}
/* files in a bubble: the picture itself, a player, or a download row; before it is here, its state */
.talk-bubble.has-file{padding:6px}
.talk-file{min-width:0; max-width:100%}
.talk-img{display:block; border:0; padding:0; background:none; cursor:zoom-in; border-radius:var(--r-md); overflow:hidden; max-width:100%}
.talk-img:focus-visible{outline:none; box-shadow:var(--focus)}
.talk-img img{display:block; max-width:280px; max-height:320px; width:auto; height:auto; object-fit:cover; background:var(--code)}
.talk-file[data-kind="audio"]{display:flex; align-items:center; gap:8px; flex-wrap:wrap}
.talk-file audio{width:min(260px, 62vw); height:40px; max-width:100%}
.talk-file video{display:block; max-width:320px; max-height:320px; border-radius:var(--r-md); background:var(--ink-stage)}
.talk-file-dur{font-size:var(--fs-xs); color:var(--dim); font-variant-numeric:tabular-nums; padding-inline-end:4px}
.talk-file-dl,.talk-file:not([data-state="ok"]){display:flex; align-items:center; gap:10px; min-width:0; padding:4px 6px; color:var(--fg); text-decoration:none; border-radius:var(--r-md)}
.talk-file-dl:hover{background:var(--lift)}
.talk-file-dl:focus-visible{outline:none; box-shadow:var(--focus)}
.talk-file-ico{flex:none; color:var(--dim)}
.talk-file-main{flex:1; min-width:0; display:grid; gap:1px}
.talk-file-name{overflow-wrap:anywhere; line-height:1.4}
.talk-file-sub{font-size:var(--fs-xs); color:var(--dim); font-variant-numeric:tabular-nums}
.talk-file[data-state="failed"] .talk-file-sub,.talk-file[data-state="no_space"] .talk-file-sub{color:var(--bad)}
.talk-lightbox{max-width:min(92vw, 60rem); width:auto; padding:14px}
.talk-lightbox img{display:block; max-width:100%; max-height:76dvh; margin:0 auto; border-radius:var(--r-md)}
.talk-lightbox .m-acts{margin-top:10px}
/* a call leaves one quiet line in the conversation */
.talk-callline{align-self:center; display:inline-flex; align-items:center; gap:6px; padding:3px 12px; border:1px solid var(--line);
  border-radius:var(--r-pill); color:var(--dim); font-size:var(--fs-sm); font-variant-numeric:tabular-nums}
.talk-callline time{font-size:var(--fs-2xs)}
.talk-glyph{display:inline-grid; place-items:center; flex:none}
.talk-glyph svg{width:16px; height:16px}
.talk-glyph.hang svg{transform:rotate(135deg)}
/* composer: sending a file · holding to talk */
.talk-upl{flex:none; margin:0; padding:6px 14px; border-top:1px solid var(--line); color:var(--dim); font-size:var(--fs-xs)}
.talk-recbar{flex:1; min-width:0; min-height:var(--tap); display:flex; align-items:center; gap:10px; padding:0 13px;
  border-radius:var(--r-md); background:var(--paper); outline:1px solid var(--line); outline-offset:-1px; font-variant-numeric:tabular-nums}
.talk-rec-dot{flex:none; width:9px; height:9px; border-radius:50%; background:var(--bad); animation:talk-pulse var(--motion-pulse) var(--ease-loop) infinite}
.talk-rec-time{flex:none; font-weight:500}
.talk-rec-hint{flex:1; min-width:0; color:var(--dim); font-size:var(--fs-xs); line-height:1.3; overflow-wrap:anywhere}
.talk-recbar.away .talk-rec-hint{color:var(--bad)}
@keyframes talk-pulse{50%{opacity:.25}}
@media (prefers-reduced-motion:reduce){.talk-rec-dot{animation:none}}
.talk-mic{touch-action:none; user-select:none; -webkit-user-select:none; -webkit-touch-callout:none}
.talk-mic.on{color:var(--bad)}
/* the call screen: always the dark media stage, whatever the theme; over the whole page and its nav rail */
.talk-call{position:fixed; inset:0; z-index:10010; display:grid; grid-template-rows:1fr auto auto; background:var(--ink-stage);
  color:var(--on-scrim); overflow:hidden; animation:fade var(--dur-2) var(--ease)}
.talk-call-remote{position:absolute; inset:0; width:100%; height:100%; object-fit:cover; background:var(--ink-stage)}
.talk-call-self{position:absolute; z-index:2; top:calc(16px + env(safe-area-inset-top)); inset-inline-end:16px; width:min(28vw, 180px);
  aspect-ratio:3/4; object-fit:cover; border-radius:var(--r-md); outline:1px solid var(--glint); background:var(--scrim-strong); transform:scaleX(-1); display:none}
.talk-call.has-local .talk-call-self{display:block}
.talk-call-who{position:relative; z-index:1; align-self:center; justify-self:center; display:grid; justify-items:center; gap:8px;
  padding:24px 16px; text-align:center; max-width:100%}
.talk-call-av{width:96px; height:96px; font-size:var(--fs-7); background:var(--glint); border:0; color:var(--on-scrim)}
.talk-call-name{font-size:var(--fs-lg); font-weight:500; overflow-wrap:anywhere}
.talk-call-status{font-size:var(--fs-sm); opacity:.8; font-variant-numeric:tabular-nums; min-height:1.4em; max-width:32rem; line-height:1.5}
.talk-call[data-media="video"].has-remote .talk-call-who{align-self:start; justify-self:start; justify-items:start; text-align:start;
  padding:calc(16px + env(safe-area-inset-top)) 16px 12px; text-shadow:0 1px 3px var(--scrim-stronger)}
.talk-call[data-media="video"].has-remote .talk-call-av{display:none}
.talk-call-err{position:relative; z-index:1; margin:0 auto 8px; max-width:min(32rem, calc(100% - 32px)); padding:10px 14px;
  border-radius:var(--r-md); background:var(--scrim-strong); font-size:var(--fs-sm); line-height:1.55; text-align:center}
.talk-call-acts{position:relative; z-index:1; display:flex; flex-wrap:wrap; justify-content:center; gap:14px 28px;
  padding:20px 16px calc(28px + env(safe-area-inset-bottom))}
.talk-call-btn{border:0; background:none; padding:0; color:var(--on-scrim); display:grid; justify-items:center; gap:6px; font:inherit;
  font-size:var(--fs-xs); cursor:pointer; min-width:64px}
.talk-call-btn .talk-glyph{width:60px; height:60px; border-radius:50%; background:var(--glint); transition:transform var(--dur-1)}
.talk-call-btn .talk-glyph svg{width:24px; height:24px}
.talk-call-btn:active .talk-glyph{transform:scale(.94)}
.talk-call-btn:focus-visible{outline:none}
.talk-call-btn:focus-visible .talk-glyph{outline:3px solid var(--on-scrim)}
.talk-call-btn.end .talk-glyph{background:var(--bad); color:var(--on-bad)}
.talk-call-btn.go .talk-glyph{background:var(--ok); color:var(--on-scrim)}
.talk-call-btn.off .talk-glyph{background:var(--on-scrim); color:var(--ink-stage)}
.talk-call-close{color:var(--on-scrim); border-color:var(--glint)}
/* 动态: composer and the feed on the left, my page · following · my posts on the right */
.talk-posts{flex:1; min-height:0; overflow-y:auto; overscroll-behavior:contain; display:grid;
  grid-template-columns:minmax(0,1fr) minmax(260px,340px); gap:var(--sp-4); align-items:start; padding-bottom:8px}
.talk-posts-main,.talk-posts-side{min-width:0; display:grid; gap:10px; align-content:start}
.talk-posts-side .sect{margin:14px 0 0}
.talk-post-new{display:grid; gap:10px}
.talk-post-new textarea{width:100%; min-width:0; resize:vertical; min-height:4.8em; line-height:1.5}
.talk-post-row{display:flex; flex-wrap:wrap; align-items:center; justify-content:space-between; gap:8px}
.talk-aud{display:inline-flex; padding:2px; gap:2px; border-radius:var(--r-pill); outline:1px solid var(--line); outline-offset:-1px}
.talk-aud button{border:0; background:none; color:var(--dim); font:inherit; font-size:var(--fs-sm); min-height:32px; padding:0 14px;
  border-radius:var(--r-pill); cursor:pointer}
.talk-aud button[aria-checked="true"]{background:var(--brand-soft); color:var(--fg); font-weight:500}
.talk-aud button:focus-visible{outline:none; box-shadow:var(--focus)}
.talk-feed-head{display:flex; align-items:center; justify-content:space-between; gap:8px; margin-top:8px}
.talk-feed-head .sect{margin:0}
.talk-feed{display:grid; gap:10px; min-width:0}
.talk-post{display:grid; gap:6px; min-width:0; padding:12px 14px; border:1px solid var(--line); border-radius:var(--r-md); background:var(--surface)}
.talk-post-head{display:flex; flex-wrap:wrap; align-items:baseline; gap:2px 10px; font-size:var(--fs-xs); color:var(--dim); font-variant-numeric:tabular-nums}
.talk-post-who{color:var(--fg); font-size:var(--fs-ui); font-weight:500; overflow-wrap:anywhere; min-width:0}
.talk-post-aud{padding:0 7px; border-radius:var(--r-pill); border:1px solid var(--line-2); line-height:1.6}
.talk-post-text{margin:0; white-space:pre-wrap; line-height:1.6; overflow-wrap:anywhere}
.talk-post-acts{display:flex; justify-content:flex-end}
.talk-mypage{display:grid; gap:6px}
.talk-mypage h2{margin:0; font-size:var(--fs-md); font-weight:500}
.talk-mypage-line{margin:0; display:flex; flex-wrap:wrap; align-items:baseline; gap:2px 12px; min-width:0}
.talk-mypage-line a{font-family:var(--mono); font-size:var(--fs-sm); overflow-wrap:anywhere; min-width:0}
.talk-follow{display:flex; gap:8px; min-width:0}
.talk-follow input{flex:1; min-width:0}
.talk-follow-row{display:flex; align-items:center; gap:8px; min-width:0; padding:6px 4px; border-bottom:1px solid var(--line-soft)}
.talk-follow-row .talk-row-name,.talk-follow-row .talk-row-sub{white-space:normal; overflow-wrap:anywhere}
/* 简介 (M10) in the identity panel; 先看看: their profile and fingerprint inside the add form */
.talk-about{display:grid; gap:6px; max-width:68ch}
.talk-about label{font-size:var(--fs-sm); color:var(--dim)}
.talk-about textarea{width:100%; min-width:0; resize:vertical; min-height:3.2em; line-height:1.45}
.talk-preview{display:grid; gap:6px; min-width:0; padding:10px 12px; border:1px solid var(--line); border-radius:var(--r-md); background:var(--surface-2)}
.talk-preview p{margin:0}
.talk-pv-head{display:flex; align-items:center; gap:10px; min-width:0}
.talk-pv-main{display:grid; gap:1px; min-width:0}
.talk-pv-name{font-weight:500; overflow-wrap:anywhere}
.talk-pv-addr{font-family:var(--mono); font-size:var(--fs-xs); color:var(--dim); overflow-wrap:anywhere}
.talk-pv-about{font-size:var(--fs-sm); line-height:1.55; white-space:pre-wrap; overflow-wrap:anywhere}
.talk-pv-about.none{color:var(--dim)}
.talk-pv-fp{display:flex; flex-wrap:wrap; align-items:baseline; gap:2px 10px; font-size:var(--fs-sm); color:var(--dim)}
.talk-pv-fp code{font-family:var(--mono); color:var(--fg); overflow-wrap:anywhere; min-width:0}
.talk-intro-tag{justify-self:start; align-self:center; font-size:var(--fs-xs); line-height:1.6; padding:0 8px; border-radius:var(--r-pill);
  color:var(--fg); background:var(--brand-soft)}
/* money (M6): cards share the 约时间 card; the amount reads as a number */
.talk-money-amt{font-variant-numeric:tabular-nums}
.talk-sch-state a,.talk-err a{color:inherit; text-decoration:underline; text-underline-offset:3px; overflow-wrap:anywhere}
.talk-money-card[data-state="verified"] .talk-sch-state{color:var(--ok)}
.talk-money-card[data-state="unverified"] .talk-sch-state,.talk-money-card[data-state="failed"] .talk-sch-state,
.talk-money-card[data-state="wrong_network"] .talk-sch-state{color:var(--bad)}
.talk-money-card[data-state="declined"] .talk-sch-state,.talk-money-card[data-state="denied"] .talk-sch-state{color:var(--dim)}
.talk-money-err:empty{display:none}
/* 共享 (M7) */
.talk-share-files{display:grid; gap:2px; min-width:0}
.talk-share-item{display:flex; align-items:baseline; gap:10px; min-width:0; padding:2px 6px}
.talk-share-item .talk-file-name,.talk-share-picked .talk-file-name{flex:1; min-width:0; overflow-wrap:anywhere}
.talk-share[data-state="revoked"] .talk-share-item{color:var(--dim); text-decoration:line-through}
.talk-share-picked{list-style:none; margin:0; padding:0; display:grid; gap:2px; max-height:12rem; overflow-y:auto}
.talk-share-picked li{display:flex; align-items:center; gap:10px; min-width:0; padding:0 4px; border-bottom:1px solid var(--line-soft)}
.talk-share-modal .talk-sch-form > .btn{justify-self:start}
.talk-err.busy{color:var(--dim)}
/* 小店 (M9): catalog, a shop being browsed, orders */
.talk-usdc{padding:8px 12px; border-radius:var(--r-md); background:var(--surface-2)}
.talk-item-row .btn{flex:none}
.talk-shop-card{gap:10px}
.talk-shop-addr{font-family:var(--mono); overflow-wrap:anywhere; min-width:0}
.talk-shop-lines{display:grid; min-width:0}
.talk-shop-line{display:flex; align-items:center; gap:10px; min-width:0; padding:6px 0; border-bottom:1px solid var(--line-soft)}
.talk-shop-line .talk-row-main{flex:1}
.talk-shop-line .talk-row-name,.talk-shop-line .talk-row-sub{white-space:normal; overflow-wrap:anywhere}
.talk-qty{flex:none; width:4.5rem; text-align:center; font-variant-numeric:tabular-nums}
.talk-shop-note{display:grid; gap:5px; font-size:var(--fs-sm); color:var(--dim)}
.talk-shop-note textarea{width:100%; min-width:0; resize:vertical; min-height:3.2em; line-height:1.45}
.talk-order-total{margin:0; font-weight:500; font-variant-numeric:tabular-nums}
.talk-order-lines{list-style:none; margin:0; padding:0; display:grid; gap:2px; font-size:var(--fs-sm)}
.talk-order-lines li{display:flex; justify-content:space-between; gap:10px; min-width:0; overflow-wrap:anywhere}
.talk-order-price{flex:none; font-variant-numeric:tabular-nums; color:var(--dim)}
.talk-order[data-state="done"] .talk-order-state{color:var(--ok)}
.talk-order[data-state="cancelled"] .talk-order-state{color:var(--dim)}
.talk-order .talk-money-card{background:var(--surface)}
.talk-order-acts{flex-wrap:wrap; align-items:center; gap:8px}
.talk-ship-note{flex:1 1 12rem; min-width:0}
@media (max-width:720px){
  .talk-body{grid-template-columns:minmax(0,1fr)}
  .talk-body[data-view="list"] .talk-thread{display:none}
  .talk-body[data-view="thread"] .talk-side{display:none}
  .p-talk[data-view="thread"] .talk-me,.p-talk[data-view="thread"] .talk-id{display:none}
  .talk-back{display:inline-grid}
  .talk-thread-head{padding-inline-start:4px}
  .talk-msg{max-width:88%}
  .talk-compose textarea{font-size:16px}
  .p-talk[data-view="thread"] .talk-tabs{display:none}
  .talk-posts{grid-template-columns:minmax(0,1fr)}
  .talk-post-new textarea,.talk-follow input,.talk-form input{font-size:16px}
  .talk-about textarea,.talk-form textarea,.talk-qty,.talk-ship-note,.talk-shop-note textarea{font-size:16px}
  .talk-img img{max-width:240px}
  .talk-file video{max-width:240px}
  .talk-file audio{width:200px}
}

/* ── the scrollbar's width is part of the first frame ─────────────────────────────────────
   A page whose content grows past the viewport gets a scrollbar mid-load; the layout then
   loses ~10px of width, so everything centred in the remaining space jumps sideways (that
   alone was 0.10 CLS on /finance). Reserving the gutter from the first frame keeps the
   settled layout — which is the one with the scrollbar — and removes the jump. */
html{scrollbar-gutter:stable}

/* ── the shell frame's first-frame geometry ──────────────────────────────────────────────
   nav.js used to inject these with its <style>, i.e. after the first paint: every page
   painted unframed and then jumped 44px down and 264px sideways (worst page CLS 0.80).
   The pages now carry class="hoop-rail hoop-docked" in their <html> tag, so the frame is
   part of the first paint; nav.js re-applies the same classes idempotently and still owns
   them. KEEP THIS BLOCK LAST: in the old order it was the document's last stylesheet, so it
   must keep winning the ties it wins today against the rules above. */
html.hoop-rail body{padding-bottom:0!important;padding-top:var(--shell-top);box-sizing:border-box;}html.hoop-rail.hoop-embedded body{padding-top:0!important;}html.hoop-rail body:not(.page){padding-inline-start:0!important;}
html.hoop-rail body.p-chat #main{height:100%;}html.hoop-rail .p-chat #side{inset-inline-start:0;top:0;}
html.hoop-rail .p-chat #msgs,html.hoop-rail .p-chat #composer{padding-inline-end:18px;}
html.hoop-rail .p-home .menubar{height:var(--shell-top);padding-top:env(safe-area-inset-top);padding-inline-end:calc(12px + var(--doors-w));box-sizing:border-box;}
html.hoop-rail body.p-chat{padding-top:0;}
html.hoop-rail .p-chat #hdr{min-height:var(--shell-top);padding-top:calc(6px + env(safe-area-inset-top));padding-bottom:6px;padding-inline-end:calc(12px + var(--doors-w))!important;box-sizing:border-box;}
html.hoop-rail body.p-chat.stage-on #stage-bar{padding-inline-end:calc(12px + var(--doors-w));min-height:var(--shell-top);box-sizing:border-box;}
html.hoop-rail #phead{padding-inline-end:calc(12px + var(--doors-w));box-sizing:border-box;}
html.hoop-rail #hooptop{display:none!important;}
/* the top bar owns the whole top row (owner 2026-10-11): an App page's bar runs the full width, over
   the rail's column, and still keeps clear of the doors (search · assistant) at its end */
html.hoop-rail:not(.hoop-embedded) .win-chrome.page{padding-inline-end:calc(12px + var(--doors-w)); z-index:898}   /* under the route surface (899) and every window */

/* the pinned panel exists only at >=1100px (nav.js DOCK_MQ); the guard keeps the markup's
   hoop-docked class inert on a phone, where the shell can never be docked. */
/* ── copy-ready first paint ─────────────────────────────────────────────────
   The UI copy is applied by i18n.js a few dozen ms after the shell's first paint. Until it
   lands the copy elements are empty (an em-wide h1, a zero-height lede), so every box below
   them is laid out short and jumps when the text arrives — measured on /finance and /mail
   at both widths (0.17–0.80). A page carrying data-copy="wait" keeps its own content out of
   that first paint — visibility, not display, so geometry and the scroll range never change
   — and i18n.js lifts the attribute a tick after it has written the copy, so the first frame
   the user sees is the settled one. boot.js carries the fail-safe (a 2s timer, the same
   attribute and value): if i18n.js never lands, the content still appears instead of staying
   hidden. Cost, measured: the first paint now carries the whole page, which reads as one
   ~55ms task before it (/finance desktop, the same as that page's original baseline); every
   other metric and the copy itself are unchanged. */
html[data-copy="wait"] main,
html[data-copy="wait"] #main,
html[data-copy="wait"] #side{visibility:hidden}
@media (min-width:1100px){
html.hoop-rail.hoop-docked{padding-inline-start:var(--matrix-w);}
html.hoop-docked #hoop-matrix{inset:0;inset-inline-end:auto;width:var(--matrix-w);height:100dvh;padding:calc(12px + env(safe-area-inset-top)) 12px 14px;background:var(--bg,var(--paper));border:0;border-radius:0;box-shadow:none;transform:none;opacity:1;pointer-events:auto;visibility:visible;transition:none;}
html.hoop-docked #hoop-matrix .hm-brand{padding:4px 4px 16px 8px;min-height:34px;}
html.hoop-docked #hooprail:before{display:none;}
html.hoop-docked .p-home .menubar,html.hoop-docked #hoop-windows,html.hoop-docked #panel{inset-inline-start:var(--matrix-w);}html.hoop-docked #chancellor-strip{inset-inline-start:calc(var(--matrix-w) + var(--sp-3,12px));}
html.hoop-docked #hoop-matrix .hm-all{border-top:0;}
}

/* Matrix uses one layout: the left edge (icon rail + history card) is the only navigation, and
   one live conversation fills the rest. The rail also holds the open and minimized apps. */
html.hoop-rail:has(body.p-chat):not(.hoop-session-embedded){padding:0!important;scrollbar-gutter:auto}
html.hoop-rail:not(.hoop-session-embedded) body.p-chat{display:grid!important;grid-template-columns:240px minmax(0,1fr)!important;grid-template-rows:minmax(0,1fr)!important;height:var(--vvh,100dvh);min-height:0;overflow:hidden;padding:var(--shell-top) 0 0!important;box-sizing:border-box;background:var(--bg)}
html.hoop-rail:not(.hoop-session-embedded) body.p-chat.noside{grid-template-columns:0 minmax(0,1fr)!important}
html.hoop-rail:not(.hoop-session-embedded) body.p-chat #side{grid-column:1;grid-row:1;position:relative!important;inset:auto!important;width:240px;height:100%;min-height:0;margin:0;opacity:1!important;background:var(--bg);border-inline-end:1px solid var(--line);overflow:hidden}
html.hoop-rail:not(.hoop-session-embedded) body.p-chat.noside #side{display:none!important}
html.hoop-rail:not(.hoop-session-embedded) body.p-chat #main{grid-column:2!important;grid-row:1!important;position:relative!important;inset:auto!important;min-width:0;min-height:0;width:100%;height:100%;padding:0!important;margin:0!important;border-radius:0;box-shadow:none;opacity:1!important;overflow:hidden;max-width:none!important;transform:none!important;z-index:var(--z-pane)}
html.hoop-rail:not(.hoop-session-embedded) body.p-chat #main{display:flex!important}
html.hoop-rail:not(.hoop-session-embedded) body.p-chat #hooprail,
html.hoop-rail:not(.hoop-session-embedded) body.p-chat #hoop-matrix:not(.hm-open),
html.hoop-rail:not(.hoop-session-embedded) body.p-chat #zen-bar{display:none!important}
html.hoop-rail body.p-chat #hdr{position:relative;inset:auto;flex:none;min-height:44px;padding:0 16px!important;height:44px;box-sizing:border-box;background:var(--bg)}
/* …and on the page that bar is one strip across the whole width, over the rail's column, with the
   history card and the rail starting under it (owner 2026-10-11). The Work split is left alone: there
   the bar deliberately shares its row with the chancellor column beside the stage. */
html.hoop-rail:not(.hoop-session-embedded) body.p-chat:not(.work-split.stage-on) #hdr{position:fixed!important;inset:0 0 auto 0!important;width:100%;min-height:var(--shell-top);z-index:2}
html.hoop-rail body.p-chat #msgs{padding-top:12px;min-height:0;flex:1;overscroll-behavior:contain}
html.hoop-rail body.p-chat #composer{bottom:0!important;padding-bottom:calc(16px + env(safe-area-inset-bottom))}
html.hoop-embedded body.p-chat #main{padding-top:0!important}
html.hoop-rail body.p-chat .hello-doors,html.hoop-rail body.p-chat #chips-more{display:none}
@media(max-width:900px){
 html.hoop-rail:not(.hoop-session-embedded) body.p-chat,html.hoop-rail:not(.hoop-session-embedded) body.p-chat.noside{grid-template-columns:minmax(0,1fr)!important}
 html.hoop-rail:not(.hoop-session-embedded) body.p-chat #main{grid-column:1!important}
 html.hoop-rail:not(.hoop-session-embedded) body.p-chat #side{display:flex!important;position:fixed!important;top:0!important;bottom:0!important;inset-inline-start:0!important;width:min(280px,85vw);height:100dvh;z-index:var(--z-drawer);transform:translateX(-105%);visibility:hidden}
 html.hoop-rail:not(.hoop-session-embedded) body.p-chat.sideopen #side{transform:none;visibility:visible}
 html[dir="rtl"].hoop-rail:not(.hoop-embedded) body.p-chat #side{transform:translateX(105%)}
 html[dir="rtl"].hoop-rail:not(.hoop-embedded) body.p-chat.sideopen #side{transform:none}
 html.hoop-rail body.p-chat.sideopen #scrim{z-index:calc(var(--z-drawer) - 1)}
}



/* Opening an app retains the existing resizable work frame inside the selected
   session; it cannot displace the session toolbar or the host history. */
html.hoop-rail body.p-chat.work-split.stage-on:not(.stage-full) #main{display:grid!important;grid-template-columns:var(--wf-chancellor,var(--wf-chancellor-ideal)) var(--wf-divider-hit) minmax(var(--wf-check-min),1fr);grid-template-rows:minmax(0,1fr)}
html.hoop-rail body.p-chat.work-split.stage-on:not(.stage-full) #hdr{position:absolute;top:0;inset-inline-start:0;width:var(--wf-chancellor,var(--wf-chancellor-ideal))}
html.hoop-rail body.p-chat.work-split.stage-on:not(.stage-full) #msgs{padding-top:58px}
html.hoop-rail body.p-chat #chancellor-strip{z-index:var(--z-pane-raised)}
html.hoop-rail:not(.hoop-session-embedded) body.p-chat.check-full #chancellor-strip{inset-inline-start:auto;inset-inline-end:12px;top:64px}
/* A session hosted by another Chat shares its history and session controls.
   A Chat AppWindow on the desktop owns its history, even though navigation is embedded. */
html.hoop-session-embedded body.p-chat #side,html.hoop-session-embedded body.p-chat #scrim,
html.hoop-session-embedded body.p-chat #side-tg,html.hoop-session-embedded body.p-chat #newconv-top,
html.hoop-session-embedded body.p-chat #chat-active:not([hidden]){display:none!important}
html.hoop-embedded body.p-chat{padding:0!important;min-height:0;height:var(--vvh,100dvh)}
html.hoop-embedded body.p-chat #main{max-width:none;height:100%;border-radius:0;margin:0}
html.hoop-rail body.p-chat #pulse{display:none}

/* Cached application routes retain their navigation above the application. */
html.hoop-rail.hoop-app-full:not(.hoop-session-embedded):has(body.p-chat) #hooprail{display:flex!important}
html.hoop-rail.hoop-app-full:not(.hoop-session-embedded):has(body.p-chat) #hoop-matrix{display:block!important}

/* ═══ one sheet (0.2.198) ═══════════════════════════════════════════════
   The window is ONE surface: rail, session bar, history and conversation stand on the same
   paper (--sheet + its faint corner light). Nothing is told apart by a second fill colour.
   What floats — the history card, the composer, the chosen tab — is glass laid on the sheet:
   translucent, blurred, rimmed with light, soft-cornered. Regions are separated by space and
   light, never by a hard line. Small windows keep ONE bar of icons instead of three rows. */
html:not(.hoop-embedded){background:var(--sheet-light),var(--sheet);background-attachment:fixed}
html.hoop-rail:not(.hoop-embedded) body,
html.hoop-rail:not(.hoop-session-embedded) body.p-chat{background:transparent!important}
html.hoop-rail:not(.hoop-embedded) #hooprail#hooprail{background:transparent!important;border-inline-end:0!important}
/* no circle, plate or rim around any rail icon (owner 2026-10-10): the chosen one is only darker ink */
#hooprail .hr-i,#hooprail .hr-i.on,#hooprail .hr-i:hover,#hooprail .hr-ava,#hooprail .hr-ava.on,#hooprail .hr-ava:hover{background:transparent!important;box-shadow:none}
#hooprail .hr-i.on:before{display:none}

/* the session bar: part of the sheet, no line under it */

/* history: a glass card floating on the sheet */
@media (min-width:901px){
  html.hoop-rail:not(.hoop-session-embedded) body.p-chat #side{margin:var(--pane-gap) 0 var(--pane-gap) var(--pane-gap)!important;width:auto;height:auto;
    border:0!important;border-radius:var(--r-xl);background:var(--pane-glass)!important;
    -webkit-backdrop-filter:var(--pane-blur);backdrop-filter:var(--pane-blur);box-shadow:var(--pane-rim)}
  html.hoop-rail:not(.hoop-session-embedded) body.p-chat{grid-template-columns:calc(240px + var(--pane-gap)) minmax(0,1fr)!important}
  html.hoop-rail:not(.hoop-session-embedded) body.p-chat.noside{grid-template-columns:0 minmax(0,1fr)!important}
}
.p-chat #convlist .on, .p-chat #convlist [aria-current="true"], .p-chat #convlist .active{background:var(--pane-on)!important;box-shadow:var(--pane-on-rim);color:var(--fg)!important}
html.hoop-rail:not(.hoop-session-embedded) body.p-chat #main,
html.hoop-rail body.p-chat #hdr{background:transparent!important}
/* Embedded App windows do not always carry the outer hoop-rail class. Keep the
   chat title strip part of the window surface in those frames too. */
body.p-chat #hdr{background:transparent!important}
/* Chat's compact tool row floats over the sheet; its controls remain reachable while the
   conversation keeps a little breathing room below it. */
html.hoop-rail body.p-chat #hdr{border:0!important;box-shadow:none!important;-webkit-backdrop-filter:none!important;backdrop-filter:none!important}
body.p-chat #hdr{border:0!important;box-shadow:none!important;-webkit-backdrop-filter:none!important;backdrop-filter:none!important}
html.hoop-rail:not(.hoop-session-embedded) body.p-chat #msgs{padding-top:20px}
html.hoop-rail:not(.hoop-session-embedded) body.p-chat #side,
.p-chat #side{border-inline-end-color:transparent}

/* the composer: the one glass object the owner touches most */
.p-chat #composer{background:linear-gradient(to bottom,transparent,var(--sheet) 34%)!important}
.p-chat #cwrap{background:transparent!important}
body.codemode.p-chat #cwrap,body.p-chat #cwrap:has(#codebar:not([hidden])){background:var(--sheet)!important;border-radius:var(--r-2xl)}
.p-chat #compose-input{border:1px solid var(--line-soft);border-radius:var(--r-2xl);background:var(--pane-glass);
  -webkit-backdrop-filter:var(--pane-blur);backdrop-filter:var(--pane-blur);box-shadow:var(--pane-rim)}
.p-chat #compose-input:focus-within{border-color:color-mix(in oklab,var(--brand) 30%,var(--line-soft))}
.p-chat #send{border-radius:var(--r-pill)}

/* other apps on the sheet: their main card is the same glass, their side columns the same paper */
html:not(.hoop-embedded) .fd{border:0;background:var(--pane-glass);-webkit-backdrop-filter:var(--pane-blur);backdrop-filter:var(--pane-blur);box-shadow:var(--pane-rim);border-radius:var(--r-xl)}
html:not(.hoop-embedded) .fd-side{background:transparent;border-inline-end-color:var(--line-soft)}

/* small windows (≤900px): ONE bar. Tabs scroll in the middle, every door is an icon. */
@media(max-width:900px){
 html.hoop-rail:not(.hoop-session-embedded) body.p-chat #side{background:var(--pane-glass)!important;-webkit-backdrop-filter:var(--pane-blur);backdrop-filter:var(--pane-blur);
   box-shadow:var(--pane-rim);border-radius:0 var(--r-xl) var(--r-xl) 0}
}
/* very short windows: give the conversation the height */
@media(max-height:560px){
 html.hoop-rail body.p-chat #hdr{height:36px;min-height:36px}
 html.hoop-rail body.p-chat #composer{padding-bottom:calc(8px + env(safe-area-inset-bottom))}
}
/* the home sheet: the menubar is the sheet's own top edge; cards are glass panes (no blur —
   there can be many of them, and the rim alone already reads as glass on the lit sheet) */
html.hoop-rail:not(.hoop-embedded) .p-home .menubar{background:transparent!important;border-bottom-color:transparent!important}
html:not(.hoop-embedded) .card{border-color:transparent;background:var(--pane-glass);box-shadow:var(--pane-rim);border-radius:var(--r-xl)}
html:not(.hoop-embedded){scrollbar-color:var(--line-2) transparent}

/* Mobile is still the desktop: the app switcher is a small vertical edge rail.
   Keep it reachable in full-screen app windows and leave the old top/bottom doors
   out of the phone layout. nav.js adds its own style block after this sheet, so
   these declarations intentionally use !important for the shell geometry only. */
@media (max-width:720px){
  .p-home .tty input,.p-home .tty textarea{font-size:16px}
  .p-home .tty-log .ln .say{min-width:0;max-width:100%;overflow-wrap:anywhere;word-break:break-word}
  .p-home .tty-work .wb-head{min-height:28px;white-space:normal;min-width:0}
  .p-home .tty-box>.tty-t{max-width:calc(100% - 24px);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
  html.hoop-rail:not(.hoop-embedded) #hooprail#hooprail{
    position:fixed!important;
    inset-block-start:50%!important;
    inset-block-end:auto!important;
    inset-inline-end:max(8px,env(safe-area-inset-right))!important;
    inset-inline-start:auto!important;
    width:48px!important;
    min-width:48px!important;
    max-width:48px!important;
    height:auto!important;
    max-height:calc(100dvh - 32px - env(safe-area-inset-top) - env(safe-area-inset-bottom))!important;
    transform:translateY(-50%)!important;
    display:flex!important;
    flex-direction:column!important;
    align-items:center!important;
    gap:2px!important;
    padding:6px 4px!important;
    border:1px solid color-mix(in oklab,var(--fg) 12%,transparent)!important;
    border-radius:var(--r-xl);
    background:var(--glass-bg,var(--surface))!important;
    box-shadow:var(--glass-rim),var(--shadow-pop)!important;
    overflow:visible!important;
    z-index:10001!important;
  }
  html[dir="rtl"].hoop-rail:not(.hoop-embedded) #hooprail#hooprail{
    inset-inline-start:max(8px,env(safe-area-inset-left))!important;
    inset-inline-end:auto!important;
  }
  html.hoop-rail:not(.hoop-embedded) #hooprail>.hr-a{display:none!important}
  html.hoop-rail:not(.hoop-embedded) #hooprail .hr-rail,
  html.hoop-rail:not(.hoop-embedded) #hooprail .hr-rail-foot{
    display:flex!important;
    flex-direction:column!important;
    align-items:center!important;
    gap:2px!important;
    width:100%!important;
    max-height:none!important;
    overflow:visible!important;
    margin:0!important;
  }
  html.hoop-rail:not(.hoop-embedded) #hooprail .hr-rail-foot{margin-top:2px!important;padding-top:2px;border-top:1px solid var(--line-soft)}
  /* One program handle on a phone. The desktop rail's Home, fixed-app stack,
     open-tab strip, search and version controls are redundant here. */
  html.hoop-rail:not(.hoop-embedded) #hooprail .hr-rail>*:not(.hr-r-apps),
  html.hoop-rail:not(.hoop-embedded) #hooprail .hr-rail-foot{display:none!important}
  html.hoop-rail:not(.hoop-embedded) #hooprail .hr-r-apps{display:grid!important}
  html.hoop-rail:not(.hoop-embedded) #hooprail:has(.hr-r-apps) .hr-r-apps{margin:0!important}
  /* The launcher is the full app switcher. Once it is open, remove the handle
     from above it so the menu is a single surface and never a stacked rail. */
  html.hoop-rail:not(.hoop-embedded) body:has(#hoop-launcher) #hooprail{display:none!important}
  /* AI worker's single mobile program handle supersedes the compatibility rail.
     The handle owns the same launcher, so there must never be two app entry points. */
  html.hoop-rail:not(.hoop-embedded):has(.hoop-mobile-app-handle[data-hoop-mobile-app-handle="true"]) #hooprail#hooprail{display:none!important}
  .hoop-mobile-app-handle[data-hoop-mobile-app-handle="true"]{
    position:fixed!important;
    inset-block-start:50%!important;
    inset-block-end:auto!important;
    inset-inline-end:max(8px,env(safe-area-inset-right))!important;
    inset-inline-start:auto!important;
    display:grid!important;
    place-items:center!important;
    width:48px!important;
    height:48px!important;
    min-width:48px!important;
    min-height:48px!important;
    padding:0!important;
    transform:translateY(-50%)!important;
    z-index:10001!important;
    border:1px solid color-mix(in oklab,var(--fg) 12%,transparent)!important;
    border-radius:var(--r-xl);
    background:var(--glass-bg,var(--surface))!important;
    color:var(--fg)!important;
    box-shadow:var(--glass-rim),var(--shadow-pop)!important;
    -webkit-backdrop-filter:var(--glass-blur);backdrop-filter:var(--glass-blur);
    touch-action:manipulation;
  }
  html[dir="rtl"] .hoop-mobile-app-handle[data-hoop-mobile-app-handle="true"]{
    inset-inline-start:max(8px,env(safe-area-inset-left))!important;
    inset-inline-end:auto!important;
  }
  html.hoop-mobile-launcher-open .hoop-mobile-app-handle[data-hoop-mobile-app-handle="true"],
  body.hoop-mobile-launcher-open .hoop-mobile-app-handle[data-hoop-mobile-app-handle="true"]{display:none!important}
  html.hoop-rail:not(.hoop-embedded) #hooprail .hr-i,
  html.hoop-rail:not(.hoop-embedded) #hooprail .hr-ava{width:40px!important;height:40px!important;min-height:40px!important}
  html.hoop-rail:not(.hoop-embedded) #hooprail .hr-i svg{width:21px;height:21px}
  html.hoop-rail:not(.hoop-embedded) #hooprail .hr-open:empty{display:none!important}
  html.hoop-rail:not(.hoop-embedded) #hooprail .hr-ver{display:flex!important;flex-direction:column!important;align-items:center!important;width:40px!important;max-width:40px!important;overflow:hidden!important;font-size:var(--fs-2xs);white-space:normal}
  html.hoop-rail:not(.hoop-embedded) #hooprail #hoop-matrix{
    position:fixed!important;
    inset-block-start:50%!important;
    inset-block-end:auto!important;
    inset-inline-end:calc(56px + env(safe-area-inset-right))!important;
    inset-inline-start:auto!important;
    width:min(300px,calc(100vw - 88px - env(safe-area-inset-right)))!important;
    max-width:calc(100vw - 88px - env(safe-area-inset-right) - env(safe-area-inset-left))!important;
    max-height:calc(100dvh - 24px - env(safe-area-inset-top) - env(safe-area-inset-bottom))!important;
    transform:translateY(-50%)!important;
    overflow-y:auto!important;
  }
  html[dir="rtl"].hoop-rail:not(.hoop-embedded) #hooprail #hoop-matrix{
    inset-inline-start:calc(56px + env(safe-area-inset-left))!important;
    inset-inline-end:auto!important;
  }
  html.hoop-rail:not(.hoop-embedded) #hooprail.hm-open #hoop-matrix{transform:translateY(-50%)!important}
  /* The launcher is the phone's app shelf. Keep every registered app in a
     readable three-column grid so the last tile is visible without a hidden
     horizontal strip or a second rail. */
  #hoop-launcher .hl-row,
  #hoop-launcher .hl-door.open .hl-row{display:grid!important;grid-template-columns:repeat(3,minmax(0,1fr));gap:4px;overflow:visible;padding-bottom:0}
  #hoop-launcher .hl-door:not(.open) .hl-row{display:none!important}
  #hoop-launcher .hl-tile{min-width:0;flex:initial;padding-inline:4px}
  #hoop-launcher .hl-tile>span{min-width:0;max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
  /* Home's always-available AI status pill occupies the bottom safe area. A
     maximised/full Chat window must stop above it, including on short phone
     viewports where the keyboard reduces the visual height. */
  html.hoop-rail:has(body.p-home) > .win.max,
  html.hoop-rail:has(body.p-home) > .win.full{bottom:calc(56px + env(safe-area-inset-bottom))!important;height:auto!important}
  /* Any editable control remains at least 16px, including the desktop command line
     and the Chat textarea, so iOS Safari does not zoom the whole desktop. */
  input:not([type="checkbox"]):not([type="radio"]),textarea,select,
  [contenteditable="true"]{font-size:calc(var(--fs-base) + 1px)!important}
  html.hoop-rail body,
  html.hoop-rail body.p-chat,
  html.hoop-rail body.p-home{min-width:0!important;max-width:100vw!important;overflow-x:hidden!important}
  html.hoop-rail body.p-chat #main{transform-origin:center center}
  /* The edge rail is part of the viewport, so the live conversation and its
     composer reserve its hit area instead of letting "to latest" and text sit
     underneath the app switcher. */
  html.hoop-rail:not(.hoop-session-embedded) body.p-chat #main{padding-inline-end:calc(56px + env(safe-area-inset-right))!important;box-sizing:border-box}
  html[dir="rtl"].hoop-rail:not(.hoop-session-embedded) body.p-chat #main{padding-inline-end:0!important;padding-inline-start:calc(56px + env(safe-area-inset-left))!important}
  html.hoop-rail body.p-chat #tolatest{inset-inline-end:calc(68px + env(safe-area-inset-right))!important}
  html[dir="rtl"].hoop-rail body.p-chat #tolatest{inset-inline-end:auto!important;inset-inline-start:calc(68px + env(safe-area-inset-left))!important}
  html.hoop-rail body.p-chat #msgs,
  html.hoop-rail body.p-chat #composer,
  html.hoop-rail body.p-chat #compose-input,
  html.hoop-rail body.p-chat #inp{min-width:0;max-width:100%;box-sizing:border-box}
  /* The desktop gutter rule adds 18px to #msgs after its grid column has
     already been narrowed for the phone rail. Make that box border-box and
     clip only the accidental horizontal gutter; message text still wraps. */
  html.hoop-rail body.p-chat #msgs{padding-inline-end:0!important;overflow-x:hidden!important}
  .p-home .mb-facts{min-inline-size:0;max-inline-size:calc(100vw - 80px);overflow:hidden}
  .p-home .mb-facts .tf{max-inline-size:100%;white-space:normal;overflow:hidden;text-overflow:ellipsis;overflow-wrap:anywhere}
  .p-home .tty-facts{display:block;min-inline-size:0;max-inline-size:100%;overflow:hidden}
  .p-home .tty-facts .tf{display:block;min-inline-size:0;width:100%;max-inline-size:100%;white-space:normal;overflow-wrap:anywhere;overflow:hidden}
}

@media (max-width:720px) and (orientation:landscape){
  html.hoop-rail:not(.hoop-embedded) #hooprail#hooprail{max-height:calc(100dvh - 16px)!important}
}
/* tabs that do not fit fade out at the end instead of being cut mid-word */

/* ── the composer as one floating glass capsule (2026-10-08) ─────────────────────────────────────
   The capsule holds only attach · words · mic · settings · send. It floats on the conversation: the
   stream runs under it and shows through, blurred, the way Apple's floating controls sit on a page.
   Who, folder, Code, machine, agency and model wait behind the settings button in one glass panel
   that rises above the capsule (gram-mind.js setComposePanel); the choices are the owner's, shared by
   every client through config.composer. */
.p-chat #composer{background:transparent;padding-top:10px}
.p-chat #cwrap{background:transparent;gap:0}
.p-chat #compose-input{align-items:flex-end;gap:2px;padding:6px;border:1px solid color-mix(in oklab,var(--fg) 8%,transparent);border-radius:var(--r-2xl);
  background:var(--glass-bg);-webkit-backdrop-filter:var(--glass-blur);backdrop-filter:var(--glass-blur);
  box-shadow:var(--capsule-shadow);
  transition:border-color var(--dur-2)}
.p-chat #compose-input:focus-within{border-color:color-mix(in oklab,var(--brand) 34%,transparent);box-shadow:var(--capsule-shadow-focus)}
.p-chat #compose-input::before{display:none}
.p-chat #compose-input .cbtn{width:38px;height:38px;border-radius:50%;color:var(--dim);transition:background var(--dur-1),color var(--dur-1)}
.p-chat #compose-input .cbtn:hover,.p-chat #compose-input .cbtn.on{color:var(--fg);background:var(--pane-on);box-shadow:var(--pane-on-rim)}
.p-chat #inp{padding:7px 6px;min-height:38px}
.p-chat #csettings svg{width:19px;height:19px}
body.codemode.p-chat #csettings{color:var(--brand-ink)}
.p-chat #send{width:38px;height:38px;margin:0;border:0;border-radius:50%;opacity:1;background:transparent;color:var(--dim);box-shadow:none}
.p-chat #send.ready{background:var(--brand);color:var(--on-brand);box-shadow:var(--send-on-shadow)}
.p-chat #send.stop{background:var(--pane-on);color:var(--fg);box-shadow:var(--pane-on-rim)}
.p-chat #send:hover,.p-chat #send:active{transform:none}

.p-chat #compose-panel{position:absolute;bottom:calc(100% + 10px);inset-inline-end:0;z-index:6;
  width:min(380px,100%);max-height:min(62vh,520px);overflow:auto;display:flex;flex-direction:column;gap:4px;
  padding:8px;border-radius:var(--r-xl);background:var(--glass-bg);-webkit-backdrop-filter:var(--glass-blur);backdrop-filter:var(--glass-blur);
  box-shadow:var(--glass-rim),var(--shadow-pop);transform-origin:bottom right;animation:compose-panel-in var(--dur-2) var(--ease-standard)}
.p-chat #compose-panel[hidden]{display:none}
/* an empty conversation lets #composer scroll its welcome; while the panel is up it must not clip it */
body.p-chat.compose-panel-open #composer{overflow:visible}
@keyframes compose-panel-in{from{opacity:0;transform:translateY(6px) scale(.98)}to{opacity:1;transform:none}}
@media (prefers-reduced-motion:reduce){.p-chat #compose-panel{animation:none}}
.p-chat #compose-panel #compose-settings,.p-chat #compose-panel #composer-context,.p-chat #compose-panel #crail,
.p-chat #compose-panel #session-controls #codebar,.p-chat #compose-panel #session-controls #codepicks{display:flex;flex-direction:column;align-items:stretch;gap:2px;padding:0;margin:0;min-height:0}
.p-chat #compose-panel #session-controls[hidden],.p-chat #compose-panel #composer-context[hidden],.p-chat #compose-panel #codeagency[hidden]{display:none}
.p-chat #compose-panel #session-controls{padding:0 0 4px;margin-bottom:4px;border-bottom:1px solid var(--line-soft)}
.p-chat #compose-panel #crail .sp,.p-chat #compose-panel #mode-state,.p-chat #compose-panel #task-state:empty{display:none}
.p-chat #compose-panel #composer-context > button,.p-chat #compose-panel #codebtn,.p-chat #compose-panel #mpick,
.p-chat #compose-panel .pick,.p-chat #compose-panel #codeback{display:flex;align-items:center;gap:10px;width:100%;max-width:none;min-height:40px;
  padding:8px 12px;border:0;border-radius:var(--r-md);background:transparent;box-shadow:none;color:var(--fg);font:inherit;font-size:var(--fs-sm);text-align:start;cursor:pointer}
.p-chat #compose-panel #composer-context > button:hover,.p-chat #compose-panel #codebtn:hover,.p-chat #compose-panel #mpick:hover,
.p-chat #compose-panel .pick:hover,.p-chat #compose-panel #codeback:hover{background:var(--pane-on);box-shadow:var(--pane-on-rim)}
.p-chat #compose-panel #composer-context .composer-context-owner>span:last-child{display:inline}
.p-chat #compose-panel #codebtn[hidden],.p-chat #compose-panel #mpick[hidden]{display:none}
.p-chat #compose-panel #codebtn.on{color:var(--brand-ink)}
.p-chat #compose-panel #mpick{justify-content:space-between}
.p-chat #compose-panel #mpick-t{flex:1;min-width:0}
.p-chat #compose-panel .pick .pk-l{flex:none;color:var(--dim)}
.p-chat #compose-panel .pick .pk-v{flex:1;min-width:0;text-align:end}
.p-chat #compose-panel #codedevcwd{width:100%;min-height:36px;border:0;border-radius:var(--r-md);background:var(--pane-on);box-shadow:var(--pane-on-rim);color:var(--fg);font:inherit;font-size:var(--fs-sm);padding:8px 12px}
.p-chat #compose-panel #codedevcwd[hidden]{display:none}
@media (max-width:720px){.p-chat #compose-panel{width:100%;inset-inline:0}}
@media (prefers-reduced-transparency:reduce){
  .p-chat #compose-input,.p-chat #compose-panel{background:var(--surface);-webkit-backdrop-filter:none;backdrop-filter:none}
}
/* the panel reads top to bottom as one list: Code first when it is on (its machine, folder, runner, agency
   follow), otherwise who and which folder; the model last. #compose-settings and #crail only group the DOM. */
.p-chat #compose-panel #compose-settings,.p-chat #compose-panel #crail{display:contents}
.p-chat #compose-panel #session-controls{order:1;padding:0;margin:0;border:0}
.p-chat #compose-panel #composer-context{order:1}
.p-chat #compose-panel #codeagency{order:2;display:flex;flex-direction:column}
.p-chat #compose-panel #mpick{order:3}
.p-chat #compose-panel #codebtn{order:4}
.p-chat #compose-panel #task-state{order:5;padding:4px 12px}
body.codemode .p-chat #compose-panel #codebtn,body.codemode.p-chat #compose-panel #codebtn{order:0;background:var(--pane-on);box-shadow:var(--pane-on-rim)}
.p-chat #compose-panel #codeback,.p-chat #compose-panel #codecoordbtn{display:none}
.p-chat #compose-panel #codepicks .pick,.p-chat #compose-panel #codeagency .pick{flex:none;align-self:stretch;width:100%;max-width:none}
.p-chat #compose-panel .pick .pk-l{display:flex}
.p-chat #compose-panel .pick .pk-c{margin-inline-start:2px;color:var(--dim)}
.p-chat #compose-panel #mpick::before{content:"";flex:none;width:16px;height:16px;opacity:.75;background:currentColor;
  -webkit-mask:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='6' y='6' width='12' height='12' rx='2'/%3E%3Cpath d='M9 2v4M15 2v4M9 18v4M15 18v4M2 9h4M2 15h4M18 9h4M18 15h4'/%3E%3C/svg%3E") center/contain no-repeat;
  mask:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='6' y='6' width='12' height='12' rx='2'/%3E%3Cpath d='M9 2v4M15 2v4M9 18v4M15 18v4M2 9h4M2 15h4M18 9h4M18 15h4'/%3E%3C/svg%3E") center/contain no-repeat}
/* the conversation runs under the capsule and shows through it; only the strip below the capsule settles
   into the sheet. The Code posture keeps the same glass instead of a sheet-coloured card. */
body.p-chat #composer{background:linear-gradient(to bottom,transparent 72%,var(--sheet))!important}
body.codemode.p-chat #composer #cwrap,body.p-chat #composer #cwrap:has(#codebar:not([hidden])){background:transparent!important}
.p-chat #compose-panel .pick .pk-v{max-width:none}
.p-chat #compose-panel #codedevcwd{flex:none;height:auto;min-height:38px}

/* ── one left navigation (2026-10-08) ──────────────────────────────────────────────────────────
   The rail and the history card are the chat page's whole navigation, as in Hoop for Mac: no
   session bar over the conversation. The card opens with 新对话 as its first row; the header's
   panel button folds the card away and brings it back, and only a folded card puts 新对话 in the
   header too. Minimized windows live in the rail (nav.js), so the floating tray stands down there. */
.p-chat #side #newconv{min-height:40px;border:0;border-radius:var(--r-md);background:none;box-shadow:none;font-weight:500;color:var(--fg);padding-inline:14px}
.p-chat #side #newconv:hover{background:var(--lift)}
.p-chat #side #newconv svg{color:var(--dim)}
.p-chat #side #newconv:hover svg{color:var(--brand-ink)}
.p-chat #side #tempconv{margin-top:0}
@media (min-width:901px){
  html.hoop-rail:not(.hoop-session-embedded) body.p-chat #hdr #side-tg{display:grid}
  html.hoop-rail:not(.hoop-session-embedded) body.p-chat:not(.noside) #hdr #newconv-top{display:none}
  html.hoop-rail:not(.hoop-session-embedded) body.p-chat.noside #hdr #newconv-top{display:grid}
}
@media (min-width:721px){ html.hoop-rail:not(.hoop-embedded) #dock-tray{display:none} }

/* ── glass controls, never filled (owner 2026-10-09) ──────────────────────────────────────────────
   No button carries a solid fill. Every control is a pane of glass: a thin see-through tint, the page
   blurred behind it, a hairline rim lit on top. A main action is told apart by the colour of its words
   and rim, never by a filled body. Status dots and switches are not buttons and keep their colour. */
.btn,.btn-primary,.btn-secondary,.btn-tonal,.btn-danger,.rec-key.go,.dp-d.on{
  background:var(--ctl-glass);-webkit-backdrop-filter:blur(18px) saturate(1.6);backdrop-filter:blur(18px) saturate(1.6);
  border:1px solid var(--ctl-rim);box-shadow:var(--ctl-lit)}
.btn:hover:not(:disabled),.btn-secondary:hover:not(:disabled),.btn-tonal:hover:not(:disabled){background:var(--ctl-glass-hover);border-color:var(--ctl-rim-hover)}
.btn-ghost{background:transparent;border-color:transparent;box-shadow:none;-webkit-backdrop-filter:none;backdrop-filter:none}
.btn-ghost:hover:not(:disabled){background:var(--ctl-glass);border-color:var(--ctl-rim);box-shadow:var(--ctl-lit)}
.btn-primary,.rec-key.go,.dp-d.on{color:var(--brand-ink);border-color:color-mix(in oklab, var(--brand) 55%, transparent);font-weight:600}
.btn-primary:hover:not(:disabled){background:var(--ctl-glass-hover);border-color:var(--brand);color:var(--brand-ink)}
.btn-danger{color:var(--bad);border-color:color-mix(in oklab, var(--bad) 45%, transparent)}
.btn-danger:hover:not(:disabled){background:var(--ctl-glass-hover);border-color:var(--bad)}

/* the composer's buttons: clear until touched, glass when hovered or on; send never fills */
.p-chat #compose-input .cbtn:hover,.p-chat #compose-input .cbtn.on{background:var(--ctl-glass);color:var(--fg);box-shadow:var(--ctl-ring)}
.p-chat #send.ready{background:var(--ctl-glass);color:var(--brand-ink);
  -webkit-backdrop-filter:blur(18px) saturate(1.6);backdrop-filter:blur(18px) saturate(1.6);
  box-shadow:var(--ctl-ring-brand)}
.p-chat #send.ready:hover{background:var(--ctl-glass-hover);box-shadow:var(--ctl-ring-brand-hover)}
.p-chat #send.stop{background:var(--ctl-glass);box-shadow:var(--ctl-ring)}

/* ── one quiet page (owner 2026-10-09) ────────────────────────────────────────────────────────────
   No send button: Enter sends, Shift+Enter is a new line. While the AI replies a quiet word 「停止」
   stands inside the capsule — words only, no circle — and Esc stops too (gram-mind.js sendUI).
   The rail has three icons (nav.js). Open things are tabs in the title bar itself, like Obsidian: the
   conversation plus every open app. With one thing open there is no strip, only its one-line title. */
.p-chat #compose-input #send:not(.stop){display:none}
.p-chat #compose-input #send.stop,.p-chat #compose-input #send.stop:hover{display:inline-flex;align-items:center;width:auto;min-width:0;height:36px;margin:0;padding:0 10px;
  border:0;border-radius:var(--r-pill);background:transparent;box-shadow:none;-webkit-backdrop-filter:none;backdrop-filter:none;
  color:var(--dim);font:inherit;font-size:var(--fs-sm);white-space:nowrap;opacity:1;filter:none;transform:none;cursor:pointer}
.p-chat #compose-input #send.stop:hover{color:var(--fg)}
.p-chat #compose-input #send.stop:focus-visible{outline:2px solid var(--brand-ink);outline-offset:-2px}
/* 停止 is a friendly shape (owner 2026-10-10): a soft warm circle holding a small rounded square, with a thin
   ring turning slowly around it while the reply is being thought — click to stop. */
.p-chat #compose-input #send.stop,.p-chat #compose-input #send.stop:hover{position:relative;align-self:center;justify-content:center;width:30px;height:30px;padding:0;margin-block:0;margin-inline:2px 3px;border-radius:50%;background:var(--brand-soft);color:var(--brand-ink)}
.p-chat #compose-input #send.stop::before{content:"";width:9px;height:9px;border-radius:var(--r-2xs);background:currentColor}
.p-chat #compose-input #send.stop::after{content:"";position:absolute;inset:0;border-radius:50%;border:1.5px solid transparent;border-top-color:var(--brand);border-inline-end-color:var(--brand);animation:send-stop-turn var(--motion-pulse) var(--ease-linear) infinite}
.p-chat #compose-input #send.stop:hover{background:var(--brand);color:var(--on-brand)}
@keyframes send-stop-turn{to{transform:rotate(360deg)}}
@media (prefers-reduced-motion:reduce){.p-chat #compose-input #send.stop::after{animation:none}}

/* a tighter page: a 40px title bar, a lower capsule, less air under it — nothing cramped */
html.hoop-rail body.p-chat #hdr{height:40px;min-height:40px;gap:4px;padding:0 10px!important}
html.hoop-rail body.p-chat #hdr .hbtn{width:32px;height:32px}
html.hoop-rail body.p-chat #hdr .hbtn svg,html.hoop-rail body.p-chat #hdr .hbtn [data-icon] svg{width:18px;height:18px}
html.hoop-rail body.p-chat #ctitle{font-size:var(--fs-sm)}
.p-chat #composer{padding-top:6px}
html.hoop-rail body.p-chat #composer{padding-bottom:calc(12px + env(safe-area-inset-bottom))}
.p-chat #compose-input{padding:4px}
.p-chat #compose-input .cbtn{width:36px;height:36px}
.p-chat #inp{min-height:36px;padding:6px}
@media (max-width:720px){
  html.hoop-rail body.p-chat #hdr{padding:env(safe-area-inset-top) 6px 0!important;height:calc(44px + env(safe-area-inset-top));min-height:0}
  html.hoop-rail .p-chat #composer{padding-inline:10px;padding-bottom:calc(8px + env(safe-area-inset-bottom))}
}

/* the tab strip */
#hoop-tabs{display:flex;align-items:center;gap:2px;flex:1 1 auto;min-width:0;height:100%;overflow-x:auto;overflow-y:hidden;scrollbar-width:none;
  -webkit-mask-image:linear-gradient(to right,var(--fg) calc(100% - 24px),transparent);mask-image:linear-gradient(to right,var(--fg) calc(100% - 24px),transparent)}
[dir=rtl] #hoop-tabs{-webkit-mask-image:linear-gradient(to left,var(--fg) calc(100% - 24px),transparent);mask-image:linear-gradient(to left,var(--fg) calc(100% - 24px),transparent)}
#hoop-tabs::-webkit-scrollbar{display:none}
#hoop-tabs[hidden]{display:none}
#hoop-tabs .ht-tab{position:relative;display:flex;align-items:center;gap:7px;flex:0 1 200px;min-width:88px;height:30px;padding-inline:10px 4px;
  border-radius:var(--r-md);color:var(--dim);font-size:var(--fs-sm);cursor:pointer;user-select:none;-webkit-user-select:none;
  transition:background var(--motion-fast),color var(--motion-fast)}
#hoop-tabs .ht-tab:hover{color:var(--fg);background:var(--lift)}
#hoop-tabs .ht-tab.on{color:var(--fg);background:var(--pane-on);box-shadow:var(--pane-on-rim)}
#hoop-tabs .ht-tab:focus-visible{outline:2px solid var(--brand-ink);outline-offset:-2px}
#hoop-tabs .ht-tab.min .ht-n{opacity:.7}
#hoop-tabs .ht-i{display:grid;place-items:center;flex:none;width:16px;height:16px}
#hoop-tabs .ht-i svg{width:16px;height:16px}
#hoop-tabs .ht-tab[data-app=chat]{padding-inline-end:10px}
#hoop-tabs .ht-n{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
#hoop-tabs .ht-x{display:grid;place-items:center;flex:none;width:22px;height:22px;padding:0;border:0;border-radius:var(--r-sm);background:none;
  color:var(--dim);font:400 16px/1 var(--font,system-ui);cursor:pointer;opacity:0}
#hoop-tabs .ht-tab:hover .ht-x,#hoop-tabs .ht-tab.on .ht-x,#hoop-tabs .ht-tab:focus-within .ht-x{opacity:1}
#hoop-tabs .ht-x:hover{color:var(--fg);background:var(--lift)}
@media (hover:none){#hoop-tabs .ht-x{opacity:1}}
/* with tabs: the title bar spans the whole page (over the conversation and the app beside it), the
   conversation's own title and the app's own bar step back — their names are on the tabs */
body.p-chat.has-tabs #ctitle{display:none}
html.hoop-rail body.p-chat.has-tabs #hdr{display:flex!important;position:absolute!important;top:0;inset-inline:0;width:auto!important;z-index:var(--z-pane-raised)}
html.hoop-rail:not(.hoop-session-embedded) body.p-chat.has-tabs #main{padding-top:40px!important}
html.hoop-rail body.p-chat.has-tabs #msgs,html.hoop-rail body.p-chat.has-tabs.work-split.stage-on:not(.stage-full) #msgs{padding-top:12px}
body.p-chat.has-tabs #chancellor-strip{display:none!important}
body.p-chat.has-tabs.stage-on #stage{padding-top:0}
/* open apps live in the rail (nav.js): the stage needs no strip of its own — but it keeps its bar, whose
   lights (close · minimize · full/split) are the way out even when the app inside never answers */
body.p-chat.rail-tabs #chancellor-strip{display:none!important}
body.p-chat.rail-tabs.stage-on #stage{padding-top:0}
body.p-chat.stage-on.stage-full #tolatest{display:none!important}
/* an app tab in front: the conversation's own buttons (history, new chat) go with the conversation */
html.hoop-rail:not(.hoop-session-embedded) body.p-chat.has-tabs.stage-full #hdr #side-tg,html.hoop-rail:not(.hoop-session-embedded) body.p-chat.has-tabs.stage-full #hdr #newconv-top{display:none!important}
/* an app tab in front fills the page: the history column it hides gives its width back */
html.hoop-rail:not(.hoop-session-embedded) body.p-chat.stage-on.stage-full{grid-template-columns:0 minmax(0,1fr)!important}
@media (min-width:721px){html.hoop-rail:not(.hoop-session-embedded) body.p-chat.has-tabs #hdr #newconv-top{display:grid}}
/* the first date in a conversation sits close under the title bar instead of a band of air */
.p-chat #msgs > :not(.m) + .m.day{margin-top:6px}

/* `/` commands (gram-mind.js): Hoop for Terminal's list above the composer, and the rows a command answers with */
#slash{max-height:min(46vh,320px);overflow:auto;padding:4px;border:1px solid var(--line-2);border-radius:var(--r-lg);background:var(--surface);box-shadow:var(--shadow-1)}
#slash[hidden]{display:none}
.slash-group{padding:8px 10px 2px;font-size:var(--fs-2xs);color:var(--dim);letter-spacing:.06em;text-transform:uppercase}
.slash-item{display:flex;align-items:baseline;gap:12px;width:100%;padding:7px 10px;border:0;border-radius:var(--r-md);background:none;color:inherit;text-align:start;font:inherit;cursor:pointer}
.slash-item.on,.slash-item:hover{background:var(--lift)}
.slash-item.off{opacity:.5;cursor:default}
.slash-name{flex:none;font-family:var(--mono);font-size:var(--fs-sm)}
.slash-desc{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--dim);font-size:var(--fs-sm)}
.slash-none{padding:10px;color:var(--dim);font-size:var(--fs-sm)}
@media (pointer:coarse){.slash-item{min-height:44px;align-items:center}.slash-desc{white-space:normal}}
.m.pa.cmd-refused .mdbody{color:var(--dim)}

/* ═══ the desktop (owner 2026-10-12) ═══════════════════════════════════════════════════════════
   A computer's Home is only a wallpaper: the top bar spans the whole top row, the rail stands under
   it, and windows float over one calm colour as light glass. home.js puts html.hoop-sky on the
   signed-in desktop at ≥721px; a phone keeps its Home exactly as it was. No stars, no gradient, no
   motion. data-wall: amber = 素色 (the theme's own colour, default) · plain = 晨雾 · ink = 墨夜 · custom. */
@media (min-width:721px){
  html.hoop-sky:not(.hoop-embedded){background:var(--bg)}
  html.hoop-sky[data-wall="plain"]:not(.hoop-embedded){background:var(--wall-plain)}
  html.hoop-sky[data-wall="ink"]:not(.hoop-embedded){background:var(--wall-ink)}
  html.hoop-sky[data-wall="custom"]:not(.hoop-embedded){background:var(--wall-ink) var(--home-wallpaper, none) center/cover no-repeat}
  html.hoop-sky body.p-home{background:transparent!important}
  /* nothing on the desktop but its colour: the phone's line, tree and app list stand down */
  html.hoop-sky .p-home .pa-home{width:auto; margin:0; padding:0; min-height:calc(100dvh - var(--shell-top,0px)); animation:none}
  html.hoop-sky .p-home .pa-home>section{display:none}
  /* on a dark wallpaper the top bar and the rail take light ink */
  html.hoop-sky body.p-home .menubar,
  html.hoop-sky body.p-home #hooprail .hr-rail,
  html.hoop-sky body.p-home #hooprail .hr-ver{
    color:var(--fg)}   /* their light ink: tokens.css (the desktop) */
  html.hoop-sky[data-wall="custom"] body.p-home :is(.menubar, #hooprail .hr-rail){text-shadow:var(--sky-text-shadow)}
  html.hoop-sky body.p-home .menubar .mb-b:hover{background:var(--lift)}
  /* a window on the desktop is light glass: the wallpaper shows softly through its edges and its page */
  html.hoop-sky .win{background:var(--sky-pane); -webkit-backdrop-filter:blur(30px) saturate(1.35); backdrop-filter:blur(30px) saturate(1.35);
    box-shadow:var(--glass-rim), var(--shadow-sky-win)}
  html.hoop-sky .win.focused{box-shadow:var(--glass-rim), var(--shadow-win-focus), var(--shadow-sky-win-focus)}
  html.hoop-sky .win .win-body, html.hoop-sky .win .appwindow-frame{background:transparent}
  html.hoop-sky .win.full{background:var(--bg)}
}
/* ═══ the terminal desktop (owner 2026-10-12: after ~/Desktop/…/cc-peorain.html, not a blank paper) ═════
   Shown only on the signed-in computer desktop (html.hoop-sky). It wears the theme like a Ghostty window
   (tokens.css --tty-*: 白 / 黄 / 黑, owner 2026-10-15); a picture shows through its glass. */
.p-home .tty{display:none}
@media (min-width:721px){
  html.hoop-sky:not(.hoop-embedded), html.hoop-sky[data-wall]:not(.hoop-embedded){background:var(--tty-ink)}
  html.hoop-sky[data-wall="custom"]:not(.hoop-embedded){background:var(--tty-ink) var(--home-wallpaper, none) center/cover no-repeat}
  html.hoop-sky .p-home .tty{display:block; position:relative; min-height:calc(100dvh - var(--shell-top,0px))}
}
/* what is inside the terminal holds at every width (phones show it too, below) */
.p-home .tty{color:var(--tty-fg); font:var(--fs-h)/1.55 var(--mono)}
  .p-home .tty ::selection{background:var(--tty-accent); color:var(--tty-ink)}
  .p-home .tty-rain{position:fixed; inset:0; width:100%; height:100%; z-index:0; pointer-events:none}
  .p-home .tty-scan{position:fixed; inset:0; z-index:1; pointer-events:none; opacity:.015; background:repeating-linear-gradient(to bottom,var(--tty-black) 0 1px,transparent 1px 3px)}
  .p-home .tty-wrap{position:relative; z-index:2; max-width:880px; margin:0 auto; padding:clamp(24px,5vh,56px) 16px 72px}
  .p-home .tty-box{position:relative; margin-top:26px; padding:18px 16px 14px; border:1px solid var(--tty-line); background:color-mix(in srgb,var(--tty-bg) 84%,transparent)}
  .p-home .tty-box>.tty-t{position:absolute; top:-.8em; left:12px; max-width:calc(100% - 24px); overflow:hidden; text-overflow:ellipsis; white-space:nowrap; padding:0 6px; background:var(--tty-ink); color:var(--tty-accent)}
  .p-home .tty-box>.tty-t::before{content:"┤ "; color:var(--tty-line)}
  .p-home .tty-box>.tty-t::after{content:" ├"; color:var(--tty-line)}
  /* one line of facts (owner 2026-10-14: the bars carry the system, compact): label dim, value bright */
  .p-home .tf{display:inline-flex; align-items:baseline; gap:.6ch; white-space:nowrap; font:inherit; color:var(--tty-hi,var(--fg)); background:none; border:0; padding:0; font-variant-numeric:tabular-nums}
  .p-home .tf>i{font-style:normal; color:var(--tty-dim,var(--dim))}
  .p-home .tf.bar{color:var(--tty-accent,var(--fg))} .p-home .tf.ok{color:var(--tty-ok,var(--fg))} .p-home .tf.warn{color:var(--tty-warn,var(--warn))} .p-home .tf.dim{color:var(--tty-dim,var(--dim))}
  .p-home button.tf{cursor:pointer} .p-home button.tf:hover, .p-home button.tf:focus-visible{color:var(--tty-accent,var(--fg)); outline:0}
  /* the owner's computers: the first line of the conversation box, under a dashed rule */
  .p-home .tty-devs{display:flex; flex-wrap:wrap; gap:4px 3ch; padding-bottom:10px; margin-bottom:6px; border-bottom:1px dashed var(--tty-line)}
  /* the facts line stands in for the two bars where they are not drawn (below 900px) */
  .p-home .tty-facts{display:none; flex-wrap:wrap; gap:2px 2.5ch; font-size:var(--fs-xs)}
  /* the conversation box grows and shrinks as lines arrive: the page must not slide to follow it */
  .p-home .tty, .p-home .tty *{overflow-anchor:none}
  .p-home .tty-term{cursor:text}
  .p-home .tty-log{max-height:calc(100dvh - var(--shell-top,0px) - 300px); min-height:220px; overflow-y:auto; white-space:pre-wrap; word-break:break-word}
  .p-home .tty-log .ln.dim{color:var(--tty-dim)} .p-home .tty-log .ln.ok{color:var(--tty-ok)} .p-home .tty-log .ln.warn{color:var(--tty-warn)}
  .p-home .tty-log .ln.err{color:var(--tty-err)} .p-home .tty-log .ln.acc{color:var(--tty-accent)} .p-home .tty-log .ln.hi{color:var(--tty-hi)}
  .p-home .tty-ps{color:var(--tty-accent); white-space:nowrap} .p-home .tty-ps i{color:var(--tty-accent); font-style:normal}
  /* 「↓ 下面还有」: the reply continues below the box's edge; one press goes there (nothing scrolls by itself) */
  .p-home .tty-more{display:block; min-height:28px; margin:2px 0 0 auto; font:inherit; font-size:var(--fs-xs); color:var(--tty-accent); background:transparent; border:0; padding:0 4px; cursor:pointer}
  .p-home .tty-more[hidden]{display:none}
  .p-home .tty-more:hover, .p-home .tty-more:focus-visible{text-decoration:underline; outline:0}
  .p-home .tty-prompt{display:flex; align-items:flex-start; gap:1ch; margin-top:4px}
  /* several lines (home.js promptWire sets the height): starts one line tall, the prompt and the tools stay on its first line */
  .p-home .tty-prompt textarea{flex:1; min-width:0; min-height:0; height:auto; resize:none; overflow-y:hidden; line-height:inherit; white-space:pre-wrap; overflow-wrap:anywhere; background:transparent!important; border:0!important; border-radius:0; box-shadow:none!important; outline:0; padding:0!important; margin:0; color:var(--tty-hi); font:inherit; caret-color:var(--tty-accent)}
  .p-home .tty-prompt textarea::placeholder{color:var(--tty-dim)}
  .p-home .tty-chips{display:flex; flex-wrap:wrap; gap:8px; margin-top:14px; padding-top:12px; border-top:1px dashed var(--tty-line)}
  .p-home .tty-chiprow{display:contents}
  .p-home .tty-chips button{font:inherit; font-size:var(--fs-xs); color:var(--tty-fg); background:transparent; border:1px solid var(--tty-line); border-radius:0; padding:2px 10px; cursor:pointer}
  .p-home .tty-chips button::before{content:"["; color:var(--tty-dim); margin-right:4px}
  .p-home .tty-chips button::after{content:"]"; color:var(--tty-dim); margin-left:4px}
  .p-home .tty-chips button:hover,.p-home .tty-chips button:focus-visible{color:var(--tty-ink); background:var(--tty-accent); border-color:var(--tty-accent); outline:0}
  .p-home .tty-status{position:fixed; left:0; right:var(--dock-w,0px); bottom:0; z-index:10001; display:flex; align-items:center; font-size:var(--fs-xs); white-space:nowrap;
    background:color-mix(in srgb,var(--tty-ink) 55%,transparent); -webkit-backdrop-filter:var(--glass-blur); backdrop-filter:var(--glass-blur);
    border-top:1px solid var(--tty-line)}   /* glass like the top bar (owner 2026-10-15): the bars belong to the desktop, never a band of their own */
  /* the bottom line holds the mode, the one hint, the clock and 雨; this Hoop's own facts are on the top bar
     (owner 2026-10-15: one changing fact at the top right, nothing repeated down here) */
  .p-home .tty-status>span{padding:4px 12px}
  .p-home .tty-status .tty-mode{background:var(--tty-accent); color:var(--tty-ink); font-weight:bold}
  .p-home .tty-status .tty-grow{flex:1; overflow:hidden; text-overflow:ellipsis; color:var(--tty-dim)}
  .p-home .tty-status input.tty-grow{width:0;min-width:0;min-height:36px;padding:6px 12px;border:0;border-radius:0;outline:0;background:transparent;box-shadow:none;font:inherit;color:var(--tty-fg)}
  .p-home .tty-status input.tty-grow::placeholder{color:var(--tty-dim);opacity:1}
  .p-home .tty-status:focus-within{border-top-color:var(--tty-accent)}
  .p-home .tty-status :is(.tty-mode,.tty-entry-send){flex:none;align-self:stretch;min-width:40px;padding:4px 12px;border:0;border-radius:0;font:inherit;cursor:pointer}
  .p-home .tty-status .tty-entry-send{background:transparent;color:var(--tty-accent);font-size:var(--fs-h)}
  .p-home .tty-status .tty-entry-send:disabled{opacity:.35;cursor:default}
  .p-home .tty-status button:focus-visible{outline:2px solid var(--tty-accent);outline-offset:-2px}
  .p-home .tty-status .tty-sep{color:var(--tty-line); padding:4px 0}
  /* the one clock of the desktop (owner 2026-10-13: not twice): date and time, one format per language */
  .p-home .tty-status .tty-clock{color:var(--tty-fg); font-variant-numeric:tabular-nums}
  /* the local preview pins its own small label (主线 <sha>) over the bottom-right corner: the status line ends before it */
  .p-home:has(> #lp-badge) .tty-status{padding-inline-end:var(--preview-badge-room)}
  /* the 雨 word is the rain's switch (the chip row no longer carries it) */
  .p-home .tty-status .tty-rainbtn{font:inherit; color:inherit; background:none; border:0; padding:4px 12px; cursor:pointer}
  .p-home .tty-status .tty-rainbtn:hover, .p-home .tty-status .tty-rainbtn:focus-visible{color:var(--tty-accent); outline:0}
  /* the box is a conversation (home.js desktop conversation): replies in the terminal's own ink, the
     working step dim; while a turn runs the prompt stays usable to say Esc */
  .p-home .tty-log .ln.reply{color:var(--tty-fg); margin-bottom:var(--sp-2)}
  .p-home .tty-log .ln.step{font-style:italic}
  .p-home .tty-log .ln.step.working{font-style:normal}
  /* the conversation's gutter (Hoop for Terminal's transcript): one 2ch column of marks, every line's words at
     the same left edge — › the owner, ● Hoop, ◌ working, ✓ done, ▲ warning, ✗ error, • a note */
  .p-home .tty-log .ln.mk{display:grid; grid-template-columns:2ch minmax(0,1fr); align-items:baseline}
  .p-home .tty-log .ln.mk>.tty-mk{white-space:pre; user-select:none}
  .p-home .tty-log .ln.reply>.tty-mk{color:var(--tty-accent)}
  .p-home .tty-log .ln.hi>.tty-mk{color:var(--tty-accent)}
  /* the Chat page's rhythm in the terminal's ink: a quiet speaker line, the words under it, air between turns */
  .p-home .tty-log .ln.hi{margin-top:var(--sp-5)} .p-home .tty-log .ln.reply{margin-top:var(--sp-4)}
  .p-home .tty-log #tty-conv>.ln.hi:first-child{margin-top:var(--sp-3)}
  /* Speaker names share the first line with short plain replies. This keeps a
     two-turn exchange readable without spending one full line on each label;
     markdown replies remain block content below their label. */
  .p-home .tty-log .ln .who{display:inline; color:var(--tty-dim); font-size:var(--fs-xs); line-height:1.6; margin-inline-end:1ch}
  .p-home .tty-log .ln .say:not(.md){display:inline}
  .p-home .tty-log .ln.hi .say{color:var(--tty-hi)}
  /* a reply in markdown (owner 2026-10-13): Chat's structure in the terminal's ink — bold, lists, tables,
     code and links — with no rounded corners and no colour that is not the terminal's own */
  .p-home .tty-log .ln .say.md{white-space:normal}
  .p-home .tty-log .ln .say.md>:first-child{margin-top:0} .p-home .tty-log .ln .say.md>:last-child{margin-bottom:0}
  .p-home .tty-log .ln .say.md :is(p, ul, ol, pre, blockquote, .tty-tblw, h1, h2, h3, h4){margin:0 0 var(--sp-2)}
  .p-home .tty-log .ln .say.md :is(h1, h2, h3, h4){font-size:inherit; color:var(--tty-accent); font-weight:bold}
  .p-home .tty-log .ln .say.md :is(ul, ol){padding-inline-start:3ch}
  .p-home .tty-log .ln .say.md ul{list-style:none} .p-home .tty-log .ln .say.md ul>li::before{content:"- "; color:var(--tty-dim); margin-inline-start:-2ch}
  .p-home .tty-log .ln .say.md strong{color:var(--tty-hi)} .p-home .tty-log .ln .say.md em{color:var(--tty-hi)}
  .p-home .tty-log .ln .say.md a{color:var(--tty-link, var(--tty-accent)); text-decoration:underline; text-underline-offset:3px; cursor:pointer}
  .p-home .tty-log .ln .say.md code{color:var(--tty-accent); font:inherit}
  .p-home .tty-log .ln .say.md pre code{color:var(--tty-fg)}   /* a block speaks in the syntax branch (hljs, as in Chat) */
  .p-home .tty-log .ln .say.md pre{white-space:pre; overflow-x:auto; padding:8px 12px; border:1px solid var(--tty-line); background:var(--tty-code, var(--tty-ink))}
  .p-home .tty-log .ln .say.md pre code{color:var(--tty-fg)}
  .p-home .tty-log .ln .say.md blockquote{padding-inline-start:2ch; border-inline-start:1px solid var(--tty-line); color:var(--tty-dim)}
  .p-home .tty-log .ln .say.md hr{border:0; border-top:1px dashed var(--tty-line); margin:var(--sp-2) 0}
  .p-home .tty-log .tty-tblw{overflow-x:auto}
  .p-home .tty-log .ln .say.md table{border-collapse:collapse; white-space:nowrap}
  .p-home .tty-log .ln .say.md :is(th, td){border:1px solid var(--tty-line); padding:2px 10px; text-align:start}
  .p-home .tty-log .ln .say.md th{color:var(--tty-accent); font-weight:normal}
  /* every page or address a reply names is one press away: [ 打开 /ui/notes ] */
  .p-home .tty-open{display:flex; flex-wrap:wrap; gap:8px; margin-top:var(--sp-2); white-space:normal}
  .p-home .tty-openchip{font:inherit; font-size:var(--fs-xs); color:var(--tty-accent); background:transparent; border:1px solid var(--tty-accent); border-radius:0; padding:2px 10px; cursor:pointer; max-width:100%; overflow:hidden; text-overflow:ellipsis; white-space:nowrap}
  .p-home .tty-openchip::before{content:"[ "; color:var(--tty-dim)} .p-home .tty-openchip::after{content:" ]"; color:var(--tty-dim)}
  .p-home .tty-openchip:hover, .p-home .tty-openchip:focus-visible{color:var(--tty-ink); background:var(--tty-accent); outline:0}
  .p-home .tty-term.busy .tty-prompt textarea::placeholder{color:transparent}
/* each pane's composer (owner 2026-10-16, home.js composerWire): at the end of the prompt line a dim word — who answers,
   Agent · model · effort — beside the adjuster's sliders, and a microphone; `/` lists the commands over the line. The
   terminal's own ink only: nothing filled until hovered, a recording counts in the error colour. */
  .p-home .tty-prompt{position:relative}
  .p-home .tty-tools{flex:none; display:flex; align-items:center; gap:2px; margin-inline-start:auto; font-size:var(--fs-xs)}
  .p-home .tty-tools button{display:inline-flex; align-items:center; gap:.8ch; min-width:28px; min-height:28px; padding:0 6px; font:inherit; color:var(--tty-dim); background:none; border:0; border-radius:0; cursor:pointer; white-space:nowrap}
  .p-home .tty-tools button:hover, .p-home .tty-tools button:focus-visible, .p-home .tty-tools button.on{color:var(--tty-accent); outline:0}
  .p-home .tty-tools svg{width:14px; height:14px; flex:none}
  .p-home .tty-adj i{display:inline-flex}
  .p-home .tty-adjt{max-width:34ch; overflow:hidden; text-overflow:ellipsis}
  .p-home .tty-mic.rec{color:var(--tty-err); font-variant-numeric:tabular-nums}
  .p-home .tty-slash{position:absolute; inset-inline:0; bottom:calc(100% + 4px); z-index:5; max-height:min(40vh,300px); overflow-y:auto; padding:4px 0; border:1px solid var(--tty-line); background:var(--tty-ink); font-size:var(--fs-sm)}
  .p-home .tty-slash[hidden]{display:none}
  .p-home .tty-sl{display:grid; grid-template-columns:minmax(10ch,max-content) minmax(0,1fr); column-gap:2ch; padding:2px 12px; color:var(--tty-dim); cursor:pointer}
  .p-home .tty-sl b{font-weight:normal; color:var(--tty-fg)}
  .p-home .tty-sl span{overflow:hidden; text-overflow:ellipsis; white-space:nowrap}
  .p-home .tty-sl.on, .p-home .tty-sl:hover{background:var(--selection)} .p-home .tty-sl.on b{color:var(--tty-accent)}
  /* a narrow pane keeps the two icons and lets the words go */
  .p-home .tty-canvas .tty-pane{container-type:inline-size}
  @container (max-width:400px){ .p-home .tty-adjt{display:none} }
/* the adjuster (a menu, so outside the terminal's colours): label · value · ›, like the Mac app's composer panel */
.menu.tty-adjm{min-width:300px; max-width:min(420px,calc(100vw - 16px)); font-family:var(--mono)}
html[data-theme^="yellow"] .menu.tty-adjm{font-family:var(--font-ui)}
.menu.tty-adjm .tty-adjrow{display:grid; grid-template-columns:max-content minmax(0,1fr) 1.5ch; gap:2ch; align-items:baseline; padding:8px 12px; border-radius:var(--r-md); font-size:var(--fs-sm); cursor:pointer}
.menu.tty-adjm .tty-adjrow:hover{background:var(--lift)}
.menu.tty-adjm .tty-adjrow .k, .menu.tty-adjm .tty-adjrow .c{color:var(--dim)}
.menu.tty-adjm .tty-adjrow .v{overflow:hidden; text-overflow:ellipsis; white-space:nowrap; text-align:end; color:var(--fg)}
.menu.tty-adjm .tty-adjrow.ro{cursor:default} .menu.tty-adjm .tty-adjrow.ro:hover{background:none}
.menu.tty-adjm .tty-adjnote{margin-top:4px; padding:6px 12px 4px; border-top:1px solid var(--line-soft); font-size:var(--fs-2xs); line-height:1.5; color:var(--dim)}
.menu.tty-adjm .mo.off{opacity:.55}
/* the status line's parts in one order whoever draws them (owner 2026-10-16): HOOP · the line · mic · send … the work
   board · the computers · the clock │ 雨 */
  .p-home .tty-status>.tty-mode{order:0} .p-home .tty-status>#tty-msg{order:1} .p-home .tty-status>.tty-entry-mic{order:2} .p-home .tty-status>.tty-entry-send{order:3}
  .p-home .tty-status>.wb-barhead{order:5} .p-home .tty-status>.tty-devbtn{order:6} .p-home .tty-status>.tty-clock{order:7} .p-home .tty-status>.tty-sep{order:8} .p-home .tty-status>.tty-rainbtn{order:9}
  .p-home .tty-status .tty-devbtn{font:inherit; color:var(--tty-dim); background:none; border:0; border-inline-start:1px solid var(--tty-line); padding:4px 12px; cursor:pointer}
  .p-home .tty-status .tty-devbtn.ok{color:var(--tty-ok)}
  .p-home .tty-status .tty-devbtn:hover, .p-home .tty-status .tty-devbtn:focus-visible{color:var(--tty-accent); outline:0}
  .p-home .tty-status .tty-devbtn[hidden]{display:none}
  @media (max-width:720px){ .p-home .tty-status>.tty-devbtn{display:none!important} }
/* the desk (owner 2026-10-14): the conversations on the left, the canvas of panes beside them. The desk fills
   the screen's height; each pane's log scrolls inside it. One pane keeps a reading width; several use it all. */
.p-home .tty-histchip{display:none}
@media (min-width:721px){
  .p-home .tty-wrap{max-width:1160px}
  .p-home .tty.tty-multi .tty-wrap{max-width:none}
  html.hoop-rail .p-home .tty.tty-multi .tty-wrap{padding-inline-end:calc(var(--rail-w) + 28px)}
  .p-home .tty-desk{display:flex; gap:20px; height:calc(100dvh - var(--shell-top,0px) - clamp(24px,5vh,56px) - 64px); min-height:420px}
  .p-home .tty-side{flex:0 0 228px; display:flex; flex-direction:column; min-height:0; margin-top:14px; border:1px solid var(--tty-line); background:color-mix(in srgb,var(--tty-bg) 84%,transparent)}
  .p-home .tty-side[hidden]{display:none}
  .p-home .tty-sidehead{display:flex; align-items:center; gap:8px; padding:8px 10px; border-bottom:1px dashed var(--tty-line); color:var(--tty-accent); font-size:var(--fs-xs)}
  .p-home .tty-sidehead>span{flex:1}
  .p-home .tty-sidehead button, .p-home .tty-sideshow{font:inherit; font-size:var(--fs-xs); color:var(--tty-fg); background:transparent; border:1px solid var(--tty-line); padding:0 8px; cursor:pointer}
  .p-home .tty-sidehead button:hover, .p-home .tty-sidehead button:focus-visible, .p-home .tty-sideshow:hover, .p-home .tty-sideshow:focus-visible{color:var(--tty-ink); background:var(--tty-accent); border-color:var(--tty-accent); outline:0}
  .p-home .tty-sideshow{display:none; align-self:flex-start; margin-top:14px; writing-mode:vertical-rl; padding:8px 2px}
  .p-home .tty.tty-noside .tty-sideshow{display:block}
  .p-home .tty-hist{flex:1; min-height:0; overflow-y:auto; padding:4px 0}
  .p-home .tty-hdim{padding:8px 12px; color:var(--tty-dim); font-size:var(--fs-xs)}
  .p-home .tty-h{display:grid; grid-template-columns:2ch minmax(0,1fr); column-gap:2px; width:100%; text-align:start; font:inherit; font-size:var(--fs-sm); line-height:1.4; color:var(--tty-fg); background:transparent; border:0; padding:5px 10px 5px 6px; cursor:pointer}
  .p-home .tty-h .tty-hm{grid-row:1 / span 2; color:var(--tty-accent)}
  .p-home .tty-h .tty-hn{overflow:hidden; text-overflow:ellipsis; white-space:nowrap}
  .p-home .tty-h .tty-ht{color:var(--tty-dim); font-size:var(--fs-xs); overflow:hidden; text-overflow:ellipsis; white-space:nowrap}
  .p-home .tty-h:hover, .p-home .tty-h:focus-visible{background:color-mix(in oklab,var(--selection) 60%,transparent); outline:0}
  .p-home .tty-h.open .tty-hn{color:var(--tty-hi)}
  .p-home .tty-h.cur{background:var(--selection)} .p-home .tty-h.cur .tty-hn{color:var(--tty-accent)}
  .p-home .tty-h.unread .tty-hm{color:var(--tty-warn)}
  .p-home .tty-stage{position:relative; flex:1; min-width:0; min-height:0; display:flex}
  .p-home .tty-canvas{flex:1; min-width:0; min-height:0; display:flex; padding-top:14px}
  .p-home .tty-split{display:flex; min-width:0; min-height:0} .p-home .tty-split.tty-row{flex-direction:row} .p-home .tty-split.tty-col{flex-direction:column}
  .p-home .tty-canvas .tty-pane{margin:0; display:flex; flex-direction:column; min-width:0; min-height:0}
  .p-home .tty-canvas .tty-pane>.tty-log{flex:1 1 auto; max-height:none; min-height:0}
  .p-home .tty-canvas .tty-pane>:is(.tty-devs,.tty-prompt,.tty-chips,.tty-more,.tty-tray){flex:none}
  .p-home .tty-canvas.multi .tty-pane.focus{border-color:color-mix(in srgb,var(--tty-accent) 70%,var(--tty-line))}
  .p-home .tty-canvas.multi .tty-pane:not(.focus) .tty-prompt{opacity:.7}
  .p-home .tty-gut{flex:none; position:relative}
  .p-home .tty-split.tty-row>.tty-gut{width:12px; cursor:col-resize} .p-home .tty-split.tty-col>.tty-gut{height:24px; cursor:row-resize}
  .p-home .tty-gut::after{content:""; position:absolute; background:var(--tty-accent); opacity:0; transition:opacity var(--motion-fast)}
  .p-home .tty-split.tty-row>.tty-gut::after{top:0; bottom:0; left:5px; width:2px} .p-home .tty-split.tty-col>.tty-gut::after{left:0; right:0; top:11px; height:2px}
  .p-home .tty-gut:hover::after{opacity:.6}
  html.tty-resizing, html.tty-resizing *{user-select:none!important}
  /* the three dots at the top of a pane: there when the pointer is near, a handle to drag, a button for the menu */
  .p-home .tty-grip{position:absolute; top:-9px; left:50%; transform:translateX(-50%); z-index:3; display:flex; gap:4px; align-items:center; justify-content:center; width:40px; height:18px; padding:0; border:1px solid var(--tty-line); background:var(--tty-ink); cursor:grab; opacity:0; transition:opacity var(--motion-fast); touch-action:none}
  .p-home .tty-grip i{width:4px; height:4px; border-radius:50%; background:var(--tty-fg)}
  .p-home .tty-pane:hover>.tty-grip, .p-home .tty-grip:focus-visible, .p-home .tty-pane.moving>.tty-grip{opacity:1}
  .p-home .tty-grip:hover, .p-home .tty-grip:focus-visible{border-color:var(--tty-accent); outline:0} .p-home .tty-grip:hover i{background:var(--tty-accent)}
  html.tty-dragging .tty-grip{cursor:grabbing}
  .p-home .tty-pane.moving{opacity:.45}
  .p-home .tty-dropguide{position:absolute; z-index:6; pointer-events:none; display:flex; align-items:center; justify-content:center; border:1px dashed var(--tty-accent); background:color-mix(in srgb,var(--tty-accent) 16%,transparent); color:var(--tty-accent); font-size:var(--fs-sm)}
  .p-home .tty-dropguide[hidden]{display:none}
  /* a long title stops short of the three dots */
  .p-home .tty-canvas .tty-pane>.tty-t{max-width:calc(50% - 40px); overflow:hidden; text-overflow:ellipsis; white-space:nowrap}
}
/* The yellow desk uses the same readable type and glass as its system windows. */
html[data-theme^="yellow"] .p-home .tty{font-family:var(--font-ui);line-height:1.65}
html[data-theme^="yellow"] .p-home .tty-log .ln .say.md code{font-family:var(--mono)}
html[data-theme^="yellow"] .p-home .tty-scan{display:none}
html[data-theme^="yellow"] .p-home .tty-rain{opacity:.25}
html[data-theme^="yellow"] .p-home :is(.tty-box,.tty-side){background:var(--glass-bg);-webkit-backdrop-filter:var(--pane-blur);backdrop-filter:var(--pane-blur);border-radius:var(--r-sm);box-shadow:var(--pane-rim)}
.p-home .tty-hist{overflow-x:hidden}
/* a computer's session in a pane (owner 2026-10-14): its steps are lines — the mark says how each went, a click
   shows what went in and what came out; its questions carry their answers as [ chips ] */
.p-home .tty-log .ln.tty-tool{cursor:pointer}
.p-home .tty-log .ln.tty-tool:hover .tx, .p-home .tty-log .ln.tty-tool:focus-visible .tx{color:var(--tty-fg); outline:0}
.p-home .tty-log .ln.tty-tool.st-done>.tty-mk{color:var(--tty-ok)} .p-home .tty-log .ln.tty-tool:is(.st-failed,.st-denied)>.tty-mk{color:var(--tty-err)}
.p-home .tty-log .ln.tty-tool.st-pending>.tty-mk{color:var(--tty-warn)}
.p-home .tty-toolsum{grid-column:2; color:var(--tty-dim); font-size:var(--fs-xs); white-space:pre-wrap}
.p-home .tty-tooldet{grid-column:2; cursor:auto}
.p-home .tty-pre{white-space:pre-wrap; word-break:break-word; margin:4px 0; padding:6px 10px; max-height:320px; overflow:auto; border:1px solid var(--tty-line); background:var(--tty-ink); color:var(--tty-fg); font:inherit; font-size:var(--fs-xs)}
.p-home .tty-pre.out{color:var(--tty-dim)}
.p-home .tty-hint{align-self:center; color:var(--tty-dim); font-size:var(--fs-xs)}
.p-home .tty-devp .tty-ps{color:var(--tty-accent)}
/* a file over a pane: where it will land */
.p-home .tty-pane.filedrop::after{content:attr(data-drop); position:absolute; inset:0; z-index:4; display:flex; align-items:center; justify-content:center; border:1px dashed var(--tty-accent); background:color-mix(in srgb,var(--tty-accent) 14%,transparent); color:var(--tty-accent); pointer-events:none}
.p-home .tty-tray{display:flex; flex-wrap:wrap; gap:6px; margin:6px 0 2px}
.p-home .tty-tray[hidden]{display:none}
.p-home .tty-up{display:inline-flex; align-items:center; gap:6px; max-width:100%; font-size:var(--fs-xs); color:var(--tty-fg); border:1px solid var(--tty-line); padding:0 0 0 8px}
.p-home .tty-up>span{overflow:hidden; text-overflow:ellipsis; white-space:nowrap; font-variant-numeric:tabular-nums}
.p-home .tty-up.ok{color:var(--tty-ok)} .p-home .tty-up.err{color:var(--tty-err)}
.p-home .tty-up>button{font:inherit; color:var(--tty-dim); background:none; border:0; border-inline-start:1px solid var(--tty-line); padding:0 8px; cursor:pointer}
.p-home .tty-up>button:hover{color:var(--tty-ink); background:var(--tty-accent)}
@media (min-width:721px){
  /* the dock on the dark desktop: dark glass, so its light icons read */
  html.hoop-sky body.p-home #hooprail{border-color:var(--tty-ink-line)!important; box-shadow:var(--shadow-tty-dock)!important}
}
/* a tablet: the dock floats over the right edge, so the terminal keeps clear of it */
@media (max-width:899px){.p-home .tty-facts{display:flex}}
@media (min-width:721px) and (max-width:1100px){html.hoop-rail .p-home .tty-wrap{padding-inline-end:calc(var(--rail-w) + 28px)}}
/* the phone's own parts (home.js, index.html) stand down on every wider screen */
.p-home :is(.tty-mbar, .tty-scrim, .tty-dfoot, .tty-att, .tty-send, .tty-upi){display:none}
/* the + menu's rows: camera, photos, files — an icon before each word */
.menu .tty-attic{display:inline-grid; place-items:center; inline-size:22px; block-size:22px; margin-inline-end:12px; color:var(--dim); vertical-align:middle}
.menu .tty-attic svg{inline-size:20px; block-size:20px}
/* a phone (≤720px, owner 2026-10-16: 「要像原生移动终端，不是缩小的桌面」): one screen that holds still, in three parts.
   At the top one status line — ☰ opens the conversations, this Hoop's facts on one line (it scrolls sideways when they do
   not fit), and at the end the Hoop button (nav.js's one program handle, moved here) for every App and search. In the
   middle the conversation, filling everything between and scrolling by itself; its chips are one row that slides. At the
   bottom the one composer: the prompt line (xingyun@xingyun:~$ and who answers), then + for a photo or a file, the
   words, the mic and ↑. The work board, the tree and the Hoop apps fold into the drawer, so nothing pushes the
   conversation away. home.js pins the screen to the visual viewport (--vv-h / --vv-top), so the composer rides on top
   of the keyboard; the page itself never scrolls, sideways or down. */
@media (max-width:720px){
  .p-home .pa-home{display:block; width:auto; min-height:0; margin:0; padding:0; animation:none}
  .p-home .pa-home>section{display:none}
  /* the page never scrolls, so it keeps no room for a scrollbar either (a desktop browser narrowed to a phone's width) */
  html:has(body.p-home #pa-home:not([hidden])), body.p-home:has(#pa-home:not([hidden])){overflow:hidden; overscroll-behavior:none; scrollbar-gutter:auto}
  .p-home .tty{display:flex; flex-direction:column; position:fixed; inset-inline:0; top:var(--vv-top); height:var(--vv-h); margin:0;
    background:var(--tty-ink); font-size:var(--fs-md); overflow:hidden}
  .p-home .tty-scan{display:block}
  /* the bottom pill asked about the page; on a phone the page IS the conversation, so its one composer is the only one */
  .p-home .tty-status{display:none!important}
  /* the page assistant's sheet (other pages): a keyboard-sized viewport may shrink its log, never its header or composer */
  .hoop-assistant .ha-log{min-height:0}
  .hoop-assistant>.ha-h,.hoop-assistant>.hoop-assistant-f{flex-shrink:0}
  /* the status line */
  .p-home .tty-mbar{position:relative; z-index:1; flex:none; display:flex; align-items:stretch; block-size:44px; box-sizing:content-box;
    padding-block-start:env(safe-area-inset-top); padding-inline:env(safe-area-inset-left) calc(44px + env(safe-area-inset-right));
    font-size:var(--fs-xs); border-block-end:1px solid var(--tty-line);
    background:color-mix(in srgb,var(--tty-ink) 82%,transparent); -webkit-backdrop-filter:var(--glass-blur); backdrop-filter:var(--glass-blur)}
  .p-home .tty-burger{flex:none; display:grid; place-items:center; inline-size:44px; block-size:44px; margin:0; padding:0; border:0; border-radius:0; background:none; color:var(--tty-fg); cursor:pointer}
  .p-home .tty-burger svg{inline-size:20px; block-size:20px}
  .p-home .tty-burger:focus-visible{outline:2px solid var(--tty-accent); outline-offset:-4px}
  .p-home .tty-mfacts{flex:1; min-inline-size:0; display:flex; align-items:stretch; overflow-x:auto; overflow-y:hidden; scrollbar-width:none; white-space:nowrap;
    padding-inline-end:12px; -webkit-mask-image:linear-gradient(to left,transparent,var(--fg) 14px); mask-image:linear-gradient(to left,transparent,var(--fg) 14px)}
  [dir="rtl"] .p-home .tty-mfacts{-webkit-mask-image:linear-gradient(to right,transparent,var(--fg) 14px); mask-image:linear-gradient(to right,transparent,var(--fg) 14px)}
  .p-home .tty-mfacts::-webkit-scrollbar{display:none}
  .p-home .tty-mfacts .tf{align-items:center; flex:none}
  .p-home .tty-mfacts .tf+.tf::before{content:"·"; color:var(--tty-dim); margin-inline:1ch}
  .p-home .tty-mfacts button.tf{min-block-size:44px}
  /* the Hoop button: nav.js's one handle for every App, at the end of the status line instead of floating over the page */
  body.p-home:has(#pa-home:not([hidden])) .hoop-mobile-app-handle[data-hoop-mobile-app-handle="true"]{inset-block-start:env(safe-area-inset-top)!important;
    inset-inline-end:0!important; inset-inline-start:auto!important; transform:none!important; inline-size:44px!important; block-size:44px!important;
    min-inline-size:44px!important; min-block-size:44px!important; border:0!important; border-radius:0; background:transparent!important;
    box-shadow:none!important; -webkit-backdrop-filter:none; backdrop-filter:none; color:var(--brand-ink)!important}
  body.p-home:is(:has(.tty.tty-dopen), :has(> .menu.sheet)) .hoop-mobile-app-handle[data-hoop-mobile-app-handle="true"]{display:none!important}
  /* the conversation: everything between the two bars */
  .p-home .tty-wrap{flex:1 1 auto; min-block-size:0; display:flex; flex-direction:column; max-inline-size:none; margin:0; padding:0}
  .p-home .tty-facts{display:none}
  .p-home :is(.tty-desk, .tty-stage, .tty-canvas, .tty-split){flex:1 1 auto; min-block-size:0; min-inline-size:0; display:flex; flex-direction:column; padding:0}
  .p-home .tty-split:not(:has(#tty-term)){display:none}
  .p-home .tty-sideshow, .p-home .tty-grip, .p-home .tty-gut, .p-home .tty-dropguide, .p-home .tty-canvas .tty-pane:not(#tty-term){display:none!important}
  .p-home #tty-term{flex:1 1 auto; min-block-size:0; display:flex; flex-direction:column; margin:14px 0 0; padding:14px 0 0; border:0; border-block-start:1px solid var(--tty-line);
    background:color-mix(in srgb,var(--tty-bg) 72%,transparent); border-radius:0; box-shadow:none}
  .p-home #tty-term>.tty-t{font-size:var(--fs-xs)}
  .p-home .tty-log{order:1; flex:1 1 auto; min-block-size:0; max-block-size:none; overflow-y:auto; overscroll-behavior:contain; scrollbar-width:none; padding:6px 14px 10px;
    -webkit-mask-image:linear-gradient(to bottom,transparent,var(--fg) 18px); mask-image:linear-gradient(to bottom,transparent,var(--fg) 18px)}
  .p-home .tty-log::-webkit-scrollbar{display:none}
  /* 「↓ 下面还有」 floats over the end of the conversation instead of taking a line of its own */
  .p-home .tty-more{order:2; position:relative; z-index:2; align-self:flex-end; min-block-size:44px; margin:-52px 12px 8px 0; padding:0 14px;
    border:1px solid var(--tty-line); border-radius:var(--r-pill); background:var(--tty-ink)}
  /* the chips: one row of equal cells that slides sideways; each is a whole 44px to tap */
  .p-home #tty-term>.tty-chips{order:3; flex:none; display:block; overflow-x:auto; overflow-y:hidden; scrollbar-width:none; scroll-snap-type:x proximity;
    margin:0; padding:2px 0 0; padding-inline-start:10px; scroll-padding-inline:10px; border:0}
  /* every cell as wide as the widest word, never narrower than a thumb; home.js chipFit makes them exactly as many whole
     cells as the row holds, so the next one starts at the edge (no word cut in half) and the row slides to the rest */
  .p-home #tty-term .tty-chiprow{display:grid; grid-auto-flow:column; grid-auto-columns:minmax(76px,1fr); inline-size:max-content; min-inline-size:100%; padding-inline-end:10px}
  .p-home #tty-term>.tty-chips::-webkit-scrollbar{display:none}
  .p-home .tty-histchip{display:block}
  .p-home #tty-term .tty-chips button{scroll-snap-align:start; min-inline-size:0; block-size:44px; min-block-size:44px; padding:0 8px; border:0;
    outline:1px solid var(--tty-line); outline-offset:-5px; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; text-align:center}
  .p-home #tty-term .tty-chips button::before{margin-inline-end:.5ch} .p-home #tty-term .tty-chips button::after{margin-inline-start:.5ch}
  .p-home #tty-term .tty-chips button:active{color:var(--tty-ink); background:var(--tty-accent); outline-color:var(--tty-accent)}
  .p-home #tty-term .tty-chips button:focus-visible{outline:0}
  /* what goes with the next line: a small chip for each file, a picture as a picture, above the composer */
  .p-home #tty-term>.tty-tray{order:4; flex:none; flex-wrap:nowrap; overflow-x:auto; scrollbar-width:none; gap:6px; margin:0; padding:8px 10px 0}
  .p-home .tty-up{flex:none; min-block-size:44px; max-inline-size:70vw; padding-inline-start:4px; gap:8px}
  .p-home .tty-up>.tty-upi{display:block; inline-size:34px; block-size:34px; object-fit:cover; flex:none}
  .p-home .tty-up>button{align-self:stretch; min-inline-size:44px; font-size:var(--fs-h)}
  /* the composer: the prompt line, then the box — + · the words · mic · ↑ */
  .p-home .tty-pane>.tty-prompt{order:5; flex:none; display:grid; grid-template-columns:44px minmax(0,1fr) 44px 44px; grid-template-rows:auto auto; align-items:end;
    gap:0; min-block-size:0; margin:0; padding:4px 10px calc(8px + env(safe-area-inset-bottom)); border-block-start:1px solid var(--tty-line);
    background:color-mix(in srgb,var(--tty-ink) 88%,transparent); -webkit-backdrop-filter:var(--glass-blur); backdrop-filter:var(--glass-blur)}
  html.tty-kb .p-home .tty-pane>.tty-prompt{padding-block-end:8px}
  .p-home .tty-pane>.tty-prompt::before{content:""; grid-area:2 / 1 / 3 / 5; align-self:stretch; border:1px solid var(--tty-line); border-radius:var(--r-md);
    background:color-mix(in srgb,var(--tty-bg) 92%,transparent); pointer-events:none}
  .p-home .tty-pane>.tty-prompt:focus-within::before{border-color:color-mix(in srgb,var(--tty-accent) 70%,var(--tty-line))}
  .p-home .tty-prompt>.tty-ps{grid-area:1 / 1 / 2 / 5; justify-self:start; max-inline-size:58%; overflow:hidden; text-overflow:ellipsis; padding:0 4px; font-size:var(--fs-xs); line-height:28px}
  .p-home .tty-prompt>.tty-tools{display:contents}
  .p-home .tty-prompt .tty-adj{grid-area:1 / 1 / 2 / 5; justify-self:end; max-inline-size:42%; min-inline-size:44px; min-block-size:44px; margin-block:-8px; padding:0 2px 0 6px; justify-content:flex-end}
  .p-home .tty-pane .tty-prompt .tty-adjt{display:block; min-inline-size:0}
  .p-home .tty-prompt>textarea{grid-area:2 / 2 / 3 / 3; align-self:center; min-block-size:44px; padding:11px 2px!important; font-size:16px; line-height:22px}
  .p-home .tty-prompt :is(.tty-att, .tty-mic, .tty-send){display:grid; place-items:center; inline-size:44px; block-size:44px; min-inline-size:44px; min-block-size:44px;
    margin:0; padding:0; border:0; border-radius:0; background:none; font:inherit; color:var(--tty-dim); cursor:pointer}
  .p-home .tty-prompt .tty-att{grid-area:2 / 1 / 3 / 2}
  .p-home .tty-prompt .tty-mic{grid-area:2 / 3 / 3 / 4; font-size:var(--fs-xs)}
  .p-home .tty-prompt .tty-send{grid-area:2 / 4 / 3 / 5}
  .p-home .tty-prompt :is(.tty-att, .tty-mic) svg{inline-size:20px; block-size:20px}
  .p-home .tty-prompt .tty-att:active, .p-home .tty-prompt .tty-att.on{color:var(--tty-accent)}
  .p-home .tty-send>i{display:grid; place-items:center; inline-size:32px; block-size:32px; box-sizing:border-box; border:1px solid var(--tty-accent); border-radius:var(--r-sm); background:var(--tty-accent); color:var(--tty-ink)}
  .p-home .tty-send svg{inline-size:18px; block-size:18px}
  .p-home .tty-send:disabled{cursor:default} .p-home .tty-send:disabled>i{background:transparent; color:var(--tty-dim); border-color:var(--tty-line)}
  .p-home .tty-send.stop>i{background:transparent; color:var(--tty-accent)}
  .p-home .tty-prompt :is(.tty-att, .tty-mic, .tty-send):focus-visible{outline:2px solid var(--tty-accent); outline-offset:-4px}
  /* the drawer: the conversations, and under them what used to push the conversation down */
  .p-home .tty-side, .p-home .tty-side[hidden]{position:fixed; z-index:10005; inset-block:0; inset-inline-start:0; display:flex; flex-direction:column;
    inline-size:min(86vw,340px); box-sizing:border-box; margin:0; padding:env(safe-area-inset-top) 0 env(safe-area-inset-bottom); padding-inline-start:env(safe-area-inset-left);
    border:0; border-inline-end:1px solid var(--tty-line); background:var(--tty-ink); transform:translateX(-100%); visibility:hidden;
    transition:transform var(--motion-base) var(--ease), visibility 0s var(--motion-base)}
  [dir="rtl"] .p-home .tty-side, [dir="rtl"] .p-home .tty-side[hidden]{transform:translateX(100%)}
  .p-home .tty.tty-dopen .tty-side{transform:none; visibility:visible; transition:transform var(--motion-base) var(--ease)}
  /* every theme: a solid sheet with square edges (the yellow desk's glass would let the page read through it) */
  .p-home #tty-side{background:var(--tty-ink); border-radius:0; box-shadow:var(--shadow-pop)}
  .p-home .tty-scrim{display:block; position:fixed; z-index:10004; inset:0; background:var(--scrim-strong); opacity:0; pointer-events:none; transition:opacity var(--motion-base)}
  .p-home .tty.tty-dopen .tty-scrim{opacity:1; pointer-events:auto}
  .p-home .tty-sidehead{flex:none; display:flex; align-items:center; gap:4px; min-block-size:44px; padding-inline:14px 4px; border-block-end:1px dashed var(--tty-line); color:var(--tty-accent); font-size:var(--fs-sm)}
  .p-home .tty-sidehead>span{flex:1}
  .p-home .tty-sidehead button{min-block-size:44px; min-inline-size:44px; padding:0 10px; font:inherit; color:var(--tty-fg); background:none; border:0; border-radius:0; cursor:pointer}
  .p-home .tty-sidehead button:active{color:var(--tty-accent)}
  .p-home .tty-hist{flex:1 1 0; min-block-size:0; overflow-y:auto; overscroll-behavior:contain; padding:4px 0}
  .p-home .tty-hdim{padding:12px 14px; color:var(--tty-dim); font-size:var(--fs-xs)}
  .p-home .tty-h{display:grid; grid-template-columns:2ch minmax(0,1fr); column-gap:2px; inline-size:100%; min-block-size:52px; align-content:center; text-align:start;
    font:inherit; font-size:var(--fs-sm); line-height:1.45; color:var(--tty-fg); background:transparent; border:0; border-radius:0; padding:6px 14px 6px 8px; cursor:pointer}
  .p-home .tty-h .tty-hm{grid-row:1 / span 2; color:var(--tty-accent)}
  .p-home .tty-h .tty-hn{overflow:hidden; text-overflow:ellipsis; white-space:nowrap}
  .p-home .tty-h .tty-ht{color:var(--tty-dim); font-size:var(--fs-xs); overflow:hidden; text-overflow:ellipsis; white-space:nowrap}
  .p-home .tty-h:active{background:color-mix(in oklab,var(--selection) 60%,transparent)}
  .p-home .tty-h.cur{background:var(--selection)} .p-home .tty-h.cur .tty-hn{color:var(--tty-accent)}
  .p-home .tty-h.unread .tty-hm{color:var(--tty-warn)}
  .p-home .tty-dfoot{display:block; flex:none; max-block-size:55%; overflow-y:auto; overscroll-behavior:contain; border-block-start:1px dashed var(--tty-line); font-size:var(--fs-sm)}
  .p-home .tty-dfoot>*+*{border-block-start:1px dashed var(--tty-line)}
  .p-home .tty-dsec>summary{display:flex; align-items:center; gap:1ch; min-block-size:44px; padding:0 14px; color:var(--tty-accent); list-style:none; cursor:pointer}
  .p-home .tty-dsec>summary::-webkit-details-marker{display:none}
  .p-home .tty-dsec>summary::before{content:"▸"; color:var(--tty-dim)}
  .p-home .tty-dsec[open]>summary::before{content:"▾"}
  .p-home .tty-dsec:not(:has(> .home-section:not([hidden]))){display:none}
  .p-home .tty-dsec .home-section{max-inline-size:none; margin:0; padding:0 14px 12px; border:0; border-radius:0; background:none; box-shadow:none; -webkit-backdrop-filter:none; backdrop-filter:none; color:var(--tty-fg); font:inherit}
  .p-home .tty-dsec .home-section-head h2{display:none}
  .p-home .tty-dsec :is(.home-branch, .home-app){padding:8px 0; border-radius:0; background:none; border-block-end:1px dashed var(--tty-line)}
  .p-home .tty-dsec :is(.home-branch-icon, .home-app>[data-icon]){color:var(--tty-dim)}
  .p-home .tty-dsec .home-branch-open{color:var(--tty-accent)}
  .p-home .tty-dsec :is(.home-branch-open, .home-branch-cut, .home-trunk-update, .btn){min-block-size:44px; min-inline-size:44px}
  .p-home .tty-drain{display:flex; align-items:center; inline-size:100%; min-block-size:44px; padding:0 14px; font:inherit; color:var(--tty-dim); background:none; border:0; border-radius:0; text-align:start; cursor:pointer}
  .p-home .tty-drain:active{color:var(--tty-accent)}
}
/* fingers: every terminal button and the tree's open/stop are at least 40px to tap */
@media (pointer:coarse){
  .p-home .tty-chips button{min-height:40px; padding:0 12px}
  .p-home .home-branch-open, .p-home .home-branch-cut{display:inline-flex; align-items:center; justify-content:center; min-height:40px; min-width:44px}
}
@media (prefers-reduced-motion:reduce){.p-home .tty-scan{display:none}}
/* ── the work board (gram-work-board.js, owner 2026-10-16): what is working on the owner's machines, like the box at
   the bottom of Claude Code — a line per thing at work, grouped by machine; a line opens in place; quiet unmerged Work
   waits folded under 没合入 in the warning colour. Wide: its head is a word in the status bar; opened, the list sits on
   the status line in the bars' glass and the desk gives up exactly its height (--work-board-h, written by the script);
   folded, the box is hidden and the desk has its whole height. Phone: in the page under the terminal, folded
   to one line until opened, so it never covers the prompt. Logical properties only: ar mirrors it. ── */
.p-home .tty-work{position:relative; z-index:3; font-size:var(--fs-xs); line-height:1.5; color:var(--tty-fg)}
.p-home .tty-work[hidden], .p-home .tty-work [hidden]{display:none}
.p-home .tty-work button{font:inherit; color:inherit; background:none; border:0; border-radius:0; margin:0; cursor:pointer; text-align:start}
.p-home .tty-work :is(.wb-head,.wb-row,.wb-stalehead):focus-visible{outline:1px solid var(--tty-accent); outline-offset:-1px}
.p-home .tty-work .wb-head{display:flex; align-items:baseline; gap:1.5ch; width:100%; padding:4px 12px; white-space:nowrap}
.p-home .tty-work .wb-name{color:var(--tty-accent)}
.p-home .tty-work .wb-head:hover .wb-name{text-decoration:underline}
.p-home .tty-work .wb-sum{min-width:0; overflow:hidden; text-overflow:ellipsis; font-variant-numeric:tabular-nums}
.p-home .tty-work .wb-dim{color:var(--tty-dim)}
.p-home .tty-work .wb-warnt{color:var(--tty-warn)}
.p-home .tty-work .wb-caret{display:inline-block; color:var(--tty-dim)}
.p-home .tty-work.wb-folded>.wb-head .wb-caret, .p-home .tty-work .wb-shut>.wb-stalehead .wb-caret{transform:rotate(-90deg)}
[dir="rtl"] .p-home .tty-work.wb-folded>.wb-head .wb-caret, [dir="rtl"] .p-home .tty-work .wb-shut>.wb-stalehead .wb-caret{transform:rotate(90deg)}
.p-home .tty-work .wb-body{max-height:32vh; overflow-y:auto; padding-bottom:4px; min-width:0}
.p-home .tty-work .wb-group,.p-home .tty-work .wb-item{padding:2px 0; min-width:0}
.p-home .tty-work .wb-machine{padding:2px 12px; color:var(--tty-dim)}
.p-home .tty-work .wb-row{display:grid; grid-template-columns:1.6ch 26ch minmax(0,1fr) max-content; align-items:baseline; column-gap:1.5ch; width:100%; min-width:0; padding:1px 12px; padding-inline-start:calc(12px + 2ch)}
.p-home .tty-work .wb-row:hover{background:color-mix(in oklab,var(--selection) 60%,transparent)}
/* a subagent steps in by 2ch and its "who" gives the 2ch back, so every "what" starts on one column */
.p-home .tty-work .wb-d1>.wb-row{padding-inline-start:calc(12px + 4ch); grid-template-columns:1.6ch 24ch minmax(0,1fr) max-content}
.p-home .tty-work .wb-d2>.wb-row{padding-inline-start:calc(12px + 6ch); grid-template-columns:1.6ch 22ch minmax(0,1fr) max-content}
.p-home .tty-work .wb-d3>.wb-row{padding-inline-start:calc(12px + 8ch); grid-template-columns:1.6ch 20ch minmax(0,1fr) max-content}
.p-home .tty-work .wb-sub>.wb-row .wb-who{color:var(--tty-fg)}
.p-home .tty-work .wb-dot{display:inline-block; inline-size:.6em; block-size:.6em; border-radius:50%; background:currentColor; color:var(--tty-dim)}
.p-home .tty-work .wb-dot.s-running{color:var(--tty-ok)}
.p-home .tty-work .wb-dot.s-waiting{color:var(--tty-accent)}
.p-home .tty-work .wb-dot.s-stale{color:var(--tty-warn)}
.p-home .tty-work .wb-who{color:var(--tty-hi); overflow:hidden; text-overflow:ellipsis; white-space:nowrap}
.p-home .tty-work .wb-what{min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:normal; overflow-wrap:anywhere; color:var(--tty-dim)}
.p-home .tty-work .wb-what>b{font-weight:normal; color:var(--tty-fg); margin-inline-end:1.5ch; white-space:normal; overflow-wrap:anywhere}
.p-home .tty-work .wb-time{display:flex; gap:1.5ch; white-space:nowrap; font-variant-numeric:tabular-nums}
.p-home .tty-work .wb-quiet{color:var(--tty-warn)}
.p-home .tty-work .wb-more{padding:2px 12px 6px; padding-inline-start:calc(12px + 5.6ch); color:var(--tty-dim)}
.p-home .tty-work .wb-full{margin:0 0 2px; color:var(--tty-fg); overflow-wrap:anywhere}
.p-home .tty-work .wb-steps{margin:0 0 4px; padding-inline-start:3ch; color:var(--tty-fg)}
.p-home .tty-work .wb-steps li{overflow-wrap:anywhere}
.p-home .tty-work .wb-facts{display:flex; flex-wrap:wrap; gap:2px 2.5ch}
.p-home .tty-work .wb-kv{display:inline-flex; gap:.6ch}
.p-home .tty-work .wb-kv>i{font-style:normal; color:var(--tty-dim)}
.p-home .tty-work .wb-kv>b{font-weight:normal; color:var(--tty-hi)}
.p-home .tty-work .wb-stale{border-top:1px dashed var(--tty-line); margin-top:2px}
.p-home .tty-work .wb-stalehead{display:flex; gap:1ch; width:100%; padding:2px 12px; color:var(--tty-warn)}
.p-home .tty-work .wb-warn .wb-who{color:var(--tty-warn)}
/* wide (owner 2026-10-16: 「工作看板 点击后会弹上去 需要固定住」): the head is a word in the status bar, put there by the
   script, so it never moves; a chevron at its end points up while folded and down while open */
.p-home .tty-status .wb-barhead{display:inline-flex; align-items:center; gap:1ch; flex:0 1 auto; min-width:0; align-self:stretch; margin:0; padding:4px 12px;
  border:0; border-inline-start:1px solid var(--tty-line); border-radius:0; background:none; font:inherit; color:var(--tty-fg); white-space:nowrap; cursor:pointer; font-variant-numeric:tabular-nums}
.p-home .tty-status .wb-barhead[hidden]{display:none}
.p-home .tty-status .wb-barhead .wb-name{flex:none; color:var(--tty-accent)}
.p-home .tty-status .wb-barhead .wb-sum{min-width:0; overflow:hidden; text-overflow:ellipsis}
.p-home .tty-status .wb-barhead .wb-dim{color:var(--tty-dim)}
.p-home .tty-status .wb-barhead .wb-warnt{color:var(--tty-warn)}
.p-home .tty-status .wb-barhead .wb-chev{flex:none; inline-size:12px; block-size:12px}
.p-home .tty-status .wb-barhead[aria-expanded="true"] .wb-chev{transform:rotate(180deg)}
.p-home .tty-status .wb-barhead:hover{color:var(--tty-accent)}
@media (min-width:721px){
  /* the floating dock keeps its column (tokens.css --dock-clear-*): the glass runs under it, the lines stop short of it.
     Only the list is in the box: it opens upward out of the bar, at most 40vh, and scrolls inside; on a short window
     it stops where the desk would drop under its 420px floor, so it never covers the desk's prompt */
  .p-home .tty-work{position:fixed; left:0; right:var(--dock-w,0px); bottom:calc(var(--fs-xs) * 1.55 + 9px); padding-inline:var(--dock-clear-start,0px) var(--dock-clear-end,0px);
    background:color-mix(in srgb,var(--tty-ink) 55%,transparent); -webkit-backdrop-filter:var(--glass-blur); backdrop-filter:var(--glass-blur); border-top:1px solid var(--tty-line)}
  .p-home .tty-work .wb-body{max-height:min(40vh, max(96px, calc(100dvh - var(--shell-top,0px) - clamp(24px,5vh,56px) - 64px - 421px))); padding-block:4px}
  .p-home .tty:has(> .tty-work:not([hidden])) .tty-desk{height:calc(100dvh - var(--shell-top,0px) - clamp(24px,5vh,56px) - 64px - var(--work-board-h))}
}
@media (max-width:720px){
  /* a phone: one folded line in the drawer (home.js phoneDock), opened in place */
  .p-home .tty-work{margin:0; border:0; background:none}
  .p-home .tty-work :is(.wb-head,.wb-row,.wb-stalehead){min-height:44px}
  .p-home .tty-work :is(.wb-head,.wb-stalehead){align-items:center; padding-inline:14px}
  .p-home .tty-work .wb-row, .p-home .tty-work :is(.wb-d1,.wb-d2,.wb-d3)>.wb-row{grid-template-columns:1.6ch minmax(0,1fr) max-content; padding-inline-start:12px}
  .p-home .tty-work .wb-row .wb-what{grid-column:2 / -1; grid-row:2}
  .p-home .tty-work .wb-d1>.wb-row{padding-inline-start:calc(12px + 2ch)}
  .p-home .tty-work :is(.wb-d2,.wb-d3)>.wb-row{padding-inline-start:calc(12px + 4ch)}
  .p-home .tty-work .wb-more{padding-inline-start:calc(12px + 3ch)}
}
@media (pointer:coarse){ .p-home .tty-work :is(.wb-head,.wb-row,.wb-stalehead){min-height:40px} }
/* ── the page assistant's drawer (gram-assistant.js, owner 2026-10-16: 「底部…要跟上面的隔开…能够直接在底部伸缩一个简洁的窗口
   进行对话. 独立设计不要直接弹窗覆盖, 每个对话都是新对话」). The bottom bar asks Hoop about what is on screen and the answer
   grows up out of the bar: the bars' glass, the panes' marks and type (it reuses .tty-log's lines and markdown), one reading
   column. Not a dialog: no scrim, nothing centred — the desk gives up exactly its height (--assist-h on .tty, written by the
   script with the drawer's bottom at the bar's top), and its top edge drags taller or shorter. A phone: a sheet over the pill. ── */
.p-home .ha-drawer{position:fixed; left:0; right:var(--dock-w,0px); bottom:0; z-index:10001; display:flex; flex-direction:column; box-sizing:border-box;
  height:max(200px,38vh); padding-inline:var(--dock-clear-start,0px) var(--dock-clear-end,0px); color:var(--tty-fg);
  background:color-mix(in srgb,var(--tty-ink) 55%,transparent); -webkit-backdrop-filter:var(--glass-blur); backdrop-filter:var(--glass-blur); border-top:1px solid var(--tty-line)}
.p-home .ha-drawer[hidden]{display:none}
.p-home .ha-grab{position:absolute; inset-inline:0; top:-5px; height:10px; z-index:1; cursor:row-resize; touch-action:none}
.p-home .ha-grab::after{content:""; position:absolute; inset-inline:0; top:4px; height:2px; background:var(--tty-accent); opacity:0; transition:opacity var(--motion-fast)}
.p-home .ha-grab:hover::after, .p-home .ha-grab:focus-visible::after, html.tty-resizing .p-home .ha-grab::after{opacity:.6}
.p-home .ha-grab:focus-visible{outline:0}
/* one thin line: what Hoop is looking at, then the drawer's words in the bar's style */
.p-home .ha-dh{flex:none; display:flex; align-items:center; font-size:var(--fs-xs); line-height:1.5; white-space:nowrap; border-bottom:1px dashed var(--tty-line)}
.p-home .ha-dctx{flex:1; min-width:0; overflow:hidden; text-overflow:ellipsis; padding:4px 12px; color:var(--tty-dim)}
.p-home .ha-dh button{flex:none; font:inherit; color:var(--tty-fg); background:none; border:0; border-radius:0; margin:0; padding:4px 10px; cursor:pointer}
.p-home .ha-dh button:hover, .p-home .ha-dh button:focus-visible{color:var(--tty-accent); outline:0}
.p-home .ha-dh button:disabled{color:var(--tty-dim); opacity:.55; cursor:default}
.p-home .ha-drawer .ha-dlog{flex:1 1 auto; min-height:0; max-height:none; overflow-y:auto; overscroll-behavior:contain; scrollbar-width:thin}
.p-home .ha-dcol{max-width:760px; margin:0 auto; padding:var(--sp-2) 16px var(--sp-4)}
.p-home .ha-dcol .ln:first-child{margin-top:0}
.p-home .ha-drawer .tty-chips{margin-top:var(--sp-2); padding-top:0; border-top:0}
/* the bar's own voice button, beside ↑; while an answer runs ↑ is ■ */
.p-home .tty-status .tty-entry-mic{flex:none; align-self:stretch; display:grid; place-items:center; min-width:36px; padding:4px 10px; margin:0; border:0; border-radius:0; background:transparent; color:var(--tty-dim); cursor:pointer}
.p-home .tty-status .tty-entry-mic svg{width:15px; height:15px}
.p-home .tty-status .tty-entry-mic:hover{color:var(--tty-accent)}
.p-home .tty-status .tty-entry-mic[aria-pressed="true"]{color:var(--tty-err)}
.p-home .tty-status .tty-entry-send.ha-stop{font-size:var(--fs-xs)}
@media (min-width:721px){
  /* wins over the work board's rule: when the drawer is up it covers the board's line, so the desk gives up the drawer's height */
  .p-home .tty.tty-assist-open:has(> .ha-drawer:not([hidden])) .tty-desk{height:calc(100dvh - var(--shell-top,0px) - clamp(24px,5vh,56px) - 64px - var(--assist-h,0px)); min-height:160px}
}
@media (max-width:720px){
  .p-home .ha-drawer{left:8px; right:8px; padding-inline:0; border:1px solid var(--tty-line); border-radius:var(--r-lg); background:var(--tty-ink); box-shadow:var(--shadow-pop)}
  .p-home .ha-dh button{min-height:40px}
  .p-home .tty-status .tty-entry-mic{color:var(--dim)}
}
/* the page inside a window on the desktop: no paper of its own, so the window's glass is its ground; quiet
   text gets a little more ink, because glass is darker than paper */
html.hoop-on-sky, html.hoop-on-sky body{background:transparent!important}
@media (prefers-reduced-transparency:reduce){html.hoop-sky .win{background:var(--surface); -webkit-backdrop-filter:none; backdrop-filter:none}}
html.hoop-reduce-transparency.hoop-sky .win{background:var(--surface); -webkit-backdrop-filter:none; backdrop-filter:none}
/* ── Hoop Terminal status line (gram-code.js #codestatus): the composer's quiet foot, one dim line under
   the input — where it runs · runner · idle/working, then two actions as plain words. No box, no rim, no
   fill (owner 2026-10-13: "很丑没有秩序"): it lines up with the text inside the input and only the
   state dot and a hovered word take colour. ── */
#codestatus{display:none}
body.codemode #codestatus{display:flex; align-items:center; gap:var(--sp-2); min-height:24px; box-sizing:border-box;
  max-width:46rem; margin:var(--sp-1) auto 0; padding:0 var(--sp-4); background:none; border:0; box-shadow:none;
  font-size:var(--fs-xs); line-height:1.4; color:var(--dim); font-family:var(--mono)}
#codestatus .cst-mode{color:var(--dim); font-weight:600; white-space:nowrap}
#codestatus .cst-where{min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap}
#codestatus .cst-state{white-space:nowrap}
#codestatus .cst-state::before{content:""; display:inline-block; width:6px; height:6px; margin-inline-end:6px; border-radius:var(--r-pill); background:var(--dim); vertical-align:middle}
#codestatus[data-state="run"] .cst-state::before{background:var(--ok)}
#codestatus .sp{flex:1}
#codestatus .cst-btn{flex:none; min-height:24px; padding:0 var(--sp-1); border:0; border-radius:var(--r-xs); background:none; color:var(--dim); font:inherit; cursor:pointer}
#codestatus .cst-btn:hover, #codestatus .cst-btn:focus-visible{color:var(--fg); text-decoration:underline; text-underline-offset:3px; outline:0}
#codestatus .cst-btn:disabled{opacity:.5; cursor:default; text-decoration:none}
.cev-pre.cev-att{color:var(--dim); font-size:var(--fs-xs)}
/* with the line the composer is two rows: the paper behind them is solid, so the work log scrolling
   beneath never shows between the input and the line */
body.codemode.p-chat #composer{background:linear-gradient(to bottom,transparent,var(--sheet) var(--sp-3))!important}
/* a phone: where it runs is the part that gives way (it ends in …); the state and both words stay */
@media (max-width:600px){ body.codemode #codestatus{padding:0 var(--sp-3)} }
/* ── the floating dock keeps its own column (tokens.css --dock-clear-*): on the top-level Chat page the
   whole layout — history, stream, work log, composer, an App beside it — stands beside the dock, never
   under it; the top bar still runs the full width over it. In a window the desk does the same
   (#hoop-windows above), so the page inside a window has nothing to make room for. ── */
html.hoop-rail:not(.hoop-session-embedded) body.p-chat{padding-inline-start:var(--dock-clear-start)!important; padding-inline-end:var(--dock-clear-end)!important}
html.hoop-rail:not(.hoop-embedded) body.p-chat .float{inset-inline-end:calc(var(--float-end) + var(--dock-clear-end))}
