/* ═══ 待办任务 · 甘特图 ═══════════════════════════════════════════ */
.panel.todo { padding: 0 0 4px; }
.todo-head {
  display: flex; align-items: center; justify-content: space-between;
  gap: 8px; padding: 12px 12px 8px;
}
.todo-head h2 { margin: 0; font-size: 15px; }
.todo-btns { display: flex; align-items: center; gap: 6px; }
.todo-stat { display: flex; gap: 5px; }
.tchip {
  font-size: 11px; padding: 2px 7px; border-radius: 10px;
  background: #eef1f6; color: #6b7482; white-space: nowrap;
}
.tchip.on { background: #e3edfd; color: #1f6feb; }
.tchip.on b { font-weight: 700; }
.tchip.err { background: #fdeceb; color: #c9362b; cursor: help; }
/* 缓存数据 + 后台正在刷新：灰调、不抢眼，数据本身照常显示 */
.tchip.stale {
  background: #f2f3f5; color: #8a919b; cursor: help;
  animation: tchipPulse 1.4s ease-in-out infinite;
}
@keyframes tchipPulse { 0%, 100% { opacity: 1; } 50% { opacity: .5; } }
@media (prefers-reduced-motion: reduce) { .tchip.stale { animation: none; } }
.todo-body { padding: 0 12px 10px; }

/* ★ 甘特不再靠 min-width 撑宽度 —— 靠上面的 clamp 三列自适应，容器永不溢出。
   overflow-x:auto 只作为极端窄屏的兜底。 */
/* ★ 1px 溢出：只写 overflow-x:auto 时，纵向溢出仍是 visible，
   在有圆角边框的容器上会算出 1px 亚像素溢出 → 手机上出现横向滚动条。
   两轴都裁掉即可（轴/条都在容器内，不会误裁内容）。 */
.gantt-wrap { overflow-x: auto; overflow-y: hidden; -webkit-overflow-scrolling: touch; }
.gantt { min-width: 0; }
.gantt .empty { padding: 18px 4px; color: #8a929e; font-size: 13px; }

.g-group { margin-bottom: 2px; }
.g-groupname {
  font-size: 11px; color: #6b7482; font-weight: 600;
  padding: 8px 0 4px; border-top: 1px solid #eef1f6; margin-top: 6px;
}
.g-groupname b { color: #1f6feb; }

/* 轴 + 行都用同一套栅格，保证竖线对齐 */
.gantt-axis, .g-row { display: flex; align-items: stretch; }
/* ★ 桌面版固定三列，宽度用 clamp() 保证总和永不超容器。
     之前 min-width:560px 写死 → 窄屏必溢出 30px。
   ★ 顺带修「长标题被裁」：列宽原封顶 200px，配 -webkit-line-clamp:2，
     稍长的任务名（如「商圈任务 · 高优先级 · 商家签约资质年审…」）实测需要 3 行
     → scrollHeight 49px vs clientHeight 32px，第 3 行直接丢内容。
     放宽到 280px 并给 3 行，长标题即可完整显示。 */
.g-lab {
  flex: 0 0 clamp(120px, 18vw, 280px);
  min-width: 0; max-width: clamp(120px, 18vw, 280px);
  padding-right: 8px; box-sizing: border-box;
}
.g-track { flex: 1 1 0; position: relative; min-height: 20px; min-width: 0; }
.g-right {
  flex: 0 0 clamp(64px, 8vw, 96px);
  min-width: 0; max-width: clamp(64px, 8vw, 96px);
  padding-left: 8px; box-sizing: border-box; text-align: right;
  font-size: 11px; color: #6b7482;
}

.gantt-axis .g-track { min-height: 18px; margin-bottom: 2px; }
/* ★ 修 1px 溢出：.g-tick 用 left:X% 定位且带 1px border-left。
   当刻度落在 left:100% 时，这条 1px 线正好画在容器右缘【之外】
   → gantt-wrap 恒定多出 1px scrollWidth（手机端也会出现横向滚动）。
   修法：margin-left:-1px 把这条线整体拉回容器内，视觉位置不变。 */
.g-tick {
  position: absolute; top: 0; bottom: 0; margin-left: -1px;
  border-left: 1px solid #f0f3f7;
}
.g-tick span {
  position: absolute; top: 0; left: 3px; font-size: 10px; color: #a3abb8; white-space: nowrap;
}
/* 靠右的刻度（JS 加 .r）：nowrap 标签会向右伸出容器，改为右对齐向左展开 */
.g-tick.r span { left: auto; right: 3px; }
.g-tick.now { border-left-color: #1f6feb; }
.g-tick.now span { color: #1f6feb; font-weight: 600; }
.g-nowline {
  position: absolute; top: 0; bottom: 0; width: 2px; margin-left: -1px;
  background: rgba(31, 111, 235, .35);
}

.g-row {
  padding: 5px 0; border-radius: 6px; cursor: pointer;
  transition: background .12s;
}
.g-row:hover { background: #f6f9fe; }
/* ★ 标题原来 nowrap+ellipsis，在 clamp 宽度下必然被截 → 改成最多三行，
   保住信息（完整内容仍有 title 悬浮提示）。
   三行是实测出来的：列宽放宽到 280px 后，最长的任务名仍需 3 行才不断字。 */
.g-title {
  font-size: 12px; color: #1f2733; line-height: 1.35;
  display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical;
  overflow: hidden; word-break: break-word;
}
.g-sub {
  font-size: 10.5px; color: #8a929e; line-height: 1.3;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}

.g-bar {
  position: absolute; top: 6px; height: 13px; border-radius: 7px;
  background: #7fa8ea; min-width: 6px; box-sizing: border-box;
}
/* 没开始时间：左段用虚线示意 */
.g-row.open .g-bar {
  background: repeating-linear-gradient(90deg, #cfdcf1 0 5px, transparent 5px 10px);
  border-top: 1px solid #b9ccea; border-bottom: 1px solid #b9ccea;
}
.g-pri {
  position: absolute; right: 4px; top: -1px; font-size: 9px;
  color: #fff; opacity: .9; letter-spacing: .2px;
}
.g-row.ok .g-bar { background: #7fa8ea; }
.g-row.soon .g-bar { background: #e0a33c; }
.g-row.over .g-bar { background: #d8674f; }

/* ★ 虚线变体要放在配色规则【之后】，否则被 .g-row.ok/.soon/.over 的实色盖掉
   （open 行只是多一个 class，优先级完全相同 → 后写的赢） */
.g-row.open .g-bar { background-image: repeating-linear-gradient(90deg, rgba(255,255,255,.75) 0 5px, transparent 5px 10px); }

.g-row.soon .g-right b { color: #b7791f; }
.g-row.over .g-right b { color: #c9362b; }
.g-right b { font-weight: 600; color: #6b7482; }
.g-right .dim { color: #a3abb8; }

/* ★ 修「备注压下一行」：.g-tip 是 .g-track 的子元素且 absolute，不占布局高度。
   .g-track 固定 min-height:20px → tip 溢出 track 又溢出 .g-row，压到下一张卡
   （实测 tip 底 295 vs row 底 288）。
   修法：只在【确实有备注】的行给 track 加下方内边距预留空间。
   判定靠 JS 输出的 .has-tip 类 —— 不用 :has()，WebView 支持不稳。
   （padding 不影响 .g-bar 定位 —— 它用的是 left/width 百分比。） */
.g-track.has-tip { padding-bottom: 15px; }

#todoTip { padding: 8px 2px 2px; font-size: 11px; }
#todoTip b.over { color: #c9362b; }

/* ═══════════════════════════════════════════════════════════════════
   手机版：≤ 720px 改成【卡片式】布局
   ───────────────────────────────────────────────────────────────────
   之前的问题：三列 flex（标题 120px + 甘特 + 到期 72px）硬塞进 390px，
   甘特只剩几十像素被压成一条缝，而且 min-width:560px 撑出 30px 横向溢出。
   → 手机上甘特图这个形态本身就不成立，改成卡片：文字全宽，甘特条退到下方
     当"进度条"用，保留视觉信息但不占横向空间。
   ═══════════════════════════════════════════════════════════════════ */
@media (max-width: 720px) {
  .todo-head { flex-wrap: wrap; padding: 10px 10px 6px; }
  .todo-head h2 { font-size: 14px; }
  .todo-stat { flex-wrap: wrap; gap: 4px; }
  .todo-body { padding: 0 10px 8px; }

  /* 卡片：整行一个块，标题/副标题/备注全宽不再截断 */
  .g-group { margin-bottom: 8px; }
  .g-groupname {
    padding: 8px 0 6px; margin-top: 8px;
    position: sticky; top: 0; z-index: 2;
    background: var(--panel-bg, #fff);
  }
  .g-row {
    display: block; position: relative;
    padding: 10px 11px 11px; margin-bottom: 6px;
    border: 1px solid #e8ecf2; border-radius: 9px;
    background: #fff;
  }
  .g-row:hover { background: #fff; }
  .g-row.over { border-color: #f3c9c0; background: #fffaf9; }
  .g-row.soon { border-color: #f2ddb8; background: #fffdf7; }

  /* 标题列 → 全宽块，但整体为右上角徽标【让出空间】。
     ★ 修重叠的关键：留白必须加在父级 .g-lab 上。
       原来只给 .g-title 加 padding-right，标题元素盒子本身仍延伸到卡片右边缘，
       absolutely positioned 的徽标就压在标题文字上（标题 3 行时第一行末尾被盖）。
       父级留白才能让整个文字块的可用宽度止步于徽标左边。 */
  .g-lab {
    flex: none; width: auto; max-width: none; min-width: 0;
    padding-right: 78px;          /* 徽标最宽 ~70px + 8px 间隙 */
  }
  .g-title {
    font-size: 13.5px; line-height: 1.4; font-weight: 600; color: #16202e;
    -webkit-line-clamp: 3;
  }
  .g-sub { font-size: 11.5px; margin-top: 2px; white-space: normal; }

  /* 到期列 → 右上角绝对定位的徽标，不再单独占一列 */
  .g-right {
    position: absolute; top: 9px; right: 11px;
    flex: none; width: auto; max-width: none; min-width: 0;
    padding-left: 0; text-align: right; font-size: 11px;
    background: none;
  }
  .g-right b {
    display: inline-block; padding: 2px 6px; border-radius: 9px;
    background: #f1f3f6; color: #6b7482; font-size: 10.5px;
  }
  .g-row.soon .g-right b { background: #fdf1dc; color: #a86a12; }
  .g-row.over .g-right b { background: #fdeceb; color: #c9362b; }
  .g-right .dim { font-size: 10.5px; }

  /* 甘特轨道 → 卡片底部的细进度条，占满卡片宽度 */
  .g-track {
    display: block; position: relative;
    min-height: 0; width: 100%; margin-top: 9px;
    /* ★ 必须 clip：条子是 absolute 定位的（left/width 是百分比），
       一旦左端落在 [0,100%] 之外就会溢出卡片外。正常数据不会这样
       （d0/d1 已按所有任务起止算出），但 open 任务 end=null、
       或平台返回了意外时间时都可能触发，兜底裁掉。 */
    overflow: hidden;
  }
  .g-bar { top: 0; height: 6px; border-radius: 3px; min-width: 3px; }
  .g-pri { top: -3px; right: 3px; font-size: 9px; }
  /* 进度条上方留一条基线，看得出条子占整条时间轴的比例 */
  .g-track::before {
    content: ""; position: absolute; left: 0; right: 0; top: 3px;
    height: 1px; background: #eef1f6;
  }

  /* 备注 → 正常文档流，不再 absolute 压在下一行上 */
  .g-tip {
    position: static; max-width: none; margin-top: 7px;
    font-size: 11.5px; color: #8a929e; line-height: 1.4;
    white-space: normal; word-break: break-word;
  }

  /* 轴在卡片布局下没有意义（各行时间轴不一致）→ 隐藏 */
  .gantt-axis { display: none; }
  .g-nowline { display: none; }
}
