/* Tag 中转站：沿用法典图鉴的 token、圆角卡片和玻璃浮层，只补功能层。 */

/* 只给读屏的文本容器。全站没有第二条规则去争这些属性，!important 是白加的；
   admin.css:25 有一份同名定义，但那份只被 review.html 用、和本文件永不同页，不冲突。 */
.sr-only{
  position:absolute;width:1px;height:1px;padding:0;margin:-1px;
  overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0;
}

/* 中转站完整继承 .float-btn 的中性圆钮样式，只负责排在快捷操作最上方。
   保留原按钮的颜色、边框、hover 和 20px 线性图标，避免同组里凭空出现一颗常驻主题色按钮。 */
.tag-relay-float-btn{transform:translateY(-52px)}
.tag-relay-count{
  position:absolute;right:-5px;top:-6px;min-width:19px;height:19px;padding:0 5px;display:grid;place-items:center;
  border:2px solid var(--panel);border-radius:999px;background:var(--new);color:#fff;
  font:800 10px/1 var(--font-ui);box-shadow:0 4px 10px rgba(28,32,58,.2);
}
/* ---------- 浏览页：中转站条目卡（侧栏列表复用） ---------- */
.tag-relay-eyebrow{display:block;color:var(--accent);font-size:10px;font-weight:900;letter-spacing:1.35px;text-transform:uppercase}
.tag-relay-primary,.tag-relay-secondary{
  min-height:38px;display:inline-flex;align-items:center;justify-content:center;gap:6px;border-radius:999px;
  padding:8px 15px;font-size:12.5px;font-weight:800;text-decoration:none;transition:transform .12s,box-shadow .12s,border-color .12s,background .12s;
}
.tag-relay-primary{border:1px solid var(--accent);background:var(--accent);color:var(--on-accent);box-shadow:0 6px 18px var(--accent-glow)}
.tag-relay-primary:hover{box-shadow:0 9px 24px var(--accent-glow);transform:translateY(-1px)}
.tag-relay-secondary{border:1px solid var(--line);background:var(--card);color:var(--muted)}
.tag-relay-secondary:hover{border-color:var(--accent);color:var(--accent)}
.tag-relay-primary:disabled,.tag-relay-secondary:disabled{opacity:.42;cursor:not-allowed;transform:none;box-shadow:none}
.tag-relay-primary:disabled:hover{transform:none;box-shadow:none}
.tag-relay-secondary:disabled:hover{border-color:var(--line);color:var(--muted)}

/* ---------- 浏览页：中转站侧栏 ---------- */
/* 形态与左侧目录栏 .sidebar 镜像对称：宽屏贴边常驻并把瀑布流挤窄（走 .layout 的 flex，
   开合先提交瀑布流终态，再同步播放两边的过渡），窄屏转浮层抽屉 + 遮罩，
   手机再转底部 sheet。这样它不像外挂上去的东西——站里本来就有一个长得一样的。 */
.tag-relay-rail{
  --relay-rail-height:calc(100dvh - var(--topbar-h) - 12px);
  position:sticky;top:var(--topbar-h);align-self:flex-start;flex:0 0 440px;width:440px;
  height:var(--relay-rail-height);max-height:var(--relay-rail-height);overflow:hidden;min-height:0;
  display:flex;flex-direction:column;
  background:var(--glass);backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px);
  border:1px solid var(--line);border-radius:18px;box-shadow:var(--shadow);
  /* 顶栏显隐时 top / height / max-height 同步过渡，保持底边稳定。
     漏掉 max-height 会先瞬间压短栏高，再随 top 下移，素材区因此回弹。 */
  /* 宽度交给外壳的受控动画：先测终态，不能让 RO 把中间宽度反复交给卡片。 */
  transition:top .3s cubic-bezier(.22,1,.36,1),height .3s cubic-bezier(.22,1,.36,1),max-height .3s cubic-bezier(.22,1,.36,1);
}
.tag-relay-rail.closed{flex-basis:0;width:0;padding:0;border-color:transparent;box-shadow:none}
.tag-relay-rail-backdrop{display:none}

.tag-relay-rail-head{
  flex:none;display:flex;align-items:center;gap:9px;padding:14px 16px 10px;
}
.tag-relay-rail-head h2{margin:0;font:800 17px/1.25 var(--font-display);letter-spacing:.5px;white-space:nowrap}
.tag-relay-rail-gap{flex:1;min-width:0}
.tag-relay-rail-close{
  flex:none;width:30px;height:30px;border:0;border-radius:10px;background:transparent;
  color:var(--muted);font-size:19px;line-height:1;cursor:pointer;
}
.tag-relay-rail-close:hover{background:var(--tagbg);color:var(--accent)}

.tag-relay-inline-action{
  flex:none;display:grid;grid-template-columns:minmax(0,1fr) auto;gap:8px 10px;
  margin:0 0 10px;padding:10px 16px;border-top:1px solid var(--line);border-bottom:1px solid var(--line);
  background:var(--tagbg);
}
.tag-relay-inline-action-copy{min-width:0}
.tag-relay-inline-action-copy b{display:block;font-size:12.5px}
.tag-relay-inline-action-copy p{margin:2px 0 0;color:var(--muted);font-size:10.5px;line-height:1.45}
.tag-relay-inline-action label{grid-column:1/-1;display:flex;align-items:center;gap:8px;color:var(--muted);font-size:10.5px;font-weight:800}
.tag-relay-inline-action label[hidden]{display:none}
.tag-relay-inline-action label span{flex:none}
.tag-relay-inline-action input{
  min-width:0;flex:1;height:32px;border:1px solid var(--line);border-radius:9px;
  background:var(--card);color:var(--text);padding:0 9px;font-size:12px;
}
.tag-relay-inline-action input:focus{outline:none;border-color:var(--accent);box-shadow:0 0 0 3px var(--accent-soft)}
.tag-relay-inline-action-buttons{display:flex;align-items:center;gap:6px}
.tag-relay-inline-action-buttons button{min-height:30px;padding:5px 10px;font-size:10.5px}
.tag-relay-inline-action-buttons .is-danger{border-color:var(--new);background:var(--new);color:#fff;box-shadow:none}

/* 侧栏常驻时右下浮动按钮会压在栏上，整组左移让位；与停靠栏、卡片同为 .32s。 */
.float-actions{transition:right .32s cubic-bezier(.22,1,.36,1)}
body.rail-docked .float-actions{right:calc(26px + 440px + 14px)}

/* 补：新增控件与角色负面提示 */
.tag-relay-tab-count{
  margin-left:5px;min-width:16px;display:inline-block;padding:0 5px;border-radius:999px;
  background:rgba(255,255,255,.24);font-size:10px;font-weight:800;
}
.tag-relay-tab-count[hidden]{display:none}
/* 两个来源页签共用的面板：列表与空态互斥显示，role="tabpanel" 挂在它们的共同父节点上。
   ⚠ 它是新插进来的一层，必须自己接住 flex:1 + min-height:0，否则列表撑不满、也滚不动。 */
.tag-relay-rail .tag-relay-source-panel{flex:1;min-height:0;display:flex;flex-direction:column}
/* 素材列表必须自己能滚：父面板 overflow:hidden，不给滚动容器就会被裁掉。
   overscroll-behavior:contain 是站内既有约定（见 styles.css 的 .tree）：抽屉/sheet 态滚到底
   若不拦住，滚动会串到后面的瀑布流上，整页跟着动。 */
.tag-relay-rail .tag-relay-source-list{
  flex:1;min-height:0;overflow-y:auto;overscroll-behavior:contain;padding:0 12px 10px;margin:0;
  display:flex;flex-direction:column;gap:7px;
  scrollbar-width:thin;scrollbar-color:var(--line) transparent;
}
/* 基础样式把这里做成两段完整的胶囊；不要留下旧侧栏的 16px 内边距，
   否则格子本身会被挤窄，右侧出现一段不对称的空白。 */
.tag-relay-rail .tag-relay-source-tabs{flex:none}
.tag-relay-rail .tag-relay-source-status{flex:none;padding:0;margin:0}
.tag-relay-rail .tag-relay-source-empty{flex:1;min-height:0}

@media (max-width:1240px){
  /* 挤不动了就改成盖：再挤下去瀑布流只剩一列，浏览就废了 */
  /* ⚠ z-index 必须低于灯箱(#lightbox=80)：.layout 是普通 flex、不建层叠上下文，这里是全局比大小。
     原来的 83/82 会让「1440px 停靠着开栏 → 打开灯箱 → 拖窄到 1100px」变成抽屉和遮罩盖住灯箱。
     68/67 仍高于要压住的一切：瀑布流(.masonry 无 z-index)、.float-actions(40)、左目录栏(25/24)、
     移动搜索条(55)；而设置类浮层(.settings-mask=70)、飞图(.lb-fly=90)、收入芯片(95)、toast(1400) 继续在它之上。 */
  .tag-relay-rail{
    --relay-rail-height:calc(100dvh - var(--topbar-h) - 8px);
    position:fixed;z-index:68;top:var(--topbar-h);right:8px;left:auto;
    width:min(440px,calc(100vw - 16px));flex-basis:auto;
    box-shadow:var(--shadow-hover);
    transition:transform .26s cubic-bezier(.22,1,.36,1),
      top .3s cubic-bezier(.22,1,.36,1),height .3s cubic-bezier(.22,1,.36,1),max-height .3s cubic-bezier(.22,1,.36,1);
  }
  .tag-relay-rail.closed{
    transform:translateX(calc(100% + 16px));width:min(440px,calc(100vw - 16px));
    flex-basis:auto;border-color:var(--line);box-shadow:none;
  }
  /* 遮罩的完整样式在本文件末尾那条同断点规则里（带淡入淡出），这里不再写第二份——
     同一个选择器分散两处就会变成"改一处不生效、改两处才生效"。 */
  body.rail-docked .float-actions{right:26px}
}

@media (max-width:600px){
  /* 手机转底部 sheet */
  .tag-relay-rail{
    --relay-rail-height:min(88dvh,720px);
    top:auto;bottom:0;right:0;left:0;width:100%;
    border-radius:22px 22px 0 0;border-bottom:0;
  }
  .tag-relay-rail.closed{transform:translateY(calc(100% + 16px));width:100%}
  .tag-relay-rail-head{padding:12px 14px 8px}
  .tag-relay-inline-action{grid-template-columns:1fr;padding:9px 14px}
  .tag-relay-inline-action-buttons{justify-content:flex-end}
}

/* 短屏里的方案改成单列横条后会多占几行；sheet 再抬高一点，尽量同时留下
   五六条方案和一整行素材，避免在两个相邻小滚动区来回滚。 */
@media (max-width:600px) and (max-height:640px){
  .tag-relay-rail{--relay-rail-height:min(calc(100dvh - 36px),720px)}
}

@media (prefers-reduced-motion:reduce){
  .tag-relay-rail{transition:none}
}

/* ---------- 中转站条目 / 块 / 输出的基础视觉 ---------- */
/* 这三节原属独立工作台，但侧栏沿用同一套类名，所以必须留下。
   2026-08-18 删独立页时曾把它们连同页面框架一起整段删掉，导致侧栏里的
   来源页签、块卡片、工具按钮、分段控件、输出框全部退回浏览器默认样式。
   ⚠ 以后再删「独立页专属」样式，先确认侧栏没在用同一个类名。 */

/* ---------- 素材架 ---------- */
.tag-relay-source-tabs{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:3px;margin:12px 12px 0;padding:3px;border:1px solid var(--line);border-radius:999px;background:var(--tagbg)}
.tag-relay-source-tabs button,.tag-relay-segment button{
  border:0;border-radius:999px;background:transparent;color:var(--muted);padding:7px 8px;font-size:11px;font-weight:800;white-space:nowrap;
}
.tag-relay-source-tabs button:hover,.tag-relay-segment button:hover{color:var(--text);background:var(--card)}
/* ⚠ 分段控件是 role="radiogroup"，选中态属性是 aria-checked（不是 aria-pressed）；
   改属性名的同时必须同步这里，否则选中的那一格没有底色。 */
.tag-relay-source-tabs button[aria-selected="true"],.tag-relay-segment button[aria-checked="true"]{background:var(--card);color:var(--accent);box-shadow:var(--shadow)}
.tag-relay-source-status{margin:0;padding:9px 14px;color:var(--muted);font-size:10.5px;line-height:1.45}
.tag-relay-source-list{flex:1;min-height:0;overflow:auto;display:flex;flex-direction:column;gap:8px;padding:0 12px 14px;scrollbar-width:thin;scrollbar-color:var(--line) transparent}
.tag-relay-source-empty{display:grid;place-items:center;align-content:center;min-height:180px;padding:24px;text-align:center;color:var(--muted);font-size:11px;line-height:1.6}
.tag-relay-source-empty b{color:var(--text);font-size:13px}
/* ⚠ .tag-relay-history-card 的定义整体挪到下面「侧栏内：编排分区」的复制历史一节，
   与原先覆盖它的那份合并成一条——历史面板只在侧栏里出现，样式没有理由分居两处。 */

.tag-relay-plan-lane{flex:1;min-height:0;overflow:auto;display:flex;flex-direction:column;gap:8px;padding:13px 14px 90px;scrollbar-width:thin;scrollbar-color:var(--line) transparent}
.tag-relay-plan-lane.is-drop-target{background:var(--accent-soft)}

/* ---------- 输出台 ---------- */
.tag-relay-output{padding-bottom:14px;overflow-y:auto;scrollbar-width:thin;scrollbar-color:var(--line) transparent}
.tag-relay-output .tag-relay-pane-head{position:sticky;top:0;z-index:3;background:var(--panel)}
.tag-relay-output-option{display:flex;align-items:center;justify-content:space-between;gap:8px;padding:10px 14px 0}
.tag-relay-output-option>span{color:var(--muted);font-size:10.5px;font-weight:800}
.tag-relay-segment{display:grid;grid-auto-flow:column;grid-auto-columns:1fr;gap:2px;padding:3px;border:1px solid var(--line);border-radius:999px;background:var(--tagbg)}
.tag-relay-segment button{padding:5px 9px;font-size:10.5px}
.tag-relay-output-box{display:flex;flex-direction:column;gap:6px;margin:13px 14px 0}
.tag-relay-output-box>span{display:flex;align-items:center;justify-content:space-between}
.tag-relay-output-box b{font-size:11px;letter-spacing:.5px}
.tag-relay-output-box small{color:var(--muted);font-size:9.5px}
/* 视觉只是一小段文字，但触屏要能点中：靠 padding 撑热区、再用负 margin 抵消掉占位 */
.tag-relay-merged{border:0;background:none;padding:8px 4px;margin:-8px -4px;font:inherit;color:var(--accent);cursor:help;text-decoration:underline dotted;text-underline-offset:2px}
.tag-relay-merged:hover{text-decoration-style:solid}
.tag-relay-output-box textarea{
  width:100%;min-height:98px;resize:vertical;border:1px solid var(--line);border-radius:12px;
  background:var(--tagbg);color:var(--text);padding:10px;font:500 10.5px/1.55 var(--font-prompt);
}
.tag-relay-output-box textarea:focus{outline:none;border-color:var(--accent);box-shadow:0 0 0 3px var(--accent-soft)}
.tag-relay-copy-secondary{align-self:flex-end;margin:6px 14px 0;border:1px solid var(--line);border-radius:999px;background:var(--card);color:var(--muted);padding:5px 10px;font-size:10.5px;font-weight:800}
.tag-relay-copy-secondary:hover{border-color:var(--accent);color:var(--accent);background:var(--accent-soft)}
.tag-relay-copy-secondary:disabled{opacity:.42;cursor:not-allowed}
.tag-relay-copy-note{margin:7px 16px 0;color:var(--muted);font-size:9.5px;line-height:1.45}

.tag-relay-mobile-tabs{display:none}
.tag-relay-plan-menu-wrap{position:relative;flex:none}
.tag-relay-history-toggle{
  flex:none;height:30px;border:1px solid var(--line);border-radius:999px;background:var(--card);
  color:var(--muted);padding:0 8px;font-size:11px;font-weight:800;
}
.tag-relay-history-toggle:hover,.tag-relay-history-toggle[aria-expanded="true"]{border-color:var(--accent);color:var(--accent);background:var(--accent-soft)}
.tag-relay-history-count{margin-left:4px;color:inherit;font-size:9px}
.tag-relay-history-count:empty{display:none}
.tag-relay-plan-more{
  width:32px;height:32px;border:0;border-radius:10px;background:transparent;
  color:var(--muted);font-size:16px;line-height:1;cursor:pointer;
}
.tag-relay-plan-more:hover{background:var(--tagbg);color:var(--accent)}
.tag-relay-plan-menu{
  position:absolute;right:0;top:calc(100% + 6px);z-index:6;min-width:132px;padding:6px;
  border:1px solid var(--popover-line);border-radius:var(--ui-popover-radius);background:var(--popover-glass);
  box-shadow:var(--popover-shadow);backdrop-filter:blur(var(--ui-popover-blur));-webkit-backdrop-filter:blur(var(--ui-popover-blur));
  display:flex;flex-direction:column;gap:2px;
}
.tag-relay-plan-menu button{
  border:0;border-radius:8px;background:transparent;color:var(--text);
  padding:7px 10px;text-align:left;font-size:12.5px;
}
.tag-relay-plan-menu button:hover:not(:disabled){background:var(--tagbg);color:var(--accent)}
.tag-relay-plan-menu button:disabled{opacity:.4;cursor:not-allowed}

.tag-relay-history{flex:none;margin:0 12px 10px;border:1px solid var(--line);border-radius:12px;background:var(--card);overflow:hidden}
.tag-relay-history>header{display:flex;align-items:center;justify-content:space-between;gap:8px;padding:8px 10px;border-bottom:1px solid var(--line)}
.tag-relay-history>header>b{font-size:12px}
.tag-relay-history>header>div{display:flex;align-items:center;gap:3px}
.tag-relay-history>header button{min-width:26px;height:26px;border:0;border-radius:7px;background:transparent;color:var(--muted);font-size:11px;font-weight:800}
.tag-relay-history>header button:hover:not(:disabled){background:var(--tagbg);color:var(--accent)}
.tag-relay-history>header button:disabled{opacity:.42;cursor:not-allowed}
.tag-relay-history>header #relayHistoryClose{font-size:17px;line-height:1}
/* overscroll-behavior:contain 同 .tree：抽屉/sheet 态里滚到底不该把后面的瀑布流顶走 */
.tag-relay-history-list{display:flex;flex-direction:column;gap:7px;max-height:228px;overflow-y:auto;overscroll-behavior:contain;padding:8px;scrollbar-width:thin;scrollbar-color:var(--line) transparent}
.tag-relay-history-empty{margin:8px;color:var(--muted);font-size:11px;line-height:1.6;text-align:center}
/* 合并自上方原「素材架」一节的重复定义：那份的 gap/border-radius/padding/box-shadow 本来就被这份盖掉。
   ⚠ .tag-relay-history-card button 必须排在下面的 .tag-relay-history-actions button 之前——
   两者特异度相同，靠先后顺序决定圆角与内边距归谁。 */
.tag-relay-history-card{display:flex;flex-direction:column;gap:6px;border:1px solid var(--line);border-radius:10px;background:var(--card);padding:8px;box-shadow:none}
.tag-relay-history-card header{display:flex;align-items:center;justify-content:space-between;gap:8px}
.tag-relay-history-card b{font-size:12.5px;min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.tag-relay-history-card time{color:var(--muted);font-size:9px;white-space:nowrap}
.tag-relay-history-card p{margin:0;color:var(--muted);font:500 9.5px/1.45 var(--font-prompt);display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}
.tag-relay-history-card button{align-self:flex-start;border:1px solid var(--accent);border-radius:999px;background:var(--accent-soft);color:var(--accent);padding:5px 10px;font-size:10.5px;font-weight:800}
.tag-relay-history-actions{display:flex;align-items:center;gap:6px}
.tag-relay-history-actions button{padding:5px 8px}
.tag-relay-history-locked{color:var(--muted);font-size:10.5px;font-weight:800}

.tag-relay-rail .tag-relay-plan-lane{
  flex:1;min-height:60px;overflow-y:auto;padding:0 12px 10px;margin:0;
  display:flex;flex-direction:column;gap:7px;
  scrollbar-width:thin;scrollbar-color:var(--line) transparent;
}

.tag-relay-rail .tag-relay-output{
  flex:none;border-top:1px solid var(--line);padding:10px 16px 14px;background:var(--bg);
  display:flex;flex-direction:column;gap:8px;overflow:visible;
}
.tag-relay-rail [data-rail-pane="compose"]{overflow:hidden;overscroll-behavior:contain}
.tag-relay-rail [data-rail-pane="compose"] .tag-relay-plan-lane{flex:1 1 120px}
.tag-relay-rail .tag-relay-output-option{
  display:grid;grid-template-columns:minmax(0,1.08fr) minmax(0,1fr);align-items:center;gap:8px;
  padding:0;
}
.tag-relay-output-option-group{display:grid;grid-template-columns:auto minmax(0,1fr);align-items:center;gap:6px;min-width:0}
.tag-relay-output-option-group>span{color:var(--muted);font-size:10.5px;font-weight:800;white-space:nowrap}
.tag-relay-output-option-group .tag-relay-segment{min-width:0}
.tag-relay-rail .tag-relay-output-box{margin:0}
.tag-relay-rail .tag-relay-output-box textarea{min-height:0;font-size:11px}
/* 次级行：两颗通道键在左，设置与成品记录靠右；窄栏换行也不会互相挤扁。 */
.tag-relay-output-actions{display:flex;flex-wrap:wrap;align-items:center;gap:6px}
.tag-relay-output-actions>button{flex:none;min-height:30px;font-size:11.5px;padding:5px 11px}
.tag-relay-output-gap{flex:1 1 0;min-width:0}

/* ⚠ 统计行不能按视口宽度藏：侧栏恒宽 440px，1100px 的抽屉里没有、1300px 的停靠里有，
   同样宽的一根栏两种表现，纯属把独立页的响应式当成了侧栏的响应式。
   真正会挤的是底部 sheet 形态，所以按形态收紧内边距；块数由方案区标题显示。 */
@media (max-width:600px){
  .tag-relay-rail .tag-relay-output{padding:10px 14px 14px}
}

@media (max-width:600px){
  .float-actions .tag-relay-float-btn{transform:translateY(-46px)}

}

@media (prefers-reduced-motion:reduce){
  /* .float-actions 也进来：它的 right 过渡是跟着侧栏滑动补的，减少动效时同样该断掉 */
  .tag-relay-rail,.tag-relay-primary,
  .float-actions{transition:none!important}
}

/* ============================================================
   一屏化改版（2026-08-20）
   素材与编排不再分页签：编排在上、素材在下、成品贴底。
   两个分区的条目统一改成**芯片**——原先一条素材占 100px（其中 28px 是常驻按钮、
   42px 是缩略图），一屏只看得到 4 条，而 tag 预览还是被省略号截断的，等于白占。
   芯片 30px 高、宽随标题自适应，440px 的栏一行放得下 2~3 个。
   ============================================================ */

/* ---- 栏头：吞掉原来的方案条 ---- */
.tag-relay-plan-picker{flex:1;min-width:0;max-width:154px;--select-font-size:11.5px}

/* ---- 分区骨架 ---- */
.tag-relay-rail .tag-relay-zone{
  display:flex;flex-direction:column;gap:7px;padding:9px 14px;min-height:0;
}
/* 工作台优先：给下限、并吃掉剩余空高；货架改成按内容收缩、只吃到上限。
   原先是反过来的（方案 max-height 封顶、货架 flex:1 吃掉全部剩余），实测空方案时
   编排区只剩 95px，比它下面那排**禁用**的输出控件（135px）还矮。 */
/* 图墙按内容长（每行 64px），所以方案区收缩到内容大小、省下的高度全给货架——
   这跟"满宽横条"时代的分配正好反过来：那时方案区要抢下限，现在它本来就不占地方。
   上限 46% 是为了 20+ 块时不至于把货架挤没。 */
/* ⚠ shrink 必须是 0：素材塞满时整栏内容会超过栏高，只要方案区可收缩，
   它就会跟着被压掉半行图块（实测 6 块本该 2 行 134px，被压成 118px 只看得见 4 块）。
   该滚的是货架，不是方案。 */
.tag-relay-rail .tag-relay-zone-plan{flex:0 1 auto;max-height:46%;min-height:114px}
.tag-relay-rail .tag-relay-zone-plan .tag-relay-plan-lane{flex:0 1 auto}
.tag-relay-rail .tag-relay-zone-source{flex:1 1 0;min-height:88px}
/* 仅列表按实际前两行裁切，分区头和空态不计入限高。其余项保持布局供重测，但不可聚焦。 */
.tag-relay-rail .tag-relay-zone-source.is-peek{flex:0 0 auto;min-height:0}
.tag-relay-rail .tag-relay-zone-source.is-peek .tag-relay-source-panel{flex:none;max-height:var(--relay-shelf-peek-height,68px);overflow:hidden}
.tag-relay-rail .tag-relay-zone-source.is-peek .tag-relay-source-panel:has(.tag-relay-source-list[hidden]){max-height:none}
.tag-relay-rail .tag-relay-zone-source.is-peek .tag-relay-source-list{flex:none;overflow:visible}
.tag-relay-rail .tag-relay-source-list{position:relative}
.tag-relay-rail:not(.is-shelf-moving) .tag-relay-chip[aria-hidden="true"]{visibility:hidden}
/* 真实高度参与排版：货架向上伸展，编辑框同步让位，不缩放文字。 */
.tag-relay-rail.is-shelf-moving .tag-relay-zone-source{flex:0 0 auto;min-height:0;overflow:hidden}
.tag-relay-rail.is-shelf-moving .tag-relay-zone-source .tag-relay-source-panel{flex:1;max-height:none;overflow:hidden}
.tag-relay-rail.is-shelf-moving .tag-relay-source-list{flex:none;overflow:visible}
/* 与邻近的 ⋯（32×32）齐平；.icon-btn 的 36px 在栏内偏大。 */
.relay-shelf-toggle{flex:none;width:32px;height:32px;font-size:13px;border-radius:10px;color:var(--muted)}
.relay-shelf-toggle[aria-expanded="true"]{color:var(--accent)}
.relay-disclosure-caret{display:block;flex:none;width:14px;height:14px;fill:none;stroke:currentColor;stroke-width:1.8;stroke-linecap:round;stroke-linejoin:round;transform-origin:center;transition:rotate .2s cubic-bezier(.22,1,.36,1)}
[aria-expanded="true"]>.relay-disclosure-caret{rotate:180deg}

.tag-relay-zone-head{display:flex;align-items:center;gap:6px;min-height:24px;flex:none}
/* 分区名：两个区都得有，否则「工作台 / 货架」全靠一条 1px 线区分。 */
.tag-relay-band{
  flex:none;display:inline-flex;align-items:center;gap:6px;
  color:var(--muted);font-size:10.5px;font-weight:900;letter-spacing:1.2px;white-space:nowrap;
}
.tag-relay-band::before{content:'';width:3px;height:11px;border-radius:2px;background:var(--accent)}
.tag-relay-zone-title{
  margin:0;flex:1;min-width:0;font-size:11px;font-weight:800;color:var(--muted);
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
}
.tag-relay-zone-empty{
  margin:0;padding:10px 2px;flex:none;color:var(--muted);font-size:11.5px;line-height:1.6;
}
.tag-relay-zone-split{flex:none;height:1px;margin:2px 14px;background:var(--line)}

/* 图墙不再有"轨道之外的死白"可解释，落点提示整块撤掉：
   方案区已经贴着内容收缩，剩余高度直接归货架。 */

/* ---- 芯片轨道 ---- */
.tag-relay-rail .tag-relay-plan-lane,
.tag-relay-rail .tag-relay-source-list{
  /* ⚠ 必须显式写 row：上面那条同特异度的旧规则把素材列设成了 column，
     只写 flex-wrap 不写方向，芯片会一条一行地竖着排，等于白改。 */
  display:flex;flex-direction:row;flex-wrap:wrap;gap:6px;align-content:flex-start;
  flex:1;min-height:0;overflow:auto;overscroll-behavior:contain;padding:1px;
}

/* ---- 素材芯片（货架，L 档的块）：素材进编辑区一律变块，所以这里也是块 ----
   圆角与编辑区块 4px、面板头 6px 成比例；左端身份标记是缩略图，没图时是 '#'。 */
.tag-relay-chip{
  display:inline-flex;align-items:center;flex:none;
  height:30px;max-width:200px;min-width:0;
  border:1px solid var(--line);border-radius:8px;background:var(--card);color:var(--text);
  transition:border-color .12s,background .12s,color .12s;
}
/* 主体是按钮、移除键是另一个按钮，所以外层只能是容器：button 里不能再嵌 button
   （本分支刚因为 label 里嵌 button 修过一轮，同一个坑不踩第二次）。 */
.tag-relay-chip-main{
  display:inline-flex;align-items:center;gap:6px;min-width:0;flex:1;
  height:100%;padding:0 9px;border:0;background:transparent;color:inherit;
  font-size:11.5px;font-weight:800;text-align:left;cursor:pointer;
}
.tag-relay-chip:hover{border-color:var(--accent);color:var(--accent)}
.tag-relay-chip:focus-within{outline:2px solid var(--accent);outline-offset:2px}
.tag-relay-chip-name{min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.tag-relay-chip-dot{
  flex:none;width:16px;height:16px;border-radius:4px;background:var(--tagbg);
  background-size:cover;background-position:center;
}
.tag-relay-chip-dot.is-blank{display:grid;place-items:center}
.tag-relay-chip-dot.is-blank::before{content:'#';color:var(--accent);font:700 10px/1 var(--font-prompt)}
.tag-relay-chip-negative{
  flex:none;width:23px;height:22px;margin-right:3px;padding:0;border:0;border-radius:6px;
  background:color-mix(in srgb,var(--new) 12%,var(--card));color:var(--new);
  font-size:9px;font-weight:900;line-height:1;cursor:pointer;
}
.tag-relay-chip-negative:hover,.tag-relay-chip-negative:focus-visible{
  outline:none;background:var(--new);color:#fff;
}
/* 移除键：桌面 hover 才现，触屏没有 hover，常驻但压低存在感 */
.tag-relay-chip-x{
  flex:none;width:24px;height:24px;margin-right:3px;padding:0;border:0;border-radius:999px;
  background:transparent;color:var(--muted);font-size:13px;line-height:1;opacity:0;
  display:grid;place-items:center;transition:opacity .12s,color .12s,background .12s;
}
.tag-relay-chip-x:hover{background:var(--tagbg)}
.tag-relay-chip:hover .tag-relay-chip-x,
.tag-relay-chip .tag-relay-chip-x:focus-visible{opacity:1}
.tag-relay-chip-x:hover{color:var(--new)}
@media (hover:none){ .tag-relay-chip-x{opacity:.5} }
.tag-relay-chip.is-locked{
  color:var(--muted);
  background:repeating-linear-gradient(135deg,color-mix(in srgb,var(--muted) 14%,var(--card)) 0 4px,var(--card) 4px 8px);
}
.tag-relay-chip.is-locked .tag-relay-chip-dot::before{color:var(--muted)}
.tag-relay-chip.is-locked .tag-relay-chip-main{cursor:not-allowed}
.tag-relay-chip.is-locked:hover{border-color:var(--line);color:var(--muted)}
.tag-relay-chip.is-dragging{opacity:.4}

/* ---- 成品：主键满宽，次级动作与设置各归各位 ---- */
.tag-relay-copy-main{
  display:flex;align-items:center;justify-content:flex-start;gap:10px;width:100%;
  min-height:46px;padding:8px 16px;border-radius:14px;font-size:14px;text-align:left;
}
.tag-relay-copy-main>span:first-child{flex:1;min-width:0}
.tag-relay-copy-hint{flex:none;font-style:normal;font-size:11px;font-weight:700;opacity:.86}
.tag-relay-copy-hint:empty{display:none}
/* 合并明细原先只写在收起的摘要里，展开才看得到细节；这里给它一行常驻但克制的位置。 */
.tag-relay-output-note{
  margin:0;padding:0 2px;color:var(--muted);font-size:10.5px;font-weight:700;line-height:1.5;
}
.tag-relay-output-note[hidden]{display:none}
/* 收起时它自己就是「当前格式」的标签，不再是一条占满宽的摘要条。 */
.tag-relay-output-summary{
  display:inline-flex;align-items:center;justify-content:center;gap:5px;width:auto;
  padding:5px 10px;border:1px solid var(--line);border-radius:999px;background:var(--card);
  color:var(--muted);font:800 11px/1.2 var(--font-prompt);white-space:nowrap;text-align:left;
}
.tag-relay-output-summary:hover{border-color:var(--accent);color:var(--accent)}
.tag-relay-output-boxes{display:flex;flex-direction:column;gap:7px}

/* ---- 成品记录：浮层，且开在自己的入口正上方 ----
   原先触发点在栏顶（y≈146）、面板落在栏底（y≈768），还盖住素材货架。
   现在它是成品区的绝对定位子节点，bottom 贴着成品区顶边向上展开。 */
.tag-relay-rail .tag-relay-output{position:relative}
.tag-relay-rail .tag-relay-history{
  position:absolute;left:14px;right:14px;bottom:calc(100% - 8px);z-index:6;
  max-height:min(52vh,340px);display:flex;flex-direction:column;
  border:1px solid var(--popover-line);border-radius:var(--ui-popover-radius);background:var(--popover-glass);
  box-shadow:var(--popover-shadow);backdrop-filter:blur(var(--ui-popover-blur));-webkit-backdrop-filter:blur(var(--ui-popover-blur));
}

@media (prefers-reduced-motion:reduce){
  .tag-relay-chip,.tag-relay-chip-x,.relay-disclosure-caret{transition:none}
}

/* ≤600px 底部 sheet：高度最紧，素材仍要至少露出一整行 */
@media (max-width:600px){
  .tag-relay-rail .tag-relay-zone{padding:8px 12px}
}

/* ============================================================
   一屏化 v2（2026-08-20，实际试用后的修正）
   ① 成品挪到编排区正下方——复制的是这个方案，中间隔着素材货架很别扭
   ② 方案块改成**带图的单列横条**：NAI 上限 512 token，一个画风 + 一个场景 +
      一个角色 + 一套服饰也就五六块；整行都是落点，比两列小卡更容易点选和拖排
   ③ 拖影用完整卡片，落点用插入线，原位卡才变淡
   ④ 分段控件加滑块过渡；格式与连接各自作为不可拆开的原子组
   ============================================================ */

/* ---- 方案块＝图墙：一行 4 个 88×64 的横块，标题白字压在图底 ----
   为什么不再用满宽横条：一条 440px 宽、46px 高的条里真正承载信息的只有 7~9 个字的标题，
   右边两百多像素全是空的；6 块吃掉 306px，块一多就得滚，每块的按钮还被推到很远的右边。
   实测（440px 栏 / 700px 高，12 块 + 18 素材）：
     满宽横条  可见 5 块 + 7 素材 = 12 条，方案区 366px
     图墙宽块  可见 12 块 + 14 素材 = 26 条，方案区 246px
   ⚠ 往**宽**了要地方、不往高了要：88px 的标题能放 7~8 个字（真实语料中位 7 字、p75 9 字），
     而省掉每行 13px 的标题行之后，总高反而和"图下写标题"差不多。 */
.tag-relay-rail .tag-relay-plan-lane{
  display:grid;grid-template-columns:repeat(auto-fill,minmax(84px,1fr));
  grid-auto-rows:64px;gap:6px;align-content:start;overflow-x:hidden;overflow-y:auto;
}

/* ---- 素材芯片：可以拖上去 ---- */
.tag-relay-chip{cursor:grab}
.tag-relay-chip:active{cursor:grabbing}
.tag-relay-chip.is-dragging{opacity:.35}
.tag-relay-plan-lane.is-drop-target{
  border-radius:12px;box-shadow:inset 0 0 0 2px color-mix(in srgb,var(--accent) 62%,transparent);
}

/* ---- 分段控件滑块 ---- */
.tag-relay-segment{position:relative}
.tag-relay-segment{--seg-n:3;--seg-i:0}
.tag-relay-segment-slider{
  --seg-unit:calc((100% - 6px - 2px * (var(--seg-n) - 1)) / var(--seg-n));
  position:absolute;top:3px;bottom:3px;
  width:var(--seg-unit);
  left:calc(3px + (var(--seg-unit) + 2px) * var(--seg-i));
  border-radius:999px;background:var(--card);box-shadow:var(--shadow);
  transition:left .24s cubic-bezier(.22,1,.36,1),width .24s cubic-bezier(.22,1,.36,1);
  pointer-events:none;
}
.tag-relay-segment button{position:relative;z-index:1}
/* 选中态的底色交给滑块，按钮本身只留文字色，否则两层背景会打架 */
.tag-relay-segment button[aria-checked="true"]{background:transparent;box-shadow:none;color:var(--accent)}

@media (prefers-reduced-motion:reduce){
  .tag-relay-segment-slider{transition:none}
}

/* 条数长在页签上（栏头那份已撤）；分区自己的「⋯」放清空。 */
.tag-relay-source-count{
  margin-left:5px;padding:0 5px;border-radius:999px;background:var(--tagbg);
  font-size:9.5px;font-weight:900;
}
.tag-relay-source-count:empty{display:none}
.tag-relay-source-tabs button[aria-selected="true"] .tag-relay-source-count{background:var(--accent-soft)}
.tag-relay-source-menu-wrap{position:relative;flex:none}
/* 素材分区永远贴着栏底，菜单只能向上开——向下会被栏的 overflow:hidden 裁掉。 */
.tag-relay-source-menu-wrap .tag-relay-plan-menu{top:auto;bottom:calc(100% + 6px)}
.tag-relay-source-menu-wrap .tag-relay-plan-menu{transform-origin:bottom right}
.tag-relay-source-menu-wrap .tag-relay-plan-menu[hidden]{translate:0 6px}
/* 状态行只在真有话说时占位（读收藏中…），空着不留空行。 */
.tag-relay-rail .tag-relay-zone-source .tag-relay-source-status{
  flex:none;margin:0;padding:0 2px;color:var(--muted);font-size:10.5px;font-weight:700;
}
.tag-relay-source-status:empty{display:none}

/* 来源切换已经搬进分区头，旧独立页的外边距/底部 padding 必须在这里归零。 */
.tag-relay-rail .tag-relay-zone-head .tag-relay-source-tabs{
  position:relative;flex:1;min-width:0;margin:0;padding:2px;
}
.tag-relay-rail .tag-relay-zone-head .tag-relay-source-tabs button{padding:5px 7px}

/* 来源页签与上方「格式 / 连接」共用同一种滑块语言；旧浏览器不支持 :has 时保留原选中底色。 */
.tag-relay-source-slider{display:none}
@supports selector(:has(*)){
  .tag-relay-source-slider{
    position:absolute;z-index:0;left:2px;top:2px;bottom:2px;
    width:calc((100% - 4px - 3px) / 2);display:block;border-radius:999px;
    background:var(--card);box-shadow:var(--shadow);pointer-events:none;
    translate:0 0;transition:translate .24s cubic-bezier(.22,1,.36,1);
  }
  .tag-relay-source-tabs:has(>[data-relay-source="favorites"][aria-selected="true"]) .tag-relay-source-slider{
    translate:calc(100% + 3px) 0;
  }
  .tag-relay-source-tabs button{position:relative;z-index:1}
  .tag-relay-source-tabs button[aria-selected="true"]{background:transparent;box-shadow:none}
}

/* 隐藏态仍由 HTML hidden 同步维护；display 的离散过渡只负责把可见退场撑到末帧，
   不延迟 aria-expanded，也不让 JS 等动画。位移使用独立 translate，避免占用 transform。 */
.tag-relay-plan-menu,
.tag-relay-output-boxes,.tag-relay-rail .tag-relay-history,.tag-relay-inline-action{
  opacity:1;translate:0 0;scale:1;
  transition:opacity .16s ease,translate .18s cubic-bezier(.22,1,.36,1),
    scale .18s cubic-bezier(.22,1,.36,1),display .18s allow-discrete;
}
.tag-relay-output-boxes,.tag-relay-inline-action{
  max-height:260px;overflow:hidden;
  transition:max-height .22s cubic-bezier(.22,1,.36,1),opacity .16s ease,
    translate .18s cubic-bezier(.22,1,.36,1),scale .18s cubic-bezier(.22,1,.36,1),
    display .22s allow-discrete;
}
.tag-relay-plan-menu{transform-origin:top center}
.tag-relay-rail .tag-relay-history{transform-origin:bottom center}
.tag-relay-plan-menu[hidden]{
  display:none;opacity:0;translate:0 -6px;scale:.97;pointer-events:none;
}
.tag-relay-output-boxes[hidden],.tag-relay-inline-action[hidden]{
  display:none;max-height:0;opacity:0;translate:0 -5px;scale:.99;pointer-events:none;
}
.tag-relay-rail .tag-relay-history[hidden]{
  display:none;opacity:0;translate:0 9px;scale:.985;pointer-events:none;
}
@starting-style{
  .tag-relay-plan-menu:not([hidden]){
    opacity:0;translate:0 -6px;scale:.97;
  }
  .tag-relay-output-boxes:not([hidden]),.tag-relay-inline-action:not([hidden]){
    max-height:0;opacity:0;translate:0 -5px;scale:.99;
  }
  .tag-relay-rail .tag-relay-history:not([hidden]){
    opacity:0;translate:0 9px;scale:.985;
  }
}

@media (prefers-reduced-motion:reduce){
  .tag-relay-source-slider,
  .tag-relay-plan-menu,
  .tag-relay-output-boxes,.tag-relay-rail .tag-relay-history,.tag-relay-inline-action{
    transition:none!important;
  }
}

@media (max-width:600px){
  .tag-relay-rail .tag-relay-zone-plan{max-height:44%}
  .tag-relay-rail .tag-relay-zone-source{min-height:88px}
  /* 图墙的列数交给 auto-fill：390px sheet 下是 3 列（每块约 112px），标题反而更长。 */
  .tag-relay-rail .tag-relay-plan-lane{gap:5px}
  .tag-relay-output-option-group{gap:4px}
  .tag-relay-output-option-group>span{font-size:10px}
  .tag-relay-output-option-group .tag-relay-segment button{padding:5px 4px;font-size:10px}
}

/* Local motion only; the main atlas has its own layout and animation owners. */
.tag-relay-motion-exit{position:absolute;z-index:4;overflow:hidden;pointer-events:none}
.tag-relay-rail .tag-relay-output-boxes{
  max-height:clamp(56px,calc(100dvh - 530px),260px);
  overflow-y:auto;overscroll-behavior:contain;scrollbar-width:thin;
}
.tag-relay-rail .tag-relay-output-boxes[hidden]{max-height:0}
.tag-relay-output-boxes>*{flex:none}
/* 控件的按压和偏好门控走 ui-kit；局部样式不能再漏掉 scale 的过渡。 */
.tag-relay-rail .ui-press{transition:var(--ui-control-transition)}
.tag-relay-rail .tag-relay-chip-x.ui-press{transition:var(--ui-control-transition),opacity .16s}
.tag-relay-chip{transition:border-color .16s,background .16s,color .16s,opacity .16s}
.tag-relay-plan-lane{transition:background .16s,box-shadow .16s}
@starting-style{
  .tag-relay-rail .tag-relay-output-boxes:not([hidden]){max-height:0}
}
@media (min-width:1241px){
  /* 收栏是把外框宽度收到 0，里面的内容不能跟着被挤扁——否则收起动画会变成"内容先塌再滑走"。 */
  .tag-relay-rail>:is(.tag-relay-rail-head,.tag-relay-zone,.tag-relay-output){min-width:438px}
}
@media (max-width:1240px){
  .tag-relay-rail-backdrop{
    display:block;position:fixed;inset:0;z-index:67;border:0;padding:0;
    background:rgba(15,18,30,.3);opacity:0;visibility:hidden;pointer-events:none;
    touch-action:none;overscroll-behavior:contain;
    transition:opacity .22s ease,visibility .22s;
  }
  .tag-relay-rail:not(.closed)+.tag-relay-rail-backdrop{opacity:1;visibility:visible;pointer-events:auto}
}
@media (max-height:480px){
  .tag-relay-rail{overflow-y:auto;overscroll-behavior:contain}
  .tag-relay-rail .tag-relay-zone-source{flex:none;min-height:100px}
}
@media (max-width:600px) and (max-height:640px){
  .tag-relay-rail .tag-relay-output{padding:8px 14px;gap:5px}
  .tag-relay-output-actions>button{min-height:28px;padding:4px 8px;font-size:11px}
}
@media (prefers-reduced-motion:reduce){
  .tag-relay-rail *,.tag-relay-rail *::after,.tag-relay-rail-backdrop{transition:none!important;animation:none!important}
}

/* 真文本与镜像共用排版；token 的颜色、图片、注音不改变字符推进宽度。 */
.tag-relay-rail .tag-relay-plan-lane.relay-editor{display:flex;flex-direction:column;flex-wrap:nowrap;align-items:stretch;align-content:normal;gap:0;min-height:0;padding:0;border:1px solid var(--line);border-radius:12px;background:var(--card);overflow:visible;transition:border-color .16s,box-shadow .16s}
.tag-relay-rail .tag-relay-plan-lane.relay-editor:focus-within{border-color:color-mix(in srgb,var(--accent) 60%,var(--line));box-shadow:0 0 0 2px var(--accent-soft)}
.tag-relay-rail .tag-relay-zone-plan{min-height:0;max-height:58%;overflow-y:auto;overscroll-behavior:contain}
/* 通道条包在 .relay-editor-bar 里（桌面 display:contents），也要一起免于被压缩。 */
.relay-editor>div,.relay-editor-bar>div{flex-shrink:0;min-width:0}
/* 通道切换：站内共用 .seg-tabs 的形制，这里只压窄尺寸去适配 440px 栏。 */
.relay-editor-channels{min-height:0;margin:0;border:0;border-bottom:1px solid var(--line);border-radius:11px 11px 0 0;background:var(--tagbg)}
.relay-editor-channels>button{min-height:28px;font-size:12px}
/* 输入框外壳。⚠ 外框只在这一层，surface 不加 padding ——
   mirror 是 position:absolute;inset:0，给 surface 加 padding 会让镜像层与 textarea 的字符落点错开。
   左右只留 4px：另外 8px 挪进了镜像与 textarea（两层同改，字的起点仍是 4 + 8 = 12px、折行宽度不变），
   给块和药丸往外画的部分留画布 —— surface 是滚动容器，画到它外面的会被裁掉（最远是停用块 7px）。 */
.relay-editor-frame{padding:4px 4px 6px;min-width:0}
.relay-save-state{display:flex;flex-wrap:wrap;align-items:center;gap:6px;margin-bottom:8px;color:var(--muted);font:11px/1.5 var(--font-ui)}
.relay-save-state button{border:1px solid var(--line);border-radius:999px;padding:3px 8px;background:var(--card);color:var(--text);font:inherit;cursor:pointer}
:is(.relay-token-panel,.relay-token-body,.relay-token-weight)>:is(button:not(.relay-token-pic),a){border:1px solid var(--line);border-radius:999px;background:var(--card);color:var(--text);padding:4px 10px;font:12px/1.5 var(--font-ui);cursor:pointer;text-decoration:none}
.relay-editor-surface{position:relative;width:100%;box-sizing:border-box;margin:0;padding:0;text-align:left;border:0;border-radius:0;background:transparent;min-height:56px;max-height:300px;overflow:auto;scrollbar-width:thin;overscroll-behavior:contain}
.relay-editor-surface>.relay-editor-mirror,.relay-editor-surface>.relay-editor-input{
  box-sizing:border-box;font:400 13px/2.6 var(--font-prompt);font-style:normal;
  letter-spacing:0;word-spacing:normal;padding:8px 8px 14px;margin:0;border:0;
  white-space:pre-wrap;overflow-wrap:break-word;word-break:normal;tab-size:2;
  /* inline token 会切断整串 shaping；两层都关掉字偶距/连字，保证断行也相同。 */
  text-transform:none;text-indent:0;text-align:left;direction:ltr;font-kerning:none;font-variant-ligatures:none;
}
/* isolation：镜像自成层叠上下文，token 沉到 -1 层，逗号 / 空格 / 换行永远压在块和药丸上面
   （拖选折叠可能产生「a,#词组」，块往左画的 6px 会盖住紧贴的逗号）。 */
.relay-editor-surface>.relay-editor-mirror{position:absolute;left:0;right:0;top:0;pointer-events:none;color:var(--text);min-height:56px;overflow:hidden;isolation:isolate}
.relay-editor-surface>.relay-editor-input{position:relative;display:block;width:100%;min-height:56px;resize:none;background:transparent;color:transparent;caret-color:var(--accent);outline:none;overflow:hidden;box-shadow:none;border-radius:0}
.relay-editor-input::selection{background:color-mix(in srgb,var(--muted) 22%,transparent);color:transparent}
.relay-editor-surface.is-empty .relay-editor-mirror::after{content:'输入 tag，或从下方选择素材';position:absolute;left:8px;top:8px;color:var(--muted)}
.relay-editor-surface.is-composing>.relay-editor-input{color:var(--text)}
.relay-editor-surface.is-composing>.relay-editor-mirror{visibility:hidden}
/* ---- tag 块「块·药丸」：编辑区、面板头、货架三处同一套语言 ----
   形状说「有几个」：普通 tag 只画文本；带修饰（加权 / 减权 / 停用）的单个 tag = 药丸；一组 tag = 块。
   颜色说「往哪推」：主题色 = 词组，绿 = 加权，蓝 = 减权；红只留给负向通道和删除。
   线型说「啥状态」：去底 + 删除线 = 停用，点线 = 重复，斜纹 = 锁定。
   底 / 字 / 环都由同一个 --h 派生，换肤自动跟随；只新增加权、减权两个语义色。 */
:root{--relay-up:#2f9e63;--relay-down:#3a78c9}
body.dark{--relay-up:#4cc98c;--relay-down:#6ea6f2}
:is(.relay-token,.relay-token-name,.relay-token-mult){
  --h:var(--text);
  --pill-fill:color-mix(in srgb,var(--h) 13%,var(--card));
  --pill-ink:color-mix(in srgb,var(--h) 62%,var(--text));
  --pill-ring:color-mix(in srgb,var(--h) 42%,var(--line));
}
/* 中性的底不能拿 --text 的 13% 去混，深色下会发灰。 */
:is(.relay-token,.relay-token-name,.relay-token-mult):not(.is-up,.is-down,.is-fold){
  --pill-fill:color-mix(in srgb,var(--text) 7%,var(--card));--pill-ink:var(--text);--pill-ring:var(--line);
}
:is(.relay-token,.relay-token-name,.relay-token-mult).is-up{--h:var(--relay-up)}
:is(.relay-token,.relay-token-name,.relay-token-mult).is-down{--h:var(--relay-down)}
:is(.relay-token,.relay-token-name).is-fold{--h:var(--accent)}

/* 编辑区（S 档）只画不占位。⚠ token 上不许有 padding / border / margin / 字重变化，否则 textarea 与镜像错位。
   药丸 = 行内背景（高度就是字的内容区）+ 左右两道零模糊投影各外扩 --pill-x。
   块左侧叠两道投影：上层底色外扩 --spine-gap 盖出缝，下层主题色再多出 --spine-w 当色脊，色脊不贴字。
   块左侧两角必须直角：圆角会让下层主题色从缝的圆角里漏出来，色脊变成「[」形。
   折行保持默认的 slice：前一截右端、后一截左端是平口，读作「接下一行」；clone 会把一个 tag 画成两颗。
   ⚠ 不加「当前词外圈」：它会和原生选区叠成错位的主题色框（09-21 删过）。 */
.relay-token{position:relative;z-index:-1;font:inherit;letter-spacing:inherit;--pill-x:3px;--spine-w:2px;--spine-gap:4px}
.relay-token:is(.is-up,.is-down,.is-fold,.is-off){
  border-radius:999px;background:var(--pill-fill);color:var(--pill-ink);
  box-shadow:calc(var(--pill-x) * -1) 0 0 var(--pill-fill),var(--pill-x) 0 0 var(--pill-fill);
}
.relay-token.is-fold{
  border-radius:0 4px 4px 0;
  box-shadow:calc(var(--spine-gap) * -1) 0 0 var(--pill-fill),
    calc((var(--spine-gap) + var(--spine-w)) * -1) 0 0 var(--h),var(--pill-x) 0 0 var(--pill-fill);
}
/* 停用：去掉色相底，只留细环 + 删除线。环是「卡片色投影盖住线色投影」，镜像底就是卡片色。 */
.relay-token.is-off{
  background:var(--card);color:var(--muted);
  text-decoration:line-through;text-decoration-color:color-mix(in srgb,var(--muted) 80%,transparent);
  box-shadow:calc(var(--pill-x) * -1) 0 0 var(--card),var(--pill-x) 0 0 var(--card),
    calc(var(--pill-x) * -1) 0 0 1px var(--line),var(--pill-x) 0 0 1px var(--line);
}
.relay-token.is-fold.is-off{
  box-shadow:calc(var(--spine-gap) * -1) 0 0 var(--card),
    calc((var(--spine-gap) + var(--spine-w)) * -1) 0 0 var(--line),var(--pill-x) 0 0 var(--card),
    calc((var(--spine-gap) + var(--spine-w)) * -1) 0 0 1px var(--line),var(--pill-x) 0 0 1px var(--line);
}
/* 重复只是「输出时会合并」的提示：点线下划线，不动形状和色相。组内重复只在注音行打点线。 */
.relay-token.is-duplicate{
  text-decoration:underline dotted;text-decoration-thickness:1.5px;text-underline-offset:2px;
  text-decoration-color:color-mix(in srgb,var(--pill-ink) 55%,transparent);
}
.relay-token.is-partial-duplicate .zh{text-decoration:underline dotted;text-underline-offset:2px}
/* 锁定：名字透明，块身斜纹、色脊退到 muted；缝与右端外扩是卡片色。 */
.relay-token.is-locked{
  color:transparent;text-decoration:none;
  background:repeating-linear-gradient(135deg,color-mix(in srgb,var(--muted) 24%,var(--card)) 0 3px,var(--card) 3px 6px);
  box-shadow:calc(var(--spine-gap) * -1) 0 0 var(--card),
    calc((var(--spine-gap) + var(--spine-w)) * -1) 0 0 var(--muted),var(--pill-x) 0 0 var(--card);
}
/* 注音行：药丸占满字的内容区后，行盒里只剩约 5.8px 给注音上下两道缝。位置不动，行高收成 1。 */
.relay-token .zh{position:absolute;left:0;top:1.75em;display:inline-flex;align-items:center;gap:4px;font:11px/1 var(--font-ui);color:var(--muted);white-space:nowrap;max-width:132px;overflow:hidden;text-overflow:ellipsis;pointer-events:none;user-select:none;text-decoration:none}
.relay-token.is-fold .zh{color:var(--accent);opacity:.75;max-width:100%}
.relay-token.is-locked .zh{color:var(--muted);opacity:1}
.relay-token .pic{flex:none;width:11px;height:11px;border-radius:2px;object-fit:cover;pointer-events:none;user-select:none}
/* 例图条：正向 / 负向页签下面一行小卡，一组一张，按正文顺序；多了横向滚，不换行。
   卡片取图的上部（人物脸通常在上三分之一），名字只占一行。当前选中的组描主题色边。 */
.relay-pics{display:flex;gap:6px;padding:8px 10px 6px;overflow-x:auto;overflow-y:hidden;scrollbar-width:thin;overscroll-behavior-x:contain;border-bottom:1px solid var(--line)}
.relay-pics[hidden]{display:none}
.relay-pic{flex:none;display:flex;flex-direction:column;gap:3px;width:60px;padding:0;border:0;background:none;color:var(--muted);font:10.5px/1.3 var(--font-ui);text-align:center;cursor:pointer}
.relay-pic-img{display:block;width:60px;height:60px;border-radius:6px;object-fit:cover;object-position:50% 22%;background:var(--tagbg);outline:1px solid var(--line);outline-offset:-1px;transition:outline-color .14s,opacity .14s}
.relay-pic-name{display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.relay-pic:hover,.relay-pic.is-current{color:var(--accent)}
.relay-pic:hover .relay-pic-img{outline-color:var(--accent)}
.relay-pic.is-current .relay-pic-img{outline:2px solid var(--accent);outline-offset:-2px}
.relay-pic:focus-visible{outline:none}
.relay-pic:focus-visible .relay-pic-img{outline:2px solid var(--accent);outline-offset:1px}
.relay-pic.is-off .relay-pic-img{filter:grayscale(1);opacity:.45}
.relay-pic.is-off .relay-pic-name{text-decoration:line-through}
/* 悬停例图时正文里对应的块加深一档，只改底色，不动形状。 */
.relay-token.is-fold.is-hot{--pill-fill:color-mix(in srgb,var(--h) 28%,var(--card))}
/* 放大的例图：挂在 body 上，层级高于侧栏（68）、低于设置浮层（70）和灯箱（80）。只看不点。 */
.relay-pic-peek{position:fixed;z-index:69;left:0;top:0;width:240px;padding:6px;border:1px solid var(--line);border-radius:10px;background:var(--card);box-shadow:var(--shadow-hover);pointer-events:none;opacity:1;transition:opacity .14s ease,display .14s allow-discrete}
.relay-pic-peek[hidden]{display:none;opacity:0}
@starting-style{.relay-pic-peek:not([hidden]){opacity:0}}
.relay-pic-peek img{display:block;width:100%;height:auto;max-height:min(360px,60vh);object-fit:contain;border-radius:6px;background:var(--tagbg)}
.relay-pic-peek-name{display:block;padding:6px 2px 0;color:var(--text);font:12px/1.4 var(--font-ui);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
@media (prefers-reduced-motion:reduce){.relay-pic-peek{transition:none}}
.relay-token-panel{display:flex;flex-wrap:wrap;align-items:center;gap:6px;border:0;border-top:1px solid var(--line);border-radius:0 0 11px 11px;background:var(--tagbg);padding:8px 12px;font:12px/1.5 var(--font-ui)}
/* 词组带图时面板分两栏：例图在左，名字和动作在右。点图钉住放大图。 */
.relay-token-panel.has-pic{display:grid;grid-template-columns:auto minmax(0,1fr);align-items:start;column-gap:10px}
.relay-token-body{display:flex;flex-wrap:wrap;align-items:center;gap:6px;min-width:0}
.relay-token-weight{display:inline-flex;align-items:center;gap:6px;flex:none}
.relay-token-pic{display:block;width:64px;height:84px;padding:0;border:0;border-radius:6px;overflow:hidden;background:var(--tagbg);outline:1px solid var(--line);outline-offset:-1px;cursor:zoom-in}
.relay-token-pic img{display:block;width:100%;height:100%;object-fit:cover;object-position:50% 22%}
.relay-token-pic:hover,.relay-token-pic:focus-visible{outline:2px solid var(--accent);outline-offset:-2px}
.relay-editor-actions{position:relative}
/* 就地命名悬浮在选区操作条上方，不参与高度分配，也不挤动滚动区。 */
.relay-editor-actions>.tag-relay-inline-action{position:absolute;left:-1px;right:-1px;bottom:calc(100% + 6px);z-index:5;grid-template-columns:minmax(0,1fr) auto;margin:0;padding:8px 12px;max-height:none;overflow:visible;border:1px solid var(--line);border-radius:10px;background:var(--card);box-shadow:var(--shadow);opacity:1;translate:0 0;scale:1;transition:opacity .16s ease,translate .18s cubic-bezier(.22,1,.36,1),display .18s allow-discrete}
.relay-editor-actions>.tag-relay-inline-action[hidden]{opacity:0;translate:0 4px}
.relay-editor-actions>.tag-relay-inline-action .tag-relay-inline-action-buttons{grid-column:2;grid-row:1}
@starting-style{
  .relay-editor-actions>.tag-relay-inline-action:not([hidden]){opacity:0;translate:0 4px}
}
.relay-token-name{max-width:140px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font:12px/1.5 var(--font-prompt)}
/* 面板头（M 档）：被点中的那一个的放大版，同形同色。「已选 N 项」「内容已锁定」不带 is-token，保持纯文字。 */
.relay-token-name.is-token{
  height:24px;max-width:180px;padding:0 9px;border-radius:999px;line-height:24px;
  background:var(--pill-fill);color:var(--pill-ink);box-shadow:inset 0 0 0 1px var(--pill-ring);
}
.relay-token-name.is-token.is-fold{border-radius:6px;padding-left:12px;box-shadow:inset 3px 0 0 var(--h),inset 0 0 0 1px var(--pill-ring)}
.relay-token-name.is-token.is-off{background:var(--card);color:var(--muted);text-decoration:line-through}
.relay-token-meaning{color:var(--muted);margin-right:auto;font-size:11px}
/* 倍率跟着方向着色，×1 时退成灰。 */
.relay-token-mult{min-width:3.4em;text-align:center;color:var(--pill-ink);font:12px/1.5 var(--font-prompt);font-variant-numeric:tabular-nums}
.relay-token-mult:not(.is-up,.is-down){color:var(--muted)}
:is(.relay-token-panel,.relay-token-body,.relay-token-weight)>:is(button:not(.relay-token-pic),a):hover{background:var(--tagbg);border-color:var(--accent)}
:is(.relay-token-panel,.relay-token-body,.relay-token-weight)>button:disabled{opacity:.4;cursor:default}
.relay-dedupe-option{display:flex;align-items:center;gap:7px;font-size:11px;color:var(--muted);padding:5px 0}
.relay-dedupe-option input{accent-color:var(--accent)}
@media(pointer:coarse){
  .relay-editor-surface>.relay-editor-mirror,.relay-editor-surface>.relay-editor-input{font-size:16px}
  /* 按用途分配触屏尺寸，不能把每个小动作都扩成同样大的按钮。 */
  .tag-relay-rail :is(.relay-editor-channels>button,.tag-relay-source-tabs>button,.tag-relay-segment>button,
    :is(.relay-token-panel,.relay-token-body,.relay-token-weight)>:is(button:not(.relay-token-pic),a),.tag-relay-inline-action-buttons>button,
    .tag-relay-history-actions>button,.relay-save-state>button){min-height:34px;min-width:30px;font-size:12px}
  .tag-relay-rail :is(.tag-relay-plan-menu>button,.ui-select-option){min-height:36px;font-size:12px}
  .tag-relay-rail :is(.tag-relay-plan-more,.tag-relay-rail-close,.relay-shelf-toggle){width:32px;height:32px;min-width:32px;min-height:32px}
  .tag-relay-rail .tag-relay-chip{height:36px;max-width:100%}
  .tag-relay-rail .tag-relay-chip-main{font-size:12px}
  .tag-relay-rail :is(.tag-relay-chip-x,.tag-relay-chip-negative){width:30px;height:32px;margin-right:0}
  .tag-relay-rail .tag-relay-output-option{grid-template-columns:1fr}
  .tag-relay-history-actions{flex-wrap:wrap}
  .relay-dedupe-option{min-height:34px}
}
@media(max-width:600px){
  .tag-relay-rail-head{gap:6px;padding:10px 12px 6px}
  .tag-relay-plan-picker .ui-select{--select-touch-height:34px;--select-font-size:12px}
  .tag-relay-rail .tag-relay-zone{padding:7px 12px;gap:6px}
  .tag-relay-rail .tag-relay-output{padding:8px 12px;gap:6px}
  .tag-relay-rail .tag-relay-copy-main{min-height:40px;padding:8px 12px;font-size:14px}
  .tag-relay-output-actions{display:grid}
  .tag-relay-output-gap{display:none}
  .tag-relay-output-actions>button{min-width:0;min-height:34px;height:auto;padding:4px 6px;font-size:12px;white-space:nowrap}
  .tag-relay-output-actions .tag-relay-output-summary{gap:3px}
  .tag-relay-output-summary>span{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
  .tag-relay-output-actions .relay-disclosure-caret{width:12px;height:12px}
  .tag-relay-rail.is-editing{background:var(--bg)}
}
/* 素材收起后，释放的高度交给可编辑区域；侧栏仍停靠，不能把死白搬到栏外。 */
.tag-relay-rail:is(:has(.tag-relay-zone-source.is-peek),.is-shelf-moving) .tag-relay-zone-plan{flex:1 1 0;min-height:0;max-height:none}
.tag-relay-rail:is(:has(.tag-relay-zone-source.is-peek),.is-shelf-moving) .tag-relay-plan-lane.relay-editor{flex:1 1 0;min-height:0}
.tag-relay-rail:is(:has(.tag-relay-zone-source.is-peek),.is-shelf-moving) .relay-editor-frame{display:flex;flex-direction:column;flex:1 1 0;min-height:0}
.tag-relay-rail:is(:has(.tag-relay-zone-source.is-peek),.is-shelf-moving) .relay-editor-frame[hidden]{display:none}
.tag-relay-rail:is(:has(.tag-relay-zone-source.is-peek),.is-shelf-moving) .relay-editor-surface{flex:1 1 0;min-height:0;max-height:none}
.tag-relay-rail:is(:has(.tag-relay-zone-source.is-peek),.is-shelf-moving) .relay-editor-mirror,
.tag-relay-rail:is(:has(.tag-relay-zone-source.is-peek),.is-shelf-moving) .relay-editor-input{min-height:100%}
@media(max-height:480px){
  /* 键盘压缩可用高度时让整栏滚动，不能把正文压成零高。 */
  .tag-relay-rail:is(:has(.tag-relay-zone-source.is-peek),.is-shelf-moving) .tag-relay-zone-plan{flex:none;overflow:visible}
  .tag-relay-rail:is(:has(.tag-relay-zone-source.is-peek),.is-shelf-moving) .tag-relay-plan-lane.relay-editor,
  .tag-relay-rail:is(:has(.tag-relay-zone-source.is-peek),.is-shelf-moving) .relay-editor-frame{flex:none}
  .tag-relay-rail:is(:has(.tag-relay-zone-source.is-peek),.is-shelf-moving) .relay-editor-surface{flex:none;min-height:56px;max-height:34dvh}
  .tag-relay-rail:is(:has(.tag-relay-zone-source.is-peek),.is-shelf-moving) .relay-editor-mirror,
  .tag-relay-rail:is(:has(.tag-relay-zone-source.is-peek),.is-shelf-moving) .relay-editor-input{min-height:56px}
}

/* 手机把正文作为主工作区；这些包装层在桌面不参与原有 flex 排版。 */
.relay-editor-bar,.relay-output-more,.relay-source-drawer{display:contents}
.relay-pics-toggle,.relay-token-view-pic,.relay-output-more-toggle,.relay-mobile-sources{display:none}
.relay-output-more[hidden],.relay-source-drawer[hidden]{display:none}
.relay-image-dialog{z-index:90;width:min(92vw,640px);max-height:90dvh;padding:12px;border:1px solid var(--line);border-radius:16px;background:var(--card);color:var(--text);box-shadow:var(--shadow-hover)}
.relay-image-dialog[open]{display:flex;flex-direction:column;gap:10px}
.relay-image-dialog:not([open]){display:none}
.relay-image-dialog::backdrop{background:rgba(15,18,30,.65)}
.relay-image-header{display:flex;align-items:center;gap:12px;flex:none}
.relay-image-title{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font:700 14px/1.5 var(--font-ui)}
.relay-image-close{flex:none;min-height:44px;padding:8px 14px;border:1px solid var(--line);border-radius:10px;background:var(--tagbg);color:var(--text);font:700 13px var(--font-ui);cursor:pointer}
.relay-image-full{display:block;min-height:0;width:100%;max-height:calc(90dvh - 90px);object-fit:contain;border-radius:8px}
@media(max-width:600px){
  #tagRelayRail{height:min(var(--relay-rail-height),var(--relay-visible-height,100dvh));max-height:min(var(--relay-rail-height),var(--relay-visible-height,100dvh));bottom:var(--relay-viewport-bottom,0px);overflow-y:auto;overscroll-behavior:contain}
  #tagRelayRail .tag-relay-zone-plan{flex:1 0 auto;min-height:214px;max-height:none;overflow:visible}
  #tagRelayRail .tag-relay-zone-plan>.tag-relay-zone-head{display:none}
  #tagRelayRail .relay-save-state:empty{display:none}
  /* 最小值包含三行触屏正文和内边距；过矮时整栏滚动，不能挤掉编辑面。 */
  #tagRelayRail .tag-relay-plan-lane.relay-editor{display:grid;grid-template-columns:minmax(0,1fr);grid-template-rows:auto auto minmax(160px,1fr) auto;flex:1 0 auto;min-height:200px}
  /* 底色、下边线和顶圆角由整条承担，「例图 N」在条内，有无例图都通到右缘。 */
  .relay-editor-bar{grid-row:1;display:flex;align-items:center;gap:8px;padding-right:8px;border-bottom:1px solid var(--line);border-radius:11px 11px 0 0;background:var(--tagbg)}
  .relay-editor-bar:has(.relay-pics-toggle[hidden]){padding-right:0}
  .relay-editor-bar .relay-editor-channels{flex:1;min-width:0;border-bottom:0;background:transparent}
  .relay-pics-toggle{display:inline-flex;align-items:center;justify-content:center;flex:none;min-height:34px;padding:5px 10px;border:1px solid var(--line);border-radius:9px;background:var(--tagbg);color:var(--muted);font:700 12px var(--font-ui);cursor:pointer}
  .relay-pics-toggle[hidden]{display:none}
  .relay-pics-toggle[aria-expanded="true"]{color:var(--accent);border-color:var(--accent)}
  #tagRelayRail .relay-pics{grid-row:2;padding:6px 10px}
  #tagRelayRail .relay-pic{width:44px}
  #tagRelayRail .relay-pic-img{width:44px;height:44px}
  #tagRelayRail .relay-pic-name{display:none}
  #tagRelayRail .relay-editor-frame{grid-row:3;display:flex;flex-direction:column;min-height:160px}
  #tagRelayRail .relay-editor-frame[hidden]{display:none}
  #tagRelayRail .relay-editor-surface{flex:1 1 0;min-height:150px;max-height:none}
  #tagRelayRail .relay-editor-mirror,#tagRelayRail .relay-editor-input{min-height:100%}
  #tagRelayRail .relay-editor-actions{grid-row:4}
  #tagRelayRail .relay-token-pic{display:none}
  #tagRelayRail .relay-token-panel.has-pic{display:flex}
  #tagRelayRail .relay-token-panel{padding:7px 9px;gap:5px}
  #tagRelayRail .relay-token-body{gap:5px;width:100%}
  #tagRelayRail .relay-token-view-pic{display:inline-flex;align-items:center;justify-content:center}
  #tagRelayRail .tag-relay-output{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:8px;padding:8px 12px;overflow:visible;flex:none}
  #tagRelayRail .tag-relay-copy-main{min-height:44px}
  #tagRelayRail .relay-output-more-toggle{display:inline-flex;min-height:44px;padding:8px 14px}
  #tagRelayRail .relay-output-more{display:flex;flex-direction:column;gap:10px;position:absolute;left:12px;right:12px;bottom:calc(100% + 4px);z-index:7;max-height:min(60dvh,360px);overflow-y:auto;overscroll-behavior:contain;padding:12px;border:1px solid var(--popover-line);border-radius:var(--ui-popover-radius);background:var(--card);box-shadow:var(--popover-shadow)}
  #tagRelayRail .relay-output-more[hidden]{display:none}
  #tagRelayRail .tag-relay-output-actions{grid-template-columns:repeat(2,minmax(0,1fr));gap:8px}
  #tagRelayRail .tag-relay-output-actions>button{min-height:40px}
  #tagRelayRail .tag-relay-output-boxes{max-height:none;overflow:visible}
  #tagRelayRail .tag-relay-output-boxes[hidden]{display:none}
  #tagRelayRail .tag-relay-zone-source{position:relative;flex:none;min-height:0;overflow:visible;padding:4px 12px max(8px,env(safe-area-inset-bottom));gap:0}
  #tagRelayRail .relay-mobile-sources{display:flex;align-items:center;gap:10px;width:100%;min-height:40px;padding:8px 10px;border:1px solid var(--line);border-radius:10px;background:var(--tagbg);color:var(--muted);text-align:left;font:12px/1.4 var(--font-ui);cursor:pointer}
  .relay-mobile-sources b{color:var(--text)}
  #relayMobileSourceCount{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
  .relay-mobile-sources[aria-expanded="true"]{border-color:var(--accent)}
  #tagRelayRail .relay-source-drawer{display:flex;flex-direction:column;gap:8px;position:absolute;left:12px;right:12px;bottom:calc(100% + 4px);z-index:8;max-height:min(55dvh,360px);padding:10px;border:1px solid var(--popover-line);border-radius:var(--ui-popover-radius);background:var(--card);box-shadow:var(--popover-shadow)}
  #tagRelayRail .relay-source-drawer[hidden]{display:none}
  #tagRelayRail .tag-relay-source-panel{flex:1 1 auto;min-height:0;max-height:none;overflow:auto;overscroll-behavior:contain}
  #tagRelayRail .tag-relay-source-list{flex:none;max-height:none;overflow:visible}
  #tagRelayRail .relay-shelf-toggle{display:none}
}
