* { margin: 0; padding: 0; box-sizing: border-box; }
:root {
  --pri: #1668dc; --pri-d: #0d47a1; --bg: #f0f3f8;
  --ok: #18a058; --warn: #f0a020; --err: #d03050; --info: #2080f0;
  --bd: #e3e8f0; --txt: #1f2d3d; --txt2: #6b7a90;
}
body { font: 14px/1.6 "Microsoft YaHei", "PingFang SC", sans-serif; background: var(--bg); color: var(--txt); }
button { font-family: inherit; cursor: pointer; }
a { color: var(--pri); text-decoration: none; }

/* 登录 */
.login-wrap { height: 100vh; display: flex; align-items: center; justify-content: center;
  background: linear-gradient(135deg, #0d2b5c 0%, #1668dc 60%, #2b8cf0 100%); }
.login-card { width: 400px; background: #fff; border-radius: 14px; padding: 40px 36px;
  box-shadow: 0 18px 60px rgba(0,0,0,.25); }
.login-card .logo { font-size: 22px; font-weight: 700; text-align: center; color: var(--pri-d);
  display: flex; align-items: center; justify-content: center; gap: 9px; }
.login-card .logo .logo-img { width: 32px; height: 32px; flex: none; }
.login-card .sub { text-align: center; color: var(--txt2); margin: 6px 0 26px; font-size: 13px; }
.login-card input { width: 100%; height: 44px; border: 1px solid var(--bd); border-radius: 8px;
  padding: 0 14px; margin-bottom: 16px; font-size: 15px; outline: none; }
.login-card input:focus { border-color: var(--pri); }
.login-card .pw-wrap { position: relative; margin-bottom: 12px; }
.login-card .pw-wrap input { margin-bottom: 0; padding-right: 44px; }
.pw-toggle { position: absolute; right: 6px; top: 50%; transform: translateY(-50%);
  border: none; background: transparent; cursor: pointer; font-size: 17px;
  line-height: 1; padding: 6px; color: #8492a6; }
.pw-toggle:active { opacity: .6; }
/* 普通文本框+圆点遮罩伪装密码（避免浏览器/安全软件按 type=password 接管键盘） */
.pw-mask { -webkit-text-security: disc; text-security: disc; }
.login-card .btn { width: 100%; height: 46px; font-size: 16px; }
.login-tip { margin-top: 18px; font-size: 12px; color: var(--txt2); background: #f6f8fc;
  border-radius: 8px; padding: 10px 12px; line-height: 1.9; }
/* 账号 / 企微扫码 登录切换 */
.login-tabs { display: flex; gap: 8px; margin-bottom: 20px; }
.login-tabs .lt { flex: 1; text-align: center; padding: 9px 0; border-radius: 8px; cursor: pointer;
  font-size: 14px; color: var(--txt2); background: #f2f5fa; user-select: none; transition: all .15s; }
.login-tabs .lt.active { background: var(--pri); color: #fff; font-weight: 600; }
.wx-qr-box { display: flex; justify-content: center; align-items: flex-start; min-height: 408px; }
.wx-qr-box iframe { border: none; }

/* 布局 */
.layout { display: flex; min-height: 100vh; }
.sidebar { width: 210px; background: #101c33; color: #c6d2e5; flex-shrink: 0;
  display: flex; flex-direction: column; position: sticky; top: 0; height: 100vh; }
.sidebar .brand { padding: 20px 18px; font-size: 16px; font-weight: 700; color: #fff;
  border-bottom: 1px solid rgba(255,255,255,.08); }
.sidebar .brand .brand-img { float: left; width: 36px; height: 36px; margin: 0 10px 4px 0;
  border-radius: 50%; background: #fff; padding: 3px; flex: none; }
.sidebar .brand small { display: block; font-size: 11px; color: #7d8bab; font-weight: 400; margin-top: 2px; }
.menu { flex: 1; padding: 10px 0; overflow-y: auto; }
.menu a { display: block; padding: 11px 20px; color: #b8c5da; font-size: 14px; border-left: 3px solid transparent; }
.menu a:hover { background: rgba(255,255,255,.06); color: #fff; }
.menu a.active { background: rgba(22,104,220,.25); color: #fff; border-left-color: #4d9fff; }
.sidebar .me { padding: 14px 18px; border-top: 1px solid rgba(255,255,255,.08); font-size: 12px; }
.sidebar .me b { color: #fff; font-size: 13px; }
.sidebar .me .logout { color: #7d8bab; cursor: pointer; margin-top: 6px; display: inline-block; }
.sidebar .me .logout:hover { color: #ff8a8a; }
.sidebar .me .manual-link { color: #7d8bab; text-decoration: none; margin-top: 6px; margin-right: 12px; display: inline-block; font-size: 12px; }
.sidebar .me .manual-link:hover { color: #8bb8ff; }

.main { flex: 1; display: flex; flex-direction: column; min-width: 0; }
.topbar { height: 52px; background: #fff; border-bottom: 1px solid var(--bd);
  display: flex; align-items: center; padding: 0 22px; justify-content: space-between;
  position: sticky; top: 0; z-index: 20; }
.topbar h2 { font-size: 17px; }
.content { padding: 18px 22px; }

/* 组件 */
.btn { border: 1px solid var(--bd); background: #fff; border-radius: 7px; padding: 7px 16px;
  font-size: 13px; color: var(--txt); transition: .15s; display: inline-flex; align-items: center; gap: 5px; }
.btn:hover { border-color: var(--pri); color: var(--pri); }
.btn.primary { background: var(--pri); color: #fff; border-color: var(--pri); }
.btn.primary:hover { background: #2b7ae8; color: #fff; }
.btn.danger { color: var(--err); border-color: #f0b8c0; }
.btn.danger:hover { background: var(--err); color: #fff; border-color: var(--err); }
.btn.warn { color: var(--warn); border-color: #f0d8a8; }
.btn.sm { padding: 3px 9px; font-size: 12px; }
.btn.ghost { background: #f5f7fb; }
.btn[disabled] { opacity: .5; cursor: not-allowed; }

.card { background: #fff; border-radius: 10px; padding: 16px 18px; margin-bottom: 16px;
  box-shadow: 0 1px 4px rgba(31,45,61,.06); }
.card-h { display: flex; justify-content: space-between; align-items: center; margin-bottom: 14px; }
.card-h h3 { font-size: 15px; }
.card-h .tools { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }

input, select, textarea { font-family: inherit; font-size: 13px; outline: none; }
.inp { height: 34px; border: 1px solid var(--bd); border-radius: 7px; padding: 0 10px; background: #fff; }
.inp:focus { border-color: var(--pri); }
select.inp { cursor: pointer; }
/* 分页条页码跳转下拉：宽度不随位数变化，最多约 1000 页也不挤 */
.pager-jump { height: 30px; min-width: 86px; max-width: 120px; padding: 0 6px; cursor: pointer; }
.tf-pager .pager-jump { height: auto; border: 1px solid var(--bd); border-radius: 6px; font-size: 13px; }

table { width: 100%; border-collapse: collapse; font-size: 13px; }
th { background: #f6f8fc; text-align: left; padding: 10px 12px; color: var(--txt2);
  font-weight: 600; white-space: nowrap; border-bottom: 1px solid var(--bd); }
td { padding: 9px 12px; border-bottom: 1px solid #f0f3f8; }
tr:hover td { background: #fafcff; }
.tbl-wrap { overflow-x: auto; }
/* 刀具类型表编码列：点击查看该类型收发流水（全员可点） */
.code-link { color: var(--pri); cursor: pointer; text-decoration: underline dotted; text-underline-offset: 3px; }
.code-link:hover { text-decoration: underline; }
.sort-ind { color: var(--pri); font-size: 11px; margin-left: 2px; }
#tf-tbl thead th { user-select: none; }
#tf-tbl thead th:hover { color: var(--pri); }

.tag { display: inline-block; padding: 1px 9px; border-radius: 11px; font-size: 12px; line-height: 20px; }
.tag.gray { background: #eef1f6; color: #6b7a90; }
.tag.blue { background: #e6f0ff; color: #1668dc; }
.tag.green { background: #e4f6ec; color: #18a058; }
.tag.orange { background: #fdf2e0; color: #d48806; }
.tag.red { background: #fde8ee; color: #d03050; }
.tag.cyan { background: #e0f4f8; color: #0e8ba0; }

.kpis { display: grid; grid-template-columns: repeat(auto-fit, minmax(165px, 1fr)); gap: 14px; }
.kpi { background: #fff; border-radius: 10px; padding: 16px 18px; position: relative; overflow: hidden;
  box-shadow: 0 1px 4px rgba(31,45,61,.06); }
.kpi .v { font-size: 27px; font-weight: 700; margin-top: 4px; }
.kpi .l { color: var(--txt2); font-size: 13px; }
.kpi .ic { position: absolute; right: 12px; top: 14px; font-size: 26px; opacity: .18; }
.kpi.b1 .v { color: var(--pri); } .kpi.b2 .v { color: var(--ok); }
.kpi.b3 .v { color: var(--warn); } .kpi.b4 .v { color: var(--err); }
.kpi.b5 .v { color: #7048d8; } .kpi.b6 .v { color: #0e8ba0; }

.grid-2 { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; }
.grid-2-1 { display: grid; grid-template-columns: 2fr 1fr; gap: 16px; }

/* 设备色块 */
.machines { display: grid; grid-template-columns: repeat(auto-fill, minmax(84px, 1fr)); gap: 7px; }
.mc { border-radius: 7px; padding: 8px 4px; text-align: center; font-size: 12px; color: #fff;
  cursor: pointer; transition: transform .1s; line-height: 1.4; }
/* 设备按操作工分组卡片：每组一个大容器，组内并列设备小卡片 */
.group-card { border: 1px solid #e6ebf3; border-radius: 9px; padding: 10px 12px; margin-bottom: 10px; background: #fbfcfe; }
.group-card h4 { display: flex; align-items: center; gap: 8px; margin: 0 0 8px; font-size: 14px; }
.group-card h4 .muted { font-size: 12px; }
.group-card .machines { margin-bottom: 0; }
.mc:hover { transform: translateY(-2px); }
.mc.running { background: linear-gradient(135deg,#18a058,#22c06b); }
.mc.idle { background: linear-gradient(135deg,#f0a020,#ffb84d); }
.mc.fault { background: linear-gradient(135deg,#d03050,#f05070); animation: blink 1.2s infinite; }
.mc.stop { background: linear-gradient(135deg,#8a97a8,#a6b2c2); }
.mc { position: relative; }
.mc small { display: block; font-size: 10px; opacity: .85; }
/* 黄灯换刀报警：设备色块黄色描边 + 右上角闪烁黄灯 */
.mc.tool-alert { box-shadow: 0 0 0 2px #ffd400, 0 0 10px rgba(255,180,0,.75); z-index: 1; }
.mc .ylamp { position: absolute; top: -5px; right: -5px; width: 13px; height: 13px;
  border-radius: 50%; background: #ffd400; border: 2px solid #fff;
  box-shadow: 0 0 7px #ffb300; animation: yblink 1s infinite; pointer-events: none; }
@keyframes blink { 50% { opacity: .55; } }
@keyframes yblink { 0%,100% { opacity: 1; } 50% { opacity: .35; } }
/* 黄灯换刀报警卡片/KPI */
.kpi.by { background: linear-gradient(135deg,#ffc400,#ffd94d); color: #5c4400; }
.kpi.by .l, .kpi.by .v, .kpi.by .ic { color: #5c4400; }
.card.alert-card { border: 1px solid #ffcf3d; box-shadow: 0 0 0 1px #ffe9a8 inset; }
.card.alert-card .card-h h3 { color: #b97e00; }
.legend { display: flex; gap: 16px; margin-bottom: 12px; font-size: 12px; color: var(--txt2); flex-wrap: wrap; }
.legend i { display: inline-block; width: 11px; height: 11px; border-radius: 3px; margin-right: 5px; vertical-align: -1px; }

/* 进度条 */
.pbar { height: 7px; background: #eef1f6; border-radius: 4px; overflow: hidden; min-width: 90px; }
.pbar i { display: block; height: 100%; background: linear-gradient(90deg,#1668dc,#4d9fff); border-radius: 4px; }
.lifebar i.warn { background: linear-gradient(90deg,#f0a020,#ffb84d); }
.lifebar i.danger { background: linear-gradient(90deg,#d03050,#f05070); }

/* 工序步骤 */
.steps { display: flex; gap: 0; margin: 6px 0 2px; }
.step { flex: 1; text-align: center; position: relative; font-size: 12px; color: var(--txt2); }
.step .dot { width: 22px; height: 22px; border-radius: 50%; background: #e3e8f0; color: #8a97a8;
  line-height: 22px; margin: 0 auto 4px; font-weight: 700; position: relative; z-index: 2; }
.step::before { content: ''; position: absolute; top: 10px; left: -50%; width: 100%; height: 3px; background: #e3e8f0; z-index: 1; }
.step:first-child::before { display: none; }
.step.done .dot { background: var(--ok); color: #fff; }
.step.done::before { background: var(--ok); }
.step.cur .dot { background: var(--pri); color: #fff; box-shadow: 0 0 0 4px rgba(22,104,220,.18); }
.step.fail .dot { background: var(--err); color: #fff; }
.step b { display: block; font-weight: 500; }
.step.fail b { color: var(--err); } .step.cur b { color: var(--pri); } .step.done b { color: var(--ok); }

/* 弹窗 */
.modal-mask { position: fixed; inset: 0; background: rgba(16,28,51,.45); z-index: 100;
  display: flex; align-items: flex-start; justify-content: center; padding-top: 60px; }
.modal-box { width: 460px; background: #fff; border-radius: 12px; box-shadow: 0 20px 70px rgba(0,0,0,.3); }
.modal-box.wide { width: 720px; max-height: 80vh; overflow: hidden; display: flex; flex-direction: column; }
.modal-box.wider { width: 1200px; max-width: 95vw; }
.modal-h { padding: 15px 20px; font-size: 16px; font-weight: 700; border-bottom: 1px solid var(--bd);
  display: flex; justify-content: space-between; align-items: center; }
.modal-x { cursor: pointer; color: var(--txt2); font-size: 22px; line-height: 1; }
.modal-b { padding: 18px 20px; max-height: 62vh; overflow-y: auto; }
.modal-box.wide .modal-b { flex: 1; }
.modal-f { padding: 13px 20px; border-top: 1px solid var(--bd); text-align: right; display: flex;
  justify-content: flex-end; gap: 10px; }
.fld { display: block; margin-bottom: 13px; }
.fld > span { display: block; font-size: 13px; margin-bottom: 5px; color: var(--txt); }
.fld > span b { color: var(--err); margin-left: 2px; }
.fld input, .fld select, .fld textarea { width: 100%; border: 1px solid var(--bd); border-radius: 7px;
  padding: 8px 11px; font-size: 14px; }
.fld input:focus, .fld select:focus, .fld textarea:focus { border-color: var(--pri); }
.fld input.bad, .fld select.bad { border-color: var(--err); }
.fld2 { display: grid; grid-template-columns: 1fr 1fr; gap: 0 14px; }

/* toast */
.toast { position: fixed; top: 22px; left: 50%; transform: translate(-50%, -16px); z-index: 300;
  background: #333; color: #fff; padding: 10px 22px; border-radius: 8px; font-size: 14px;
  opacity: 0; transition: .25s; box-shadow: 0 8px 30px rgba(0,0,0,.25); }
.toast.show { opacity: 1; transform: translate(-50%, 0); }
.toast.ok { background: #18a058; } .toast.err { background: #d03050; }

.tabs { display: flex; gap: 4px; border-bottom: 1px solid var(--bd); margin-bottom: 16px; }
.tabs span { padding: 9px 18px; cursor: pointer; color: var(--txt2); border-bottom: 2px solid transparent;
  margin-bottom: -1px; font-size: 14px; }
.tabs span.active { color: var(--pri); border-bottom-color: var(--pri); font-weight: 600; }
.muted { color: var(--txt2); font-size: 12px; }
.right { text-align: right; }
.mt8 { margin-top: 8px; } .mt16 { margin-top: 16px; }
.empty { text-align: center; color: var(--txt2); padding: 40px 0; }
.kv { display: grid; grid-template-columns: 96px 1fr; gap: 7px 10px; font-size: 13px; }
.kv dt { color: var(--txt2); } .kv dd { font-weight: 500; }
.qr { text-align: center; } .qr img { width: 170px; height: 170px; }
.bar-chart { display: flex; align-items: flex-end; gap: 14px; height: 170px; padding-top: 10px; }
.bar-chart .bc { flex: 1; display: flex; flex-direction: column; align-items: center; gap: 6px; font-size: 12px; }
.bar-chart .bc i { width: 70%; background: linear-gradient(180deg,#4d9fff,#1668dc); border-radius: 5px 5px 0 0; min-height: 2px; display: block; }
.bar-chart .bc span { color: var(--txt2); }
.donut-list .di { display: flex; align-items: center; gap: 8px; margin-bottom: 9px; font-size: 13px; }
.donut-list .di i { width: 10px; height: 10px; border-radius: 2px; }
@media (max-width: 1100px) { .grid-2, .grid-2-1 { grid-template-columns: 1fr; } }
