/* PolyForge — Max-like dark theme.
   Light DOM components share this single global stylesheet. */

:root {
  --bg:            #2b2b2b;
  --panel:         #383838;
  --panel-hi:      #454545;
  --panel-lo:      #303030;
  --border:        #1e1e1e;
  --border-hi:     #565656;
  --text:          #cfcfcf;
  --text-dim:      #8f8f8f;
  --accent:        #e0a13c;   /* Max-ish selection amber */
  --accent-2:      #d24b4b;   /* x-axis / warnings */
  --active-vp:     #d0d0d0;   /* active viewport border */
  --axis-x:        #c8464b;
  --axis-y:        #6fbf4f;
  --axis-z:        #4b7bd2;
  --toolbar-h:     30px;
  --menubar-h:     22px;
  --statusbar-h:   24px;
  --cmdpanel-w:    312px;
  --font:          11px/1.4 "Segoe UI", system-ui, sans-serif;
  --mono:          11px/1.4 "Cascadia Mono", "Consolas", monospace;
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  height: 100%;
  overflow: hidden;
  background: var(--bg);
  color: var(--text);
  font: var(--font);
  user-select: none;
  -webkit-user-select: none;
  cursor: default;
}

/* ---- App layout ---------------------------------------------------------- */
pf-app {
  display: grid;
  height: 100vh;
  grid-template-columns: 1fr var(--cmdpanel-w);
  grid-template-rows: var(--menubar-h) var(--toolbar-h) 1fr var(--statusbar-h);
  grid-template-areas:
    "menubar   menubar"
    "toolbar   toolbar"
    "viewport  cmdpanel"
    "statusbar statusbar";
  background: var(--border);
  gap: 1px;
}

pf-menubar      { grid-area: menubar; }
pf-toolbar      { grid-area: toolbar; }
pf-viewport     { grid-area: viewport; position: relative; overflow: hidden; }
pf-command-panel{ grid-area: cmdpanel; overflow: hidden; }
pf-statusbar    { grid-area: statusbar; }

/* ---- Menu bar ------------------------------------------------------------ */
pf-menubar {
  display: flex;
  align-items: center;
  gap: 2px;
  padding: 0 6px;
  background: var(--panel);
  font-size: 11px;
  /* In a frameless shell this bar IS the title bar, so its empty space drags the window. The property
     is meaningless in a browser and simply ignored there, which is why there is one menu bar and not
     two — everything below re-declares the interactive parts as non-draggable. */
  -webkit-app-region: drag;
  app-region: drag;
}
pf-menubar .menu,
pf-menubar .menu-label,
pf-menubar .menu-drop,
pf-menubar .brand,
pf-menubar .account-chip,
pf-menubar .pro-badge {
  -webkit-app-region: no-drag;
  app-region: no-drag;
}
/* Room for the window controls the shell overlays on the right. The width comes from the shell via
   the Window Controls Overlay API rather than being guessed, because it differs between platforms
   and with the system scale factor. Zero in a browser, where the variables do not resolve. */
html.native-titlebar pf-menubar {
  padding-right: calc(100vw - env(titlebar-area-width, 100vw) - env(titlebar-area-x, 0px) + 6px);
}
pf-menubar .brand {
  display: inline-flex;
  align-items: center;
  margin: 0 14px 0 6px;
  cursor: pointer;
  user-select: none;
}
pf-menubar .brand .brand-logo {
  height: 14px;
  width: auto;
  display: block;
  opacity: 0.9;
  transition: opacity 120ms ease;
}
pf-menubar .brand:hover .brand-logo { opacity: 1; }
pf-menubar .menu { position: relative; color: var(--text); }
pf-menubar .menu-label { display: inline-block; padding: 2px 8px; border-radius: 3px; cursor: pointer; }
pf-menubar .menu-label:hover,
pf-menubar .menu.open .menu-label { background: var(--panel-hi); }
pf-menubar .menu-drop {
  display: none;
  position: absolute;
  top: 100%;
  left: 0;
  z-index: 600;
  min-width: 172px;
  background: var(--panel);
  border: 1px solid var(--border-hi);
  border-radius: 3px;
  padding: 3px;
  box-shadow: 0 6px 16px #000a;
}
pf-menubar .menu.open .menu-drop { display: block; }
pf-menubar .menu-item {
  display: block;
  width: 100%;
  text-align: left;
  padding: 4px 10px;
  background: none;
  border: 0;
  border-radius: 3px;
  color: var(--text);
  font: inherit;
  cursor: pointer;
}
pf-menubar .menu-item:hover { background: var(--panel-hi); }

/* ---- Toolbar ------------------------------------------------------------- */
pf-toolbar {
  display: flex;
  align-items: center;
  gap: 3px;
  padding: 0 6px;
  background: var(--panel);
  border-top: 1px solid var(--border-hi);
}
.tb-group { display: flex; gap: 2px; align-items: center; }
.tb-env-lbl { color: var(--text-dim); font-size: 11px; margin-right: 3px; }
#pbr-environment { max-width: 150px; height: 24px; }
.tb-sep { width: 1px; height: 20px; background: var(--border); margin: 0 5px; }

.tb-btn {
  min-width: 24px;
  height: 24px;
  padding: 0 6px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 4px;
  background: var(--panel-lo);
  border: 1px solid var(--border);
  border-radius: 3px;
  color: var(--text);
  font-size: 11px;
  cursor: pointer;
}
.tb-btn:hover { background: var(--panel-hi); border-color: var(--border-hi); }
.tb-btn.active {
  background: color-mix(in srgb, var(--accent) 30%, var(--panel-lo));
  border-color: var(--accent);
  color: #fff;
}
.tb-btn kbd {
  font: var(--mono);
  color: var(--text-dim);
  font-size: 9px;
}
.tb-select {
  height: 24px;
  min-width: 112px;
  padding: 0 5px;
  background: var(--panel-lo);
  border: 1px solid var(--border);
  border-radius: 3px;
  color: var(--text);
  font-size: 11px;
}
.tb-select:focus { outline: 1px solid var(--accent); }

/* ---- Viewport ------------------------------------------------------------ */
pf-viewport { background: #202020; }
/* A material is being dragged over the viewport: say that a drop will land, because a drag with no
   feedback is indistinguishable from a drag into something that will ignore you. */
pf-viewport.material-drop::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 5;
  pointer-events: none;
  border: 2px solid var(--accent);
  box-shadow: inset 0 0 0 9999px color-mix(in srgb, var(--accent) 8%, transparent);
}
pf-viewport canvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
}
/* overlay layer holds per-viewport labels + active border, drawn over canvas */
.vp-overlay {
  position: absolute;
  inset: 0;
  pointer-events: none;
}
.vp-frame {
  position: absolute;
  border: 1px solid transparent;
}
.vp-frame.active { border-color: var(--active-vp); }
.vp-label {
  position: absolute;
  top: 2px;
  left: 4px;
  padding: 1px 5px;
  border-radius: 3px;
  font-size: 11px;
  color: var(--text);
  text-shadow: 0 1px 2px #000;
  pointer-events: auto;
  cursor: pointer;
}
.vp-shade {
  position: absolute;
  top: 2px;
  right: 4px;
  padding: 1px 5px;
  border-radius: 3px;
  font-size: 10px;
  color: var(--text-dim);
  text-shadow: 0 1px 2px #000;
  pointer-events: auto;
  cursor: pointer;
}
.vp-label:hover, .vp-shade:hover { background: color-mix(in srgb, var(--panel-hi) 85%, transparent); color: #fff; }

/* Per-viewport label dropdown (camera preset + display options), 3ds Max-style. */
.vp-menu {
  position: absolute;
  z-index: 540;
  min-width: 150px;
  max-height: 82%;
  overflow-y: auto;
  padding: 4px;
  background: color-mix(in srgb, var(--panel) 95%, #000);
  border: 1px solid var(--border-hi);
  border-radius: 6px;
  box-shadow: 0 10px 26px rgba(0, 0, 0, 0.5);
  pointer-events: auto;
  animation: caddy-pop 110ms ease-out;
}
.vp-menu-title {
  padding: 4px 8px 2px;
  font-size: 9.5px;
  letter-spacing: 0.6px;
  text-transform: uppercase;
  color: var(--text-dim);
}
.vp-menu-sep { height: 1px; background: var(--border); margin: 4px 2px; }
.vp-menu-item {
  display: block;
  width: 100%;
  text-align: left;
  padding: 4px 10px 4px 20px;
  position: relative;
  background: none;
  border: 0;
  border-radius: 3px;
  color: var(--text);
  font: inherit;
  cursor: pointer;
}
.vp-menu-item:hover { background: var(--panel-hi); }
.vp-menu-item.active { color: #fff; }
.vp-menu-item.active::before { content: "✓"; position: absolute; left: 6px; color: var(--accent); }

/* ---- Command panel ------------------------------------------------------- */
pf-command-panel {
  display: flex;
  flex-direction: column;
  background: var(--panel);
}
.cp-tabs {
  display: flex;
  border-bottom: 1px solid var(--border);
}
.cp-tab {
  flex: 1;
  text-align: center;
  padding: 5px 0;
  color: var(--text-dim);
  cursor: pointer;
  border-right: 1px solid var(--border);
}
.cp-tab:last-child { border-right: none; }
.cp-tab.active { color: var(--text); background: var(--panel-hi); box-shadow: inset 0 -2px 0 var(--accent); }
.cp-body { flex: 1; overflow-y: auto; }
.cp-group[hidden] { display: none; }

/* modifier stack */
.stack {
  background: var(--panel-lo);
  margin: 6px;
  border: 1px solid var(--border);
  border-radius: 3px;
  min-height: 96px;
  max-height: 190px;
  overflow-y: auto;
}
.stack-item {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 3px 6px;
  border-bottom: 1px solid var(--panel);
  cursor: pointer;
}
.stack-item:hover { background: var(--panel); }
.stack-item.selected { background: color-mix(in srgb, var(--accent) 28%, var(--panel-lo)); color: #fff; }
.stack-item .toggle { width: 12px; text-align: center; color: var(--text-dim); cursor: pointer; }
.tex-slot-ch { display: flex; align-items: center; gap: 3px; font-size: 10px; color: var(--text-dim); }
.tex-slot-ch input { width: 34px; background: var(--panel); color: var(--text); border: 1px solid var(--border); border-radius: 3px; font: 10px system-ui; padding: 0 3px; }
.stack-item .toggle.on { color: var(--accent); }
/* A modifier with nothing to suspend is not offered a switch: no hover, no pointer, dimmed. */
.stack-item .toggle.fixed { cursor: default; opacity: 0.35; }
.stack-item .toggle:not(.fixed):hover { color: var(--text); }
/* A switched-off modifier reads as switched off from across the panel, not only at its dot. */
.stack-item.off .name { color: var(--text-dim); text-decoration: line-through; text-decoration-thickness: 1px; }
.stack-item .name { flex: 1; }
.stack-toolbar { display: flex; gap: 2px; padding: 4px 6px; }
.stack-toolbar .cp-btn { display: inline-flex; align-items: center; gap: 3px; }

/* Selected modifier's parameters, below the stack. */
.mod-params { margin: 0 6px 6px; }
.mod-params:empty { display: none; }
.mod-params .mod-params-title {
  padding: 4px 8px;
  background: var(--panel-hi);
  border: 1px solid var(--border);
  border-bottom: none;
  border-radius: var(--radius) var(--radius) 0 0;
  font-weight: 600;
  font-size: 10.5px;
}
.mod-params .row {
  padding: 5px 8px;
  background: var(--panel-lo);
  border: 1px solid var(--border);
  border-top: none;
}
.mod-params .row:last-child { border-radius: 0 0 var(--radius) var(--radius); }
.cp-hint { color: var(--text-dim); font-size: 10.5px; line-height: 1.45; }
.cp-hint b { color: var(--text); font-weight: 600; }

/* sub-object level buttons row */
.subobj-row { display: flex; gap: 2px; padding: 4px 6px; }
.subobj-btn {
  flex: 1;
  height: 26px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: var(--panel-lo);
  border: 1px solid var(--border);
  border-radius: 3px;
  color: var(--text);
  cursor: pointer;
}
.subobj-btn.active { background: color-mix(in srgb, var(--accent) 34%, var(--panel-lo)); border-color: var(--accent); color: #fff; }

/* rollout */
.rollout { margin: 6px; border: 1px solid var(--border); border-radius: 3px; overflow: hidden; }
.rollout > summary {
  list-style: none;
  padding: 5px 8px;
  background: var(--panel-hi);
  cursor: pointer;
  font-weight: 600;
}
.rollout > summary::-webkit-details-marker { display: none; }
.rollout > summary::before { content: "▸ "; color: var(--text-dim); }
.rollout[open] > summary::before { content: "▾ "; }
.rollout .rollout-body { padding: 6px 8px; background: var(--panel-lo); display: flex; flex-direction: column; gap: 5px; }

.row { display: flex; align-items: center; gap: 6px; }
.row label { flex: 1; color: var(--text-dim); }
.cp-btn {
  padding: 4px 8px;
  background: var(--panel-lo);
  border: 1px solid var(--border);
  border-radius: 3px;
  color: var(--text);
  cursor: pointer;
}
.cp-btn:hover { background: var(--panel-hi); }
.cp-btn.active { background: color-mix(in srgb, var(--accent) 34%, var(--panel-lo)); border-color: var(--accent); color: #fff; }
/* Selection category rollout (§5.19) */
.sel-rollout .row { flex-wrap: wrap; gap: 4px; }
.sel-rollout .sel-head { font-size: 9px; letter-spacing: .06em; text-transform: uppercase; color: var(--muted, #8a8a92); margin: 4px 1px 0; }
.sel-seg { display: flex; }
.sel-seg .cp-btn { flex: 1; border-radius: 0; border-right-width: 0; }
.sel-seg .cp-btn:first-child { border-top-left-radius: 3px; border-bottom-left-radius: 3px; }
.sel-seg .cp-btn:last-child { border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-right-width: 1px; }
.cp-num {
  width: 64px;
  padding: 3px 6px;
  background: var(--panel-lo);
  border: 1px solid var(--border);
  border-radius: 3px;
  color: var(--text);
}
.cp-color {
  width: 64px;
  height: 24px;
  padding: 2px;
  background: var(--panel-lo);
  border: 1px solid var(--border);
  border-radius: 3px;
}
.cp-range { width: 112px; accent-color: var(--accent); }
.range-value { width: 32px; text-align: right; color: var(--text-dim); font: var(--mono); }
.cp-select {
  width: 100%;
  padding: 3px 5px;
  background: var(--panel-lo);
  border: 1px solid var(--border);
  border-radius: 3px;
  color: var(--text);
}
.environment-select { width: 170px; }
.texture-name {
  min-height: 17px;
  overflow: hidden;
  color: var(--text-dim);
  font: var(--mono);
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* PBR texture-map grid: one tile per slot, thumbnail + name + size, with a clear (✕) badge. */
.tex-thumb {
  position: relative;
  width: 46px;
  height: 46px;
  padding: 0;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--panel-lo);
  background-image:
    linear-gradient(45deg, #333 25%, transparent 25%, transparent 75%, #333 75%),
    linear-gradient(45deg, #333 25%, #2a2a2a 25%, #2a2a2a 75%, #333 75%);
  background-size: 12px 12px;
  background-position: 0 0, 6px 6px;
  cursor: pointer;
  overflow: hidden;
  transition: border-color var(--ease), box-shadow var(--ease);
}
.tex-thumb:hover { border-color: var(--border-hi); }
.mat-slot.has-map .tex-thumb { border-color: var(--accent); }
.tex-thumb-img {
  position: absolute;
  inset: 0;
  background-size: cover;
  background-position: center;
}
.tex-thumb-add {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--text-dim);
}
.mat-slot.has-map .tex-thumb-add { display: none; }
.tex-clear {
  position: absolute;
  top: -5px; right: -5px;
  width: 17px; height: 17px;
  display: inline-flex; align-items: center; justify-content: center;
  padding: 0;
  border: 1px solid var(--border-hi);
  border-radius: 50%;
  background: var(--panel-hi);
  color: var(--text);
  cursor: pointer;
  z-index: 2;
}
.tex-clear .ico { width: 11px; height: 11px; }
.tex-clear:hover { background: var(--accent-2); border-color: var(--accent-2); color: #fff; }
/* A map sampling with its own tiling looks like a bug until you know it has one — say so on the tile. */
.mat-slot.has-xform .tex-thumb::after {
  content: "UV";
  position: absolute;
  left: 3px; bottom: 3px;
  z-index: 2;
  padding: 0 3px;
  border-radius: 2px;
  background: color-mix(in srgb, var(--accent) 88%, #000);
  color: #fff;
  font: 600 8px system-ui;
  letter-spacing: .04em;
}

/* UV transform rows: the material-wide default, and one on every assigned map's own card that
   overrides it — see xformFields in js/ui/MaterialEditor.js. */
.xf-row { flex-wrap: wrap; gap: 2px 6px; }
.xf-row > label {
  flex: 1 1 auto;
  overflow: hidden;
  color: var(--text);
  font-size: 10.5px;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.xf-pair { display: flex; align-items: center; gap: 3px; }
.xf-lbl { color: var(--text-dim); font-size: 9px; }
.xf-row .spinner { width: 50px; height: 21px; }
.xf-row .spin-arrows { width: 13px; }
.cp-num.xf { font-size: 10.5px; text-align: right; }
/* Still reading the material-wide value: shown, but visibly not this map's own. */
.cp-num.xf.inherited { color: var(--text-dim); border-style: dashed; }
.xf-reset {
  display: inline-flex; align-items: center; justify-content: center;
  width: 19px; height: 19px;
  padding: 0;
  border: 1px solid var(--border);
  border-radius: 3px;
  background: var(--panel-lo);
  color: var(--text-dim);
  cursor: pointer;
}
.xf-reset .ico { width: 11px; height: 11px; }
.xf-reset:hover { background: var(--panel-hi); color: var(--text); }
.xf-reset[hidden] { display: none; }

/* ---- Status bar ---------------------------------------------------------- */
pf-statusbar {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 0 8px;
  background: var(--panel);
  border-top: 1px solid var(--border-hi);
  font: var(--mono);
  color: var(--text-dim);
}
pf-statusbar .prompt { flex: 1; color: var(--text); }
pf-statusbar .coord { min-width: 210px; }
pf-statusbar .raykast-credit {
  display: inline-flex;
  align-items: center;
  padding-left: 10px;
  border-left: 1px solid var(--border-hi);
  opacity: 0.55;
  transition: opacity 120ms ease;
}
pf-statusbar .raykast-credit img { height: 12px; width: auto; display: block; }
pf-statusbar .raykast-credit:hover { opacity: 1; }

/* ---- Unsupported gate ---------------------------------------------------- */
#unsupported {
  position: fixed;
  inset: 0;
  display: grid;
  place-items: center;
  background: #1a1a1a;
  z-index: 999;
}
/* The base rule's `display` would override the [hidden] attribute (ID specificity beats the
   UA `[hidden]{display:none}`), so the gate must hide itself explicitly. */
#unsupported[hidden] { display: none; }
#unsupported .panel { text-align: center; max-width: 460px; padding: 30px; }
#unsupported h1 { color: var(--accent-2); font-weight: 600; }
#unsupported .detail { color: var(--text-dim); font: var(--mono); margin-top: 12px; }
#unsupported .hint { color: var(--text-dim); font-size: 12px; margin-top: 16px; opacity: 0.7; }

/* ---- About / splash ------------------------------------------------------ */
#about-overlay {
  position: fixed;
  inset: 0;
  display: grid;
  place-items: center;
  background: rgba(10, 10, 12, 0.62);
  backdrop-filter: blur(3px);
  z-index: 1000;
  animation: about-fade 140ms ease-out;
}
@keyframes about-fade { from { opacity: 0; } to { opacity: 1; } }

/* Keyboard shortcuts panel (generated from the keymap) */
#sc-overlay {
  position: fixed; inset: 0; display: grid; place-items: center;
  background: rgba(10, 10, 12, 0.62); backdrop-filter: blur(3px);
  z-index: 1000; animation: about-fade 140ms ease-out;
}
#sc-overlay .sc-card {
  width: min(780px, 92vw); max-height: 84vh; display: flex; flex-direction: column;
  background: var(--panel); border: 1px solid var(--border-hi); border-radius: 8px;
  box-shadow: 0 18px 52px rgba(0, 0, 0, 0.6);
}
#sc-overlay .sc-head {
  display: flex; align-items: center; justify-content: space-between;
  padding: 10px 14px; border-bottom: 1px solid var(--border); font-weight: 600; color: var(--text);
}
#sc-overlay .sc-body { padding: 12px 14px; overflow-y: auto; column-width: 330px; column-gap: 24px; }
#sc-overlay .sc-group { break-inside: avoid; margin-bottom: 14px; }
#sc-overlay .sc-group h4 { margin: 0 0 5px; color: var(--accent); font-size: 10.5px; letter-spacing: 0.6px; text-transform: uppercase; }
#sc-overlay .sc-row { display: flex; justify-content: space-between; gap: 12px; padding: 2px 0; font-size: 12px; }
#sc-overlay .sc-label { color: var(--text); }
#sc-overlay .sc-keys { color: var(--text-dim); font-family: ui-monospace, "Cascadia Code", monospace; white-space: nowrap; }
#about-overlay .about-card {
  width: min(760px, 92vw);
  background: var(--panel);
  border: 1px solid var(--border-hi);
  border-radius: 6px;
  overflow: hidden;
  box-shadow: 0 24px 70px rgba(0, 0, 0, 0.55);
}
/* Banner: RAYKAST render if assets/threever-banner.png is present, else a CSS wordmark. */
#about-overlay .about-banner {
  position: relative;
  background: linear-gradient(120deg, #f4f4f5 0%, #e9eaec 55%, #dedfe2 100%);
  display: grid;
  place-items: center;
  min-height: 190px;
}
#about-overlay .about-banner img {
  display: block;
  width: 100%;
  height: auto;
}
#about-overlay .about-meta { padding: 18px 22px 20px; }
#about-overlay .about-meta p { margin: 0 0 12px; color: var(--text); font: var(--font); line-height: 1.55; }
#about-overlay .about-credit { display: flex; align-items: center; gap: 12px; color: var(--text-dim); }
#about-overlay .about-credit .about-raykast { height: 15px; width: auto; opacity: 0.85; transition: opacity 120ms ease; }
#about-overlay .about-credit a:hover .about-raykast { opacity: 1; }
#about-overlay .about-close { margin-top: 6px; }

/* ---- Snap settings modal ------------------------------------------------- */
#snap-overlay {
  position: fixed;
  inset: 0;
  display: grid;
  place-items: center;
  background: rgba(10, 10, 12, 0.5);
  z-index: 1000;
  animation: about-fade 120ms ease-out;
}
#snap-overlay .snap-card {
  width: min(300px, 92vw);
  padding: 14px 16px 16px;
  background: var(--panel);
  border: 1px solid var(--border-hi);
  border-radius: 8px;
  box-shadow: 0 20px 50px rgba(0, 0, 0, 0.55);
  display: flex;
  flex-direction: column;
  gap: 8px;
}
#snap-overlay .snap-head { font-weight: 600; letter-spacing: 0.4px; margin-bottom: 4px; }
#snap-overlay .snap-row { display: flex; align-items: center; gap: 8px; }
#snap-overlay .snap-row > span { flex: 1; color: var(--text); }
#snap-overlay .snap-row input[type="checkbox"] { accent-color: var(--accent); width: 15px; height: 15px; }
#snap-overlay .snap-row input[type="number"] { width: 74px; }
#snap-overlay .snap-row kbd { font: var(--mono); font-size: 9px; color: var(--text-dim); }
#snap-overlay .snap-close { margin-top: 6px; align-self: flex-end; }

/* ---- Region (rectangle) selection marquee -------------------------------- */
.marquee-rect {
  position: absolute;
  z-index: 500;
  pointer-events: none;
  display: none;
  border: 1px solid var(--accent);
  background: color-mix(in srgb, var(--accent) 14%, transparent);
  box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.35);
}
/* SVG overlay for gizmo widgets (Slice Plane). */
.tool-overlay { position: absolute; z-index: 501; pointer-events: none; display: none; overflow: visible; }
.tool-overlay .slice-face { fill: color-mix(in srgb, var(--accent) 12%, transparent); stroke: none; }
.tool-overlay .slice-edge { fill: none; stroke: var(--accent); stroke-width: 1.5; stroke-dasharray: 5 4; }
.tool-overlay .slice-normal { stroke: var(--axis-y); stroke-width: 2; }
.tool-overlay .slice-knob { fill: var(--axis-y); stroke: #000; stroke-width: 1; }
/* Rubber-band preview line for interactive click-tools (QuickSlice / Cut). */
.tool-line {
  position: absolute;
  z-index: 501;
  pointer-events: none;
  display: none;
  height: 0;
  border-top: 1.5px dashed var(--accent);
  transform-origin: 0 0;
  filter: drop-shadow(0 0 1px rgba(0, 0, 0, 0.6));
}

/* ---- UI modernization pass (light polish over the base widgets) ---------- */
:root { --radius: 5px; --ease: 140ms ease; }

.cp-btn, .cp-num, .cp-color, .cp-select, .subobj-btn {
  border-radius: var(--radius);
  transition: background var(--ease), border-color var(--ease), box-shadow var(--ease), transform var(--ease);
}
.cp-btn:hover { border-color: var(--border-hi); }
.cp-btn:active { transform: translateY(1px); }
.cp-btn:focus-visible, .cp-num:focus, .cp-color:focus, .cp-select:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 2px color-mix(in srgb, var(--accent) 30%, transparent);
}
.subobj-btn { transition: background var(--ease), border-color var(--ease), color var(--ease); }
.subobj-btn:hover { border-color: var(--border-hi); background: var(--panel); }

.cp-tab {
  font-weight: 600;
  letter-spacing: 0.6px;
  text-transform: uppercase;
  font-size: 10.5px;
  transition: background var(--ease), color var(--ease);
}
.cp-tab:hover { color: var(--text); background: color-mix(in srgb, var(--panel-hi) 60%, transparent); }

.rollout { border-radius: var(--radius); }
.rollout > summary { letter-spacing: 0.4px; transition: background var(--ease); }
.rollout > summary:hover { background: var(--border-hi); }

/* Slim, unobtrusive scrollbars for the panels (WebKit/Chromium). */
.cp-body, .stack, .menu-drop { scrollbar-width: thin; scrollbar-color: var(--border-hi) transparent; }
.cp-body::-webkit-scrollbar, .stack::-webkit-scrollbar { width: 10px; }
.cp-body::-webkit-scrollbar-thumb, .stack::-webkit-scrollbar-thumb {
  background: var(--border-hi); border-radius: 6px; border: 3px solid var(--panel);
}
.cp-body::-webkit-scrollbar-thumb:hover, .stack::-webkit-scrollbar-thumb:hover { background: #6a6a6a; }

/* ---- Inline SVG icons ---------------------------------------------------- */
.ico { width: 16px; height: 16px; display: inline-block; vertical-align: middle; flex: none; pointer-events: none; }
/* Icon buttons keep the label as a tooltip; the glyph carries the meaning. Text labels that
   remain (e.g. toolbar tool names) sit beside the icon with a small gap (see .tb-btn gap). */
.tb-btn .ico { margin: 0; }
.cp-btn .ico, .subobj-btn .ico { margin-right: 5px; }
.cp-btn.icon-only, .tb-btn.icon-only { gap: 0; }
.cp-btn.icon-only .ico, .tb-btn.icon-only .ico { margin: 0; }
.cp-btn { display: inline-flex; align-items: center; justify-content: center; }
.subobj-btn { flex-direction: column; gap: 1px; font-size: 9.5px; }
.subobj-btn .ico { margin: 0; width: 15px; height: 15px; }

/* ---- Scrub spinner (friendly numeric field) ----------------------------- */
.spinner {
  display: inline-flex;
  align-items: stretch;
  width: 74px;
  height: 24px;
  flex: none;
  background: var(--panel-lo);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  overflow: hidden;
  transition: border-color var(--ease), box-shadow var(--ease);
}
.spinner:focus-within { border-color: var(--accent); box-shadow: 0 0 0 2px color-mix(in srgb, var(--accent) 30%, transparent); }
.spinner .spin-input {
  width: 100%;
  min-width: 0;
  border: none;
  background: none;
  color: var(--text);
  padding: 0 5px;
  font: inherit;
  -moz-appearance: textfield;
  appearance: textfield;
}
.spinner .spin-input:focus { outline: none; }
.spinner .spin-input::-webkit-outer-spin-button,
.spinner .spin-input::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
.spin-arrows {
  display: flex;
  flex-direction: column;
  width: 16px;
  flex: none;
  border-left: 1px solid var(--border);
  touch-action: none;
}
.spin-up, .spin-down {
  flex: 1;
  display: flex; align-items: center; justify-content: center;
  border: none;
  background: var(--panel);
  color: var(--text-dim);
  padding: 0;
  cursor: ns-resize;
}
.spin-up { border-bottom: 1px solid var(--border); }
.spin-up:hover, .spin-down:hover { background: var(--panel-hi); color: var(--text); }
.spin-arrows .ico { width: 11px; height: 11px; }
/* Keep the wrapped spinners compact inside command-panel rows so three fit next to a button. */
.rollout-body .spinner { width: 66px; }

/* ---- In-viewport caddy (3ds Max-style floating settings) ----------------- */
.caddy {
  position: absolute;
  z-index: 520;
  min-width: 156px;
  padding: 6px;
  background: color-mix(in srgb, var(--panel) 92%, #000);
  border: 1px solid var(--border-hi);
  border-radius: 8px;
  box-shadow: 0 12px 30px rgba(0, 0, 0, 0.5);
  pointer-events: auto;
  user-select: none;
  font: var(--font);
  animation: caddy-pop 120ms ease-out;
}
.caddy[hidden] { display: none; }
@keyframes caddy-pop { from { opacity: 0; transform: scale(0.96) translateY(3px); } to { opacity: 1; transform: none; } }
.caddy-head {
  display: flex; align-items: center; gap: 6px;
  padding: 2px 3px 6px;
  margin-bottom: 6px;
  color: var(--text);
  font-weight: 600; letter-spacing: 0.3px;
  border-bottom: 1px solid var(--border);
}
.caddy-head .ico { color: var(--accent); }
.caddy-fields { display: flex; flex-direction: column; gap: 5px; }
.caddy-field { display: flex; align-items: center; gap: 8px; }
.caddy-label { flex: 1; color: var(--text-dim); }
.caddy .spinner { width: 88px; }
.caddy-actions { display: flex; gap: 5px; margin-top: 9px; }
.caddy-btn {
  flex: 1; height: 26px;
  display: inline-flex; align-items: center; justify-content: center;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--panel-lo);
  color: var(--text);
  cursor: pointer;
  transition: background var(--ease), border-color var(--ease);
}
.caddy-btn:hover { background: var(--panel-hi); border-color: var(--border-hi); }
.caddy-ok {
  background: color-mix(in srgb, var(--axis-y) 24%, var(--panel-lo));
  border-color: color-mix(in srgb, var(--axis-y) 55%, var(--border));
}
.caddy-ok:hover { background: color-mix(in srgb, var(--axis-y) 38%, var(--panel-lo)); }
.caddy-apply {
  background: color-mix(in srgb, var(--accent) 18%, var(--panel-lo));
  border-color: color-mix(in srgb, var(--accent) 45%, var(--border));
}
.caddy-apply:hover { background: color-mix(in srgb, var(--accent) 30%, var(--panel-lo)); }
.caddy-cancel:hover { border-color: var(--accent-2); color: #fff; }
.caddy-btn:disabled { opacity: 0.4; cursor: not-allowed; background: var(--panel-lo); border-color: var(--border); }
/* Choice control (Extrude Mode etc.) — a native select styled to match the numeric fields. */
.caddy-choice {
  width: 88px; height: 24px;
  border: 1px solid var(--border-hi);
  border-radius: var(--radius);
  background: var(--panel-lo);
  color: var(--text);
  font: inherit;
  padding: 0 4px;
  cursor: pointer;
}
/* Invalid preview (§27): red frame + label so the result reads as non-committable. */
.caddy.invalid { border-color: var(--accent-2); box-shadow: 0 0 0 1px var(--accent-2), 0 12px 30px rgba(0, 0, 0, 0.5); }
.caddy.invalid .caddy-head { color: var(--accent-2); border-bottom-color: color-mix(in srgb, var(--accent-2) 50%, var(--border)); }

/* ---- Optional accounts ------------------------------------------------------------------------
   The dialog is dismissible in every case, including at start-up, because the editor never requires
   an account. Styled to match the About card rather than as an interstitial, so it reads as an
   invitation and not a gate. */
.account-overlay {
  position: fixed;
  inset: 0;
  z-index: 60;
  display: grid;
  place-items: center;
  background: rgba(6, 8, 12, 0.62);
}
.account-card {
  width: min(28rem, calc(100vw - 2rem));
  padding: 1.5rem 1.5rem 1.25rem;
  border: 1px solid var(--line, #2a2f3a);
  border-radius: 10px;
  background: var(--panel, #171a21);
  box-shadow: 0 18px 48px rgba(0, 0, 0, 0.5);
}
.account-card h2 { margin: 0 0 0.35rem; font-size: 1.15rem; }
.account-lead { margin: 0 0 1rem; opacity: 0.72; font-size: 0.85rem; line-height: 1.45; }
.account-field { display: block; margin-bottom: 0.7rem; }
.account-field > span { display: block; margin-bottom: 0.25rem; font-size: 0.78rem; opacity: 0.78; }
.account-field input {
  width: 100%;
  padding: 0.45rem 0.55rem;
  border: 1px solid var(--line, #2a2f3a);
  border-radius: 6px;
  background: var(--bg, #0f1116);
  color: inherit;
  font: inherit;
}
.account-field input:focus-visible { outline: 2px solid var(--accent, #ff8a3d); outline-offset: 1px; }
.account-error {
  margin: 0 0 0.7rem;
  padding: 0.45rem 0.55rem;
  border-radius: 6px;
  background: rgba(255, 90, 90, 0.12);
  color: #ff9a9a;
  font-size: 0.8rem;
}
.account-actions { display: flex; gap: 0.5rem; align-items: center; }
.account-actions button {
  padding: 0.45rem 0.8rem;
  border: 1px solid var(--line, #2a2f3a);
  border-radius: 6px;
  background: var(--bg, #0f1116);
  color: inherit;
  font: inherit;
  cursor: pointer;
}
.account-primary { background: var(--accent, #ff8a3d); border-color: transparent; color: #14161b; font-weight: 600; }
.account-primary:disabled { opacity: 0.6; cursor: default; }
.account-switch { margin: 0.85rem 0 0; text-align: center; }
.account-toggle {
  border: 0;
  background: none;
  color: var(--accent, #ff8a3d);
  font: inherit;
  font-size: 0.82rem;
  cursor: pointer;
  text-decoration: underline;
}
/* The signed-in hint in the menu bar. */
.account-chip {
  margin-left: auto;
  padding: 0 0.7rem;
  align-self: center;
  font-size: 0.8rem;
  opacity: 0.72;
  cursor: pointer;
  white-space: nowrap;
  max-width: 14rem;
  overflow: hidden;
  text-overflow: ellipsis;
}
.account-chip:hover { opacity: 1; }
.account-chip.signed-in { opacity: 0.95; color: var(--accent, #ff8a3d); }

/* Pro entitlement markers. Deliberately quiet: the badge states a fact, it is not an advert. */
.pro-badge {
  align-self: center;
  margin-right: 0.6rem;
  padding: 0.05rem 0.35rem;
  border: 1px solid var(--accent, #ff8a3d);
  border-radius: 4px;
  color: var(--accent, #ff8a3d);
  font-size: 0.62rem;
  font-weight: 700;
  letter-spacing: 0.05em;
}
.pro-badge.loading { opacity: 0.55; border-style: dashed; }
/* Contributed entries carry the same accent, so it is obvious which parts of the interface the
   entitlement brought. */
.menu-item.pro-item::after {
  content: "PRO";
  margin-left: 0.5rem;
  color: var(--accent, #ff8a3d);
  font-size: 0.6rem;
  font-weight: 700;
  letter-spacing: 0.05em;
}
.rollout.pro-rollout > summary::after {
  content: "PRO";
  float: right;
  color: var(--accent, #ff8a3d);
  font-size: 0.6rem;
  font-weight: 700;
  letter-spacing: 0.05em;
}
.rollout.pro-rollout { border-color: color-mix(in srgb, var(--accent) 40%, var(--border)); }

/* ---- Pro feature panels (background maps, bake) --------------------------- */
/* Shared compact controls for module-supplied rollouts and dialogs, so a pro panel looks like the
   rest of the app rather than like a bolt-on. */
.pf-grid { display: grid; grid-template-columns: auto 1fr; align-items: center; gap: 5px 7px; }
.pf-grid > label { color: var(--text-dim); font-size: 10.5px; white-space: nowrap; }
.pf-grid .cp-select, .pf-grid .cp-num { width: 100%; }
.pf-actions { display: flex; gap: 5px; margin-top: 2px; }
.pf-actions .cp-btn { flex: 1; text-align: center; }
.pf-note { color: var(--text-dim); font-size: 10px; line-height: 1.45; }
.pf-progress {
  position: relative;
  height: 5px;
  margin: 2px 0;
  border-radius: 3px;
  background: var(--panel);
  overflow: hidden;
}
.pf-progress > i { position: absolute; inset: 0 auto 0 0; width: 0; background: var(--accent); transition: width .12s linear; }
.pf-swatch {
  width: 100%;
  aspect-ratio: 1 / 1;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background-color: var(--panel-lo);
  background-size: cover;
  background-position: center;
}

/* Modeless floating panel. Modeless on purpose: these settings are adjusted while watching the
   viewport, and a modal dialog would cover the thing it is describing. */
.pf-dialog {
  position: absolute;
  top: 84px; right: 336px;
  z-index: 540;
  width: 268px;
  display: flex;
  flex-direction: column;
  background: var(--panel);
  border: 1px solid var(--border-hi);
  border-radius: var(--radius);
  box-shadow: 0 10px 34px rgba(0, 0, 0, .48);
  font-size: 11px;
}
.pf-dialog[hidden] { display: none; }
.pf-dialog-head {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 5px 6px 5px 9px;
  background: var(--panel-hi);
  border-bottom: 1px solid var(--border);
  border-radius: var(--radius) var(--radius) 0 0;
  cursor: move;
  touch-action: none;
}
.pf-dialog-title { flex: 1; font-weight: 600; }
.pf-dialog-pro {
  padding: 0 4px;
  border: 1px solid var(--accent, #ff8a3d);
  border-radius: 3px;
  color: var(--accent, #ff8a3d);
  font-size: 8.5px;
  font-weight: 700;
  letter-spacing: .05em;
}
.pf-dialog-close {
  width: 19px; height: 19px;
  display: inline-flex; align-items: center; justify-content: center;
  padding: 0;
  border: 1px solid var(--border);
  border-radius: 3px;
  background: var(--panel-lo);
  color: var(--text-dim);
  cursor: pointer;
}
.pf-dialog-close:hover { background: var(--accent-2); border-color: var(--accent-2); color: #fff; }
.pf-dialog-body { display: flex; flex-direction: column; gap: 7px; padding: 8px 9px 9px; }
.pf-dialog-body .cp-num { width: 100%; }

/* Background dialog: image chip (thumbnail + name + actions) and the slider rows. */
.pbg-image { display: grid; grid-template-columns: 62px 1fr; gap: 8px; align-items: start; }
.pbg-image-meta { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.pbg-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pbg-slider { display: flex; align-items: center; gap: 5px; }
.pbg-slider .cp-range { flex: 1; width: auto; min-width: 0; }

/* Bake window: settings, progress, then the result chip (preview + assign / download). */
.bake-dialog { width: 296px; }
.bake-result {
  display: grid;
  grid-template-columns: 62px 1fr;
  gap: 8px;
  align-items: start;
  padding-top: 6px;
  border-top: 1px solid var(--border);
}
.bake-result[hidden] { display: none; }
.bake-result-meta { display: flex; flex-direction: column; gap: 5px; min-width: 0; }

/* Lights rollout: the list, then the selected light's properties. */
.lights-panel { display: flex; flex-direction: column; gap: 6px; }
.lights-panel .cp-num { width: 100%; }
.light-list {
  max-height: 132px;
  overflow-y: auto;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 3px;
}
.light-row {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 3px 6px;
  border-bottom: 1px solid var(--panel-lo);
  cursor: pointer;
}
.light-row:last-child { border-bottom: none; }
.light-row:hover { background: var(--panel-hi); }
.light-row.selected { background: color-mix(in srgb, var(--accent) 28%, var(--panel)); color: #fff; }
.light-toggle { width: 12px; text-align: center; color: var(--text-dim); }
.light-toggle.on { color: var(--accent); }
.light-swatch { width: 11px; height: 11px; border: 1px solid var(--border-hi); border-radius: 2px; }
.light-name { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.light-kind { color: var(--text-dim); font-size: 9.5px; }
.light-xyz { display: flex; gap: 3px; }
.light-xyz .cp-num { width: 100%; min-width: 0; text-align: right; }
.pf-note.light-over { color: var(--accent-2, #e2603c); }

/* Cloth rollout: the same compact controls as the others. */
.cloth-panel { display: flex; flex-direction: column; gap: 6px; }
.cloth-panel .cp-num { width: 100%; }

/* ---- Material Editor ------------------------------------------------------
   The scene's materials, edited on their own. A floating panel and not a rollout, because a material
   is not a property of whichever object is selected -- see js/ui/MaterialEditor.js. */
.material-editor { width: 330px; top: 64px; right: 320px; max-height: calc(100vh - 96px); }
/* While a material ball is being dragged the panel is transparent to hit-testing, so a drop can
   land on a model sitting behind it. See MaterialEditor's dragstart. Dimmed as well, so it is
   visibly out of the way rather than mysteriously unclickable. */
.material-editor.dragging { pointer-events: none; opacity: 0.55; }
.material-editor .pf-dialog-body { max-height: calc(100vh - 140px); overflow-y: auto; }
/* The body scrolls; its children must not be squashed to fit. Without this the ball grid collapses
   to a sliver on a short window, which reads as "the library is empty". */
.material-editor .pf-dialog-body > * { flex: none; }
.mat-lib-bar { gap: 3px; }
.mat-section {
  display: flex; align-items: baseline; gap: 6px;
  margin-top: 2px;
  color: var(--text);
  font-weight: 600; font-size: 10.5px;
}
.mat-section-hint { color: var(--text-dim); font-weight: 400; font-size: 9.5px; }

/* The library. Each material is a ball you can drag onto an object in the viewport. */
.mat-balls {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(58px, 1fr));
  gap: 6px;
  max-height: 188px;
  padding: 5px;
  overflow-y: auto;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--panel-lo);
}
.mat-ball {
  display: flex; flex-direction: column; align-items: center; gap: 3px;
  padding: 3px 2px;
  border: 1px solid transparent;
  border-radius: var(--radius);
  cursor: grab;
  user-select: none;
}
.mat-ball:hover { background: var(--panel); border-color: var(--border-hi); }
.mat-ball.selected { background: color-mix(in srgb, var(--accent) 26%, var(--panel-lo)); border-color: var(--accent); }
.mat-ball:active { cursor: grabbing; }
.mat-ball-face {
  width: 42px; height: 42px;
  border-radius: 50%;
  border: 1px solid var(--border-hi);
  box-shadow: inset 0 -2px 6px rgba(0,0,0,.5);
  background: var(--panel);
  flex: none;
}
.mat-ball-name {
  max-width: 100%;
  overflow: hidden;
  color: var(--text-dim);
  font-size: 9px;
  text-align: center;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.mat-ball.selected .mat-ball-name { color: #fff; }

/* One card per texture slot: the map, and the map's OWN tiling and offset directly underneath it. */
.mat-slots { display: flex; flex-direction: column; gap: 5px; }
.mat-slot {
  display: flex; gap: 7px;
  padding: 5px;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--panel-lo);
}
.mat-slot.has-map { border-color: color-mix(in srgb, var(--accent) 55%, var(--border)); }
.mat-slot > .tex-thumb { flex: none; }
.mat-slot-main { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 4px; }
.mat-slot-head { display: flex; align-items: center; gap: 6px; }
.mat-slot-name { flex: none; color: var(--text); font-size: 10.5px; font-weight: 600; }
.mat-slot-file { flex: 1; overflow: hidden; color: var(--text-dim); font: 9px "Cascadia Mono", "Consolas", monospace; text-overflow: ellipsis; white-space: nowrap; }
.mat-slot .tex-clear { position: static; width: 16px; height: 16px; flex: none; }
.mat-slot .row { padding: 0; background: none; border: none; }
.mat-slot .xf-row > label { flex: 0 0 auto; color: var(--text-dim); font-size: 9.5px; }
.mat-xf-all { padding: 5px 6px; border: 1px dashed var(--border-hi); border-radius: var(--radius); }
.mat-slider { display: flex; align-items: center; gap: 6px; }
.mat-slider .cp-range { flex: 1; }
.cp-text {
  width: 100%;
  padding: 2px 5px;
  border: 1px solid var(--border);
  border-radius: 3px;
  background: var(--panel);
  color: var(--text);
  font: 11px system-ui;
}
.cp-text:disabled { opacity: .45; }

/* The active object's material, in the command panel: a swatch and a dropdown. Assignment, not
   editing -- editing is the Material Editor's, and two copies of every control would disagree. */
.material-summary .row { display: flex; align-items: center; gap: 6px; }
.material-summary .mat-ball-face { width: 26px; height: 26px; }
.material-summary .mat-ball-face.empty { background: var(--panel); opacity: .4; }
.material-summary select { flex: 1; min-width: 0; }
