修正交付形态：把三帧的重复标记改为 SVG sprite + 单模板渲染（上一版把 logo path 与卡片标记重复了三遍，体积失控被截断）。**这不是设计变更，只是同一份设计的紧凑实现**——组件镜像、token 来源、三帧状态、分隔线、零新增页签全部不变。

```html
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Device Local Settings — Type of source × NDI</title>

<!--
  TVU Design System · 增量设计 mockup（Path B / code；R7 场景 2.2 已有产品增量；US-3）
  Deliverable: 设备本地设置页「Type of source:」二选一 → 三选一（新增 NDI）

  provenance（改值前回真源核，别把本文件当真源）:
    tokens  src/tokens/variables.css        —— 下方 :root 是它的逐字节选（仅保留本页用到的档位）
    topbar  src/components/TopBar/TopBar.vue
    tabs    src/components/Tab/TabList.vue + TabItem.vue      （Type=Line）
    radio   src/components/Radio/Radio.vue                    （含 data-figma-status 显式状态映射）
    form    src/components/FormItem/FormItem.vue              （Layout=1 line, Label Width=120）
    select  src/components/Select/Select.vue                  （line variant, size M）
    input   src/components/Input/Input.vue                    （line variant, size M）
    button  src/components/Button/Button.vue                  （PALETTE_SPEC + SIZE_GEOMETRY M）
    icons   src/icons/raw.ts                                  （SVG 逐字复制，未重画 path）
    divider DS 库内无分隔线组件 → 范式 = 1px 线绑 Line/Deep Divider
            （figma-component-catalog.md §Border / divider, 2026-08-03 实测收口）

  单一深色主题（domain-tvu M4：operator surface dark only）。light 覆盖块刻意未内联——
  真实构建里页面 <link> 由 copyDesignTokensPlugin 拷出的完整 tvu-tokens.css，token 真源一份。
-->

<style>
/* ══ 1 · TOKENS —— src/tokens/variables.css 逐字节选（值未改动、未近似） ══ */
:root {
  --color-grey-14: #000000;
  --brand: #2fb54e; --brand-hover: #41c760; --brand-disable: #1a652c; --brand-match: #0b2b13;
  --text-heading: #ffffff; --text-body: #f8f8f8; --text-2: #cccccc; --text-tips: #9e9e9e;
  --text-placeholder: #7b7b7b; --text-disabled: #595959; --text-primary-btn: #f8f8f8;
  --icon-default: #9e9e9e; --icon-disabled: #595959; --icon-placeholder: #7b7b7b;
  --bg-layer1: #141414; --bg-layer2: #1f1f1f; --bg-layer3: #262626; --bg-layer4: #353535;
  --bg-topbar: #000000; --bg-grey-btn-en: #434343; --bg-grey-btn-hv: #595959;
  --line-border: #595959; --line-deep: #353535; --line-light: #434343;
  --input-line-border: var(--line-border); --input-disabled-border: var(--line-border);
  --select-disabled-border: var(--line-border);
  --sp-xxs: 4px; --sp-xs: 8px; --sp-s: 12px; --sp-m: 16px; --sp-l: 24px; --sp-xl: 32px; --sp-xxxl: 56px;
  --r-xs: 2px; --r-s: 4px; --r-m: 8px;
  --bp-sm: 640px; --bp-lg: 1100px; --bp-xl: 1280px; --container-page: 1600px;
  --font-family-en: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, 'Fira Sans',
    'Droid Sans', 'Helvetica Neue', sans-serif;
  --font-family-zh: 'PingFang SC', 'Microsoft YaHei', Helvetica, Arial, sans-serif;
  --font-family-base: var(--font-family-en), var(--font-family-zh);
  /* ⚠️ family 段不是 Roboto：走系统字体栈（variables.css 登记的 code-first divergence
     font-family-system-stack-not-roboto-2026-08-13）。别据此断言 Figma 稿与渲染同字形。 */
  --text-style-tips: 400 12px/16px var(--font-family-base);
  --text-style-body: 400 14px/21px var(--font-family-base);
  --text-style-pop-title: 600 16px/24px var(--font-family-base);
  --text-style-headline-2: 600 18px/27px var(--font-family-base);
  --shadow-l1: 0 5px 12px 4px #00000017, 0 3px 6px 0 #0000001f, 0 1px 2px -2px #00000029;
  --topbar-height: 64px; --topbar-section-gap: 80px;
  --radio-circle-size: 16px; --radio-circle-border-width: 1.2px; --radio-selected-dot-size: 6px;
  --form-item-row-height: 32px; --form-item-label-width-120: 120px;
  --form-item-root-width-single-line: 638px; --control-height-xxs: 32px;
  --line-divider-deep: var(--line-deep);
  --control-disabled-bg: var(--line-deep); --control-disabled-border: var(--line-border);
  --radio-default-border: var(--text-tips); --radio-selected-dot: var(--bg-layer1);
  --radio-disabled-selected-bg: var(--brand-disable);
}

/* ══ 2 · ELEMENT BASE —— variables.css 尾部「语义 HTML 兜底」节选 ══ */
* { box-sizing: border-box; }
body { margin: 0; font: var(--text-style-body); background: var(--color-grey-14); color: var(--text-body); }
button { font: var(--text-style-body); color: inherit; border-radius: var(--r-s); }
input, select { font: var(--text-style-body); color: var(--text-body); border-radius: var(--r-s); }

/* ══ 3 · 交付页外壳（annotation 层 —— 非产品 UI，允许双语） ══ */
.sheet { max-width: var(--container-page); margin: 0 auto; padding: var(--sp-xl) var(--sp-l) var(--sp-xxxl);
  display: flex; flex-direction: column; gap: var(--sp-xl); }
.sheet__title { font: var(--text-style-headline-2); color: var(--text-heading); }
.sheet__sub { font: var(--text-style-body); color: var(--text-2); }
.sheet__sub--zh { font: var(--text-style-tips); color: var(--text-tips); }
/* 中性 accent：刻意不用 brand、也不用 M23 的 navy（M-COLOR §C4 两者不混用） */
.anno { display: flex; flex-direction: column; gap: 2px; padding-left: var(--sp-s);
  border-left: var(--sp-xxs) solid var(--line-light); margin-bottom: var(--sp-s); }
.anno__no { font: var(--text-style-tips); color: var(--text-placeholder); letter-spacing: .04em; }
.anno__en { font: 600 14px/21px var(--font-family-base); color: var(--text-body); }
.anno__zh { font: var(--text-style-tips); color: var(--text-tips); }
.frame { width: 100%; max-width: var(--bp-xl); border: 1px solid var(--line-light);
  border-radius: var(--r-m); overflow: hidden; background: var(--bg-layer1); box-shadow: var(--shadow-l1); }

/* ══ 4 · TOP BAR —— TopBar.vue 逐字 mirror（Tag=After Login） ══ */
.topbar { display: flex; align-items: center; padding: var(--sp-xs) var(--sp-m);
  background: var(--bg-topbar); border: 1px solid var(--line-deep);
  gap: var(--topbar-section-gap); flex-shrink: 0; width: 100%; height: var(--topbar-height); }
.topbar-brand { display: flex; align-items: center; gap: var(--sp-m); flex-shrink: 0; }
.topbar-title { font: var(--text-style-pop-title); color: var(--text-heading); white-space: nowrap; }
.topbar-right { display: flex; align-items: center; gap: var(--sp-xs); flex-shrink: 0;
  margin-left: auto; font: var(--text-style-tips); color: var(--text-tips); }
.topbar-brand .ico { width: 24px; height: 24px; }

/* ══ 5 · TAB LIST / ITEM —— Tab/*.vue 逐字 mirror ══ */
.tab-list { display: flex; align-items: stretch; padding: 0 var(--sp-m); background: var(--bg-layer1); }
.tab-list--line { border-bottom: 1px solid var(--line-deep); }
.tab-list__items { display: inline-flex; align-items: center; gap: var(--sp-l); }
.tab-item { display: inline-flex; align-items: center; gap: var(--sp-xs); height: 32px;
  padding: 0 var(--sp-m); font: var(--text-style-body); color: var(--text-tips); cursor: pointer;
  white-space: nowrap; user-select: none; transition: color .15s, border-color .15s; }
.tab-item--line { border-bottom: 1px solid transparent; margin-bottom: -1px; }
.tab-item--line.tab-item--active-white { color: var(--text-body); border-bottom-color: var(--line-light); font-weight: 700; }
.tab-item--disabled { color: var(--text-disabled); cursor: not-allowed; }

/* ══ 6 · 页面主体 ══ */
.page { padding: var(--sp-l) var(--sp-m) var(--sp-xl); background: var(--bg-layer1); }
.card { background: var(--bg-layer2); border: 1px solid var(--line-deep);
  border-radius: var(--r-m); padding: var(--sp-l); }

/* FORM ITEM —— FormItem.vue 逐字 mirror */
.form-item { --fi-label: var(--text-tips); color: var(--text-body); }
.form-item__main { display: flex; gap: var(--sp-xs); align-items: flex-start; }
.form-item__label { display: inline-flex; align-items: center; gap: var(--sp-xxs);
  min-height: var(--form-item-row-height); width: var(--form-item-label-width-120);
  padding: var(--sp-xxs) 0; font: var(--text-style-body); color: var(--fi-label); flex-shrink: 0; }
.form-item__label--dynamic { width: auto; }
.form-item__content { display: flex; flex: 1 1 auto; min-width: 0; flex-direction: column; gap: var(--sp-xxs); }
.form-item__message { margin: 0; font: var(--text-style-tips); color: var(--fi-label); }

/* RADIO —— Radio.vue 逐字 mirror */
.radio-group { display: flex; align-items: center; gap: var(--sp-l); flex-wrap: wrap;
  min-height: var(--form-item-row-height); }
.radio { display: inline-flex; align-items: center; gap: var(--sp-xs); height: 21px; cursor: pointer;
  font: var(--text-style-body); color: var(--text-body); user-select: none; }
.radio--disabled { cursor: not-allowed; color: var(--text-disabled); }
.radio:focus-visible { outline: 2px solid var(--brand); outline-offset: 2px; border-radius: var(--r-xs); }
.radio-circle { flex-shrink: 0; width: var(--radio-circle-size); height: var(--radio-circle-size);
  border-radius: 50%; border: var(--radio-circle-border-width) solid var(--radio-default-border);
  background: transparent; display: flex; align-items: center; justify-content: center;
  transition: border-color .15s, background .15s, box-shadow .15s; }
.radio-dot { width: var(--radio-selected-dot-size); height: var(--radio-selected-dot-size);
  border-radius: 50%; background: var(--radio-selected-dot); }
/* Figma-first explicit state mapping（四态逐字；disabled 两态本页未演示，CSS 就位供 dev 用） */
.radio[data-figma-status="off"][data-figma-enable="yes"] .radio-circle {
  background: transparent; border-color: var(--radio-default-border); box-shadow: none; }
.radio[data-figma-status="off"][data-figma-enable="no"] .radio-circle {
  background: var(--control-disabled-bg); border-color: transparent;
  box-shadow: inset 0 0 0 1.2px var(--control-disabled-border); }
.radio[data-figma-status="on"][data-figma-enable="yes"] .radio-circle {
  background: var(--brand); border-color: var(--brand); box-shadow: none; }
.radio[data-figma-status="on"][data-figma-enable="no"] .radio-circle {
  background: var(--radio-disabled-selected-bg); border-color: var(--radio-disabled-selected-bg); box-shadow: none; }

/* locked spec ③ 选择行 ↔ 内容区的视觉分隔：库内无分隔线组件 → 1px 线绑 Line/Deep Divider。
   full-bleed 到卡片内边缘，才读得出「上下两段」而不是一条装饰线。 */
.panel-divider { height: 1px; background: var(--line-divider-deep);
  margin: var(--sp-m) calc(var(--sp-l) * -1); }

/* SELECT —— Select.vue 逐字 mirror（line, size M） */
.select-wrap { position: relative; display: inline-block; width: 100%; }
.select { display: block; width: 100%; height: var(--control-height-xxs); background: transparent;
  border: 1px solid var(--line-light); border-radius: var(--r-s); color: var(--text-body);
  font-size: 13px; font-family: var(--font-family-base); outline: none; appearance: none;
  -webkit-appearance: none; cursor: pointer; padding: 0 36px 0 var(--sp-s);
  transition: border-color .15s; white-space: nowrap; text-overflow: ellipsis; /* R23 (a) */ }
.select:hover:not(:disabled), .select:focus { border-color: var(--brand); }
.select:disabled { color: var(--text-tips); cursor: not-allowed; border-color: var(--select-disabled-border); }
.select option { background: var(--bg-layer2); color: var(--text-body); }
/* overlay indicator anchored to the select box —— 本页唯一的 absolute，R14 要求注明 affordance */
.select-arrow { position: absolute; right: 12px; top: 50%; transform: translateY(-50%);
  pointer-events: none; color: var(--text-tips); display: flex; align-items: center; }

/* INPUT —— Input.vue 逐字 mirror（line, size M） */
.tvu-input { display: block; width: 100%; height: 32px; padding: var(--sp-xs) var(--sp-s);
  background: transparent; border: 1px solid var(--input-line-border); border-radius: var(--r-s);
  color: var(--text-body); font-size: 14px; font-family: var(--font-family-base);
  outline: none; transition: border-color .15s; }
.tvu-input::placeholder { color: var(--text-placeholder); }
.tvu-input:hover:not(:disabled), .tvu-input:focus:not(:disabled) { border-color: var(--brand); }
.tvu-input:disabled { border-color: var(--input-disabled-border); color: var(--text-tips); cursor: not-allowed; }

/* BUTTON —— Button.vue PALETTE_SPEC + SIZE_GEOMETRY[M] mirror */
.btn { --btn-bg: transparent; --btn-color: var(--text-2); --btn-border: transparent;
  --btn-bg-hover: transparent; --btn-color-hover: var(--text-2); --btn-border-hover: transparent;
  --btn-border-width: 1px; --btn-gap: 0px;
  display: inline-flex; align-items: center; justify-content: center; gap: var(--btn-gap);
  height: 32px; padding-inline: var(--sp-m); border: var(--btn-border-width) solid var(--btn-border);
  border-radius: var(--r-s); background: var(--btn-bg); color: var(--btn-color);
  font-family: var(--font-family-base); font-size: 14px; font-weight: 400; line-height: 21px;
  cursor: pointer; white-space: nowrap; outline: none; user-select: none;
  transition: background .15s, color .15s, border-color .15s; }
.btn:hover:not(:disabled) { background: var(--btn-bg-hover); color: var(--btn-color-hover); border-color: var(--btn-border-hover); }
.btn:focus-visible { outline: 2px solid var(--brand); outline-offset: 2px; }
.btn:disabled { cursor: not-allowed; }
.btn--icon { --btn-gap: var(--sp-xxs); }
.btn--fill-green { --btn-bg: var(--brand); --btn-color: var(--text-primary-btn);
  --btn-bg-hover: var(--brand-hover); --btn-color-hover: var(--text-primary-btn); }
.btn--fill-green:disabled { --btn-bg: var(--brand-disable); --btn-color: var(--text-tips); }
.btn--ghost-gray { --btn-border-width: 1.2px; --btn-border: var(--bg-grey-btn-en);
  --btn-bg-hover: var(--bg-grey-btn-en); --btn-border-hover: var(--bg-grey-btn-en); }
.btn--ghost-gray:disabled { --btn-color: var(--text-placeholder); }

/* ══ 7 · 内容区 A —— IP Source 既有卡片网格（Keep：预览 / IP / 目标接收端 / Apply） ══ */
.source-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--sp-m); }
.source-card { display: flex; flex-direction: column; gap: var(--sp-s); background: var(--bg-layer3);
  border: 1px solid var(--line-deep); border-radius: var(--r-m); padding: var(--sp-s); }
.preview { aspect-ratio: 16 / 9; background: var(--bg-layer4); border-radius: var(--r-s);
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: var(--sp-xxs); color: var(--icon-default); }
.preview--offline { color: var(--icon-disabled); }
.preview .ico { width: 24px; height: 24px; }
.preview__label { font: var(--text-style-tips); color: var(--text-tips); }
.meta-row { display: flex; align-items: baseline; gap: var(--sp-xs); min-width: 0; }
.meta-row__k { font: var(--text-style-tips); color: var(--text-tips); flex-shrink: 0; }
.meta-row__v { font: var(--text-style-body); color: var(--text-body);
  font-variant-numeric: tabular-nums;  /* variables.css §Typography 注释指定 */
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; /* R23 (a) */ }
.card-actions { display: flex; justify-content: flex-end; margin-top: var(--sp-xxs); } /* M17 右缘对齐 */

/* ══ 8 · 内容区 B —— NDI 专属表单（本轮新增） ══ */
.ndi { display: grid; grid-template-columns: minmax(0, 2fr) minmax(0, 1fr);
  gap: var(--sp-xl); align-items: start; }
.ndi__form { display: flex; flex-direction: column; gap: var(--sp-m);
  max-width: var(--form-item-root-width-single-line); }
.row-inline { display: flex; gap: var(--sp-xs); align-items: flex-start; }
.row-inline .select-wrap { flex: 1 1 auto; min-width: 0; }
.ndi__actions { display: flex; justify-content: flex-end;
  max-width: var(--form-item-root-width-single-line); margin-top: var(--sp-xxs); }
.ndi__side { display: flex; flex-direction: column; gap: var(--sp-s); background: var(--bg-layer3);
  border: 1px solid var(--line-deep); border-radius: var(--r-m); padding: var(--sp-s); }
.ndi__side-title { font: var(--text-style-tips); color: var(--text-tips); }

/* ══ 9 · 内容区 C —— HDMI/SDI/USB：既有面板，本轮不改动
   Scope Handling「不动 ≠ 删 / 隐藏」：保留版面位置 + 显式标注，
   ⛔ 无基线源，不凭印象重画（见交付说明未决项 ①） ══ */
.baseline { border: 1px dashed var(--line-light); border-radius: var(--r-m);
  padding: var(--sp-xl) var(--sp-l); display: flex; flex-direction: column; align-items: center;
  gap: var(--sp-xs); text-align: center; color: var(--icon-default); }
.baseline .ico { width: 24px; height: 24px; }
.baseline__en { font: var(--text-style-body); color: var(--text-2); }
.baseline__zh { font: var(--text-style-tips); color: var(--text-tips); }

/* ══ 10 · 响应式（断点取 --bp-* 档位值，不写 off-scale 数字） ══ */
@media (max-width: 1100px) {
  .source-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .ndi { grid-template-columns: minmax(0, 1fr); }
}
@media (max-width: 640px) {
  .source-grid { grid-template-columns: minmax(0, 1fr); }
  .topbar { gap: var(--sp-m); }
  .form-item__main { flex-direction: column; gap: 0; }
}
</style>

<!-- SVG sprite：图标 path 逐字取自 src/icons/raw.ts，只放一份，用 <use> 引用。
     ⛔ 零 Unicode 字符图标、零自画 path、零 emoji（R13 Step 4 黑名单）。 -->
<svg width="0" height="0" style="position:absolute" aria-hidden="true" focusable="false">
  <!-- icon/logo · logo/TVU —— 品牌绿由 SVG 自带（raw.ts 头注释：logo icons retain brand color） -->
  <symbol id="i-logo" viewBox="0 0 16 16"><path fill-rule="evenodd" clip-rule="evenodd" d="M15.9933 8.68971V8.69001C15.9962 8.96317 16 9.31582 16 9.81499V13.9033C16 13.9033 16 16 13.6733 15.9997H7.99586L7.97996 16H7.93922C7.93922 16 7.94419 16 7.9538 15.9997C3.55876 15.9857 0 12.4098 0 8.00017C0 3.5819 3.573 0 7.97996 0C12.1057 0 15.5005 3.13931 15.9165 7.16512L15.9185 7.18106C15.946 7.45033 15.99 7.97375 15.99 8.25C15.99 8.37606 15.9915 8.51693 15.9933 8.68971ZM1.19653 7.97028C1.19653 11.7388 4.24392 14.7937 8.00305 14.7937C11.7622 14.7937 14.8096 11.7388 14.8096 7.97028C14.8096 4.20178 11.7622 1.14681 8.00305 1.14681C4.24392 1.14681 1.19653 4.20178 1.19653 7.97028ZM13.4204 15.2121V13.212L15.0122 14.2386L13.4204 15.2121ZM12.8146 8.39867V5.86667H13.669V8.41467C13.669 8.90067 13.6164 9.27267 13.3229 9.53167C13.0294 9.79067 12.5968 9.92 12.0253 9.92C11.4538 9.92 11.022 9.79034 10.7291 9.53167C10.4366 9.273 10.3843 8.90134 10.3843 8.41734V5.86667H11.2394V8.39867C11.2394 8.67167 11.2963 8.875 11.4098 9.00867C11.5233 9.14233 11.7705 9.20934 12.0257 9.20934C12.2772 9.20934 12.524 9.14534 12.6402 9.01667C12.7564 8.888 12.8146 8.682 12.8146 8.39867ZM9.02194 5.86667L8.01441 8.853L7.00721 5.86667H6.03979L7.53984 9.92H8.46061L9.96033 5.86667H9.02194ZM3.48276 6.554H2.2251V5.86667H5.61583V6.554H4.35817V9.92H3.48276V6.554Z" fill="#56AF31"/></symbol>
  <!-- navigation/arrow-dropdown（= icon/Arrow/Dropdown, key eba15c0b…） -->
  <symbol id="i-chevron" viewBox="0 0 16 16"><path d="M3.05146 6.20128C3.27161 5.95374 3.65086 5.93145 3.89853 6.15148L7.86707 9.67727C7.94284 9.74458 8.05698 9.74458 8.13274 9.67727L12.1013 6.15148C12.349 5.93145 12.7282 5.95374 12.9484 6.20128C13.1685 6.44883 13.1462 6.82788 12.8985 7.04791L8.39841 11.046C8.17112 11.2479 7.8287 11.2479 7.60141 11.046L3.10129 7.04791C2.85362 6.82788 2.83131 6.44883 3.05146 6.20128Z" fill="currentColor"/></symbol>
  <!-- action/refresh -->
  <symbol id="i-refresh" viewBox="0 0 16 16"><path d="M10.8367 1.60055C9.46757 0.993637 7.93986 0.84184 6.47805 1.16746C5.01623 1.49308 3.69739 2.27896 2.71528 3.40962C1.73317 4.54028 1.13958 5.95612 1.02172 7.44912C0.903855 8.94211 1.26794 10.4336 2.06047 11.7043C2.853 12.9751 4.0322 13.9581 5.42481 14.5091C6.81743 15.0601 8.35004 15.1499 9.79746 14.7653C11.2449 14.3807 12.5308 13.5421 13.4663 12.3726C13.6733 12.1138 13.6313 11.7362 13.3726 11.5292C13.1138 11.3222 12.7362 11.3642 12.5292 11.623C11.7541 12.592 10.6886 13.2869 9.48933 13.6055C8.29003 13.9242 7.02016 13.8498 5.86628 13.3933C4.71239 12.9367 3.73534 12.1222 3.07867 11.0693C2.422 10.0164 2.12034 8.78061 2.21799 7.54355C2.31565 6.3065 2.80748 5.13338 3.62123 4.19654C4.43498 3.25971 5.52773 2.60856 6.73895 2.33876C7.95017 2.06895 9.21599 2.19473 10.3504 2.6976C11.3659 3.14773 12.2282 3.87877 12.8379 4.80078H11.6C11.2686 4.80078 11 5.06941 11 5.40078C11 5.73215 11.2686 6.00078 11.6 6.00078H14.4C14.7314 6.00078 15 5.73215 15 5.40078V2.6C15 2.26863 14.7314 2 14.4 2C14.0686 2 13.8 2.26863 13.8 2.6V4.08078C13.0666 2.99539 12.0409 2.13433 10.8367 1.60055Z" fill="currentColor"/></symbol>
  <!-- media/video-camera -->
  <symbol id="i-cam" viewBox="0 0 16 16"><path d="M13.1916 4.51507C13.9915 4.0445 15 4.62129 15 5.54939V10.4513C15 11.3794 13.9915 11.9562 13.1916 11.4856L11.6 10.5494V11.2003C11.6 12.1945 10.7941 13.0003 9.8 13.0003H2.8C1.80589 13.0003 1 12.1945 1 11.2003V4.8C1 3.80586 1.80594 2.99996 2.80008 3L9.80007 3.00029C10.7942 3.00033 11.6 3.80621 11.6 4.80029V5.45129L13.1916 4.51507ZM13.4986 10.274C13.6319 10.3524 13.8 10.2563 13.8 10.1016V5.89907C13.8 5.74439 13.6319 5.64826 13.4986 5.72669L11.4549 6.92885C10.9883 7.20335 10.4 6.86689 10.4 6.3255V4.80029C10.4 4.46893 10.1314 4.2003 9.80002 4.20029L2.80003 4.2C2.46865 4.19999 2.2 4.46862 2.2 4.8V11.2003C2.2 11.5317 2.46863 11.8003 2.8 11.8003H9.8C10.1314 11.8003 10.4 11.5317 10.4 11.2003V9.67518C10.4 9.13379 10.9883 8.79733 11.4549 9.07183L13.4986 10.274Z" fill="currentColor"/></symbol>
  <!-- media/source-unavailable -->
  <symbol id="i-nosignal" viewBox="0 0 16 16"><path d="M1 2.2C1 1.53726 1.53726 1 2.2 1H13.8C14.4627 1 15 1.53726 15 2.2V13.8C15 14.4627 14.4627 15 13.8 15H2.2C1.53726 15 1 14.4627 1 13.8V2.2ZM2.20001 2.39922V3.9C2.20001 3.95523 2.24478 4 2.30001 4H4.25819C4.33806 4 4.3857 3.91099 4.3414 3.84453L3.27421 2.24375C3.25566 2.21593 3.22444 2.19922 3.19101 2.19922H2.40001C2.28956 2.19922 2.20001 2.28876 2.20001 2.39922ZM5.94078 4H7.75819C7.83806 4 7.8857 3.91099 7.8414 3.84453L6.77421 2.24375C6.75566 2.21593 6.72444 2.19922 6.69101 2.19922H4.8736C4.79373 2.19922 4.74609 2.28823 4.79039 2.35469L5.85758 3.95547C5.87613 3.98329 5.90735 4 5.94078 4ZM9.44078 4H11.2583C11.3381 4 11.3858 3.91098 11.3415 3.84453L10.2742 2.24375C10.2557 2.21593 10.2245 2.19922 10.191 2.19922H8.3736C8.29373 2.19922 8.24609 2.28823 8.29039 2.35469L9.35758 3.95547C9.37613 3.98329 9.40735 4 9.44078 4ZM12.9409 4H13.7C13.7552 4 13.8 3.95523 13.8 3.9V2.39922C13.8 2.28876 13.7105 2.19922 13.6 2.19922H11.8736C11.7938 2.19922 11.7461 2.28824 11.7904 2.35469L12.8577 3.95547C12.8762 3.98329 12.9075 4 12.9409 4ZM2.30001 5.2C2.24478 5.2 2.20001 5.24477 2.20001 5.3V13.5992C2.20001 13.7097 2.28956 13.7992 2.40001 13.7992H13.6C13.7105 13.7992 13.8 13.7097 13.8 13.5992V5.3C13.8 5.24477 13.7552 5.2 13.7 5.2H2.30001ZM9.26989 11.5179C9.5042 11.7522 9.8841 11.7522 10.1184 11.5179C10.3527 11.2836 10.3527 10.9037 10.1184 10.6694L8.91678 9.46776C8.87773 9.42871 8.87773 9.36539 8.91678 9.32634L10.1184 8.12468C10.3528 7.89037 10.3528 7.51047 10.1184 7.27615C9.88413 7.04184 9.50423 7.04184 9.26991 7.27615L8.06826 8.47781C8.0292 8.51687 7.96589 8.51687 7.92683 8.47781L6.7243 7.27528C6.48999 7.04097 6.11009 7.04097 5.87578 7.27528C5.64146 7.5096 5.64146 7.8895 5.87578 8.12381L7.07831 9.32634C7.11736 9.36539 7.11736 9.42871 7.07831 9.46776L5.8758 10.6703C5.64149 10.9046 5.64149 11.2845 5.8758 11.5188C6.11012 11.7531 6.49002 11.7531 6.72433 11.5188L7.92683 10.3163C7.96589 10.2772 8.0292 10.2772 8.06826 10.3163L9.26989 11.5179Z" fill="currentColor"/></symbol>
</svg>

<div class="sheet">
  <div>
    <div class="sheet__title">Device Local Settings · Video Source — “Type of source:” 2 → 3 (NDI)</div>
    <div class="sheet__sub">Increment on an existing page. Baseline kept; delta = third option + divider + NDI-only form. No new nav tab.</div>
    <div class="sheet__sub sheet__sub--zh" lang="zh-Hans">三帧 = 三个选中态（帧标注写的是该帧的初始态）。每帧的选择行是活的：点击 / 空格 / 回车选一项即可切换该帧的内容区，用来核交互。</div>
  </div>
  <div id="frames"></div>
</div>

<script>
/* ── 产品 UI 文案：单语 const map（R16 —— 即使还没接 i18n 也隔离，禁双语拼接） ── */
const T = {
  productName: 'Device Local Settings', deviceMeta: 'TVU One · SN 2317-0042',
  typeOfSource: 'Type of source:',
  ip: 'IP', targetReceiver: 'Target receiver', selectReceiver: 'Select receiver',
  apply: 'Apply', refresh: 'Refresh',
  preview: 'Preview', noSignal: 'No signal',
  ndiSource: 'NDI source', bandwidth: 'Bandwidth', discoveryServer: 'Discovery server',
  discoveryHint: '3 sources found on this network. Discovery runs automatically; set a Discovery server below if the list stays empty.',
  discoveryPlaceholder: 'Optional — leave empty to use automatic discovery',
  selectedSource: 'Selected source', format: 'Format', audio: 'Audio',
  baselineEn: 'Existing HDMI / SDI / USB panel — unchanged in this round',
};
/* 顶部导航：既有页签集，本轮零新增（NDI 不是导航项）。label 待换成产品真实页签。 */
const TABS = ['Status', 'Video Source', 'Network', 'Streaming', 'System'];
const ACTIVE_TAB = 'Video Source';
const OPTIONS = [ { id: 'hdmi', label: 'HDMI/SDI/USB' }, { id: 'ip', label: 'IP Source' }, { id: 'ndi', label: 'NDI' } ];
const RECEIVERS = ['RX-Studio-A', 'RX-Studio-B', 'RX-Truck-01', 'RX-Backup-Long-Name-Studio-Annex'];
/* 示意数据（非真实设备数据）。第 3 条刻意用长接收端名演示 R23/M43 截断 + title 兜底。 */
const IP_SOURCES = [
  { ip: '10.0.24.11', rx: 'RX-Studio-A', signal: true },
  { ip: '10.0.24.12', rx: 'RX-Studio-B', signal: true },
  { ip: '10.0.24.15', rx: 'RX-Backup-Long-Name-Studio-Annex', signal: true },
  { ip: '10.0.24.13', rx: '', signal: true },
  { ip: '10.0.24.14', rx: 'RX-Truck-01', signal: true },
  { ip: '10.0.24.16', rx: '', signal: false },
];
const NDI_SOURCES = ['STUDIO-PC (Camera 1)', 'STUDIO-PC (Screen Capture)', 'OB-TRUCK-2 (Cam 3)'];
const FRAMES = [
  { state: 'hdmi', en: '“HDMI/SDI/USB” selected — existing panel, unchanged this round',
    zh: '本轮只改选择行（二选一→三选一）与新增的分隔线。下方既有面板无基线源，按「不动 ≠ 不显示」留位并标注，未凭印象重画。' },
  { state: 'ip', en: '“IP Source” selected — existing source-card grid, kept as-is',
    zh: '既有网格四要素（预览 / IP / 目标接收端 / Apply）原样保留：未加 badge、未加卡片选中态、未改按钮词 —— 增量不借机改基线。' },
  { state: 'ndi', en: '“NDI” selected — new NDI-only form replaces the card grid',
    zh: '新增内容区：NDI source + Refresh / Bandwidth / Discovery server / Target receiver + Apply；右侧源预览沿用卡片网格的同一视觉词汇。「Target receiver」「Apply」与既有网格同词，未另造动词。' },
];

const esc = s => String(s).replace(/[&<>"]/g, c => ({ '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;' }[c]));
const ico = (id, cls) => `<svg class="ico ${cls || ''}" aria-hidden="true"><use href="#${id}"/></svg>`;

function select({ label, options, value, placeholder }) {
  const opts = (placeholder ? `<option value="" ${value ? '' : 'selected'} disabled>${esc(placeholder)}</option>` : '')
    + options.map(o => `<option ${o === value ? 'selected' : ''}>${esc(o)}</option>`).join('');
  return `<div class="select-wrap">
      <select class="select" aria-label="${esc(label)}" ${value ? `title="${esc(value)}"` : ''}>${opts}</select>
      <span class="select-arrow">${ico('i-chevron')}</span>
    </div>`;
}
const formRow = (id, label, content, hint) => `<div class="form-item">
    <div class="form-item__main">
      <span class="form-item__label" id="${id}">${esc(label)}</span>
      <div class="form-item__content">${content}${hint ? `<p class="form-item__message">${esc(hint)}</p>` : ''}</div>
    </div>
  </div>`;
const previewTile = ok => `<div class="preview ${ok ? '' : 'preview--offline'}">
    ${ico(ok ? 'i-cam' : 'i-nosignal')}<span class="preview__label">${ok ? T.preview : T.noSignal}</span></div>`;
const metaRow = (k, v) => `<div class="meta-row"><span class="meta-row__k">${esc(k)}</span>
    <span class="meta-row__v" title="${esc(v)}">${esc(v)}</span></div>`;

const ipGrid = () => `<div class="source-grid">` + IP_SOURCES.map(s => `<article class="source-card">
    ${previewTile(s.signal)}
    ${metaRow(T.ip, s.ip)}
    ${select({ label: `${T.targetReceiver} for ${s.ip}`, options: RECEIVERS, value: s.rx, placeholder: T.selectReceiver })}
    <div class="card-actions"><button type="button" class="btn btn--fill-green">${T.apply}</button></div>
  </article>`).join('') + `</div>`;

const ndiForm = i => `<div class="ndi">
    <div>
      <div class="ndi__form">
        ${formRow(`f${i}-ndi-src`, T.ndiSource,
          `<div class="row-inline">
             ${select({ label: T.ndiSource, options: NDI_SOURCES, value: NDI_SOURCES[0] })}
             <button type="button" class="btn btn--ghost-gray btn--icon">${ico('i-refresh')}${T.refresh}</button>
           </div>`, T.discoveryHint)}
        ${formRow(`f${i}-ndi-bw`, T.bandwidth,
          select({ label: T.bandwidth, options: ['Highest (full quality)', 'Lowest (proxy)'], value: 'Highest (full quality)' }))}
        ${formRow(`f${i}-ndi-ds`, T.discoveryServer,
          `<input class="tvu-input" type="text" aria-label="${esc(T.discoveryServer)}" placeholder="${esc(T.discoveryPlaceholder)}" />`)}
        ${formRow(`f${i}-ndi-rx`, T.targetReceiver,
          select({ label: T.targetReceiver, options: RECEIVERS, value: RECEIVERS[0], placeholder: T.selectReceiver }))}
      </div>
      <div class="ndi__actions"><button type="button" class="btn btn--fill-green">${T.apply}</button></div>
    </div>
    <aside class="ndi__side">
      <span class="ndi__side-title">${T.selectedSource}</span>
      ${previewTile(true)}
      ${metaRow(T.ndiSource, NDI_SOURCES[0])}
      ${metaRow(T.format, '1920×1080p59.94')}
      ${metaRow(T.audio, '2 ch')}
    </aside>
  </div>`;

const baselinePanel = () => `<div class="baseline">${ico('i-cam')}
    <span class="baseline__en">${esc(T.baselineEn)}</span>
    <span class="baseline__zh" lang="zh-Hans">占位，非交付内容：既有面板保留原位、原样。补齐它需要该帧的截图 / Figma 帧 id（按 M17 实测取值再画）。</span>
  </div>`;

function frame(f, i) {
  const radios = OPTIONS.map(o => {
    const on = o.id === f.state;
    return `<span class="radio" role="radio" tabindex="0" aria-checked="${on}" data-panel="${o.id}"
        data-figma-component="radio" data-figma-status="${on ? 'on' : 'off'}" data-figma-enable="yes">
        <span class="radio-circle${on ? ' radio-circle--selected' : ''}">${on ? '<span class="radio-dot"></span>' : ''}</span>${esc(o.label)}</span>`;
  }).join('');
  const panel = (id, html) => `<div data-panel-id="${id}" ${id === f.state ? '' : 'hidden'}>${html}</div>`;
  return `<section>
    <div class="anno">
      <span class="anno__no">FRAME ${i + 1} / ${FRAMES.length}</span>
      <span class="anno__en">${esc(f.en)}</span>
      <span class="anno__zh" lang="zh-Hans">${esc(f.zh)}</span>
    </div>
    <div class="frame" data-frame="${i}">
      <header class="topbar">
        <div class="topbar-brand">${ico('i-logo')}<span class="topbar-title">${esc(T.productName)}</span></div>
        <div class="topbar-right">${esc(T.deviceMeta)}</div>
      </header>
      <nav class="tab-list tab-list--line">
        <div class="tab-list__items" role="tablist" aria-label="Device settings">
          ${TABS.map(t => {
            const on = t === ACTIVE_TAB;
            return `<div class="tab-item tab-item--line${on ? ' tab-item--active-white' : ''}" role="tab"
              aria-selected="${on}" tabindex="${on ? 0 : -1}">${esc(t)}</div>`;
          }).join('')}
        </div>
      </nav>
      <main class="page"><section class="card">
        <div class="form-item">
          <div class="form-item__main">
            <span class="form-item__label form-item__label--dynamic" id="f${i}-src">${esc(T.typeOfSource)}</span>
            <div class="form-item__content">
              <div class="radio-group" role="radiogroup" aria-labelledby="f${i}-src">${radios}</div>
            </div>
          </div>
        </div>
        <div class="panel-divider"></div>
        ${panel('hdmi', baselinePanel())}
        ${panel('ip', ipGrid())}
        ${panel('ndi', ndiForm(i))}
      </section></main>
    </div>
  </section>`;
}

document.getElementById('frames').innerHTML = FRAMES.map(frame).join('');

/* 互斥选择：状态驱动内容区显隐（R14 —— 显隐是状态，走条件渲染语义的 hidden，
   不用 position:absolute + visibility 留尸 DOM；实现侧对应 v-if）。
   键盘 Space / Enter 选中，与 Radio.vue 的 onKeydown 一致。 */
document.querySelectorAll('[data-frame]').forEach(frameEl => {
  const radios = [...frameEl.querySelectorAll('[role="radio"]')];
  const pick = r => {
    if (r.classList.contains('radio--disabled')) return;
    radios.forEach(x => {
      const on = x === r;
      x.setAttribute('aria-checked', String(on));
      x.setAttribute('data-figma-status', on ? 'on' : 'off');
      const circle = x.querySelector('.radio-circle');
      circle.classList.toggle('radio-circle--selected', on);
      const dot = circle.querySelector('.radio-dot');
      if (on && !dot) circle.insertAdjacentHTML('beforeend', '<span class="radio-dot"></span>');
      if (!on && dot) dot.remove();
    });
    frameEl.querySelectorAll('[data-panel-id]').forEach(p => { p.hidden = p.dataset.panelId !== r.dataset.panel; });
  };
  radios.forEach(r => {
    r.addEventListener('click', e => { e.preventDefault(); pick(r); });
    r.addEventListener('keydown', e => { if (e.key === ' ' || e.key === 'Enter') { e.preventDefault(); pick(r); } });
  });
});
</script>
```

四条 locked spec 的落点：三选一互斥 = `role="radiogroup"` + DS radio 的 `data-figma-status` 状态映射；内容区由选中项驱动（`hidden` ↔ 实现侧 `v-if`）；分隔线 = `--line-deep` 1px full-bleed（库内无分隔线组件，走 catalog 记的线范式）；导航 5 个页签、`TABS` 数组零新增。

上一版被截断的原因是标记重复三份 + logo path 内联三次；这版改 sprite + 单模板渲染，设计与镜像来源未变。

**仍未闭合的两项**（不是我漏写，是缺输入）：HDMI/SDI/USB 面板要基线截图或 Figma 帧 id 才能按 M17 实测补；NDI 源掉网 / 空列表的反馈态待先定这条页面归设备侧 `Message` 还是 web 侧 `Notification`（domain-tvu M12 谱系隔离），定了我再补那一帧。