@charset "UTF-8";
:root{--bg:#0b0f14;--surface:#121820;--surface-raised:#19212b;--border:#26313c;--muted:#a0adbb;--text:#edf3f8;--green:#83e8bc;--amber:#ffcc80;--red:#ff9393;--blue:#8cbcff;--sidebar:238px;font-family:Inter,-apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif;font-size:16px;color:var(--text);background:var(--bg);font-synthesis:none}
*{box-sizing:border-box}body{margin:0}a{color:inherit;text-decoration:none}button,input,select,textarea{font:inherit}button,a,input,select,textarea{-webkit-tap-highlight-color:transparent}button{cursor:pointer}button:disabled{opacity:.5;cursor:wait}button:focus-visible,a:focus-visible,input:focus-visible,select:focus-visible,textarea:focus-visible{outline:2px solid var(--green);outline-offset:4px}p{line-height:1.6;margin:10px 0 0}h1,h2,h3{margin:0;font-weight:560;letter-spacing:-.035em}h1{font-size:clamp(2rem,3vw,2.75rem);line-height:1.15}h2{font-size:1.125rem;letter-spacing:-.02em}h3{font-size:1.2rem;line-height:1.3}small{font-size:.8125rem}strong{font-weight:580}.muted{color:var(--muted)}.mono,code{font-family:"SFMono-Regular",Consolas,monospace;font-size:.8125rem}.separator{padding:0 10px;color:var(--border)}
.sidebar{width:var(--sidebar);position:fixed;inset:0 auto 0 0;background:#10151c;border-right:1px solid var(--border);padding:32px 18px 0;display:flex;flex-direction:column;z-index:10}.brand{display:flex;gap:12px;align-items:center;padding:0 10px;margin-bottom:56px;font-size:1.3rem;letter-spacing:.15em;font-weight:650}.brand-mark{height:40px;width:36px;display:grid;place-items:center;background:var(--green);color:#102a22;font-size:1.65rem;border-radius:2px;transform:skew(-7deg);font-weight:700}.brand-sub{display:block;font-size:.625rem;letter-spacing:.07em;color:var(--muted);white-space:nowrap;margin-top:5px}.brand-sub b{margin-left:3px;color:var(--green)}.sidebar nav{display:grid;gap:6px}.sidebar nav a{display:flex;align-items:center;gap:12px;padding:14px;font-size:.875rem;color:#aebbca;border:1px solid transparent;border-radius:5px}.sidebar nav a:hover{color:var(--text);background:#18212a}.sidebar nav a.active{color:var(--green);background:#182a27;border-color:#28463b}.nav-icon{font-size:1.3rem;font-weight:400;width:20px;text-align:center}.sidebar-bottom{margin-top:auto;padding:24px 12px 0}.user-row{display:flex;align-items:center;gap:10px;margin-top:26px;padding:22px 0;border-top:1px solid var(--border);font-size:.8125rem}.avatar{display:grid;place-items:center;height:34px;width:34px;background:#26313d;color:#d1dbe7;border-radius:50%;font-size:.8rem}.user-row small{display:block;color:var(--muted);font-size:.6875rem;margin-top:3px}.user-row form{margin-left:auto}.icon-button{border:0;background:transparent;color:var(--muted);font-size:1.3rem;padding:8px;display:inline-block}.icon-button:hover{color:var(--green)}
.workspace{margin-left:var(--sidebar);min-height:100vh;display:flex;flex-direction:column}.environment-banner{min-height:32px;padding:8px 36px;background:#303020;border-bottom:1px solid #504b2e;color:#efda95;letter-spacing:.08em;font-size:.6875rem;display:flex;align-items:center;gap:10px}.banner-detail{letter-spacing:0;color:#c9c3a5;margin-left:8px}.topbar{height:48px;border-bottom:1px solid var(--border);padding:0 36px;display:flex;align-items:center;justify-content:flex-end;font-size:.8125rem}.topbar-right{display:flex;align-items:center;gap:22px;color:var(--muted);font-variant-numeric:tabular-nums}.version-tag{font-size:.625rem;font-weight:650;letter-spacing:.13em;border:1px solid var(--border);padding:6px 8px;border-radius:3px;color:var(--muted)}main{padding:38px 36px 26px;flex:1;min-width:0}.page-heading{display:flex;align-items:center;justify-content:space-between;gap:24px;margin-bottom:30px}.eyebrow{font-size:.6875rem;letter-spacing:.16em;color:#9dafbd;margin-bottom:13px;font-weight:600}.page-heading p{font-size:.875rem;color:var(--muted);margin-top:10px}.heading-actions{display:flex;gap:22px;align-items:center}.refresh-status{display:flex;align-items:center;gap:7px;font-size:.75rem;color:var(--muted)}.signal-dot,.dot{display:inline-block;width:6px;height:6px;border-radius:50%;background:var(--green);flex-shrink:0}.signal-dot{box-shadow:0 0 0 4px #83e8bc0c}.refresh-status.failed{color:var(--red)}.refresh-status.failed .signal-dot{background:var(--red)}.button{display:inline-flex;justify-content:center;align-items:center;gap:14px;min-height:42px;border:1px solid transparent;border-radius:5px;padding:10px 15px;font-size:.8125rem;font-weight:550;white-space:nowrap}.button.primary{background:var(--green);color:#092519}.button.primary:hover{background:#a2f5ce}.button.secondary{background:#17202a;border-color:#34404d;color:#dce6ef}.button.secondary:hover{background:#25313d}.wide{width:100%;justify-content:space-between}.stat-grid{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:16px;margin-bottom:32px}.stat-card{display:flex;flex-direction:column;background:var(--surface);border:1px solid var(--border);padding:21px 23px;border-radius:7px;min-height:158px}.stat-card>span{font-size:.8125rem;color:#b8c4d0;display:flex;gap:7px;align-items:center}.stat-card>strong{font-size:2.65rem;letter-spacing:-.055em;font-weight:480;font-variant-numeric:tabular-nums;line-height:1.15;margin:15px 0 12px}.stat-card>small{font-size:.6875rem;color:var(--muted);display:flex;justify-content:space-between;gap:8px}.stat-card.green>strong{color:var(--green)}.stat-card.amber>strong{color:var(--amber)}a.stat-card:hover{border-color:#526474}.green-dot{background:var(--green)}.amber-dot{background:var(--amber)}.gray-dot{background:#8191a1}.section-heading{display:flex;justify-content:space-between;align-items:center;gap:16px;margin-bottom:20px}.section-heading h2>span{font-size:.75rem;letter-spacing:0;color:#a6b9c9;background:#1d2935;border:1px solid #2c3e4b;padding:3px 7px;border-radius:4px;margin-left:8px}.section-heading>.muted{font-size:.75rem}.section-heading p{font-size:.8125rem;margin:7px 0 0}.filters{display:flex;align-items:center;gap:10px;margin-bottom:22px}.search-field{position:relative;flex:1}.search-field>span{position:absolute;left:13px;top:7px;font-size:1.5rem;color:#8393a3}.search-field input{padding-left:40px}input,select,textarea{background:#111820;color:var(--text);border:1px solid #303d49;border-radius:4px;min-height:42px;padding:10px 12px;font-size:.875rem;width:100%}input::placeholder{color:#8e9dad}select{width:auto;min-width:135px}.clear-filter{color:var(--muted);font-size:.8125rem;padding:10px}.machine-grid{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:18px}.machine-card{background:var(--surface);border:1px solid var(--border);border-radius:7px;padding:21px;overflow:hidden;transition:border-color .15s,transform .15s;min-width:0}.machine-card:hover{border-color:#607a8a}.machine-card.has-alert{border-color:#735a36}.card-top{display:flex;align-items:center;justify-content:space-between;gap:8px;margin-bottom:18px}.model-chip{font-family:"SFMono-Regular",Consolas,monospace;font-size:.6875rem;letter-spacing:.04em;color:#aebfd0;padding:4px 6px;background:#1b2530;border:1px solid #2b3948;border-radius:3px}.status-pill{font-size:.6875rem;display:inline-flex;align-items:center;gap:6px;padding:5px 8px;border-radius:3px;background:#1b322c;color:var(--green);white-space:nowrap}.status-pill.offline,.status-pill.waiting,.status-pill.disabled{background:#242b33;color:#b2bdc9}.status-pill.offline .dot,.status-pill.waiting .dot,.status-pill.disabled .dot{background:#96a2af}.machine-meta{font-size:.6875rem;color:#a3b0be;margin-top:8px;line-height:1.5;overflow-wrap:anywhere}.machine-meta span{padding:0 5px}.card-items{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:16px 15px;margin-top:18px;padding-top:18px;border-top:1px solid var(--border)}.card-item{min-width:0}.card-item>span{display:block;font-size:.6875rem;color:var(--muted);margin-bottom:7px}.card-value>strong{display:block;font-size:1.95rem;letter-spacing:-.055em;font-weight:450;font-variant-numeric:tabular-nums;line-height:1.2;white-space:nowrap}.card-value>strong small{font-size:.8125rem;color:#9aafbe;margin-left:5px;letter-spacing:0}.freshness{display:block;font-size:.625rem;font-style:normal;color:#e7c99c;margin-top:5px}.freshness.not_sent{color:#8a98a6}.uncertain{color:#a2adba}.pad-heading{display:flex;justify-content:space-between;font-size:.625rem;color:var(--muted);margin-bottom:10px}.pads{display:flex;gap:6px;flex-wrap:wrap}.pad{flex:1;min-width:34px;background:#18282a;border:1px solid #2a4142;padding:7px 4px 8px;text-align:center;border-radius:3px}.pad>span{font-size:.5625rem;display:block;color:#aac5c3}.pad>strong{display:block;font-weight:500;font-variant-numeric:tabular-nums;font-size:.8125rem;margin-top:5px;color:#d1eee1;white-space:nowrap}.pad strong small{font-size:.6875rem}.pad-unknown{background:#1a2129;border-color:#303b45}.pad-unknown strong{color:#a4b1bd}.card-bottom{border-top:1px solid var(--border);display:flex;align-items:center;justify-content:space-between;gap:8px;min-height:45px;margin:18px 0 -21px;font-size:.6875rem}.card-alert{color:var(--amber);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.card-arrow{font-size:1.1rem;color:#a5b7c5}.empty-state{grid-column:1/-1;text-align:center;border:1px dashed #344552;border-radius:7px;padding:65px 25px;background:#10161d}.empty-symbol{display:block;font-size:2.3rem;color:var(--green);margin-bottom:16px}.empty-state p{max-width:540px;margin:12px auto 22px;color:var(--muted);font-size:.875rem}.panel{background:var(--surface);border:1px solid var(--border);border-radius:7px;padding:25px;margin-bottom:22px;min-width:0}.back-link{color:var(--muted);font-size:.8125rem;display:inline-block;margin-bottom:24px}.back-link:hover{color:var(--green)}.notice{padding:15px 18px;margin-bottom:22px;border:1px solid #345044;background:#172e26;border-radius:5px;color:#bbe4d0;font-size:.875rem;line-height:1.5}.notice.warning{border-color:#5c4b32;background:#2b241b;color:#e7c99c}.now-metrics{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,190px),1fr));gap:12px;margin-top:16px}.now-metric{border:1px solid #2d3c45;background:#162126;padding:16px 18px;border-radius:5px;min-width:0}.now-metric>.muted{font-size:.8125rem}.big-metric{font-size:2.55rem;letter-spacing:-.055em;line-height:1.2;margin:16px 0 9px;font-variant-numeric:tabular-nums}.big-metric small{color:var(--muted);font-size:1rem;margin-left:5px}.quality-label{color:var(--muted);font-size:.6875rem}.chart{min-height:245px;display:flex;align-items:center;justify-content:center;overflow:hidden}.chart svg{width:100%;height:250px;display:block}.chart text{font-family:inherit;font-size:12px;fill:#9cb0c0}.chart-line{fill:none;stroke-width:2;vector-effect:non-scaling-stroke}.chart-grid{stroke:#293542;stroke-width:1;stroke-dasharray:3 5}.chart-axis{stroke:#394958;stroke-width:1}.chart-legend{display:flex;gap:18px;flex-wrap:wrap;min-height:20px;font-size:.75rem;margin-top:12px;color:#b5c4d1}.chart-legend>span{display:flex;align-items:center;gap:6px}.legend-dot{width:8px;height:8px;border-radius:50%;display:inline-block}.chart-footnote{font-size:.6875rem;color:var(--muted);line-height:1.5;margin-top:16px}.range-tabs{display:flex;border:1px solid #334150;border-radius:4px;overflow:hidden}.range-tabs button,.range-tabs a{font-size:.75rem;padding:8px 12px;color:#aebdcc;border:0;background:transparent;white-space:nowrap}.range-tabs .selected{background:#2c3e49;color:#e3f3f2}.range-tabs button:hover,.range-tabs a:hover{background:#22323c}.detail-columns{display:grid;grid-template-columns:1fr 1fr;gap:20px}.small-chart,.small-chart svg{min-height:200px;height:200px}.table-scroll{overflow:auto}table{width:100%;border-collapse:collapse;text-align:left;white-space:nowrap}th{font-size:.6875rem;color:#a6b7c6;font-weight:500;padding:14px 16px 14px 0;border-bottom:1px solid #344350}td{padding:17px 16px 17px 0;border-bottom:1px solid #25313c;font-size:.8125rem;color:#d2dee8}tr:last-child td{border:0}td small{display:block;font-size:.6875rem;color:var(--muted);margin-top:5px}.table-link{color:var(--green)}.form-panel{max-width:750px}.form-panel p{font-size:.875rem;line-height:1.6;margin-bottom:22px}.form-field{margin-bottom:22px}label{display:block;font-size:.875rem;color:#c4d0da;margin-bottom:9px}.form-field small{display:block;color:var(--muted);font-size:.75rem;line-height:1.5;margin-top:8px}.form-field select{width:100%}.checkbox-field{display:flex;flex-wrap:wrap;flex-direction:row-reverse;align-items:center;justify-content:flex-end;gap:12px}.checkbox-field input{width:20px;min-height:20px;accent-color:var(--green);flex:none}.checkbox-field label{flex:1;line-height:1.5;margin:0}.errorlist,.error{color:var(--red);font-size:.8125rem;line-height:1.5}.error{margin-bottom:18px}.alert-item{display:flex;align-items:center;gap:22px}.alert-symbol{color:var(--amber);font-size:1.75rem}.alert-body{flex:1}.alert-body .eyebrow{margin-bottom:9px;font-size:.625rem}.alert-body p{font-size:.875rem;color:#c5d1db;margin-bottom:12px}.alert-body>.muted{font-size:.6875rem}.facts{margin:20px 0 0}.facts>div{display:flex;justify-content:space-between;gap:16px;border-bottom:1px solid var(--border);padding:14px 0;font-size:.8125rem}.facts>div:last-child{border:0}.facts dt{color:var(--muted)}.facts dd{margin:0;text-align:right}
.login-workspace{margin:0}.login-workspace main{padding:0;display:flex;align-items:center;justify-content:center;min-height:calc(100vh - 32px)}.login-layout{width:min(1100px,100%);padding:70px 40px;display:grid;grid-template-columns:1.2fr 1fr;gap:100px;align-items:center}.wordmark{font-size:1.6rem;letter-spacing:.15em;font-weight:600;margin-bottom:100px;color:#dcf1e9}.wordmark span{font-size:.75rem;font-weight:400;letter-spacing:.2em;display:block;margin-top:7px;color:var(--muted)}.login-intro .eyebrow{color:var(--green)}.login-intro h1{font-size:clamp(2.5rem,4vw,3.9rem);line-height:1.1;margin-top:25px;letter-spacing:-.055em}.login-intro p{color:var(--muted);max-width:400px;margin-top:25px;font-size:.9375rem}.login-grid{display:flex;gap:25px;font-size:.625rem;letter-spacing:.08em;color:#9ab2bd;border-top:1px solid var(--border);margin-top:70px;padding-top:22px}.login-card{padding:36px;background:var(--surface);border:1px solid #334450;border-radius:8px}.login-card h2{font-size:1.75rem}.login-card>.muted{font-size:.875rem;margin-bottom:30px}.login-card input{margin-bottom:22px;min-height:47px}.login-card .button{margin-top:7px;min-height:47px}.login-foot{margin-top:27px;text-align:center;color:#91a5b5;font-size:.6875rem}.preview-access{padding:16px;background:#21261e;border:1px solid #3b4732;border-radius:4px;margin-top:24px;color:#c7d7b5;font-size:.75rem}.preview-access span,.preview-access strong{display:block;margin-bottom:6px}.preview-access code{font-size:.6875rem;color:#e0ecd1}
html:has(>body.tv-mode){scrollbar-gutter:stable}.tv-mode .sidebar{display:none}.tv-mode .workspace{margin:0}.tv-mode .topbar{height:44px}.tv-mode main{padding:25px 30px}.tv-mode .page-heading{margin-bottom:20px}.tv-mode h1{font-size:2rem}.tv-mode .page-heading p,.tv-mode .page-heading .eyebrow,.tv-mode .filters,.tv-mode #customize-cards,.tv-mode #live-region>.section-heading{display:none}.tv-mode .stat-grid{margin-bottom:22px}.tv-mode .stat-card{padding:12px 22px;min-height:84px;display:grid;grid-template-columns:1fr auto;align-items:center;gap:5px 20px}.tv-mode .stat-card>strong{grid-column:2;grid-row:1/3;margin:0}.tv-mode .stat-card small{grid-column:1}.tv-mode .machine-grid{grid-template-columns:repeat(auto-fit,minmax(290px,1fr))}.tv-mode .machine-card{padding-top:17px}.tv-mode .card-value>strong{font-size:2.15rem}.tv-mode .refresh-status{font-size:.875rem}
@media(min-width:1700px){.machine-grid{grid-template-columns:repeat(4,minmax(0,1fr))}main{padding:42px 45px}.topbar,.environment-banner{padding-left:45px;padding-right:45px}}
@media(max-width:1250px){:root{--sidebar:210px}.sidebar{padding-left:10px;padding-right:10px}.brand{gap:10px;font-size:1.15rem}.brand-sub{font-size:.5625rem}.sidebar nav a{font-size:.8125rem}.machine-grid{grid-template-columns:repeat(2,minmax(0,1fr))}.heading-actions{gap:12px;flex-direction:column;align-items:flex-end}.stat-card{padding:18px 16px}.stat-card>span{font-size:.75rem}.stat-card small{line-height:1.5}.detail-columns{grid-template-columns:1fr}.stat-grid{gap:12px}main{padding:30px 24px}.topbar,.environment-banner{padding-left:24px;padding-right:24px}.alert-item{flex-wrap:wrap}}
@media(max-width:850px){:root{--sidebar:0px}.sidebar{position:static;width:auto;flex-direction:row;padding:15px 20px;border-right:0;border-bottom:1px solid var(--border);gap:25px;overflow:auto}.brand{margin:0;padding:0;font-size:1rem;gap:10px;flex:none}.brand-mark{height:30px;width:27px;font-size:1.3rem}.brand-sub{font-size:.5rem}.sidebar nav{display:flex;gap:4px}.sidebar nav a{white-space:nowrap;font-size:.75rem;padding:8px 12px}.nav-icon{display:none}.sidebar-bottom{display:none}.workspace{margin:0}.topbar{height:44px}.stat-card>strong{font-size:2.3rem}.filters{flex-wrap:wrap}.search-field{flex-basis:100%}.filters select{flex:1}.login-layout{gap:35px;padding:45px 30px}.wordmark{margin-bottom:65px}.login-grid{gap:12px}.login-card{padding:25px}.topbar-right{gap:10px}}
@media(max-width:600px){main{padding:28px 18px 20px}.environment-banner{padding:9px 18px;gap:6px;font-size:.5625rem}.banner-detail{font-size:.5625rem;margin-left:4px}.topbar{padding:0 18px}.topbar .version-tag{display:none}.topbar-right{font-size:.6875rem}.page-heading{align-items:flex-start;gap:14px;flex-wrap:wrap;margin-bottom:24px}.page-heading h1{font-size:2rem}.page-heading p{font-size:.8125rem}.heading-actions{width:100%;flex-direction:row;align-items:center;justify-content:space-between}.stat-grid{grid-template-columns:repeat(2,minmax(0,1fr));gap:10px;margin-bottom:25px}.stat-card{min-height:143px;padding:17px 14px}.stat-card>span{font-size:.6875rem}.stat-card>strong{font-size:2.2rem}.stat-card small{font-size:.625rem}.machine-grid{grid-template-columns:1fr;gap:14px}.machine-card{padding-left:20px;padding-right:20px}.machine-card h3{font-size:1.3rem}.card-value>strong{font-size:2.15rem}.card-item>span,.pad-heading{font-size:.75rem}.pad>span{font-size:.625rem}.pad>strong{font-size:.875rem}.machine-meta,.card-bottom,.status-pill{font-size:.75rem}.panel{padding:20px}.now-metrics{gap:10px}.now-metric{padding:14px}.big-metric{font-size:2.15rem}.section-heading{flex-wrap:wrap}.range-tabs button,.range-tabs a{padding:8px 11px}.chart{min-height:220px}.chart svg{height:220px}.alert-item{gap:14px}.alert-body{flex-basis:80%}.alert-body h2{font-size:1.05rem}.alert-item form{margin-left:35px}.alert-body .eyebrow{font-size:.6875rem}.login-layout{display:block;padding:30px 20px}.login-intro{margin-bottom:35px}.wordmark{margin-bottom:35px;font-size:1.2rem}.login-intro h1{font-size:2.4rem}.login-intro p,.login-grid{display:none}.login-card{padding:28px 24px}.login-workspace main{align-items:flex-start}.login-intro .eyebrow{font-size:.625rem}.login-intro h1 br{display:none}.tv-mode .machine-grid{grid-template-columns:1fr}.tv-mode main{padding:20px 18px}}
@media(prefers-reduced-motion:reduce){*{scroll-behavior:auto!important;transition:none!important}}

.pagination{display:flex;align-items:center;justify-content:space-between;gap:16px;margin-top:24px;color:var(--muted);font-size:.8125rem}.pagination>div{display:flex;align-items:center;gap:10px}@media(max-width:600px){.pagination{align-items:flex-start;flex-direction:column}}
.tv-mode .machine-card{padding:16px}.tv-mode .card-top{margin-bottom:12px}.tv-mode .card-items{margin-top:12px;padding-top:12px;gap:12px 15px}.tv-mode .card-value>strong{font-size:1.85rem}.tv-mode .pads{display:grid;grid-auto-flow:column;grid-auto-columns:minmax(0,1fr);gap:3px}.tv-mode .pad{min-width:0;padding:6px 1px}.tv-mode .pad>strong{font-size:.75rem}.tv-mode .card-bottom{min-height:36px;margin:12px 0 -16px}.tv-mode .machine-meta{font-size:.625rem}

.status-pill.identity_review{background:#382e1d;color:var(--amber)}.status-pill.identity_review .dot{background:var(--amber)}

/* Niori logo: white wordmark sits straight on the dark UI. */
.brand{flex-direction:column;align-items:stretch;gap:10px;letter-spacing:normal}.brand-logo{display:block;padding:6px 4px}.brand-logo img{display:block;width:100%;height:auto}.brand .brand-sub{margin-top:0;padding-left:4px}
.wordmark{display:inline-block;padding:6px 0}.wordmark img{display:block;width:220px;max-width:100%;height:auto}
@media(max-width:850px){.brand{flex-direction:row;align-items:center}.brand-logo{padding:4px 8px;border-radius:6px}.brand-logo img{width:auto;height:30px}.wordmark img{width:170px}}

/* Measurement history: stacked charts share one time axis and one y-axis gutter width. */
.history-heading{align-items:flex-start;gap:16px;flex-wrap:wrap}.history-controls{display:flex;gap:10px;flex-wrap:wrap;align-items:center}.zoom-controls{display:flex;border:1px solid #334150;border-radius:4px;overflow:hidden}.zoom-controls button{font-size:.75rem;padding:8px 11px;min-width:34px;color:#aebdcc;border:0;background:transparent;cursor:pointer}.zoom-controls button:hover{background:#22323c}.zoom-controls button+button{border-left:1px solid #334150}.zoom-controls .zoom-step{font-size:1.05rem;line-height:1;padding:6px 12px}.zoom-controls button:focus-visible{outline-offset:-3px} /* the group clips its edges, so the ring is drawn inside each button */.range-tabs button{cursor:pointer}
.history-stack{display:grid;gap:16px;margin-top:6px}.history-chart{margin:0;border-top:1px solid var(--border);padding-top:14px;min-width:0}.history-chart figcaption{display:flex;justify-content:space-between;font-size:.8125rem;font-weight:600;margin-bottom:6px}.history-canvas{position:relative;min-height:120px;min-width:0}.history-empty{padding:40px 0;text-align:center}
.history-canvas .uplot{font-family:inherit}.history-canvas .u-over{cursor:grab;touch-action:pan-y}.history-canvas .u-over.panning{cursor:grabbing}.history-canvas .u-legend{color:#b5c4d1;font-size:.75rem;text-align:left;margin-top:4px;max-width:100%}.history-canvas .u-legend tbody{display:flex;flex-wrap:wrap;gap:0 6px}.history-canvas .u-legend .u-marker{border-radius:50%}.history-canvas .u-legend th{font-weight:500}
.history-tip{position:absolute;z-index:5;pointer-events:none;background:#0f151c;border:1px solid #334150;border-radius:6px;padding:8px 10px;font-size:.75rem;line-height:1.55;color:var(--text);white-space:nowrap;box-shadow:0 6px 18px rgba(0,0,0,.45)}.history-tip strong{display:block;color:var(--muted);font-weight:500;margin-bottom:2px}.history-tip small{display:block;color:var(--muted);font-size:.68rem;margin:-2px 0 4px}.history-tip i{display:inline-block;width:8px;height:8px;border-radius:50%;margin-right:6px}
.cycle-table{margin-top:14px}.cycle-table td,.cycle-table th{white-space:nowrap}.cycle-table input{width:16px;height:16px;accent-color:var(--green);cursor:pointer}.cycle-chart{border-top:0;padding-top:4px}


/* Simplified fleet page: status boxes are the status filter; machine cards follow each user's layout. */
.status-boxes{margin-bottom:22px}.status-box{min-height:0;padding:17px 21px}.status-box>strong{font-size:2.3rem;margin:10px 0 8px}.status-box.selected{background:#15241f;border-color:#4f8a73;box-shadow:inset 0 0 0 1px #4f8a73}.status-box.selected>span{color:var(--text)}a.status-box.selected:hover{border-color:#6fb497}.tv-mode .status-box>strong{grid-row:1}.status-box.online>strong{color:var(--green)}.status-box.attention>strong{color:var(--amber)}.clear-filter[hidden]{display:none}
/* Cards per row: the CSP (style-src 'self') drops inline styles, so --cols is set here per class. At most --cols cards
   per row, never narrower than 230px so the fixed header (model chip + status pill) fits; 18px is the grid gap. */
.machine-grid.cols-1{--cols:1}.machine-grid.cols-2{--cols:2}.machine-grid.cols-3{--cols:3}.machine-grid.cols-4{--cols:4}.machine-grid.cols-5{--cols:5}.machine-grid.cols-6{--cols:6}
.machine-grid.cols-1,.machine-grid.cols-2,.machine-grid.cols-3,.machine-grid.cols-4,.machine-grid.cols-5,.machine-grid.cols-6{grid-template-columns:repeat(auto-fill,minmax(max(250px,(100% - (var(--cols) - 1) * 18px) / var(--cols) - 1px),1fr))}
.machine-card{container:card/inline-size}.card-top{flex-wrap:wrap}.machine-card h3{overflow-wrap:anywhere}.card-pads,.card-text{grid-column:1/-1}.card-text{display:flex;align-items:baseline;justify-content:space-between;gap:10px}.card-text>span{margin:0}.card-text>strong{font-size:.8125rem;font-weight:500;font-variant-numeric:tabular-nums;text-align:right}.card-pads>strong{display:block;font-size:1.3rem;font-weight:450}.pad-heading .freshness{display:inline;margin:0;font-size:inherit}.pad-not-sent{border-style:dashed}.card-value.not_sent>strong,.card-pads.not_sent>strong{color:#8a98a6}
@container card (max-width:250px){.card-items{grid-template-columns:minmax(0,1fr)}.card-value>strong{font-size:1.5rem}.tv-mode .pads{display:flex;flex-wrap:wrap}.tv-mode .pad{min-width:34px}}
@container card (max-width:150px){.card-value>strong{font-size:1.2rem}}
.card-dialog{width:min(460px,calc(100vw - 32px));max-height:calc(100vh - 32px);overflow:auto;background:var(--surface);color:var(--text);border:1px solid #334450;border-radius:8px;padding:24px;box-shadow:0 18px 50px rgba(0,0,0,.55)}.card-dialog::backdrop{background:rgba(5,8,12,.72)}.card-dialog h2{font-size:1.25rem}
.card-choices{list-style:none;margin:0 0 20px;padding:0;border:1px solid var(--border);border-radius:5px}.card-choice{display:flex;align-items:center;justify-content:space-between;gap:10px;padding:6px 8px 6px 12px;border-bottom:1px solid var(--border)}.card-choice:last-child{border-bottom:0}.card-choice label{display:flex;align-items:center;gap:10px;flex:1;min-height:36px;margin:0;font-size:.875rem;cursor:pointer}.card-choice input{width:18px;height:18px;min-height:0;padding:0;margin:0;flex:none;accent-color:var(--green)}
.move-buttons{display:flex;gap:4px}.move-buttons button{width:34px;height:34px;padding:0;border:1px solid #34404d;border-radius:4px;background:#17202a;color:#dce6ef;font-size:.9rem}.move-buttons button:hover:not(:disabled){background:#25313d}.move-buttons button:disabled{opacity:.35;cursor:default}.dialog-actions{display:flex;flex-wrap:wrap;gap:10px}
.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}

/* Machine page: Now panel with every heating pad, collapsed technical details. */
.last-report{margin-top:6px}.last-report strong{color:var(--text);font-weight:550}.last-report strong.uncertain{color:#a2adba}.now-metric .big-metric{margin:10px 0 4px}.now-metric.not_sent{background:#141b22;border-color:#28323c}.now-pads{margin-top:20px}.now-pads .pad{min-width:52px;padding:9px 4px 10px}.now-pads .pad>span{font-size:.6875rem}.now-pads .pad>strong{font-size:1rem}
.tech-details>summary{cursor:pointer;list-style:none}.tech-details>summary::-webkit-details-marker{display:none}.tech-details>summary::before{content:"▸ ";color:var(--muted)}.tech-details[open]>summary::before{content:"▾ "}
.tech-details>summary{display:flex;align-items:baseline;flex-wrap:wrap;gap:6px 14px}.tech-details>summary h2{display:inline}.tech-details>summary .muted{font-size:.75rem}.tech-details[open]>summary{margin-bottom:16px}

@media(max-width:600px){.machine-grid.cols-1,.machine-grid.cols-2,.machine-grid.cols-3,.machine-grid.cols-4,.machine-grid.cols-5,.machine-grid.cols-6{grid-template-columns:minmax(0,1fr)}
.heading-actions{flex-wrap:wrap}.status-box{padding:14px}.status-box>strong{font-size:2rem}.card-dialog{padding:20px 16px}
}

/* Flash messages float below the top bar and dismiss themselves (app.js); hovering keeps them open. */
.toasts{position:fixed;top:64px;right:24px;z-index:60;display:grid;gap:10px;width:min(400px,calc(100vw - 32px));pointer-events:none}.toast{pointer-events:auto;display:flex;align-items:flex-start;gap:12px;padding:13px 14px 13px 18px;border:1px solid #345044;background:#172e26;border-radius:6px;color:#bbe4d0;font-size:.875rem;line-height:1.5;box-shadow:0 10px 30px rgba(0,0,0,.45);animation:toast-in .2s ease-out;transition:opacity .3s,transform .3s}.toast>span{flex:1}.toast.leaving{opacity:0;transform:translateY(-8px)}.toast-close{flex:none;border:0;background:none;color:inherit;opacity:.7;font-size:1.15rem;line-height:1;padding:2px 4px;border-radius:4px}.toast-close:hover{opacity:1}@keyframes toast-in{from{opacity:0;transform:translateY(-8px)}}@media(max-width:600px){.toasts{top:auto;bottom:16px;right:16px}}@media(prefers-reduced-motion:reduce){.toast{animation:none;transition:none}}

/* Pinned machines. A card is a tile: the card link plus, as its sibling (never inside the link), the pin form laid over
   the top-right corner. The tile is the grid item and stretches; it carries the hover lift so the pin moves with it. */
.machine-tile{position:relative;display:flex;min-width:0;transition:transform .15s}.machine-tile:hover{transform:translateY(-2px)}.machine-tile>.machine-card{flex:1 1 auto}.machine-tile .card-top{padding-right:36px}.machine-tile>.pin-form{position:absolute;top:16px;right:13px;margin:0;z-index:1}
.pin-button{display:grid;place-items:center;width:34px;height:34px;padding:0;border:1px solid transparent;border-radius:5px;background:transparent;color:#8a98a6}.pin-button:hover{color:var(--text);background:#1b2530;border-color:#34404d}.pin-button[aria-pressed=true]{color:var(--green)}.pin-button[aria-pressed=true]:hover{color:#a2f5ce}.pin-button svg{width:17px;height:17px;fill:none;stroke:currentColor;stroke-width:1.8;stroke-linecap:round;stroke-linejoin:round}.pin-button[aria-pressed=true] .pin-head{fill:currentColor}
.machine-card.is-pinned{border-top-color:#4f8a73;box-shadow:inset 0 1px 0 #4f8a73}
.tv-mode .pin-form{display:none}.tv-mode .machine-tile .card-top{padding-right:0}
.device-actions{display:flex;align-items:center;gap:12px;flex:none}.device-actions .pin-button{border-color:#34404d;background:#17202a}.device-actions .pin-button:hover{background:#25313d}
/* Customize dialog: the pin section is ruled off above and below, so the card-layout buttons after it read as the
   dialog's own actions (Save, Cancel), not as more pin actions. */
.pin-section{margin:0 0 22px;padding:18px 0 20px;border-top:1px solid var(--border);border-bottom:1px solid var(--border)}.pin-section h3{font-size:.875rem;font-weight:560;letter-spacing:0;color:#c4d0da}.pin-list{margin:10px 0 0;padding-left:22px;font-size:.875rem;line-height:1.7}.pin-section p.muted{font-size:.75rem;margin:8px 0 0}.pin-section .dialog-actions{margin-top:14px}

/* Full screen (internally tv-mode). The toggle shows a maximize icon, or an x inside the mode, from its aria-pressed. */
.fullscreen-toggle{gap:8px}.fullscreen-toggle svg{width:16px;height:16px;flex:none;fill:none;stroke:currentColor;stroke-width:2;stroke-linecap:round;stroke-linejoin:round}.fullscreen-toggle[aria-pressed=true] .icon-enter,.fullscreen-toggle[aria-pressed=false] .icon-exit{display:none}
/* Idle (app.js, 3 s without movement): the Exit button fades but keeps its place, so the fitted layout never changes
   height, and the pointer hides. The faded button takes no taps, so a tap that wakes the screen cannot exit; keyboard
   focus keeps it visible and usable. */
.tv-mode #tv-toggle{transition:opacity .3s}.tv-mode.idle #tv-toggle:not(:focus-visible){opacity:0;pointer-events:none}.tv-mode.idle,.tv-mode.idle *{cursor:none}
/* Rotation: a large page count and a thin bar filling over the 20 s, inside .pagination so the fit measures them. */
.tv-mode .pagination{flex-direction:row;align-items:center;justify-content:flex-start;gap:20px}.tv-mode .page-summary,.tv-mode .page-links{display:none}
.page-count{font-size:1.5rem;font-weight:560;letter-spacing:-.02em;line-height:1.2;color:var(--text);font-variant-numeric:tabular-nums;white-space:nowrap}
.rotation-progress{display:block;flex:1 1 auto;min-width:60px;height:4px;border-radius:2px;background:var(--border);overflow:hidden}.rotation-progress>i{display:block;height:100%;background:var(--green);transform:scaleX(0);transform-origin:left center;animation:rotation-fill 20s linear forwards}
@keyframes rotation-fill{from{transform:scaleX(0)}to{transform:scaleX(1)}}
body:not(.tv-mode) .page-count,body:not(.tv-mode) .rotation-progress{display:none}
/* "Showing only" chip: full screen hides the filters, so the header names them. One line, so the header height the fit
   measured never changes when it appears. A long filter shortens what it names, never the "N of M machines" count. */
.filter-chip{display:none}.tv-mode .filter-chip:not([hidden]){display:flex;gap:.3em;flex:0 1 auto;min-width:0;margin-right:auto;overflow:hidden;white-space:nowrap;padding:7px 14px;border:1px solid #6b5530;border-radius:999px;background:#2f2617;color:var(--amber);font-size:.9375rem;font-weight:550}.filter-chip .filter-what{min-width:0;overflow:hidden;text-overflow:ellipsis}.filter-chip .filter-count{flex:none}

/* Connection lost (app.js adds body.stale). In full screen the bar is fixed, so it never changes the layout height the fit
   measures; values dim; every status badge reads Unknown, including badges in markup a refresh has just replaced. The
   bar takes its own taps, so none reaches a link hidden under it. In the normal view on narrow screens it sits in the flow
   (first in <body>, sticky), so it pushes the nav strip down instead of covering it. On the synthetic preview it covers
   the watermark banner, so it names the preview itself. */
.stale-bar{display:none}
.stale .stale-bar{display:flex;position:fixed;top:0;left:0;right:0;z-index:80;align-items:center;justify-content:center;flex-wrap:wrap;padding:10px 24px;background:#7a1f24;border-bottom:2px solid var(--red);color:#fff;font-size:1rem;font-weight:550;line-height:1.4;text-align:center;box-shadow:0 6px 24px rgba(0,0,0,.5)}.stale .stale-bar strong{font-weight:700;white-space:nowrap}.stale .stale-bar span{white-space:pre-wrap}
@media(min-width:900px){.tv-mode.stale .stale-bar{font-size:1.25rem;padding:12px 30px}}
@media(max-width:600px){.stale .stale-bar{display:block;padding:8px 14px;font-size:.875rem}}
@media(max-width:850px){.stale:not(.tv-mode) .stale-bar{position:sticky}}
[data-environment=synthetic].stale .stale-bar::before{content:"Synthetic preview · ";white-space:pre}
.stale .machine-card{filter:saturate(.25)}.stale .machine-card>:not(.card-top),.stale .machine-card .model-chip,.stale .status-box,.stale .detail-metrics,.stale #device-heading .last-report,.stale #reading-evidence .table-scroll{opacity:.45;filter:saturate(.25)}
.stale .status-pill{background:#242b33;color:#b2bdc9}.stale .status-pill .dot{background:#96a2af}.stale .status-pill .pill-label{display:none}.stale .status-pill::after{content:"Unknown"}
.stale .refresh-status{color:var(--red)}.stale .refresh-status .signal-dot{background:var(--red)}.stale .rotation-progress>i{animation-play-state:paused}

/* Period (period.js): one control above the measurement history that also sets the processing cycles. "Custom…" opens
   an inline panel of two native date fields; [hidden] must win over the panel's own display. The button group clips its
   corners, so the focus ring is drawn inside each button. */
.period-panel{padding:18px 25px}.period-row{display:flex;align-items:center;flex-wrap:wrap;gap:10px 16px}.period-row h2{font-size:.9375rem}
.period-options{display:flex;border:1px solid #334150;border-radius:4px;overflow:hidden}.period-options button{font-size:.75rem;min-height:34px;padding:8px 12px;color:#aebdcc;border:0;border-left:1px solid #334150;background:transparent;white-space:nowrap}.period-options button:first-child{border-left:0}.period-options button:hover{background:#22323c}.period-options button[aria-pressed=true]{background:#2c3e49;color:#e3f3f2}.period-options button:focus-visible{outline-offset:-3px}
.period-label{margin:0;font-size:.8125rem;font-variant-numeric:tabular-nums}
.period-custom{display:grid;gap:12px;max-width:520px;margin-top:14px;padding-top:14px;border-top:1px solid var(--border)}.period-custom[hidden]{display:none}
.period-fields{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,150px),1fr));gap:10px}.period-field{min-width:0}.period-field label{font-size:.75rem;margin-bottom:6px}.period-field input{min-height:40px;padding:8px 10px}.period-field input[aria-invalid=true]{border-color:var(--red)}
.period-error{margin:0;color:var(--red);font-size:.8125rem;line-height:1.5}.period-error:empty{display:none}.period-actions{display:flex;flex-wrap:wrap;gap:10px}.period-actions .button{min-height:38px;padding:8px 16px}
@media(max-width:600px){.period-panel{padding:16px 20px}.period-options{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));width:100%}.period-options button{padding:8px 4px;white-space:normal}}

/* ⓘ info notes: a section's routine explanation, beside its heading or controls (app.js). The note hangs below the
   row it sits in (.info-row), from the row's right edge (left edge with .info-start) and never wider than that row,
   so it fits a phone screen and the Customize dialog. Full screen shows no ⓘ. */
.info-tip{position:relative}.info-button{width:30px;height:30px;border-radius:50%;border:1px solid #334150;background:transparent;color:#aebdcc;font:italic 600 .95rem/1 Georgia,"Times New Roman",serif;cursor:pointer;display:inline-grid;place-items:center}.info-button:hover,.info-button[aria-expanded=true]{background:#22323c;color:var(--text)}.info-pop{position:absolute;right:0;top:calc(100% + 8px);z-index:30;width:min(340px,calc(100vw - 40px));background:var(--surface-raised);border:1px solid var(--border);border-radius:8px;padding:14px 16px;box-shadow:0 10px 30px rgba(0,0,0,.45);font-size:.8125rem;line-height:1.5;color:var(--text);text-align:left}.info-pop[hidden]{display:none}.info-pop ul{margin:8px 0 0;padding-left:18px}.info-pop li{margin:4px 0}.info-pop p{margin:10px 0 0;color:var(--muted);font-size:inherit}.chart-footnote[hidden]{display:none}
.info-pop>:first-child{margin-top:0}.info-pop>strong{display:block}.info-pop>*+strong{margin-top:14px}.info-tip.compact .info-button{width:24px;height:24px;font-size:.8125rem}
.info-row{position:relative}.info-row .info-tip{position:static}.info-row .info-pop{width:min(340px,100%)}.info-row.info-start .info-pop{left:0;right:auto}
.page-heading>.info-tip{align-self:center;margin:0 auto 0 -12px}@media(max-width:600px){.page-heading>.info-tip{margin-left:0}}
.panel-title{display:flex;align-items:center;justify-content:space-between;gap:12px}.dialog-heading{display:flex;align-items:center;justify-content:space-between;gap:12px;margin-bottom:18px}.pin-heading{display:flex;align-items:center;justify-content:space-between;gap:12px}.now-pads .pad-heading{align-items:center}.pad-title{display:flex;align-items:center;gap:8px}.period-row .info-tip{margin-left:auto}
.tv-mode .info-tip{display:none}
/* Registry machine page: held reports, profile preview and the onboarding steps. */
th small{display:block;font-size:.625rem;color:var(--muted);font-weight:400;margin-top:4px}th small.problem,.held-table .problem{color:var(--amber)}.held-table tr.unmapped td{color:var(--muted)}.profile-text{min-height:280px;font-family:"SFMono-Regular",Consolas,monospace;font-size:.75rem;line-height:1.5;resize:vertical}.findings{margin:18px 0 0;padding-left:20px;color:var(--amber);font-size:.8125rem;line-height:1.6}.form-panel .findings{margin:0 0 22px}.draft-form{margin-bottom:26px;padding-bottom:22px;border-bottom:1px solid var(--border)}.form-panel .section-heading{margin-bottom:14px}.facts dd small{display:block;font-size:.6875rem;color:var(--muted);margin-top:4px}
.backfill-result h3{margin:28px 0 12px;font-size:.9375rem}.backfill-result .confirm-form{margin-top:24px}
.report-form{display:flex;align-items:center;flex-wrap:wrap;gap:10px;margin-top:20px;padding-top:20px;border-top:1px solid var(--border)}.report-form label{margin:0 6px 0 0;font-size:.8125rem}

/* Portfolio demo banner: Niori ember rather than the preview amber. */
.portfolio-banner{background:#24140c;border-bottom-color:#5a2a10;color:#f3a46d}
