/* ═══════════════════════════════════════════
   components.css — Modals, Toast, Notifications, Switches
   ═══════════════════════════════════════════ */

/* ── Modal (shared) ── */
.modal-mask{position:fixed;inset:0;background:rgba(0,0,0,.45);z-index:1200;display:flex;align-items:center;justify-content:center}
.modal-mask.is-hidden{display:none}
.modal-panel{width:680px;max-width:calc(100vw - 40px);background:var(--bg2);border:1px solid var(--border);border-radius:10px;overflow:hidden}
.modal-panel-wide{width:920px;max-width:calc(100vw - 40px)}
.modal-panel-xwide{width:1100px;max-width:calc(100vw - 40px)}
.modal-header{display:flex;align-items:center;justify-content:space-between;padding:12px 16px;background:var(--bg3);border-bottom:1px solid var(--border)}
.modal-header h3{font-size:var(--fs-title-section)}
.modal-body{padding:0;max-height:calc(100vh - 160px);overflow-y:auto}
.modal-footer{display:flex;justify-content:space-between;gap:8px;padding:12px 16px;border-top:1px solid var(--border);background:var(--bg3)}
.modal-left,.modal-right{display:flex;align-items:center;gap:8px}

/* ── Tag tabs ── */
.tag-tabs{display:flex;gap:0;border-bottom:2px solid var(--border);padding:0 16px;background:var(--bg3)}
.tag-tab{padding:10px 20px;font-size:var(--fs-body);color:var(--text2);cursor:pointer;border-bottom:2px solid transparent;margin-bottom:-2px;transition:color .15s,border-color .15s;user-select:none}
.tag-tab:hover{color:var(--text)}
.tag-tab.active{color:var(--cyan);border-bottom-color:var(--cyan);font-weight:600}
.tag-tab-panel{display:none}
.tag-tab-panel.active{display:block}

/* ── ECU Configuration · category picker ── */
.ecucfg-panel{width:min(960px,96vw)}
.ecucfg-panel .modal-body{padding:16px 22px 22px}

/* Select-ECU Step 1: keep header controls fixed, scroll only the ECU list */
#sj-tag-step1-body{display:flex;flex-direction:column;overflow:hidden}
#sj-tag-ecu-scroll{flex:1 1 auto;min-height:160px;overflow:auto}
.ecucfg-intro{font-size:12.5px;color:var(--text2);line-height:1.6;margin:2px 0 16px}
.ecucfg-cards{display:grid;grid-template-columns:1fr 1fr;gap:12px}
@media(max-width:640px){.ecucfg-cards{grid-template-columns:1fr}}
.ecucfg-card{display:flex;gap:12px;align-items:flex-start;text-align:left;padding:16px;background:var(--bg2);border:1.5px solid color-mix(in srgb,var(--cyan) 32%,var(--border));border-radius:10px;cursor:pointer;transition:border-color .14s,background .14s,transform .06s,box-shadow .14s}
.ecucfg-card:hover{border-color:var(--cyan);background:color-mix(in srgb,var(--cyan) 8%,var(--bg2));box-shadow:0 4px 16px color-mix(in srgb,var(--cyan) 22%,transparent)}
.ecucfg-card:active{transform:translateY(1px)}
.ecucfg-card-icon{flex:0 0 auto;font-size:20px;line-height:1;margin-top:1px}
.ecucfg-card-body{display:flex;flex-direction:column;gap:5px;min-width:0}
.ecucfg-card-title{display:flex;align-items:center;flex-wrap:wrap;gap:8px;font-size:14px;font-weight:700;letter-spacing:.01em;color:var(--text)}
.ecucfg-card-desc{font-size:12px;color:var(--text2);line-height:1.55}
.ecucfg-card-acr{display:flex;align-items:center;flex-wrap:wrap;gap:5px;margin:1px 0 2px}
.ecucfg-card-badge{font-size:9.5px;font-weight:700;letter-spacing:.04em;text-transform:uppercase;color:var(--yellow);background:color-mix(in srgb,var(--yellow) 14%,transparent);border:1px solid color-mix(in srgb,var(--yellow) 35%,transparent);border-radius:999px;padding:1px 8px}

/* ── ECU Configuration · module mockup (Step 3 preview) ── */
.ecucfg-mock-flag{font-size:11px;color:var(--text3);margin-right:12px;align-self:center}
.ecucfg-mock-intro{font-size:12.5px;color:var(--text2);line-height:1.6;margin:0 0 14px}
.ecucfg-mock-targets{font-size:12px;color:var(--text2);padding:8px 12px;margin:0 0 14px;background:var(--bg2);border:1px solid var(--border);border-radius:8px}
.ecucfg-mock-targets b{color:var(--text)}
.ecucfg-mock-row{display:flex;align-items:center;gap:12px;padding:7px 2px;border-bottom:1px solid color-mix(in srgb,var(--border) 60%,transparent)}
.ecucfg-mock-k{flex:0 0 168px;font-size:12px;color:var(--text2)}
.ecucfg-mock-v{flex:1 1 auto;display:flex;align-items:center;flex-wrap:wrap;gap:8px;font-size:12.5px;color:var(--text)}
.ecucfg-mock-hint{font-size:11px;color:var(--text3)}
.ecucfg-mock-input{padding:5px 8px;background:var(--bg3);border:1px solid var(--border);border-radius:6px;color:var(--text);font-size:12px;outline:none;min-width:80px}
.ecucfg-mock-input:focus{border-color:var(--cyan)}
.ecucfg-mock-toggle{display:inline-flex;align-items:center;gap:6px;font-size:12px;color:var(--text)}
.ecucfg-mock-subhead{font-size:11px;font-weight:700;letter-spacing:.05em;text-transform:uppercase;color:var(--text3);margin:16px 0 8px}
.ecucfg-mock-import{margin-top:6px}
.ecucfg-mock-step{display:flex;gap:8px;align-items:flex-start;font-size:12.5px;color:var(--text2);line-height:1.6;margin:6px 0}
.ecucfg-mock-num{flex:0 0 auto;display:inline-flex;align-items:center;justify-content:center;width:18px;height:18px;border-radius:50%;background:color-mix(in srgb,var(--cyan) 16%,transparent);border:1px solid color-mix(in srgb,var(--cyan) 40%,var(--border));color:var(--cyan);font-size:10px;font-weight:700;margin-top:1px}
.ecucfg-mock-sheets{margin:4px 0 4px 34px;padding:0;font-size:12px;color:var(--text2);line-height:1.7}
.ecucfg-mock-sheets b{color:var(--text)}
.ecucfg-mock-dropzone{margin:12px 0 2px;padding:18px;text-align:center;font-size:12.5px;color:var(--text3);background:var(--bg2);border:1.5px dashed color-mix(in srgb,var(--cyan) 35%,var(--border));border-radius:10px}
.ecucfg-mock-acr{display:flex;align-items:center;flex-wrap:wrap;gap:8px;margin:0 0 14px;padding:8px 12px;background:var(--bg2);border:1px solid var(--border);border-radius:8px}
.ecucfg-mock-acr-k{font-size:9px;font-weight:700;letter-spacing:.08em;text-transform:uppercase;color:var(--text3)}
.ecucfg-mock-acr-v{display:flex;flex-wrap:wrap;gap:6px}
.ecucfg-acr-chip,.ecucfg-acr-chip.is-pn{font-size:11px;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;color:var(--text2);background:var(--bg3);border:1px solid var(--border);border-radius:5px;padding:1px 7px}
.ecucfg-mock-note{margin:14px 0 2px;padding:9px 12px;font-size:11.5px;line-height:1.6;color:var(--text2);background:color-mix(in srgb,var(--yellow) 8%,transparent);border:1px solid color-mix(in srgb,var(--yellow) 28%,var(--border));border-radius:8px}
.ecucfg-mock-note b{color:var(--text)}

/* ── Sync Tag · Import wizard (Step 3) ── */
.tag-import-summary{display:flex;flex-wrap:wrap;gap:8px 24px;padding:10px 14px;margin:0 0 14px;background:var(--bg2);border:1px solid var(--border);border-radius:8px}
.tag-import-summary-item{display:flex;flex-direction:column;gap:2px;min-width:0}
.tag-import-summary-l{font-size:9px;font-weight:700;letter-spacing:.08em;text-transform:uppercase;color:var(--text3)}
.tag-import-summary-v{font-size:12px;color:var(--text)}

.tag-import-stepper{display:flex;flex-wrap:wrap;align-items:center;gap:6px;margin:0 0 16px;font-size:var(--fs-xs)}
.tag-import-step{display:inline-flex;align-items:center;gap:6px;color:var(--text3);white-space:nowrap;padding:4px 8px;border-radius:999px;border:1px solid transparent}
.tag-import-step .tag-import-step-n{display:inline-flex;align-items:center;justify-content:center;width:18px;height:18px;border-radius:50%;background:var(--bg3);border:1px solid var(--border);font-size:10px;font-weight:700}
.tag-import-step.active{color:var(--cyan);font-weight:600;border-color:color-mix(in srgb,var(--cyan) 40%,var(--border));background:color-mix(in srgb,var(--cyan) 8%,transparent)}
.tag-import-step.active .tag-import-step-n{background:var(--cyan);color:#04121a;border-color:var(--cyan)}
.tag-import-step.done{color:var(--green)}
.tag-import-step.done .tag-import-step-n{background:color-mix(in srgb,var(--green) 20%,transparent);border-color:var(--green);color:var(--green)}
.tag-import-step.clickable{cursor:pointer}
.tag-import-step.clickable:hover{color:var(--text);background:var(--bg3)}
.tag-import-step.disabled{opacity:.5;cursor:not-allowed}
.tag-import-step-sep{color:var(--text3)}

.tag-import-panel{padding:14px 16px;background:var(--bg2);border:1px solid var(--border);border-radius:8px}
.tag-import-panel-title{font-size:13px;font-weight:700;color:var(--text);margin:0 0 4px}
.tag-import-panel-desc{font-size:12px;color:var(--text2);line-height:1.6;margin:0 0 12px}
.tag-import-field{display:flex;align-items:center;gap:10px;margin:0 0 4px}
.tag-import-field label{flex:0 0 120px;font-size:12px;color:var(--text2)}
.tag-import-field select,.tag-import-field input{flex:1;padding:6px 8px;background:var(--bg3);border:1px solid var(--border);border-radius:6px;color:var(--text);font-size:12px;font-family:monospace}
.tag-import-actions{display:flex;flex-wrap:wrap;align-items:center;gap:10px}
.tag-import-actions input[type=file]{font-size:12px;color:var(--text)}
.tag-import-status{font-size:12px;color:var(--text2);margin-top:10px;line-height:1.6}

.tag-import-badges{display:flex;flex-wrap:wrap;gap:8px;margin-bottom:4px}
.tag-import-badge{display:inline-flex;align-items:center;padding:2px 10px;border-radius:999px;font-size:11px;font-weight:600;border:1px solid transparent;text-transform:capitalize}
.tag-import-badge.add{color:var(--green);background:color-mix(in srgb,var(--green) 14%,transparent);border-color:color-mix(in srgb,var(--green) 35%,transparent)}
.tag-import-badge.update{color:var(--yellow);background:color-mix(in srgb,var(--yellow) 14%,transparent);border-color:color-mix(in srgb,var(--yellow) 35%,transparent)}
.tag-import-badge.skip{color:var(--text2);background:var(--bg3);border-color:var(--border)}
.tag-import-badge.total{color:var(--cyan);background:color-mix(in srgb,var(--cyan) 12%,transparent);border-color:color-mix(in srgb,var(--cyan) 35%,transparent)}

/* collapsible "Applies to" list */
.tag-import-link{color:var(--cyan);font-size:11px;margin-left:6px;text-decoration:none}
.tag-import-link:hover{text-decoration:underline}
.tag-import-targets-hint{font-size:11px;color:var(--text3);margin-top:2px}
.tag-import-ecu-chips{display:none;flex-wrap:wrap;gap:4px;margin-top:6px;max-height:120px;overflow:auto;padding:6px;background:var(--bg3);border:1px solid var(--border);border-radius:6px}
.tag-import-chip{font-size:10px;font-family:monospace;color:var(--text2);background:var(--bg2);border:1px solid var(--border);border-radius:4px;padding:1px 6px}

/* searchable ECU combobox */
.tag-import-combo{position:relative;flex:1}
.tag-import-combo>input{width:100%;padding:6px 8px;background:var(--bg3);border:1px solid var(--border);border-radius:6px;color:var(--text);font-size:12px}
.tag-import-combo-dd{position:absolute;z-index:20;left:0;right:0;top:calc(100% + 2px);max-height:240px;overflow:auto;background:var(--bg2);border:1px solid var(--border);border-radius:6px;box-shadow:0 8px 24px rgba(0,0,0,.4)}
.tag-import-combo-opt{display:flex;justify-content:space-between;gap:12px;padding:6px 10px;font-size:12px;cursor:pointer}
.tag-import-combo-opt:hover{background:var(--bg3)}
.tag-import-combo-opt .mono{font-family:monospace;color:var(--text3)}
.tag-import-combo-empty{padding:8px 10px;font-size:12px;color:var(--text3)}

/* ── Sync Tag · Tag Operation wizard (Step 3, non-import) ── */
/* setting-rows are full-bleed with their own 16px inset; give the wizard's other
   content (stepper, step titles/descs, overview/confirm blocks) the same inset so
   nothing sits flush against the modal edge. */
#sj-tag-op-modal .tag-import-stepper,
#sj-tag-op-modal .tag-import-panel-title,
#sj-tag-op-modal .tag-import-panel-desc,
#sj-tag-op-modal #sj-tag-op-overview,
#sj-tag-op-modal #sj-tag-op-confirm,
#sj-tag-op-modal #sj-tag-op-s1-note,
/* MQTT / Data Logger detail form + Data Center delete/update tables live in
   plain divs with no inset of their own — give them the same 16px gutter so the
   Details step never sits flush against the modal edge. */
#sj-tag-op-modal #mtagop-s2-body,
#sj-tag-op-modal #sj-tag-op-update-table,
#sj-tag-op-modal #sj-tag-op-delete-table{padding-left:16px;padding-right:16px}
#sj-tag-op-modal .modal-body{padding-bottom:10px}
/* The tag picker is a searchable combobox whose dropdown is absolutely positioned;
   the modal body scrolls (overflow-y:auto) and would clip it. Reserve vertical room
   in the Details step so the ~240px dropdown is fully visible below the input. */
#sj-tag-op-modal #mtagop-s2-body{min-height:320px}
/* Import (Spreadsheet) wizard: the body is a stack of summary + stepper + card
   panels; pad it so the cards breathe instead of hugging the modal edges. */
#sj-tag-import-modal .modal-body{padding:14px 16px}
/* Reference ECU picker: option text is long (device breakdown), let it fill the row. */
#sj-tag-op-ref-ecu-row{gap:16px}
#sj-tag-op-ref-ecu-row .v{flex:1;min-width:0}
#sj-tag-op-ref-ecu{width:100%}

/* ── Field validation ── */
.field-error-msg{display:none;font-size:11px;color:var(--red);padding:2px 16px 0;text-align:right}
.setting-row.has-error input,.setting-row.has-error select{border-color:var(--red) !important;box-shadow:0 0 0 1px var(--red)}
.setting-row.has-error + .field-error-msg{display:block}

/* ── Switch wrap ── */
.sw-wrap{display:inline-flex;align-items:center;gap:8px}
.sw-wrap input[type=checkbox]{accent-color:var(--cyan)}
.sw-text{min-width:24px;text-align:right}

/* ── Notification center ── */
.notify-bell{position:relative;cursor:pointer;padding:4px 6px;border-radius:4px;transition:background .15s;display:flex;align-items:center;color:var(--text2)}
.notify-bell:hover{background:var(--bg3);color:var(--cyan)}
.bell-svg{display:block}
.notify-badge{position:absolute;top:-4px;right:-6px;background:var(--red);color:#fff;font-size:10px;font-weight:700;min-width:16px;height:16px;border-radius:8px;display:flex;align-items:center;justify-content:center;padding:0 4px;line-height:1}
.notify-panel{position:fixed;top:48px;right:0;width:380px;max-height:calc(100vh - 60px);background:var(--bg2);border:1px solid var(--border);border-radius:0 0 0 8px;box-shadow:0 8px 32px rgba(0,0,0,.45);z-index:9000;display:none;flex-direction:column}
.notify-panel.open{display:flex}
.notify-header{display:flex;align-items:center;justify-content:space-between;padding:12px 16px;border-bottom:1px solid var(--border);font-size:13px;font-weight:600;color:var(--text)}
.notify-list{flex:1;overflow-y:auto;max-height:420px}
.notify-item{padding:12px 16px;border-bottom:1px solid var(--bg3);cursor:pointer;transition:background .12s}
.notify-item:hover{background:var(--bg3)}
.ni-title{font-size:13px;font-weight:600;color:var(--cyan);margin-bottom:3px}
.ni-body{font-size:12px;color:var(--text2);line-height:1.4}
.ni-time{font-size:10px;color:var(--gray);margin-top:4px}
.notify-empty{padding:40px 16px;text-align:center;color:var(--text2);font-size:13px}

/* ── Toast (notification animation) ── */
.notify-toast{position:fixed;top:50%;left:50%;transform:translate(-50%,-50%) scale(.85);width:340px;padding:16px 20px;background:var(--bg2);border:1px solid var(--cyan);border-radius:8px;box-shadow:0 8px 32px rgba(0,0,0,.5);z-index:9999;opacity:0;transition:all .5s cubic-bezier(.22,.68,0,1.2);pointer-events:none}
.notify-toast.show{opacity:1;transform:translate(-50%,-50%) scale(1)}
.notify-toast.fly{transition:all .55s cubic-bezier(.6,0,.4,1);width:120px;padding:6px;border-radius:4px}
.nt-title{font-size:13px;font-weight:700;color:var(--cyan);margin-bottom:4px}
.nt-body{font-size:12px;color:var(--text2);line-height:1.4}

/* ── Sync job toast ── */
.sj-toast{position:fixed;top:24px;left:50%;transform:translateX(-50%);z-index:99999;padding:10px 28px;border-radius:8px;font-size:13px;font-weight:500;color:#fff;pointer-events:none;opacity:0;transition:opacity .4s ease}
.sj-toast.visible{opacity:1}
.sj-toast.toast-ok{background:var(--green,#20c997)}
.sj-toast.toast-err{background:var(--red,#e74c3c)}
.sj-toast.toast-info{background:var(--cyan,#17a2b8)}
