/* Fira Code is self-hosted on purpose.
           The Google Fonts build of Fira Code is subsetted down to 456 glyphs and keeps only
           calt/dnom/frac/locl/numr, which drops the OpenType features that control the shape of
           the zero. Its zero is then permanently the slashed glyph, and that cannot be turned off
           from CSS -- font-feature-settings: 'zero' 0 has nothing to act on. The full 6.2 release
           keeps zero/ss05/ss06 alongside the rest, so the plain zero becomes selectable again.
           Variable font, one 113 KB file covering weights 300-700. */
        @font-face {
            font-family: 'Fira Code';
            font-style: normal;
            font-weight: 300 700;
            font-display: swap;
            /* Relative to this stylesheet's document (/admin/), so the font lives one level up at
               the webapp root. A bare 'fonts/...' would resolve to /admin/fonts/ and 404, which
               fails silently -- the browser just falls back to monospace and the slashed zero
               comes back with it. */
            src: url('../fonts/FiraCode-VF.woff2') format('woff2-variations');
        }
        :root {
            /* Fira Code's default zero carries a diagonal stroke. Declared once here so every
               figure on the page -- card values, timestamps, device codes, coordinates -- picks
               it up, rather than repeating it per selector and forgetting one.
               'cv11' is the bare ring; 'zero' 0 guards in case the default ever flips; 'tnum'
               keeps digits tabular so columns of numbers line up.
               This inherits, but a component that sets its own `font:` shorthand resets it and
               needs its own copy -- the card value rule below does exactly that. */
            font-feature-settings: 'cv11' 1, 'zero' 0, 'tnum' 1;
            --color-primary: #1E293B; --color-on-primary: #FFFFFF; --color-secondary: #334155; --color-on-secondary: #FFFFFF;
            --color-accent: #22C55E; --color-on-accent: #0F172A; --color-background: #0F172A; --color-foreground: #F8FAFC;
            --color-card: #1B2336; --color-card-foreground: #F8FAFC; --color-muted: #272F42; --color-muted-foreground: #94A3B8;
            --color-border: #475569; --color-destructive: #EF4444; --color-ring: #FFFFFF;
            --surface-page: #F6F8F4; --surface-panel: rgba(255,255,255,.9); --surface-panel-solid: #FFFFFF;
            --surface-soft: #EEF5EC; --text-strong: #17221B; --text: #29352D; --text-secondary: #5F6F65; --text-muted: #718077;
            --border-soft: #DDE7DA; --border-strong: #B9C9B6; --success: #16834B; --warning: #B45309; --danger: #C9302C;
            --primary: var(--color-primary); --primary-dark: #0F172A; --bg: var(--surface-page); --card-bg: var(--surface-panel-solid);
            --sidebar-w: 224px; --header-h: 60px;
            --space-xs: 2px; --space-sm: 4px; --space-md: 8px; --space-lg: 12px; --space-xl: 16px; --space-2xl: 24px; --space-3xl: 32px;
            --radius-sm: 6px; --radius-md: 8px; --radius-lg: 10px;
            --shadow-sm: 0 1px 2px rgba(15,23,42,.06); --shadow-md: 0 8px 24px rgba(15,23,42,.08); --shadow-lg: 0 18px 48px rgba(15,23,42,.16);
        }
        * { margin: 0; padding: 0; box-sizing: border-box; }
        body { font-family: 'Fira Sans', 'Microsoft YaHei', 'PingFang SC', sans-serif; background: radial-gradient(circle at 20% -10%, rgba(34,197,94,.16), transparent 32%), linear-gradient(180deg, #F8FAF7 0%, var(--surface-page) 45%, #EEF4EA 100%); color: var(--text); min-height: 100vh; font-size: 14px; line-height: 1.55; }
        a { color: var(--primary); text-decoration: none; }
        button, input, select, textarea { font: inherit; }
        button, select, [onclick], .clickable { touch-action: manipulation; }
        :focus-visible { outline: 3px solid rgba(34,197,94,.45); outline-offset: 2px; }
        .btn, .icon-button {
            min-height: 40px; border-radius: var(--radius-sm); border: 1px solid transparent; cursor: pointer;
            transition: background .2s ease, border-color .2s ease, color .2s ease, box-shadow .2s ease, opacity .2s ease;
        }
        .btn { padding: 8px 14px; font-weight: 600; }
        .btn-primary { background: var(--color-accent); color: var(--color-on-accent); box-shadow: 0 10px 22px rgba(34,197,94,.18); }
        .btn-primary:hover { background: #16A34A; }
        .icon-button {
            display: inline-flex; align-items: center; justify-content: center; width: 40px; background: transparent;
            color: var(--text-strong); border-color: var(--border-soft);
        }
        .icon-button:hover { background: var(--surface-soft); border-color: var(--border-strong); }
        .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; }

        /* 登录页 */
        #loginPage {
            display: flex; justify-content: center; align-items: center; min-height: 100vh;
            background: radial-gradient(circle at 24% 20%, rgba(34,197,94,.26), transparent 30%), linear-gradient(135deg, #0F172A 0%, #1E293B 52%, #14532D 100%);
        }
        .login-box {
            background: rgba(255,255,255,.92); padding: 44px 40px; border-radius: var(--radius-lg); width: 390px;
            border: 1px solid rgba(255,255,255,.42); box-shadow: var(--shadow-lg); text-align: center; backdrop-filter: blur(16px);
        }
        .login-box h2 { margin-bottom: 8px; color: var(--primary); font-family: 'Fira Code', 'Microsoft YaHei', monospace; font-size: 22px; }
        .login-box .sub { color: var(--text-secondary); font-size: 13px; margin-bottom: 28px; }
        .login-box input {
            width: 100%; padding: 12px 14px; margin-bottom: 16px;
            border: 1px solid var(--border-soft); border-radius: var(--radius-md); font-size: 15px;
            transition: border-color 0.2s ease, box-shadow 0.2s ease;
        }
        .login-box input:focus { border-color: var(--color-accent); box-shadow: 0 0 0 3px rgba(34,197,94,.18); outline: none; }
        .login-box button {
            width: 100%; min-height: 44px; padding: 12px; background: var(--color-accent); color: var(--color-on-accent);
            border: none; border-radius: var(--radius-md); font-size: 16px; cursor: pointer; font-weight: 700;
            transition: background .2s ease, box-shadow .2s ease, opacity .2s ease;
        }
        .login-box button:hover { background: #16A34A; box-shadow: 0 10px 22px rgba(22,163,74,.24); }
        .login-error { color: var(--danger); margin-top: 12px; font-size: 13px; display: none; }

        /* 主框架 */
        #mainPage { display: none; visibility: hidden; min-height: 100vh; }
        #mainPage.ready { visibility: visible; }
        .sidebar {
            position: fixed; top: 0; left: 0; bottom: 0; width: var(--sidebar-w);
            background: linear-gradient(180deg, rgba(15,23,42,.98), rgba(30,41,59,.98)); color: #CBD5E1; z-index: 200; display: flex; flex-direction: column;
            transition: left 0.25s ease; border-right: 1px solid rgba(255,255,255,.12); box-shadow: 12px 0 32px rgba(15,23,42,.16);
        }
        .sidebar.collapsed { left: calc(var(--sidebar-w) * -1); }
        .sidebar-logo { padding: 0 20px; height: var(--header-h); display: flex; align-items: center;
            font-family: 'Fira Code', 'Microsoft YaHei', monospace; font-size: 17px; font-weight: 700; color: #fff; border-bottom: 1px solid rgba(255,255,255,0.08); }
        .sidebar-logo .dot { width: 8px; height: 8px; background: var(--color-accent); border-radius: 50%; margin-right: 10px; box-shadow: 0 0 0 4px rgba(34,197,94,.16); }
        .sidebar nav { flex: 1; padding: 12px 0; overflow-y: auto; }
        .sidebar .nav-item {
            display: flex; align-items: center; gap: 10px; min-height: 44px; padding: 10px 20px;
            cursor: pointer; font-size: 14px; transition: background .18s ease, color .18s ease, border-color .18s ease; border-left: 3px solid transparent;
            color: #B6C2D2; margin: 2px 0;
        }
        .sidebar .nav-item:hover { background: rgba(255,255,255,0.08); color: #F8FAFC; }
        .sidebar .nav-item.active {
            background: rgba(34,197,94,0.14); color: #fff; border-left-color: var(--color-accent);
        }
        .sidebar .nav-item .icon { font-size: 18px; width: 24px; text-align: center; filter: grayscale(.1); }
        .sidebar .nav-item .badge-count {
            margin-left: auto; background: var(--color-destructive); color: #fff; font-size: 11px;
            padding: 2px 8px; border-radius: 10px; font-weight: 600;
        }
        .sidebar-footer {
            padding: 12px 20px; border-top: 1px solid rgba(255,255,255,0.08); font-size: 13px;
        }
        .sidebar-footer button {
            width: 100%; min-height: 40px; padding: 8px; background: rgba(255,255,255,0.08); color: #D1D9E5;
            border: 1px solid rgba(255,255,255,0.12); border-radius: var(--radius-sm); cursor: pointer; font-size: 13px;
            transition: background .2s ease, color .2s ease;
        }
        .sidebar-footer button:hover { background: rgba(255,255,255,0.15); color: #fff; }

        /* 主内容区 */
        .main-content { margin-left: var(--sidebar-w); min-height: 100vh; transition: margin-left 0.25s ease; }
        .sidebar.collapsed ~ .main-content { margin-left: 0; }
        .topbar {
            position: sticky; top: 0; z-index: 50; height: var(--header-h);
            background: rgba(255,255,255,.88); border-bottom: 1px solid var(--border-soft); display: flex;
            align-items: center; justify-content: space-between; padding: 0 24px; backdrop-filter: blur(14px);
        }
        .breadcrumb { font-size: 13px; color: var(--text-secondary); }
        .breadcrumb span { color: var(--text-strong); }
        .breadcrumb a { color: var(--primary); cursor: pointer; }
        .breadcrumb .sep { margin: 0 6px; color: var(--text-muted); }

        .page-content { padding: var(--space-2xl); scroll-padding-top: calc(var(--header-h) + var(--space-xl)); }

        /* 统计卡片 */
        .stats-row { display: flex; gap: var(--space-xl); margin-bottom: var(--space-2xl); flex-wrap: wrap; }
        .stat-card {
            flex: 1; min-width: 160px; background: var(--surface-panel); padding: 18px 20px;
            border: 1px solid rgba(255,255,255,.7); border-radius: var(--radius-lg); box-shadow: var(--shadow-sm); display: flex;
            align-items: center; gap: 14px;
        }
        .stat-card .sc-icon {
            width: 44px; height: 44px; border-radius: 10px; display: flex;
            align-items: center; justify-content: center; font-size: 20px;
        }
        .stat-card .sc-icon.users { background: #E8EEF8; color: #1E293B; }
        .stat-card .sc-icon.devices { background: #DCFCE7; color: var(--success); }
        .stat-card .sc-icon.bound { background: #FEF3C7; color: var(--warning); }
        .stat-card .sc-icon.unbound { background: #FEE2E2; color: var(--danger); }
        .stat-card .sc-num { font-family: 'Fira Code', monospace; font-size: 26px; font-weight: 700; color: var(--text-strong); }
        .stat-card .sc-label { font-size: 12px; color: var(--text-secondary); }

        /* 面板 */
        .panel {
            background: var(--surface-panel); border: 1px solid rgba(185,201,182,.66); border-radius: var(--radius-lg); box-shadow: var(--shadow-sm);
            margin-bottom: var(--space-2xl); backdrop-filter: blur(10px);
        }
        .panel-header {
            padding: 14px 20px; border-bottom: 1px solid var(--border-soft); font-weight: 700;
            font-size: 15px; display: flex; align-items: center; justify-content: space-between;
            color: var(--text-strong); gap: var(--space-md); flex-wrap: wrap;
        }
        .detail-collapse-header { cursor: pointer; user-select: none; }
        .detail-collapse-header:hover { background: rgba(34,197,94,.08); }
        .detail-collapse-icon { color: var(--success); font-size: 15px; line-height: 1; font-weight: 700; }
        .detail-record-count { color: var(--text-muted); font-size: 12px; font-weight: 400; margin-left: 4px; }
        .detail-group-card { background: rgba(255,255,255,.72); border: 1px solid var(--border-soft); border-radius: var(--radius-lg); box-shadow: var(--shadow-sm); padding: 0 16px; margin-bottom: var(--space-2xl); }
        .detail-group-title { padding: 15px 4px 12px; color: var(--text-strong); font-size: 16px; font-weight: 700; border-bottom: 1px solid var(--border-soft); }
        .detail-group-card > .panel { margin: 12px 0; border: 1px solid var(--border-soft); box-shadow: none; }
        .detail-group-card > .panel:last-child { margin-bottom: 16px; }
        .detail-group-card > .panel .panel-header { min-height: 48px; }
        .detail-group-card > .panel .panel-body { border-radius: 0 0 8px 8px; }
        #deviceBasicData .panel { border: 2px solid rgba(34,197,94,.34); }
        #deviceBasicData .panel-header { background: rgba(34,197,94,.1); color: #14532D; font-size: 16px; }
        .panel-body { padding: 0; }

        /* 搜索 */
        .search-wrap { padding: 12px 20px; border-bottom: 1px solid var(--border-soft); }
        .search-wrap input {
            width: 100%; max-width: 360px; min-height: 40px; padding: 9px 14px; border: 1px solid var(--border-soft);
            border-radius: var(--radius-sm); font-size: 13px;
        }
        .search-wrap input:focus { border-color: var(--color-accent); box-shadow: 0 0 0 3px rgba(34,197,94,.14); outline: none; }

        /* 表格 */
        table { width: 100%; border-collapse: collapse; }
        th {
            background: rgba(238,245,236,.86); padding: 10px 14px; text-align: left; font-size: 12px;
            color: var(--text-secondary); border-bottom: 1px solid var(--border-soft); font-weight: 700; cursor: pointer;
            user-select: none; white-space: nowrap;
        }
        th:hover { color: var(--success); }
        th .sort-arrow { margin-left: 4px; font-size: 10px; }
        td { padding: 10px 14px; border-bottom: 1px solid #ECF1EA; font-size: 13px; color: var(--text); vertical-align: middle; }
        tr.clickable { cursor: pointer; transition: background 0.16s ease; }
        tr.clickable:hover { background: rgba(34,197,94,.1) !important; }
        .empty-row td { text-align: center; color: var(--text-muted); padding: 50px; }

        /* 徽章 */
        .badge {
            display: inline-block; padding: 3px 10px; border-radius: 999px;
            font-size: 11px; font-weight: 700; line-height: 1.45; border: 1px solid transparent;
        }
        .badge-bound { background: #DCFCE7; color: #166534; border-color: #BBF7D0; }
        .badge-unbound { background: #FEE2E2; color: #991B1B; border-color: #FECACA; }
        .badge-online { background: #DCFCE7; color: #166534; border-color: #BBF7D0; }
        .badge-offline { background: #F1F5F9; color: #475569; border-color: #E2E8F0; }

        /* 消息记录：手机号分组 → 组内按类型折叠 */
        .msg-type.tone-danger { background: #FEE2E2; color: #991B1B; border-color: #FECACA; }
        .msg-type.tone-info { background: #E8F0FE; color: #1A73E8; border-color: #D2E3FC; }
        .msg-type.tone-neutral { background: #F1F5F9; color: #475569; border-color: #E2E8F0; }
        .msg-type.tone-muted { background: #F5F3FF; color: #6D28D9; border-color: #DDD6FE; }
        .msg-type-raw { margin-left: 4px; font-size: 10px; color: #9aa0a6; }
        .msg-read { background: #F1F3F4; color: #5F6368; border-color: #E2E8F0; }
        .msg-unread { background: #DCFCE7; color: #166534; border-color: #BBF7D0; }
        tr.msg-row.unread td:first-child { box-shadow: inset 3px 0 0 #ef4444; }

        .msg-detail { padding: 10px 20px 14px; font-size: 12px; }
        .msg-detail-head {
            display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
            padding-bottom: 8px; border-bottom: 1px solid #E2E8F0;
        }
        .msg-detail-meta { color: #94a3b8; font-size: 11px; }
        .msg-detail-hint { color: #9aa0a6; font-size: 11px; }

        /* One collapsible section per message type inside a phone. The left rule carries the
           severity colour so the alarm bucket is identifiable before it is opened. */
        .msg-type-section {
            margin-top: 8px; border: 1px solid #E2E8F0; border-radius: 6px; overflow: hidden; background: #fff;
        }
        .msg-type-head {
            display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
            padding: 8px 12px; cursor: pointer; background: #FBFCFA;
            border-left: 3px solid #E2E8F0; transition: background .16s ease;
        }
        .msg-type-head:hover { background: #F3F7F1; }
        .msg-type-head.tone-danger { border-left-color: #DC2626; }
        .msg-type-head.tone-info { border-left-color: #1A73E8; }
        .msg-type-head.tone-neutral { border-left-color: #64748B; }
        .msg-type-head.tone-muted { border-left-color: #7C3AED; }
        .msg-type-caret { font-size: 11px; color: #94a3b8; }
        .msg-type-count { font-size: 12px; font-weight: 700; color: var(--text-strong); }
        .msg-type-latest {
            flex: 1; min-width: 120px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
            font-size: 12px; color: #6b7280;
        }
        .msg-type-latest-time { font-size: 11px; color: #9aa0a6; font-family: 'Fira Code', monospace; }

        .msg-type-body { border-top: 1px solid #EEF2F6; }
        .msg-item {
            display: flex; align-items: center; gap: 10px; padding: 7px 12px;
            border-bottom: 1px solid #F1F5F9; font-size: 12px;
        }
        .msg-item:last-child { border-bottom: 0; }
        .msg-item-pick { display: inline-flex; align-items: center; margin: 0; cursor: pointer; }
        .msg-item-time { min-width: 132px; font-size: 11px; color: #9aa0a6; font-family: 'Fira Code', monospace; }
        .msg-item-title { flex: 1; min-width: 140px; font-weight: 600; color: var(--text-strong); }
        .msg-item-body { flex: 2.5; min-width: 160px; color: #666; }
        /* pre-wrap keeps the newlines the alarm bodies carry; the collapsed view needs them gone
           without leaving the line-height behind as a gap, and display:none does exactly that
           where a font-size or line-height trick would leak into the expanded text. */
        .msg-preview { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
        .msg-full { white-space: pre-wrap; word-break: break-word; }
        .msg-item:not(.expanded) .msg-full { display: none; }
        .msg-del-btn {
            padding: 4px 12px; font-size: 11px; font-family: inherit; white-space: nowrap;
            border: 1px solid #f5c2c2; background: #fdecea; color: #c5221f;
            border-radius: 4px; cursor: pointer; font-weight: 600;
        }
        .msg-del-btn:hover { background: #fbd9d6; }

        /* 用户详情 */
        .back-btn {
            display: inline-flex; align-items: center; gap: 4px; min-height: 40px; padding: 7px 14px;
            border: 1px solid var(--border-soft); border-radius: var(--radius-sm); cursor: pointer; font-size: 13px;
            background: var(--surface-panel-solid); margin-bottom: 16px; color: var(--text-strong);
            transition: background .2s ease, border-color .2s ease, color .2s ease;
        }
        .back-btn:hover { background: var(--surface-soft); border-color: var(--border-strong); }
        .info-grid {
            display: grid; grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
            gap: 14px; margin-bottom: 20px;
        }
        .info-grid .info-item {
            background: var(--surface-panel-solid); padding: 14px 16px; border-radius: var(--radius-md);
            border: 1px solid var(--border-soft); box-shadow: var(--shadow-sm);
        }
        .info-grid .info-item label { font-size: 11px; color: var(--text-secondary); display: block; margin-bottom: 4px; }
        .info-grid .info-item .value { font-family: 'Fira Code', 'Microsoft YaHei', monospace; font-size: 15px; font-weight: 600; color: var(--text-strong); overflow-wrap: anywhere; }

        /* 设备详情表 */
        .ddt { background: var(--surface-panel-solid); border-radius: var(--radius-lg); overflow: hidden; margin-bottom: 20px; border: 1px solid var(--border-soft); }
        .ddt-row { display: flex; }
        .ddt-labels { background: var(--surface-soft); }
        .ddt-labels .ddt-cell { padding: 10px 16px; font-size: 11px; color: var(--text-secondary); font-weight: 700; text-transform: uppercase; letter-spacing: 0; }
        .ddt-values .ddt-cell { padding: 14px 16px; font-size: 14px; font-weight: 600; overflow-wrap: anywhere; }
        .ddt-cell { flex: 1; border-right: 1px solid var(--border-soft); }
        .ddt-cell:last-child { border-right: none; }

        /* 参数卡片 */
        .param-cards { display: flex; gap: 12px; margin-bottom: 20px; flex-wrap: wrap; }
        .param-card {
            flex: 1; min-width: 120px; background: var(--surface-panel-solid); padding: 16px;
            border-radius: var(--radius-lg); text-align: center; border: 1px solid var(--border-soft); box-shadow: var(--shadow-sm);
        }
        .param-card .p-label { font-size: 11px; color: var(--text-secondary); margin-bottom: 4px; }
        .param-card .p-value { font-family: 'Fira Code', monospace; font-size: 20px; font-weight: 700; color: var(--success); }

        /* 地图 */
        .map-wrap { margin-bottom: 20px; }
        .map-wrap .map-title {
            font-size: 15px; font-weight: 700; margin-bottom: 10px;
            display: flex; align-items: center; gap: 12px;
        }
        .map-wrap .map-title a { font-size: 12px; font-weight: 600; color: var(--success); }
        .photo-modal { display:none; position:fixed; inset:0; z-index:500; padding:24px; background:rgba(15,23,42,.62); align-items:center; justify-content:center; backdrop-filter: blur(4px); }
        .photo-modal.open { display:flex; }
        .photo-dialog { width:min(900px,100%); max-height:90vh; overflow:auto; background:#fff; border-radius:var(--radius-lg); box-shadow:var(--shadow-lg); border: 1px solid rgba(255,255,255,.5); }
        .photo-dialog-header { display:flex; justify-content:space-between; align-items:center; padding:16px 20px; border-bottom:1px solid var(--border-soft); font-weight:700; }
        .photo-dialog-close { border:0; background:transparent; font-size:24px; line-height:1; color:#64748b; cursor:pointer; }
        .photo-grid { display:grid; grid-template-columns:repeat(auto-fill,minmax(190px,1fr)); gap:14px; padding:20px; }
        .photo-card { border:1px solid #e2e8f0; border-radius:8px; overflow:hidden; background:#fff; }
        .photo-card img { display:block; width:100%; height:150px; object-fit:cover; background:#f1f5f9; }
        .photo-card time { display:block; padding:8px 10px; color:#64748b; font-size:12px; }
        .photo-empty { padding:44px 20px; text-align:center; color:#64748b; }
        .photo-folders { display:grid; grid-template-columns:repeat(auto-fill,minmax(190px,1fr)); gap:14px; padding:20px; }
        .photo-folder { border:1px solid var(--border-soft); border-radius:var(--radius-md); padding:16px; text-align:left; background:var(--surface-soft); color:var(--text-strong); cursor:pointer; font:inherit; transition: background .2s ease, border-color .2s ease; }
        .photo-folder:hover { background:#E1F3DF; border-color:var(--border-strong); }
        .photo-folder strong { display:block; margin:7px 0 3px; font-size:14px; }
        .photo-folder span { color:#64748b; font-size:12px; }
        .photo-folder-back { display:none; margin-left:auto; margin-right:12px; border:1px solid var(--border-soft); border-radius:5px; background:#fff; color:var(--primary); padding:5px 9px; cursor:pointer; font-size:12px; }
        .map-container { width: 100%; height: 400px; border-radius: var(--radius-lg); box-shadow: var(--shadow-sm); border: 1px solid var(--border-soft); }
        .map-placeholder {
            width: 100%; height: 300px; border-radius: var(--radius-lg); background: var(--surface-panel-solid);
            display: flex; flex-direction: column; justify-content: center; align-items: center;
            border: 2px dashed var(--border-strong); text-align: center; color: var(--text-secondary);
        }
        .location-info { display: flex; gap: 10px; margin-bottom: 10px; font-size: 12px; color: var(--text-secondary); flex-wrap: wrap; }
        .location-info span { background: var(--surface-soft); padding: 4px 10px; border-radius: var(--radius-sm); border: 1px solid var(--border-soft); }
        .home-summary-shell {
            margin: 0 0 20px;
            padding: 16px;
            border: 1px solid rgba(185,203,184,.56);
            border-radius: 8px;
            background: rgba(255,255,255,.72);
            box-shadow: var(--shadow-sm);
            backdrop-filter: blur(12px);
        }
        .home-summary-shell-header {
            display: flex;
            align-items: center;
            justify-content: space-between;
            gap: 12px;
            margin-bottom: 12px;
        }
        .home-summary-kicker {
            display: block;
            margin-bottom: 5px;
            color: var(--success);
            font-size: 11px;
            font-weight: 700;
            letter-spacing: .14em;
            text-transform: uppercase;
        }
        .home-summary-shell-header strong {
            color: var(--text-strong);
            font: 600 18px/1.1 'Fira Sans','Microsoft YaHei',sans-serif;
        }
        .home-summary-hint {
            color: var(--text-muted);
            font-size: 12px;
            white-space: nowrap;
        }
        .home-summary-carousel {
            display: grid;
            grid-template-columns: repeat(4, minmax(0, 1fr));
            gap: 14px;
        }
        .home-summary-carousel-card {
            position: relative;
            min-height: 136px;
            padding: 18px 18px 16px;
            overflow: hidden;
            display: flex;
            flex-direction: column;
            justify-content: space-between;
        }
        .home-summary-carousel-card.is-switching .home-summary-card-inner {
            opacity: 0;
            transform: translateY(8px);
        }
        .home-summary-card-inner {
            display: flex;
            flex-direction: column;
            gap: 10px;
            transition: opacity .22s ease, transform .22s ease;
        }
        .home-summary-carousel-toolbar { display: none; }
        /* The alarm card is the only clickable summary card; it opens the alarm detail dialog. */
        .home-summary-carousel-card.is-clickable {
            cursor: pointer;
            transition: box-shadow .2s ease, border-color .2s ease, transform .2s ease;
        }
        .home-summary-carousel-card.is-clickable:hover {
            box-shadow: var(--shadow-md);
            border-color: var(--border-strong);
            transform: translateY(-2px);
        }
        .home-summary-carousel-card.is-clickable:focus-visible {
            outline: 2px solid var(--primary);
            outline-offset: 2px;
        }
        .home-summary-card-more {
            position: absolute;
            right: 14px;
            bottom: 12px;
            font-size: 12px;
            font-weight: 600;
            color: var(--danger);
            opacity: .75;
            transition: opacity .2s ease;
        }
        .home-summary-carousel-card.is-clickable:hover .home-summary-card-more { opacity: 1; }
        .alarm-modal { display:none; position:fixed; inset:0; z-index:600; padding:24px; background:rgba(15,23,42,.62); align-items:center; justify-content:center; backdrop-filter: blur(4px); }
        .alarm-modal.open { display:flex; }
        .alarm-dialog { width:min(980px,100%); max-height:90vh; display:flex; flex-direction:column; background:#fff; border-radius:var(--radius-lg); box-shadow:var(--shadow-lg); border:1px solid rgba(255,255,255,.5); }
        .alarm-dialog-header { display:flex; align-items:center; gap:12px; padding:16px 20px; border-bottom:1px solid var(--border-soft); font-weight:700; }
        .alarm-dialog-header .alarm-dialog-sub { font-weight:400; font-size:12px; color:#64748b; }
        .alarm-dialog-close { margin-left:auto; border:0; background:transparent; font-size:24px; line-height:1; color:#64748b; cursor:pointer; }
        .alarm-dialog-close:hover { color:var(--text-strong); }
        .alarm-scopes { display:flex; align-items:center; gap:8px; padding:12px 20px 0; flex-wrap:wrap; }
        .alarm-scope { border:1px solid var(--border-soft); border-radius:10px; background:#fff; color:var(--text-secondary); padding:8px 16px; font:inherit; font-size:13px; font-weight:600; cursor:pointer; transition:background .2s ease, border-color .2s ease, color .2s ease; }
        .alarm-scope:hover { border-color:var(--border-strong); background:var(--surface-soft); }
        .alarm-scope.is-active { background:var(--primary); border-color:var(--primary); color:#fff; }
        .alarm-scope .alarm-scope-count { font-weight:400; opacity:.85; margin-left:4px; }
        .alarm-scope-hint { margin-left:auto; font-size:12px; color:#64748b; }
        .alarm-filters { display:flex; flex-wrap:wrap; gap:8px; padding:12px 20px 0; }
        .alarm-filter { border:1px solid var(--border-soft); border-radius:999px; background:#fff; color:var(--text-secondary); padding:6px 14px; font:inherit; font-size:13px; cursor:pointer; transition:background .2s ease, border-color .2s ease, color .2s ease; }
        .alarm-filter:hover { border-color:var(--border-strong); background:var(--surface-soft); }
        .alarm-filter.is-active { background:var(--primary); border-color:var(--primary); color:#fff; font-weight:600; }
        .alarm-body { padding:16px 20px 20px; overflow:auto; }
        .alarm-list { display:grid; gap:10px; }
        .alarm-item { border:1px solid var(--border-soft); border-left-width:4px; border-radius:8px; padding:12px 14px; background:#fff; }
        .alarm-item.level-warning { border-left-color:var(--danger); background:linear-gradient(90deg,#fff8f5 0%,#fff 60%); }
        .alarm-item.level-notice { border-left-color:#d9912b; background:linear-gradient(90deg,#fffaf0 0%,#fff 60%); }
        .alarm-item-head { display:flex; align-items:center; gap:8px; flex-wrap:wrap; margin-bottom:6px; }
        .alarm-tag { font-size:12px; font-weight:600; padding:2px 9px; border-radius:999px; }
        .alarm-tag.level-warning { background:#fdecea; color:#b3261e; }
        .alarm-tag.level-notice { background:#fdf3e2; color:#8a5a12; }
        .alarm-item-device { font-weight:600; font-size:13px; color:var(--text-strong); }
        .alarm-item-time { margin-left:auto; font-size:12px; color:#64748b; }
        .alarm-item-reason { font-size:13px; color:var(--text-strong); line-height:1.55; }
        .alarm-item-meta { display:flex; flex-wrap:wrap; gap:6px 14px; margin-top:8px; font-size:12px; color:#64748b; }
        .alarm-item-meta b { font-weight:600; color:var(--text-secondary); }
        .alarm-empty { padding:44px 20px; text-align:center; color:#64748b; }
        .home-summary-arrow {
            width: 32px;
            height: 32px;
            border: 1px solid var(--border-soft);
            border-radius: 999px;
            background: rgba(255,255,255,.82);
            color: var(--text-strong);
            font-size: 18px;
            line-height: 1;
        }
        .home-summary-arrow:hover {
            border-color: var(--border-strong);
            background: #fff;
            color: var(--success);
        }
        .home-summary-label {
            color: var(--text-secondary);
            font-size: 13px;
            font-weight: 600;
            letter-spacing: .01em;
            text-transform: none;
        }
        .home-summary-value {
            color: var(--text-strong);
            font-family: 'Fira Code', monospace;
            font-size: 26px;
            font-weight: 700;
            line-height: 1.1;
            white-space: nowrap;
            /* The plain zero needs cv11, and that is not the obvious answer.
               In Fira Code the default zero glyph is already the slashed one -- its third
               contour is a 4-point straight line running corner to corner. The features that
               select a zero do not remove that stroke, they replace it: 'zero' picks a dotted
               zero, 'cv13' a vertical-bar zero, 'ss05' the slashed one again.
               cv11 is the only one of them that is a bare ring with no mark inside, so that is
               what is asked for. See the character-variant table in the font's own documentation.
               'zero' 0 is kept as a belt-and-braces guard in case a future font build flips the
               default; 'tnum' keeps the digits tabular so figure columns stay aligned.
               This only works because the self-hosted @font-face above carries these features --
               against the Google Fonts subset, which drops them all, this silently does nothing. */
            font-feature-settings: 'cv11' 1, 'zero' 0, 'tnum' 1;
            font-variant-numeric: lining-nums tabular-nums;
        }
        .home-summary-unit { color: var(--text-muted); font-size: 12px; margin-left: 4px; font-weight: 400; }
        .home-summary-meta {
            color: var(--text-muted);
            font-size: 12px;
            overflow: hidden;
            text-overflow: ellipsis;
            white-space: nowrap;
        }
        .home-summary-card.alarm .home-summary-value { color: var(--danger); }
        .home-summary-card.online .home-summary-value { color: var(--success); }
        .home-summary-indicators { display: none; }
        .home-summary-dot {
            width: 8px;
            height: 8px;
            padding: 0;
            border: 0;
            border-radius: 999px;
            background: rgba(185,203,184,.95);
            opacity: .8;
        }
        .home-summary-dot.active {
            width: 24px;
            background: var(--color-accent);
            opacity: 1;
        }
        @media (max-width: 900px) {
            .home-summary-carousel { grid-template-columns: repeat(2, minmax(0, 1fr)); }
            .home-summary-carousel-card { min-height: 132px; }
        }
        @media (max-width: 560px) {
            .home-summary-shell { padding: 14px 12px 12px; }
            .home-summary-carousel { grid-template-columns: 1fr; }
        }
        @media (max-width: 420px) {
            .home-summary-carousel-card { min-height: 132px; padding: 14px; }
            .home-summary-value { font-size: 22px; }
        }
        /* Keep the map and summary cards within the first viewport when possible. */
        .home-map {
            width: 100%;
            /* Fill the space left after the topbar, page padding, panel header and summary cards. */
            height: max(260px, calc(100dvh - 310px));
            min-height: 260px;
        }
        @media (max-width: 700px) {
            .home-map {
                /* The summary becomes two rows on small screens. */
                height: max(240px, calc(100dvh - 365px));
                min-height: 240px;
            }
        }

        /* 设备详情信息卡片行。
           ⚠️ 2026-09-23 改，原写法 `repeat(3, 1fr)` + 默认 `align-items: stretch` 有两个毛病：
             ① 只有 2 个面板时（现在就是：硬件与固件信息 / 播种机全局设置）最右侧空出 1/3；
             ② **两个面板被强行拉成等高** —— 展开其中一个，另一个没展开的也被撑成同高，
                于是那张卡片是一整块空白（用户截图反馈"另一个却没有展开，呈现空白"）。
           改成 auto-fit 自适应列数 + align-items:start：有几个面板就铺满几列，
           每张卡片按自己的内容定高，折叠的那张就只剩标题栏。
           ⚠️ minmax 下限取 280px 不是随手写的：内容区窄于 2×280 时会自动折成 1 列，
              908px 视口（内容区约 612px）刚好还能保持并排，与用户原有的观感一致。
           原来 1100px / 700px 两条改列数的断点已随之删除 —— auto-fit 天然覆盖它们，
           留着只会变成"有规则没作用"的死代码。 */
        .info-cards-row {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
            align-items: start;
            gap: 16px;
            margin-bottom: 16px;
        }

        /* 分页 */
        .pagination { display: flex; gap: 8px; padding: 12px 20px; justify-content: center; align-items: center; }
        .pagination button {
            padding: 5px 12px; border: 1px solid #ddd; border-radius: 4px;
            background: #fff; cursor: pointer; font-size: 13px;
        }
        .pagination button:disabled { opacity: 0.4; cursor: default; }
        .pagination button.active { background: var(--primary); color: #fff; border-color: var(--primary); }
        .pagination select { padding: 5px 8px; border: 1px solid #ddd; border-radius: 4px; font-size: 13px; }

        /* ===== 响应式布局 ===== */
        @media (max-width: 1024px) {
            :root { --sidebar-w: 200px; }
            .stats-row { gap: 8px; }
            .stat-card { padding: 14px 12px; min-width: 130px; }
            .stat-card .sc-num { font-size: 20px; }
            .stat-card .sc-icon { width: 36px; height: 36px; font-size: 16px; }
            .param-cards { gap: 8px; }
            .param-card { min-width: 100px; padding: 12px; }
            .param-card .p-value { font-size: 16px; }
        }

        @media (max-width: 768px) {
            :root { --sidebar-w: 200px; }
            /* 侧边栏悬浮模式 */
            .sidebar { left: calc(var(--sidebar-w) * -1); z-index: 300; box-shadow: 4px 0 20px rgba(0,0,0,0.3); }
            .sidebar:not(.collapsed) { left: 0; }
            .sidebar ~ .main-content { margin-left: 0 !important; }
            /* 遮罩：用 main-content 的伪元素，遮挡在侧边栏之下 */
            .main-content { position: relative; }
            .sidebar:not(.collapsed) ~ .main-content::after {
                content: ''; position: fixed; inset: 0; background: rgba(0,0,0,0.35); z-index: 250;
            }
            /* 弹窗登录 */
            .login-box { width: min(92vw, 390px); padding: 32px 24px; }

            /* 统计卡片两列 */
            .stats-row { gap: 6px; }
            .stat-card { min-width: calc(50% - 6px); padding: 12px; }
            .stat-card .sc-num { font-size: 22px; }
            .stat-card .sc-icon { width: 38px; height: 38px; font-size: 18px; }

            /* 表格横向滚动 */
            .panel-body { overflow-x: auto; }
            table { min-width: 600px; font-size: 12px; }
            th, td { padding: 8px 10px; }

            /* 搜索框全宽 */
            .search-wrap input { max-width: 100%; }

            /* 面包屑 */
            .topbar { padding: 0 12px; }
            .page-content { padding: 12px; }

            /* 设备详情表 */
            .ddt-row { flex-wrap: wrap; }
            .ddt-cell { flex: 1 1 50%; min-width: 50%; border-bottom: 1px solid #e8e8e8; }

            /* 参数卡片两列 */
            .param-card { min-width: calc(50% - 6px); }

            /* 用户信息网格 */
            .info-grid { grid-template-columns: 1fr 1fr; gap: 8px; }

            /* 地图 */
            .map-container { height: 280px; }

            /* 顶栏 */
            .topbar { font-size: 13px; }
        }

        @media (max-width: 480px) {
            .stat-card { min-width: 100%; }
            .info-grid { grid-template-columns: 1fr; }
            .param-card { min-width: 100%; }
            .ddt-cell { flex: 1 1 100%; }
            .pagination { flex-wrap: wrap; gap: 4px; }
            .pagination button { min-height: 40px; padding: 4px 8px; font-size: 11px; }
            .panel-header, .search-wrap, .page-content { padding-left: 12px; padding-right: 12px; }
        }

        /* ===== 2026 workspace visual system ===== */
        :root {
            --color-accent: #c7f36b;
            --color-on-accent: #132018;
            --surface-page: #f2f4ef;
            --surface-panel: rgba(255,255,255,.94);
            --surface-panel-solid: #ffffff;
            --surface-soft: #e8eee4;
            --text-strong: #14221a;
            --text: #344239;
            --text-secondary: #64736a;
            --text-muted: #89958d;
            --border-soft: #dce5d9;
            --border-strong: #b9cbb8;
            --success: #2f8f62;
            --warning: #b66b2a;
            --danger: #bd4d46;
            --sidebar-w: 248px;
            --header-h: 72px;
            --shadow-sm: 0 8px 24px rgba(23, 42, 30, .055);
            --shadow-md: 0 18px 48px rgba(23, 42, 30, .10);
            --shadow-lg: 0 28px 80px rgba(7, 18, 13, .24);
        }

        html { background: #f2f4ef; }
        body {
            font-family: 'Fira Sans', 'Fira Sans', 'Microsoft YaHei', 'PingFang SC', sans-serif;
            background:
                radial-gradient(circle at 86% -8%, rgba(199,243,107,.26), transparent 27%),
                radial-gradient(circle at 16% 0%, rgba(91,171,143,.13), transparent 24%),
                linear-gradient(135deg, #f7f9f4 0%, #eef2ec 52%, #e8eee6 100%);
            color: var(--text);
            letter-spacing: 0;
        }
        body::before {
            content: '';
            position: fixed;
            inset: 0;
            pointer-events: none;
            opacity: .28;
            background-image: linear-gradient(rgba(20,34,26,.025) 1px, transparent 1px), linear-gradient(90deg, rgba(20,34,26,.025) 1px, transparent 1px);
            background-size: 36px 36px;
            mask-image: linear-gradient(to bottom, black, transparent 70%);
        }
        button, input, select, textarea { font-family: inherit; }
        .btn, .icon-button, .back-btn, .pagination button, .sidebar-footer button { border-radius: 5px; }
        .btn-primary {
            background: var(--color-accent);
            color: var(--color-on-accent);
            border-color: rgba(19,32,24,.08);
            box-shadow: 0 10px 24px rgba(142, 177, 69, .22);
        }
        .btn-primary:hover { background: #d7fb89; transform: translateY(-1px); }
        .btn, .icon-button, .back-btn, .pagination button { transition: transform .22s ease, background .22s ease, border-color .22s ease, box-shadow .22s ease, color .22s ease; }

        #loginPage {
            position: relative;
            overflow: hidden;
            background:
                radial-gradient(circle at 15% 20%, rgba(199,243,107,.18), transparent 24%),
                radial-gradient(circle at 82% 78%, rgba(84,164,124,.20), transparent 30%),
                #14251b;
        }
        #loginPage::before {
            content: 'FIELD / CONTROL';
            position: absolute;
            top: 12vh;
            left: 8vw;
            color: rgba(255,255,255,.09);
            font: 600 clamp(3rem, 10vw, 10rem)/.9 'Fira Sans', sans-serif;
            letter-spacing: -.04em;
        }
        #loginPage::after {
            content: '';
            position: absolute;
            right: -12vw;
            bottom: -20vw;
            width: 54vw;
            height: 54vw;
            border: 1px solid rgba(199,243,107,.26);
            border-radius: 50%;
            box-shadow: 0 0 0 36px rgba(199,243,107,.04), 0 0 0 72px rgba(199,243,107,.025);
        }
        .login-box {
            position: relative;
            z-index: 1;
            width: min(430px, calc(100vw - 32px));
            padding: 42px;
            background: rgba(255,255,255,.92);
            border: 1px solid rgba(255,255,255,.55);
            border-radius: 8px;
            box-shadow: var(--shadow-lg);
            text-align: left;
            backdrop-filter: blur(18px);
            animation: panel-in .7s cubic-bezier(.2,.8,.2,1) both;
        }
        .login-box::before {
            content: 'ADMIN CONSOLE';
            display: block;
            margin-bottom: 34px;
            color: var(--success);
            font-size: 11px;
            font-weight: 700;
            letter-spacing: .18em;
        }
        .login-box h2 {
            margin-bottom: 10px;
            color: var(--text-strong);
            font: 600 clamp(25px, 4vw, 34px)/1.06 'Fira Sans', 'Microsoft YaHei', sans-serif;
            letter-spacing: -.02em;
        }
        .login-box .sub { margin-bottom: 28px; color: var(--text-secondary); font-size: 14px; }
        .login-box input {
            min-height: 48px;
            margin-bottom: 14px;
            padding: 12px 14px;
            border-color: var(--border-soft);
            border-radius: 5px;
            background: rgba(255,255,255,.72);
        }
        .login-box button {
            min-height: 48px;
            border-radius: 5px;
            background: var(--text-strong);
            color: #fff;
            box-shadow: 0 12px 24px rgba(20,34,26,.18);
        }
        .login-box button:hover { background: #254230; }

        .sidebar {
            width: var(--sidebar-w);
            background: #14251b;
            border-right: 1px solid rgba(255,255,255,.08);
            box-shadow: 18px 0 44px rgba(11,26,17,.16);
        }
        .sidebar-logo {
            height: 88px;
            padding: 0 26px;
            border-bottom-color: rgba(255,255,255,.10);
            font: 600 18px/1 'Fira Sans', 'Microsoft YaHei', sans-serif;
            letter-spacing: -.02em;
        }
        .sidebar-logo .dot { width: 9px; height: 9px; margin-right: 12px; background: var(--color-accent); box-shadow: 0 0 0 5px rgba(199,243,107,.12); }
        .sidebar nav { padding: 26px 14px; }
        .sidebar .nav-item {
            min-height: 48px;
            margin: 4px 0;
            padding: 11px 14px;
            border-left: 0;
            border-radius: 5px;
            color: #a9b9ad;
            font-size: 14px;
        }
        .sidebar .nav-item:hover { background: rgba(255,255,255,.08); color: #fff; transform: translateX(2px); }
        .sidebar .nav-item.active {
            background: var(--color-accent);
            color: var(--color-on-accent);
            box-shadow: 0 12px 24px rgba(142,177,69,.15);
        }
        .sidebar .nav-item .icon { width: 28px; font-size: 17px; opacity: .9; }
        .sidebar-footer { padding: 18px 20px 22px; border-top-color: rgba(255,255,255,.10); }
        .sidebar-footer button { color: #c9d5cc; background: rgba(255,255,255,.06); border-color: rgba(255,255,255,.14); }
        .sidebar-footer button:hover { background: rgba(255,255,255,.12); color: #fff; }

        .main-content { transition: margin-left .35s cubic-bezier(.2,.8,.2,1); }
        .topbar {
            height: var(--header-h);
            padding: 0 30px;
            background: rgba(247,249,244,.78);
            border-bottom-color: rgba(185,203,184,.58);
            backdrop-filter: blur(18px);
        }
        .topbar .icon-button { width: 42px; min-height: 42px; background: rgba(255,255,255,.7); border-color: var(--border-soft); }
        .topbar .icon-button:hover { background: var(--text-strong); color: #fff; border-color: var(--text-strong); }
        .breadcrumb { color: var(--text-muted); font-size: 13px; letter-spacing: .01em; }
        .breadcrumb span { color: var(--text-strong); font-weight: 600; }
        .breadcrumb a { color: var(--success); }
        .page-content { max-width: 1560px; padding: 34px 34px 72px; }
        #listView { animation: panel-in .55s cubic-bezier(.2,.8,.2,1) both; }

        .panel {
            margin-bottom: 24px;
            background: rgba(255,255,255,.88);
            border: 1px solid rgba(185,203,184,.72);
            border-radius: 7px;
            box-shadow: var(--shadow-sm);
            backdrop-filter: blur(12px);
            overflow: hidden;
        }
        .panel:hover { box-shadow: var(--shadow-md); }
        .panel-header {
            min-height: 58px;
            padding: 16px 22px;
            color: var(--text-strong);
            border-bottom-color: var(--border-soft);
            font-size: 15px;
            letter-spacing: .01em;
        }
        .panel-header strong { color: var(--success) !important; font-size: 18px; }
        .home-summary-shell { margin-bottom: 24px; }
        .home-summary { gap: 14px; }
        .home-summary-card {
            position: relative;
            min-height: 128px;
            padding: 20px;
            border-radius: 7px;
            border: 1px solid rgba(185,203,184,.72);
            background: rgba(255,255,255,.86);
            box-shadow: var(--shadow-sm);
            overflow: hidden;
            animation: rise-in .6s cubic-bezier(.2,.8,.2,1) both;
        }
        .home-summary-card:nth-child(2) { animation-delay: .06s; }
        .home-summary-card:nth-child(3) { animation-delay: .12s; }
        .home-summary-card:nth-child(4) { animation-delay: .18s; }
        .home-summary-card::after {
            content: '';
            position: absolute;
            right: -22px;
            bottom: -28px;
            width: 108px;
            height: 108px;
            border: 1px solid rgba(47,143,98,.15);
            border-radius: 50%;
        }
        .home-summary-card.alarm { background: linear-gradient(135deg, #fff 0%, #fff4ef 100%); }
        .home-summary-card.online { background: linear-gradient(135deg, #fff 0%, #f0f8eb 100%); }
        .home-summary-label { color: var(--text-secondary); font-size: 12px; font-weight: 600; }
        .home-summary-value { margin-top: 14px; font: 600 clamp(30px, 3vw, 42px)/.9 'Fira Code', monospace; letter-spacing: -.04em; }
        /* The shorthand above resets font-feature-settings to normal, so the bare zero has to be
           requested again for the larger/mobile variants of this selector. */
        .home-summary-value { font-feature-settings: 'cv11' 1, 'zero' 0, 'tnum' 1; }
        .home-summary-value .home-summary-unit { font-family: 'Fira Sans','Microsoft YaHei',sans-serif; font-size: .38em; font-weight: 600; letter-spacing: 0; }
        .home-summary-meta { margin-top: 12px; color: var(--text-muted); font-size: 11px; }
        .home-map { min-height: 330px; height: max(330px, calc(100dvh - 350px)); filter: saturate(.82) contrast(1.03); }
        #homePanel .panel-header { background: #fff; }
        #homePanel .panel-header select, #homePanel .panel-header input {
            min-height: 34px;
            padding: 7px 10px !important;
            border: 1px solid var(--border-soft) !important;
            border-radius: 4px !important;
            background: #f7faf5;
            color: var(--text);
        }
        #homePanel .panel-header input { width: 220px !important; }

        .search-wrap { padding: 16px 22px; background: #fbfcfa; border-bottom-color: var(--border-soft); }
        .search-wrap input {
            min-height: 42px;
            max-width: 420px;
            padding: 10px 13px;
            border-color: var(--border-soft);
            border-radius: 4px;
            background: #fff;
        }
        .search-wrap input:focus, input:focus, select:focus, textarea:focus {
            border-color: var(--success) !important;
            box-shadow: 0 0 0 3px rgba(47,143,98,.14) !important;
            outline: none;
        }
        table { font-size: 13px; }
        th {
            padding: 12px 16px;
            background: #f2f6ef;
            color: var(--text-secondary);
            border-bottom-color: var(--border-soft);
            font-size: 11px;
            letter-spacing: .06em;
            text-transform: uppercase;
        }
        th:hover { color: var(--success); background: #ecf4e8; }
        td { padding: 14px 16px; color: var(--text); border-bottom-color: #edf1eb; }
        tr.clickable:hover { background: rgba(199,243,107,.16) !important; }
        .empty-row td { padding: 68px 20px; color: var(--text-muted); }
        .badge { padding: 4px 9px; border-radius: 4px; letter-spacing: .01em; }
        .badge-bound, .badge-online { background: #e7f6d9; color: #2a6a3e; border-color: #c8e7b1; }
        .badge-unbound { background: #fff0ee; color: #a94640; border-color: #f0c8c3; }
        .badge-offline { background: #eef1ef; color: #68766d; border-color: #dce4de; }

        .back-btn { margin-bottom: 22px; padding: 9px 14px; background: rgba(255,255,255,.82); color: var(--text-strong); border-color: var(--border-soft); }
        .back-btn:hover { background: var(--text-strong); color: #fff; border-color: var(--text-strong); transform: translateX(-2px); }
        .info-grid { gap: 12px; }
        .info-grid .info-item, .param-card {
            border-radius: 5px;
            border-color: var(--border-soft);
            background: #fbfcfa;
            box-shadow: none;
        }
        .info-grid .info-item .value { font-family: 'Fira Code', 'Microsoft YaHei', monospace; }
        .ddt { border-radius: 5px; border-color: var(--border-soft); box-shadow: none; }
        .ddt-labels { background: #edf4ea; }
        .ddt-labels .ddt-cell { color: var(--text-secondary); }
        .ddt-values .ddt-cell { color: var(--text-strong); }
        .map-wrap { padding: 22px; margin: 0 0 20px; }
        .map-wrap .map-title { margin-bottom: 12px; }
        .map-wrap .map-title a { padding: 5px 8px; border: 1px solid var(--border-soft); border-radius: 4px; background: #f7faf5; }
        .map-wrap .map-title a:hover { background: var(--text-strong); color: #fff; }
        .location-info span { padding: 6px 10px; border-radius: 4px; background: #f2f7ef; border-color: var(--border-soft); }
        .map-container, .map-placeholder { border-radius: 5px; border-color: var(--border-soft); }
        .map-placeholder { background: linear-gradient(135deg, #f8fbf6, #eef4ec); }
        .photo-dialog { border-radius: 7px; }
        .photo-card, .photo-folder { border-radius: 5px; }
        .pagination { padding: 16px 22px; }
        .pagination button { min-height: 34px; padding: 6px 11px; border-color: var(--border-soft); color: var(--text); }
        .pagination button.active { background: var(--text-strong); border-color: var(--text-strong); color: #fff; }
        .detail-collapse-header { background: #fbfcfa; }
        .detail-collapse-header:hover { background: #eff7ea; }
        .detail-collapse-icon { color: var(--success); }

        @keyframes panel-in { from { opacity: 0; transform: translateY(16px); } to { opacity: 1; transform: translateY(0); } }
        @keyframes rise-in { from { opacity: 0; transform: translateY(18px) scale(.985); } to { opacity: 1; transform: translateY(0) scale(1); } }
        @media (max-width: 768px) {
            .page-content { padding: 22px 14px 48px; }
            .topbar { padding: 0 14px; }
            .home-map { min-height: 260px; height: 52vh; }
            #homePanel .panel-header input { width: 100% !important; margin-left: 0 !important; }
            #homePanel .panel-header { align-items: flex-start; }
            .map-wrap { padding: 16px; }
        }
        @media (prefers-reduced-motion: reduce) {
            *, *::before, *::after { animation-duration: .01ms !important; transition-duration: .01ms !important; scroll-behavior: auto !important; }
        }

        /* Operations workspace refresh: calm paper surface, strong navigation contrast, faster scanning. */
        :root {
            --surface-page: #f4f6f1;
            --surface-panel: rgba(255,255,255,.96);
            --surface-panel-solid: #ffffff;
            --surface-soft: #edf2eb;
            --text-strong: #17221b;
            --text: #2d3931;
            --text-secondary: #66736b;
            --text-muted: #8b9690;
            --border-soft: #dce5dc;
            --border-strong: #b8c8b9;
            --success: #27764f;
            --color-accent: #d9912b;
            --color-on-accent: #1f170b;
            --sidebar-w: 248px;
            --header-h: 68px;
            --shadow-sm: 0 1px 2px rgba(23,34,27,.05);
            --shadow-md: 0 12px 28px rgba(23,34,27,.09);
        }
        body {
            background: #f4f6f1;
            color: var(--text);
            font-family: 'Fira Sans', 'Microsoft YaHei', 'PingFang SC', sans-serif;
        }
        #loginPage {
            background: radial-gradient(circle at 18% 14%, rgba(217,145,43,.18), transparent 28%), linear-gradient(135deg, #17221b, #294737 72%, #4e6d48);
        }
        .login-box { border-radius: 12px; width: min(410px, calc(100vw - 32px)); padding: 46px 42px; box-shadow: 0 24px 70px rgba(0,0,0,.24); }
        .login-box h2 { font-family: 'Fira Sans','Microsoft YaHei',sans-serif; letter-spacing: -.02em; font-size: 24px; }
        .login-box button { background: var(--color-accent); color: var(--color-on-accent); }
        .sidebar {
            background: #17221b;
            border-right: 1px solid rgba(255,255,255,.08);
            box-shadow: 12px 0 34px rgba(23,34,27,.12);
        }
        .sidebar-logo { height: var(--header-h); padding: 0 24px; font-family: 'Fira Sans','Microsoft YaHei',sans-serif; letter-spacing: .02em; }
        .sidebar-logo .dot { background: var(--color-accent); box-shadow: 0 0 0 4px rgba(217,145,43,.16); }
        .sidebar nav { padding: 18px 12px; }
        .sidebar .nav-item { min-height: 46px; padding: 11px 14px; border-left: 0; border-radius: 7px; color: #afbeb3; }
        .sidebar .nav-item:hover { background: rgba(255,255,255,.07); color: #fff; }
        .sidebar .nav-item.active { background: #2b4936; color: #fff; border-left: 0; box-shadow: inset 3px 0 var(--color-accent); }
        .sidebar .nav-item .icon { color: #d5e0d6; font-size: 17px; }
        .sidebar-footer { padding: 14px 18px 18px; }
        .sidebar-footer button { border-radius: 6px; color: #cad6cc; }
        .main-content { background: #f4f6f1; }
        .topbar { height: var(--header-h); padding: 0 30px; background: rgba(255,255,255,.9); border-bottom: 1px solid var(--border-soft); }
        .topbar .icon-button { border: 0; width: 36px; color: var(--text-secondary); }
        .topbar .icon-button:hover { background: var(--surface-soft); color: var(--text-strong); }
        .breadcrumb { font-size: 13px; font-weight: 600; letter-spacing: .01em; }
        .page-content { width: 100%; max-width: none; padding: 30px 34px 76px; }
        #listView::before { content: ''; display: none; }
        .panel { border-radius: 8px; border: 1px solid var(--border-soft); box-shadow: var(--shadow-sm); }
        .panel:hover { box-shadow: var(--shadow-md); }
        .panel-header { min-height: 56px; padding: 15px 20px; font-size: 14px; letter-spacing: .015em; }
        #homePanel .panel-header { gap: 10px; flex-wrap: wrap; background: #fff; }
        #homePanel .panel-header strong { order: 0; margin-left: auto; font-size: 14px; }
        #homePanel .panel-header select, #homePanel .panel-header input { background: #f8faf7; border-radius: 6px !important; min-height: 36px; }
        .home-map { min-height: 380px; height: min(60vh, 660px); filter: saturate(.72) contrast(1.02); }
        .home-summary { gap: 14px; margin: 0 0 22px; }
        .home-summary-card { min-height: 126px; padding: 20px; border-radius: 8px; border: 1px solid var(--border-soft); box-shadow: var(--shadow-sm); }
        .home-summary-card::after { border-color: rgba(217,145,43,.2); }
        .home-summary-card.alarm { background: linear-gradient(135deg,#fff,#fff6e8); }
        .home-summary-card.online { background: linear-gradient(135deg,#fff,#edf6ee); }
        .home-summary-value {
            margin-top: 12px;
            font-size: clamp(28px, 2.7vw, 38px);
            letter-spacing: -.03em;
            white-space: nowrap;
        }
        .search-wrap { padding: 13px 20px; background: #fafcf9; }
        .search-wrap input { border-radius: 6px; min-height: 40px; background: #fff; }
        table { table-layout: auto; }
        th { background: #f0f4ef; padding: 11px 15px; font-size: 11px; letter-spacing: .045em; }
        td { padding: 13px 15px; }
        tr.clickable:hover { background: #f7f9f4 !important; box-shadow: inset 3px 0 var(--color-accent); }
        .badge { border-radius: 999px; padding: 4px 9px; }
        .badge-bound, .badge-online { background: #e8f4e7; color: #276640; border-color: #c9e4c8; }
        .badge-unbound { background: #fff0dd; color: #9a5a16; border-color: #f3d4a6; }
        .badge-offline { background: #eef1ef; color: #66736b; border-color: #d9e1db; }
        .btn-primary { background: var(--color-accent); color: var(--color-on-accent); box-shadow: 0 7px 16px rgba(217,145,43,.2); }
        .btn-primary:hover { background: #c57e1f; }
        .back-btn { border-radius: 6px; }
        .map-wrap { padding: 20px; }
        .map-wrap .map-title a { border-radius: 999px; }
        .location-info span { border-radius: 999px; }
        .detail-collapse-header { background: #fafcf9; }
        .pagination button { border-radius: 5px; }
        /* ===== 重渲染时的滚动锚点（重要，改这块前先读）=====

           设备详情页每 2 秒重渲染一次（loadDeviceDetail 用 setInterval），
           重渲染时这几个容器全走 innerHTML = ''，整棵子树被换掉；
           被换掉的节点连带浏览器的滚动锚点一起消失，浏览器只能重新挑锚，
           实测会让 scrollY 一次跳 2400px 以上 —— 用户看到的就是
           "展开单体数据后页面被强制往上滑，停不到想看的区域"。

           解法：在这些**会被整块替换**的容器上关掉 overflow-anchor，
           让浏览器不要拿它们内部的节点当锚（它们随时会没）。
           关掉后实测同一场景位移从 +2436px 降到 −17px（噪声级）。
           父级 .page-content 保持 auto，让锚点落在稳定的外层内容上。

           注意：这里是**整块替换**的容器，不是"内容会变"的容器。
           只是文本变化（如表格数字刷新）不需要加这条。 */
        #deviceBasicData,
        #deviceInfoCards,
        #deviceUnitTables,
        #deviceUnitChart { overflow-anchor: none; }
        #deviceBasicData .device-basic-panel {
            overflow: hidden;
            border: 1px solid var(--border-soft);
            background: var(--surface-panel);
            box-shadow: var(--shadow-sm);
        }
        /* 基础数据标题：左侧面板名，右侧挂「任务名称」。
           注意 .panel-header 基类本来就是 flex + space-between，
           但这条规则把 justify-content 覆盖成了 flex-start ——
           如果只保留 flex-start，右侧 meta 会紧贴在标题后面而不是靠右，
           所以这里显式改回 space-between，并保留 flex-wrap 让窄屏自然折行。 */
        #deviceBasicData .device-basic-header {
            justify-content: space-between;
            min-height: 56px;
            border-bottom: 1px solid var(--border-soft);
            background: #fff;
            color: var(--text-strong);
            font: 700 16px/1.2 'Fira Sans','Microsoft YaHei',sans-serif;
            text-shadow: none;
        }
        /* 2026-09-20：标题右侧的「任务名称」胶囊**已整体删除**。
           任务名现在渲染在顶部 .basic-task-strip 最左侧的格子里（见 theme.css），
           同一个值只能留一处 —— 标题右侧再挂一个胶囊就是"同一值显示两遍"。
           随之删除的死规则（都只服务那个胶囊，已无任何元素匹配）：
             #deviceBasicData .basic-header-meta
             #deviceBasicData .basic-meta-item  /  .basic-meta-item em  /  .basic-meta-item b
           以及 575px 的标题折行断点块（那段是给胶囊算的阈值，胶囊没了就没有意义）。
           留住它们的害处不只是"多几行"：basic_totals_test 里有一组断言在检查
           "575px 断点仍存在且为 575" —— 规则还在、元素却不再渲染，
           断言会一直绿着，等于用一个假通过的测试把死代码锁死。 */
        /* 2026-09-20 第三版（状态前置）：本区块原有的以下规则**已随结构删除**：
             .device-basic-dashboard       双栏容器（主卡 | 330px 状态列）
             .basic-main-card              主卡（两带布局）
             .basic-gauge-band             圆环带（三列 / 两列）
             .basic-read-col / .basic-read-row   圆环两侧的读数栈与读数卡
           取而代之的是：
             .basic-main   成果卡 | 工况区 两列
             .basic-yield  成果卡（播种面积主数字）
             .basic-cells / .basic-cell / .basic-gauge-cell   工况区（圆环 + 读数格）
           ——为什么删而不是留着：规则还在、元素却不再渲染时，测试里那些
           "结构断言"会一直绿着，等于用假通过的测试把死代码锁死（这个坑踩过两次）。
           圆环本身的视觉（conic 渐变 + container-type）仍保留在下面，只是尺寸改由
           theme.css 的 `.basic-gauge{width:130px}` 控制。 */
        .basic-gauge {
            width: min(232px, 72%);
            aspect-ratio: 1;
            justify-self: center;
            display: grid;
            place-items: center;
            border-radius: 50%;
            background:
                radial-gradient(circle, #fff 0 50%, transparent 51%),
                repeating-conic-gradient(from -38deg, rgba(39,118,79,.82) 0deg 3.2deg, rgba(39,118,79,.12) 3.6deg 7deg, transparent 7.4deg 9deg),
                radial-gradient(circle, rgba(217,145,43,.14) 57%, transparent 58%),
                conic-gradient(from 210deg, rgba(217,145,43,.78) 0 238deg, rgba(184,200,185,.30) 238deg 360deg);
            box-shadow: inset 0 0 0 1px rgba(39,118,79,.12), 0 16px 36px rgba(23,34,27,.08);
        }
        .basic-gauge-core {
            width: 74%;
            height: 74%;
            display: flex;
            flex-direction: column;
            align-items: center;
            justify-content: center;
            border-radius: 50%;
            border: 1px solid var(--border-soft);
            background: #fff;
            text-align: center;
        }
        .basic-gauge-core span {
            color: var(--text-secondary);
            font-size: 14px;
            font-weight: 700;
            letter-spacing: .02em;
        }
        /* 内圈读数字号：必须由内圈尺寸反算，不能按视口写。
           内圈 = 圆环直径 × 74%。Fira Code 等宽、字符宽约 0.6em，
           "13.95" 是 5 字符 → 需要 3em 宽。
             圆环 300 → 内圈 222 → 上限 74.0px
             圆环 232 → 内圈 172 → 上限 57.3px
             圆环 194 → 内圈 144 → 上限 47.9px

           原来的 clamp(40px, 4.6vw, 68px) 是**按视口算的**，与圆环尺寸完全脱钩：
           实测 1584px 视口下取到上限 68px，需要 204px 宽度，而内圈只有 172px —— 
           "13.95" 左右各越出内圈 15px，直接压在色环刻度上（截图里 .95 已贴上环）。
           现在用容器查询单位 cqw 按圆环自身宽度算：
           内圈 = 74cqw，留 8% 余量 → 可用 68.1cqw，字号上限 = 68.1 ÷ 3 = 22.7cqw。 */
        .basic-gauge {
            container-type: inline-size;
        }
        .basic-gauge-core strong {
            margin-top: 8px;
            color: var(--text-strong);
            font: 700 clamp(38px, 4.6vw, 68px)/.92 'Fira Code', monospace;
            font-feature-settings: 'cv11' 1, 'zero' 0, 'tnum' 1;
            text-shadow: none;
        }
        @supports (font-size: 1cqw) {
            .basic-gauge-core strong {
                font-size: clamp(36px, 22cqw, 74px);
            }
        }
        .basic-gauge-core em {
            margin-top: 8px;
            color: var(--text-secondary);
            font-style: normal;
            font-size: 15px;
            font-weight: 700;
        }
        /* 2026-09-17 第四轮：原先的「指标带」（下种量 + 速度组 + 肥料组）已拆掉 —— 
           下种量/底肥量/口肥量三个读数移到圆环两侧的 .basic-read-col，
           速度三件套并入下面的合并带。随之删除的死规则：
           .basic-speed-row / .basic-speed-group / .basic-yield-stack /
           .basic-yield-card / .basic-yield-cell 及其全部派生规则（含 JS 里的 yieldCard()）。
           这些类名连同它们踩过的特异度坑一并消失，不再需要 :not(.basic-yield-card)
           之类的规避写法。 */
        /* 2026-09-20 第二版：连那条「合并带」本身也删掉了。
           用户截图反馈"这部分布局很混乱" —— 根因是左列只剩 2 张卡却要与约 480px 高的圆环
           并排，上下各留约 170px 死白；底部又横着一条 4 格的速度带，两种容器形状挤在一起。
           现在那 4 个读数搬进左列读数栈（6 张等高卡），主卡只剩圆环带一带。
           随之删除的死规则（已无任何元素匹配）：
             .basic-bottom-strip  /  .basic-strip-merged .basic-metric  /  .basic-metric
             及其 span / strong / small 派生规则，外加 768px、480px 两个断点里的底部条规则。
           留住它们不止是"多几行"：basic_totals_test 里有一组断言在检查底部条的结构，
           规则还在、元素却不再渲染 → 断言会一直绿着，等于用假通过的测试把死代码锁死。 */
        /* 2026-09-20 第三版：右列三张状态卡（.basic-side-stack / .basic-status-card /
           .basic-progress / .basic-fert-row）已整体删除 —— 状态被提到基础数据面板的
           第一行做成「状态带」（.basic-statebar，样式在 theme.css），机具/开关/GPS/肥箱
           降级成一行 chip。原因：全屏最重要的一句话"能不能播、为什么不能"原本在视线
           最后到达的位置。 */
        /* ===== 单体柱形统计图 =====
           放在基础数据与设备配置之间。三组指标量级差很大
           （播种数上千、肥量个位数），所以每组各自撑满图高（独立满量程），
           柱顶标真实值；跨组的柱高刻意不可比较。
           单体按 row_count 全部出柱，缺值的画虚线空柱并标「暂无」——
           画成 0 高柱会被误读成"该单体确实没播"。 */
        .unit-chart-panel {
            border: 1px solid var(--border-soft);
            background: var(--surface-panel);
            box-shadow: var(--shadow-sm);
            overflow: hidden;
        }
        .unit-chart-header {
            display: flex;
            flex-wrap: wrap;
            align-items: center;
            gap: 10px;
            min-height: 56px;
            padding: 10px 20px;
            border-bottom: 1px solid var(--border-soft);
            background: #fff;
        }
        .unit-chart-title {
            color: var(--text-strong);
            font: 700 16px/1.2 'Fira Sans','Microsoft YaHei',sans-serif;
            margin-right: auto;
        }
        /* 切换按钮：一行等宽的 pill。选中态用深绿实底，未选白底描边。 */
        .unit-chart-switch {
            display: flex;
            flex-wrap: wrap;
            gap: 6px;
        }
        .unit-chart-btn {
            padding: 7px 15px;
            border: 1px solid #cfe0d4;
            border-radius: 999px;
            background: #fff;
            color: #276640;
            font: 600 13px/1 'Fira Sans','Microsoft YaHei',sans-serif;
            cursor: pointer;
            transition: background .15s, color .15s, border-color .15s;
        }
        .unit-chart-btn:hover { border-color: #27764f; }
        .unit-chart-btn.is-active {
            background: #27764f;
            border-color: #27764f;
            color: #fff;
        }
        .unit-chart-btn small {
            margin-left: 5px;
            font-size: 11px;
            opacity: .72;
        }
        .unit-chart-body { padding: 20px; }
        /* 绘图区：左侧留出 Y 轴刻度，底部留出单体标签。
           高度固定，否则切到肥量组时整块会塌下去。 */
        .unit-chart-plot {
            display: grid;
            grid-template-columns: 54px minmax(0, 1fr);
            gap: 0 8px;
            min-height: 216px;
        }
        .unit-chart-axis {
            display: flex;
            flex-direction: column;
            justify-content: space-between;
            align-items: flex-end;
            color: var(--text-muted);
            font: 600 11px/1 'Fira Code', monospace;
        }
        /* 柱区用 flex 让每根柱等分宽度；柱数从 1 到 18 都要成立，
           所以柱宽不写死，由 flex:1 分配，柱间距用 gap。
           底部不再留 26px —— 序号已挪到柱区之外的 .unit-chart-labels。 */
        .unit-chart-bars {
            position: relative;
            display: flex;
            align-items: flex-end;
            gap: 6px;
            border-bottom: 1px solid var(--border-soft);
        }
        /* 横向网格线：3 条等分线，纯装饰，不参与命中 */
        .unit-chart-bars::before {
            content: '';
            position: absolute;
            inset: 0;
            pointer-events: none;
            background-image:
                linear-gradient(to bottom, var(--border-soft) 0 1px, transparent 1px);
            background-size: 100% 50%;
        }
        .unit-chart-col {
            flex: 1 1 0;
            min-width: 0;
            height: 100%;
            display: flex;
            flex-direction: column;
            justify-content: flex-end;
            align-items: center;
            /* 必须定位：下面的 .unit-chart-label 是 absolute，
               少了这句它会以 .unit-chart-bars 为基准，6 根柱的序号全叠在一起
               （视觉上就是底部出现一个糊掉的字符）。 */
            position: relative;
        }
        .unit-chart-bar {
            width: 100%;
            max-width: 46px;
            min-height: 3px;
            border-radius: 4px 4px 0 0;
            background: linear-gradient(180deg, #3E9A6B, #27764f);
            transition: height .28s ease;
        }
        /* 缺值是"没有读数"，不是 0：用虚线空柱 + 灰色，视觉上明确区别于低值。 */
        .unit-chart-col.is-empty .unit-chart-bar {
            background: repeating-linear-gradient(45deg, #e6ebe6 0 4px, #f6f8f6 4px 8px);
            border: 1px dashed #c3cdc4;
            border-bottom: 0;
            min-height: 26px;
        }
        .unit-chart-value {
            margin-bottom: 4px;
            color: var(--text-strong);
            font: 700 12px/1 'Fira Code', monospace;
            font-feature-settings: 'tnum' 1;
            white-space: nowrap;
        }
        .unit-chart-col.is-empty .unit-chart-value {
            color: var(--text-muted);
            font-weight: 600;
        }
        /* 柱很密时（柱宽装不下柱顶数字）不再标数字，改为鼠标悬停/点击看 title。
           18 单体在 390px 宽下每列只有约 14px，而 "1029" 要 33px ——
           硬标会互相压成一团黑，比不标更难读。
           渲染时按 row_count 判一个够宽的阈值加上这个类（见 renderUnitChart），
           不靠 CSS 媒体查询：断点取决于单体数，不是视口宽度。 */
        .unit-chart-bars.is-dense .unit-chart-value {
            display: none;
        }
        /* 单体序号行：必须与 .unit-chart-bars 的几何完全对齐，
           否则第 i 个序号对不上第 i 根柱。
           柱区在 .unit-chart-plot 这个 grid 的第 2 列，所以左边距要等于
           第 1 列宽 + gap（54px + 8px）——与上面 grid-template-columns 同源，
           改那两处必须同步改这里。再加同样的 gap 与 flex:1 1 0 等分。 */
        .unit-chart-labels {
            display: flex;
            gap: 6px;
            margin-top: 7px;
            margin-left: 62px;
            color: var(--text-secondary);
            font: 600 11px/1 'Fira Sans','Microsoft YaHei',sans-serif;
        }
        .unit-chart-label {
            flex: 1 1 0;
            min-width: 0;
            text-align: center;
            white-space: nowrap;
        }
        .unit-chart-foot {
            margin-top: 12px;
            display: flex;
            flex-wrap: wrap;
            gap: 6px 18px;
            color: var(--text-secondary);
            font: 600 12px/1.5 'Fira Sans','Microsoft YaHei',sans-serif;
        }
        .unit-chart-foot b {
            color: var(--text-strong);
            font-family: 'Fira Code', monospace;
            font-feature-settings: 'tnum' 1;
        }
        .unit-chart-empty {
            padding: 34px 0;
            text-align: center;
            color: var(--text-muted);
            font-size: 13px;
        }
        @media (max-width: 768px) {
            .unit-chart-header { padding: 10px 14px; }
            .unit-chart-body { padding: 16px 14px; }
            .unit-chart-plot { grid-template-columns: 42px minmax(0, 1fr); min-height: 180px; }
            /* 左列 42px + gap 8px —— 必须跟着上面的 grid-template-columns 一起改，
               否则序号行与柱子错位。 */
            .unit-chart-labels { margin-left: 50px; }
            .unit-chart-value { font-size: 11px; }
        }
        /* Compact homepage summary cards while preserving the four-column layout. */
        #listView {
            min-height: calc(100dvh - var(--header-h) - 34px);
            display: flex;
            flex-direction: column;
            margin-bottom: 0;
        }
        #homePanel {
            flex: 0 0 auto;
        }
        .home-summary-shell {
            /* Reserve the open space beneath the map for the summary block. */
            margin-top: auto;
            margin-bottom: 0;
            padding: 9px 12px 10px;
        }
        .home-summary-shell-header {
            margin-bottom: 5px;
        }
        .home-summary-shell-header strong {
            font-size: 16px;
        }
        .home-summary-carousel {
            margin-top: 10px;
        }
        .home-summary-carousel-card {
            min-height: 90px;
            padding: 10px 13px 9px;
        }
        .home-summary-card-inner {
            gap: 4px;
        }
        .home-summary-label {
            font-size: 12px;
        }
        .home-summary-value {
            font-size: clamp(22px, 2.1vw, 30px);
            white-space: nowrap;
        }
        .home-summary-meta {
            font-size: 10px;
        }
        .home-map {
            /* Fit the map and the complete summary block inside one desktop viewport. */
            min-height: 360px;
            height: max(360px, calc(100dvh - 430px));
        }
        @media (max-width: 900px) {
            .home-summary-carousel-card { min-height: 88px; }
        }
        @media (max-width: 560px) {
            #listView { min-height: calc(100dvh - var(--header-h) - 70px); }
            .home-summary-shell { margin-top: 20px; }
            .home-summary-shell { padding: 10px 11px 12px; }
            .home-summary-carousel { margin-top: 14px; }
        }
        @media (max-width: 768px) {
            .topbar { padding: 0 14px; }
            .page-content { padding: 22px 14px 48px; }
            #listView { min-height: calc(100dvh - var(--header-h) - 70px); margin-bottom: 0; }
            .home-map { min-height: 280px; height: 54vh; }
            #homePanel .panel-header { align-items: flex-start; }
            #homePanel .panel-header strong { margin-left: 0; }
            .home-summary { grid-template-columns: repeat(2, minmax(210px,1fr)); }
        }
        /* （此处原有 575px 的「标题右侧任务名称折行」断点块。
           它的唯一作用是让胶囊在窄屏独占一行 —— 胶囊已随顶部任务栏的引入删除，
           这块规则一并移除。断点阈值是按胶囊宽度实测出来的，胶囊没了便不再适用。） */
