/* ============================================================
   m3-tree.css — D3 树节点卡片 / 连线 / 聚焦与暗淡 (4.2 / 4.3 / 6.3)
   ============================================================ */

.ft-link {
  fill: none;
  stroke: var(--md-outline-variant);      /* #49454F */
  stroke-width: 1.5px;
  stroke-linecap: round;
  transition: opacity var(--dur-focus) var(--ease-entrance);
}

.ft-node {
  position: relative;
  width: 120px;             /* 4.2 */
  height: 56px;
  border-radius: 12px;
  background: var(--md-surface-container-low);   /* #1D1B20 */
  border: 1px solid rgba(73, 69, 79, 0.9);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 2px;
  cursor: pointer;
  overflow: hidden;
  transform-origin: center center;
  transition: transform var(--dur-focus) var(--ease-entrance),
              background-color var(--dur-focus) var(--ease-entrance),
              border-color var(--dur-focus) var(--ease-entrance),
              opacity var(--dur-focus) var(--ease-entrance),
              filter var(--dur-focus) var(--ease-entrance);
}

/* Hover: 内部 8% 白色状态层 */
.ft-node::after {
  content: "";
  position: absolute;
  inset: 0;
  background: rgba(230, 224, 233, 0);
  transition: background-color var(--dur-focus) var(--ease-entrance);
  pointer-events: none;
}
.ft-node:hover::after { background: rgba(230, 224, 233, 0.08); }

.ft-node__name {
  font-size: 16px;          /* 4.2 */
  font-weight: 500;
  line-height: 1.15;
  color: var(--md-on-surface);
  max-width: 104px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.ft-node__meta {
  font-size: 12px;
  font-weight: 400;
  line-height: 1.15;
  color: var(--md-on-surface-variant);
}

/* 折叠计数: 该节点还有 N 位后人未在当前视野展开 */
.ft-node__more {
  position: absolute;
  right: 4px;
  bottom: 2px;
  padding: 1px 5px;
  border-radius: 6px;
  background: rgba(208, 188, 255, 0.16);
  font-size: 10px;
  line-height: 1.3;
  color: var(--md-primary);
}

/* 6.3 聚焦: 2px 主色描边 + 提亮 + 放大 1.1 */
.ft-node.is-focus {
  border: 2px solid var(--md-primary);
  background: var(--md-surface-container-high);
  transform: scale(1.1);
  z-index: 3;
}
.ft-node.is-focus .ft-node__name { color: var(--md-on-surface); }

/* 6.3 无关节点: 透明 0.4 + 100% 灰度 */
.ft-node.is-dim {
  opacity: 0.4;
  filter: grayscale(1);
}
.ft-link.is-dim { opacity: 0.25; }

/* 7.2 断代节点: 标红 */
.ft-node.is-dangling { border-color: var(--md-error); }
.ft-node.is-dangling .ft-node__meta { color: var(--md-error); }

/* 未校验数据标记 (数据质量可视化) */
.ft-node.is-unverified::before {
  content: "";
  position: absolute;
  top: 6px;
  right: 6px;
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: var(--md-outline);
  opacity: 0.85;
}
.ft-node.is-verified::before {
  content: "";
  position: absolute;
  top: 6px;
  right: 6px;
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: var(--md-primary);
}

/* 虚拟锚点: 始迁祖之前 / 门 / 待考散人 —— 纯逻辑, 不是族人, 故用透明+虚线表示 */
.ft-node.is-virtual {
  background: transparent;
  border: 1px dashed var(--md-outline-variant);
  box-shadow: none;
}
.ft-node.is-virtual .ft-node__name { color: var(--md-on-surface-variant); font-weight: 400; }
.ft-node.is-virtual .ft-node__meta { color: var(--md-outline); }

/* 树干顶端: 更明显的虚线 + 弱化填充 */
.ft-node.is-virtual--root {
  border: 1px dashed var(--md-outline);
  border-radius: var(--shape-full);
  background: transparent;
}
.ft-node.is-virtual--root .ft-node__name {
  color: var(--md-on-surface-variant);
  font-size: 15px;
  letter-spacing: .06em;
}

/* 四门: 虚线但用主色勾出分支起点 */
.ft-node.is-virtual--door {
  border: 1px dashed var(--md-primary);
  background: transparent;
}
.ft-node.is-virtual--door .ft-node__name { color: var(--md-primary); font-weight: 500; }

/* 待考散人: 更弱 */
.ft-node.is-virtual--orphan {
  border-color: #6E6659;
}
.ft-node.is-virtual--orphan .ft-node__name { color: var(--md-outline); }

/* 语义缩放: k < 0.42 时节点退化为「等屏幕尺寸」的点, 保证整树轮廓可见
   --inv-k 由 JS 在 zoom 时写入 (1/k, 上限 14) */
.is-dot-mode .ft-node {
  position: absolute;
  left: 50%;
  top: 50%;
  width: calc(9px * var(--inv-k, 1));
  height: calc(9px * var(--inv-k, 1));
  min-width: 0;
  min-height: 0;
  transform: translate(-50%, -50%);
  border-radius: 50%;
  border-width: calc(1px * var(--inv-k, 1));
  background: var(--md-primary);
  border-color: var(--md-primary);
  opacity: 0.85;
  overflow: visible;
}
.is-dot-mode .ft-node__name,
.is-dot-mode .ft-node__meta,
.is-dot-mode .ft-node__more { display: none; }
.is-dot-mode .ft-node::before { display: none; }
.is-dot-mode .ft-node.is-virtual--bridge,
.is-dot-mode .ft-node.is-virtual { background: var(--md-outline); border-color: var(--md-outline); }
.is-dot-mode .ft-node.is-dim { opacity: 0.12; }
.is-dot-mode .ft-link { stroke-width: calc(1px * var(--inv-k, 1)); opacity: 0.55; }
.is-dot-mode .ft-node.is-focus { transform: translate(-50%, -50%) scale(1); border-width: calc(2px * var(--inv-k, 1)); }

/* 6.1 错峰入场初始态 (JS 逐节点施加)
   注意: 结束态只负责「过渡声明」, 不写 opacity/transform 值,
   否则会以同等优先级覆盖掉 .is-dim / .is-focus。 */
.ft-node.is-entering {
  opacity: 0;
  transform: translateY(15px) scale(0.9);
}
.ft-node.is-entered {
  transition:
    opacity var(--dur-entrance) var(--ease-entrance),
    transform var(--dur-entrance) var(--ease-entrance),
    background-color var(--dur-focus) var(--ease-entrance),
    border-color var(--dur-focus) var(--ease-entrance),
    filter var(--dur-focus) var(--ease-entrance);
}

/* 缩放很低时隐藏次要信息, 降低视觉噪声 */
.is-zoomed-out .ft-node__meta { opacity: 0; }
