:root{
  color-scheme: light;
  --surface-0:#f5f5f3; --surface-1:#fcfcfb; --surface-2:#eceae5;
  --line:#dedbd4; --line-strong:#c4c0b6;
  --text-primary:#0b0b0b; --text-secondary:#52514e; --text-muted:#78766f;
  --accent:#2a78d6; --accent-ink:#fff;
  --good:#1baf7a; --warn:#eda100; --bad:#e34948;
  --seq-100:#cde2fb; --seq-300:#6da7ec; --seq-450:#2a78d6; --seq-600:#184f95; --seq-700:#0d366b;
  --shadow:0 1px 2px rgba(0,0,0,.06),0 8px 24px rgba(0,0,0,.06);
}
@media (prefers-color-scheme: dark){
  :root:where(:not([data-theme="light"])){
    color-scheme: dark;
    --surface-0:#111110; --surface-1:#1a1a19; --surface-2:#232321;
    --line:#333330; --line-strong:#4a4a46;
    --text-primary:#fff; --text-secondary:#c3c2b7; --text-muted:#8e8d84;
    --accent:#3987e5;
    --good:#199e70; --warn:#c98500; --bad:#e66767;
    --shadow:0 1px 2px rgba(0,0,0,.4),0 8px 24px rgba(0,0,0,.35);
  }
}
:root[data-theme="dark"]{
  color-scheme: dark;
  --surface-0:#111110; --surface-1:#1a1a19; --surface-2:#232321;
  --line:#333330; --line-strong:#4a4a46;
  --text-primary:#fff; --text-secondary:#c3c2b7; --text-muted:#8e8d84;
  --accent:#3987e5; --good:#199e70; --warn:#c98500; --bad:#e66767;
  --shadow:0 1px 2px rgba(0,0,0,.4),0 8px 24px rgba(0,0,0,.35);
}
*{box-sizing:border-box}
html,body{height:100%}
body{
  margin:0; background:var(--surface-0); color:var(--text-primary);
  font:14px/1.5 ui-sans-serif,system-ui,-apple-system,"Segoe UI",Roboto,sans-serif;
  display:flex; flex-direction:column; overflow:hidden;
}
.topbar{
  display:flex; align-items:center; justify-content:space-between; gap:16px;
  padding:10px 16px; background:var(--surface-1); border-bottom:1px solid var(--line);
  flex:0 0 auto;
}
.brand{font-weight:650; letter-spacing:-.01em}
.brand span{font-weight:450; color:var(--text-muted); margin-left:6px}
.topbar-actions{display:flex; gap:8px; align-items:center}
.upload-btn>span,button{
  font:inherit; cursor:pointer; border-radius:7px; border:1px solid var(--line-strong);
  background:var(--surface-2); color:var(--text-primary); padding:6px 12px;
}
.upload-btn>span{background:var(--accent); border-color:transparent; color:var(--accent-ink); display:inline-block}
button:hover{border-color:var(--accent)}
button.active{background:var(--accent); border-color:transparent; color:var(--accent-ink)}
button.ghost{background:transparent}

#layout{flex:1 1 auto; display:grid; grid-template-columns:minmax(0,1fr) 380px; min-height:0}
#viewport{position:relative; min-width:0; min-height:280px; background:var(--surface-0); overflow:hidden}
#gl{width:100%; height:100%; display:block}
#panel{
  background:var(--surface-1); border-left:1px solid var(--line);
  overflow-y:auto; padding:16px; min-width:0;
}
.dropzone{
  position:absolute; inset:16px; border:2px dashed var(--line-strong); border-radius:12px;
  display:grid; place-items:center; text-align:center; color:var(--text-secondary);
  pointer-events:none; transition:border-color .15s, background .15s;
}
.dropzone.drag{border-color:var(--accent); background:color-mix(in srgb,var(--accent) 8%,transparent)}
.dropzone.hidden{display:none}
.dz-title{font-size:17px; font-weight:600; color:var(--text-primary); margin:0 0 4px}
.dz-sub{margin:0; font-size:13px}

/* The busy overlay reports progress; it must never eat input. With pointer
   events on it swallowed every drag while a recompute was running - which is
   after almost every interaction - and read as the viewer refusing to rotate. */
.overlay{
  position:absolute; inset:0; display:flex; gap:12px; align-items:center; justify-content:center;
  background:color-mix(in srgb,var(--surface-0) 55%,transparent); z-index:5; font-weight:500;
  pointer-events:none;
}
.overlay.hidden{display:none}
.spinner{
  width:20px;height:20px;border-radius:50%;
  border:2.5px solid var(--line-strong); border-top-color:var(--accent);
  animation:spin .8s linear infinite;
}
@keyframes spin{to{transform:rotate(360deg)}}

/* The overlay is bounded by construction: it can wrap, it never runs under the
   axis gizmo, and it never extends past the viewport on any window size. */
.viewer-tools{
  position:absolute; left:12px; bottom:12px; z-index:6;
  display:flex; flex-wrap:wrap; gap:8px;
  max-width:calc(100% - 24px - 152px);   /* keeps clear of the view cube */
  max-height:calc(100% - 24px); overflow:auto;
  scrollbar-width:thin;
}
.tool-group{
  display:flex; align-items:center; gap:4px; padding:5px;
  background:var(--surface-1); border:1px solid var(--line); border-radius:9px; box-shadow:var(--shadow);
}
.tool-group button{padding:4px 9px; font-size:13px; border-color:transparent; background:transparent; white-space:nowrap}
.tool-group button:hover{background:var(--surface-2)}
.tool-group button.active{background:var(--accent); color:var(--accent-ink)}
.tool-label{font-size:12px; color:var(--text-muted); padding:0 4px 0 6px}
.hint{
  position:absolute; top:12px; left:50%; transform:translateX(-50%); z-index:6;
  pointer-events:none;
  background:var(--accent); color:var(--accent-ink); padding:6px 14px; border-radius:20px;
  font-size:13px; box-shadow:var(--shadow);
}
.hint.hidden{display:none}

h2{font-size:16px; margin:0 0 2px}
h3{font-size:12px; text-transform:uppercase; letter-spacing:.06em;
   color:var(--text-muted); margin:22px 0 8px; font-weight:600}
.muted{color:var(--text-muted); font-weight:400}
.empty h2{margin-bottom:8px}
.empty p{color:var(--text-secondary)}
.hidden{display:none}
.file-head{border-bottom:1px solid var(--line); padding-bottom:12px}
.file-head p{margin:2px 0 0; font-size:12px}

dl.values{display:grid; grid-template-columns:1fr auto; gap:7px 12px; margin:0; align-items:baseline}
dl.values dt{color:var(--text-secondary); font-size:13px}
dl.values dd{margin:0; text-align:right; font-variant-numeric:tabular-nums; white-space:nowrap}
dl.values dd b{font-size:15px; font-weight:600}
dl.small dt,dl.small dd{font-size:12px}
.prov{
  font-style:normal; font-size:10px; text-transform:uppercase; letter-spacing:.04em;
  padding:2px 5px; border-radius:4px; margin-left:6px; vertical-align:1px;
}
.prov.exact{background:color-mix(in srgb,var(--good) 18%,transparent); color:var(--good)}
.prov.assist{background:color-mix(in srgb,var(--warn) 20%,transparent); color:var(--warn)}
.prov.derived{background:var(--surface-2); color:var(--text-muted)}
.note{font-size:12px; color:var(--text-muted); margin:10px 0 0}
.warn-box{
  border:1px solid color-mix(in srgb,var(--warn) 45%,var(--line));
  background:color-mix(in srgb,var(--warn) 10%,transparent);
  border-radius:8px; padding:8px 10px; margin:12px 0 0; font-size:12.5px;
}
.warn-box.bad{border-color:color-mix(in srgb,var(--bad) 45%,var(--line));
  background:color-mix(in srgb,var(--bad) 10%,transparent)}
.warn-box ul{margin:4px 0 0; padding-left:18px}

.chart{margin:0 0 14px; position:relative}
.chart figcaption{font-size:12px; color:var(--text-secondary); margin-bottom:6px}
#hist{width:100%; display:block; cursor:crosshair}
.tip{
  position:absolute; pointer-events:none; z-index:8; background:var(--surface-1);
  border:1px solid var(--line-strong); border-radius:6px; padding:5px 8px;
  font-size:12px; box-shadow:var(--shadow); white-space:nowrap;
  font-variant-numeric:tabular-nums;
}
.tip.hidden{display:none}
.diag{margin-top:22px; border-top:1px solid var(--line); padding-top:10px}
.diag summary{cursor:pointer; font-size:12px; color:var(--text-muted)}
.diag dl{margin-top:8px}
@media (max-width:900px){
  #layout{grid-template-columns:1fr; grid-template-rows:minmax(260px,45vh) 1fr}
  #panel{border-left:none; border-top:1px solid var(--line)}
  body{overflow:auto}
}


/* ---- structure tree ---------------------------------------------------- */
.tree{
  position:absolute; top:12px; left:12px; z-index:6;
  width:212px; display:flex; flex-direction:column;
  /* Bounded to the upper half so it can never reach the toolbar, which grows
     taller as it wraps on a short viewport. The list scrolls inside. */
  max-height:calc(55% - 18px);
  background:var(--surface-1); border:1px solid var(--line); border-radius:9px;
  box-shadow:var(--shadow); font-size:13px; overflow:hidden;
}
.tree.hidden{display:none}
.tree-head{
  display:flex; align-items:center; justify-content:space-between;
  padding:6px 8px 6px 10px; border-bottom:1px solid var(--line); font-weight:600;
}
.tree-head button{padding:0 7px; line-height:1.4; border-color:transparent; background:transparent}
.tree ul{list-style:none; margin:0; padding:4px; overflow-y:auto}
.tree li{display:flex; align-items:center; gap:7px; padding:4px 6px; border-radius:6px}
.tree li:hover{background:var(--surface-2)}
.tree li.active{background:color-mix(in srgb,var(--accent) 12%,transparent)}
.tree .nm{flex:1 1 auto; min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap}
.tree .vol{color:var(--text-muted); font-variant-numeric:tabular-nums; font-size:11.5px}
.tree input[type=radio],.tree input[type=checkbox]{accent-color:var(--accent); margin:0; cursor:pointer}
.tree-note{margin:0; padding:6px 10px 8px; font-size:11px; color:var(--text-muted);
  border-top:1px solid var(--line)}
.tree.collapsed ul,.tree.collapsed .tree-note{display:none}

/* ---- axis gizmo -------------------------------------------------------- */
.viewcube{position:absolute; right:12px; bottom:12px; z-index:5}
.axes{
  display:block; width:132px; height:132px; cursor:pointer;
}
.viewcube #view-home{
  position:absolute; top:0; left:0; width:24px; height:24px; padding:0;
  font-size:15px; line-height:1; border-radius:6px;
  background:var(--surface-1); border:1px solid var(--line); color:var(--text-secondary);
  box-shadow:var(--shadow); cursor:pointer;
}
.viewcube #view-home:hover{border-color:var(--accent); color:var(--accent)}

/* ---- opacity slider ---------------------------------------------------- */
.slider{display:flex; align-items:center; gap:6px}
.slider input[type=range]{width:88px; accent-color:var(--accent); cursor:pointer}
.slider output{font-size:12px; color:var(--text-muted); width:34px;
  font-variant-numeric:tabular-nums; text-align:right}

/* ---- narrow windows ------------------------------------------------------
   These must stay at the end of the file: the .axes and .tree base rules are
   declared below .viewer-tools, and equal specificity means source order wins. */
/* Narrow: keep the reserve, shrink the gizmo rather than let them collide. */
@media (max-width:700px){
  .viewer-tools{ max-width:calc(100% - 24px - 92px) }
  .axes{ width:84px; height:84px }
  .tree{ width:180px }
}
@media (max-width:460px){
  .viewer-tools{ max-width:calc(100% - 24px - 72px) }
  .axes{ width:64px; height:64px }
  .viewcube #view-home{width:20px;height:20px;font-size:13px}
}

/* FW/WS worst case against the thresholds the Instruction sheet names */
.ratio-watch{color:var(--warn)}
.ratio-critical{color:var(--bad)}
