/* 3D model viewer (pairs with static/js/model_viewer.js). Self-contained
   mv-* classes with a hardcoded fallback on every theme var, so it renders
   the same on a page that does not load the planner's palette. The shell is
   the DWG viewer's (dwg_viewer.css) at HALF the screen — Jack, 2026-09-17 —
   with a ⤢ that takes it to most of it. */

/* The control — sits beside a name, like the drawing eye. */
.mv-open {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    padding: 2px 4px;
    margin-left: 6px;
    border: 1px solid var(--line, #d9d6cf);
    background: var(--surface, #fff);
    color: var(--ink-80, #4a4a4a);
    cursor: pointer;
    border-radius: 3px;
    font: inherit;
    font-size: 11px;
    vertical-align: middle;
}
.mv-open svg, .mv-modal__cube svg { width: 14px; height: 14px; }
.mv-open:hover { color: var(--ink, #1a1a1a); border-color: var(--line-strong, #8a8a8a); }

/* THE SQUARE beside a name — a picture, or the cube while there is none. */
.mv-hero {
    width: 20px;
    height: 20px;
    padding: 0;
    margin: 0;
    gap: 0;
    justify-content: center;
    flex: none;
    overflow: hidden;
    background: var(--surface, #fff);
}
.mv-hero img { display: block; width: 100%; height: 100%; object-fit: contain; }
.mv-hero--none { color: var(--ink-20, #bbb); border-style: dashed; }
.mv-hero--none:hover { color: var(--ink-60, #555); }
.mv-hero svg { width: 12px; height: 12px; }

/* Overlay + panel. */
.mv-modal { display: none; }
.mv-modal--open { display: block; position: fixed; inset: 0; z-index: 2000; }
.mv-modal__backdrop { position: absolute; inset: 0; background: var(--scrim, rgba(28, 28, 28, 0.45)); }
.mv-modal__panel {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    /* BIGGER (Jack, 2026-09-17): a bill's tree wants the height, a model
       wants the width; the half-screen pane made both fight. */
    width: 78vw;
    height: 84vh;
    min-width: min(960px, 96vw);
    min-height: min(560px, 92vh);
    display: flex;
    flex-direction: column;
    background: var(--surface, #fff);
    border: 1px solid var(--line, #d9d6cf);
    /* THE PAGE'S OWN CORNERS (2026-09-28): the planner draws square, the yard
       app sets `--mv-radius` to its cards' radius. */
    border-radius: var(--mv-radius, 0);
    overflow: hidden;
    box-shadow: var(--shadow-modal, 0 24px 64px rgba(0, 0, 0, 0.4));
    outline: none;
    transition: width 0.18s ease, height 0.18s ease;
}
.mv-modal--large .mv-modal__panel { width: 94vw; height: 92vh; }

.mv-modal__head {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 8px 10px 8px 12px;
    border-bottom: 1px solid var(--line, #d9d6cf);
    flex: none;
}
.mv-modal__cube { display: inline-flex; color: var(--ink-40, #8a8a8a); }
.mv-modal__title { font-weight: 600; font-size: 13px; color: var(--ink, #1a1a1a); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.mv-modal__sub { font-size: 11px; color: var(--ink-40, #7a7a7a); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; min-width: 0; }
.mv-hbtn {
    border: none;
    background: transparent;
    color: var(--ink-80, #4a4a4a);
    font-size: 15px;
    line-height: 1;
    cursor: pointer;
    padding: 4px 6px;
    border-radius: 3px;
}
.mv-hbtn:first-of-type { margin-left: auto; }
/* The 2D | 3D pick — one segmented control, the planner's view-pill shape. */
.mv-mode { display: inline-flex; margin-left: auto; border: 1px solid var(--line, #d9d6cf); border-radius: var(--mv-pill-radius, 4px); overflow: hidden; flex: none; }
.mv-mode[hidden] { display: none; }
.mv-mode + .mv-hbtn { margin-left: 4px; }
/* Which model (`variants`): the 2D | 3D pill's look, beside it. */
.mv-mode.mv-variant { margin-left: 6px; }
.mv-variant[hidden] { display: none; }
.mv-mode__b { border: 0; background: transparent; font: inherit; font-size: 11px; font-weight: 600; padding: 3px 9px; cursor: pointer; color: var(--ink-60, #4a4a4a); }
.mv-mode__b + .mv-mode__b { border-left: 1px solid var(--line, #d9d6cf); }
.mv-mode__b--on { background: var(--accent, #C8531C); color: var(--surface, #fff); cursor: default; }
/* 2D: the picture takes the stage; the tree and the model's tools step aside. */
.mv-pic { position: absolute; inset: 0; z-index: 2; background: var(--mv-stage-bg); overflow: hidden; cursor: grab; }
.mv-pic[hidden] { display: none; }
.mv-pic__img { width: 100%; height: 100%; object-fit: contain; display: block; transform-origin: 0 0; will-change: transform; user-select: none; -webkit-user-drag: none; }
.mv-modal--2d .mv-tree, .mv-modal--2d .mv-bar, .mv-modal--2d .mv-info, .mv-modal--2d .mv-hint, .mv-modal--2d .mv-tip, .mv-modal--2d .mv-load, .mv-modal--2d .mv-fail { display: none; }
.mv-hbtn:hover { color: var(--ink, #1a1a1a); background: var(--paper-warm, rgba(0, 0, 0, 0.05)); }

.mv-body { display: flex; flex: 1; min-height: 0; }

/* The tree, on the left. */
.mv-tree {
    width: 400px;
    flex: none;
    display: flex;
    flex-direction: column;
    border-right: 1px solid var(--line, #d9d6cf);
    background: var(--surface, #fff);
    min-height: 0;
}
.mv-tree__find {
    margin: 8px;
    padding: 5px 8px;
    border: 1px solid var(--line, #d9d6cf);
    border-radius: var(--mv-field-radius, 4px);
    font: inherit;
    font-size: 12px;
    color: var(--ink, #1a1a1a);
    background: var(--surface, #fff);
    outline: none;
}
.mv-tree__find:focus { border-color: var(--line-strong, #8a8a8a); }
.mv-tree__list { flex: 1; overflow: auto; padding: 0 0 8px; font-size: 12px; }
.mv-n {
    display: flex;
    align-items: center;
    gap: 5px;
    padding: 2px 8px 2px calc(4px + var(--d) * 14px);
    cursor: pointer;
    white-space: nowrap;
    color: var(--ink, #1a1a1a);
    line-height: 20px;
}
.mv-n:hover, .mv-n--hov { background: var(--paper-warm, rgba(0, 0, 0, 0.04)); }
.mv-n--sel { background: var(--accent-tint, rgba(200, 83, 28, 0.10)); color: var(--accent, #C8531C); font-weight: 600; }
.mv-n--dim { color: var(--ink-40, #8a8a8a); }
.mv-n--dim .mv-n__kind { opacity: 0.55; }
.mv-n__fold {
    flex: none;
    width: 14px;
    height: 14px;
    padding: 0;
    border: 0;
    background: transparent;
    color: var(--ink-40, #8a8a8a);
    cursor: pointer;
    position: relative;
}
.mv-n__fold::before {
    content: "";
    position: absolute;
    left: 4px;
    top: 3px;
    width: 5px;
    height: 5px;
    border-right: 1.5px solid currentColor;
    border-bottom: 1.5px solid currentColor;
    transform: rotate(-45deg);
    transition: transform 0.1s;
}
.mv-n[aria-expanded="true"] > .mv-n__fold::before { transform: rotate(45deg); top: 2px; }
.mv-n__fold--leaf { cursor: default; }
.mv-n__fold--leaf::before { display: none; }
.mv-n__kind {
    flex: none;
    font-size: 9px;
    font-weight: 700;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    padding: 0 4px;
    border-radius: 3px;
    line-height: 14px;
    background: var(--paper-grey, #eee);
    color: var(--ink-60, #555);
}
.mv-n--product > .mv-n__kind { background: var(--ink, #222); color: var(--surface, #fff); }
.mv-n--assembly > .mv-n__kind { background: var(--paper-deep, #ddd); color: var(--ink-80, #333); }
.mv-n--part > .mv-n__kind { background: #d8e8ff; color: #0b3d91; }
.mv-n--body > .mv-n__kind { background: #e6f4e6; color: #1e5e1e; }
.mv-n__name { overflow: hidden; text-overflow: ellipsis; min-width: 0; }
/* THE BILL'S QUANTITY beside the name (per one of the product), as the
   Model BOM view prints it; a piece of an aggregate has none */
.mv-n__qty { flex: none; font-size: 10px; color: var(--ink-40, #7a7a7a); font-variant-numeric: tabular-nums; }
.mv-n--piece .mv-n__kind { background: #eef3e8; color: #3f6a2a; }
.mv-n__ft { flex: 0 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; font-size: 9px; padding: 0 4px; border-radius: 3px; background: #ffe8c9; color: #7a4a00; line-height: 14px; }
.mv-n__count { flex: none; margin-left: auto; font-size: 10px; color: var(--ink-40, #8a8a8a); font-weight: 400; }

/* The stage, on the right. */
.mv-stage {
    --mv-stage-bg: #f4f4f2;
    position: relative;
    flex: 1;
    min-width: 0;
    min-height: 0;
    overflow: hidden;
    background: var(--mv-stage-bg);
    contain: strict;
}
.mv-canvas { display: block; width: 100% !important; height: 100% !important; touch-action: none; }
.mv-bar {
    position: absolute;
    top: 8px;
    left: 8px;
    right: 8px;
    display: flex;
    gap: 8px;
    align-items: flex-start;
    pointer-events: none;
}
.mv-bar > * { pointer-events: auto; }
.mv-crumb {
    display: flex;
    flex: 0 1 auto;
    min-width: 0;
    align-items: center;
    gap: 2px;
    background: rgba(255, 255, 255, 0.92);
    border: 1px solid var(--line, #d9d6cf);
    border-radius: 4px;
    padding: 3px 6px;
    overflow: hidden;
    white-space: nowrap;
    font-size: 12px;
}
.mv-crumb:empty { display: none; }
.mv-crumb__s {
    border: 0;
    background: transparent;
    font: inherit;
    color: var(--accent, #C8531C);
    cursor: pointer;
    padding: 1px 3px;
    border-radius: 3px;
    overflow: hidden;
    text-overflow: ellipsis;
    max-width: 220px;
}
.mv-crumb__s:hover { background: var(--accent-tint, rgba(200, 83, 28, 0.10)); }
.mv-crumb__s[aria-current] { color: var(--ink, #1a1a1a); cursor: default; font-weight: 600; }
.mv-crumb__s[aria-current]:hover { background: transparent; }
.mv-crumb__sep { color: var(--ink-40, #8a8a8a); }
.mv-tools { margin-left: auto; display: flex; gap: 4px; flex: none; }
.mv-btn {
    background: rgba(255, 255, 255, 0.92);
    border: 1px solid var(--line, #d9d6cf);
    border-radius: 4px;
    padding: 4px 9px;
    cursor: pointer;
    font: inherit;
    font-size: 12px;
    color: var(--ink-80, #4a4a4a);
    white-space: nowrap;
}
.mv-btn:hover { color: var(--ink, #1a1a1a); border-color: var(--line-strong, #8a8a8a); }
.mv-btn:disabled { opacity: 0.45; cursor: default; }
.mv-btn--on { background: var(--accent-tint, rgba(200, 83, 28, 0.10)); border-color: var(--accent, #C8531C); color: var(--accent, #C8531C); }

.mv-info {
    position: absolute;
    left: 8px;
    bottom: 8px;
    display: flex;
    align-items: baseline;
    gap: 8px;
    max-width: 64%;
    background: rgba(255, 255, 255, 0.92);
    border: 1px solid var(--line, #d9d6cf);
    border-radius: 4px;
    padding: 4px 8px;
    font-size: 11px;
    color: var(--ink-60, #4a4a4a);
    white-space: nowrap;
    overflow: hidden;
    pointer-events: none;
}
.mv-info:empty { display: none; }
/* When the bar is short of room the SOURCE FILE gives way first, then the
   name; the kind, the size and the count never do — they are the figures. */
.mv-info b { color: var(--ink, #1a1a1a); font-size: 12px; overflow: hidden; text-overflow: ellipsis; flex: 0 1 auto; min-width: 80px; }
.mv-info__kind { flex: none; font-size: 9px; font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase; color: var(--ink-40, #8a8a8a); }
.mv-info__src { flex: 0 20 auto; min-width: 0; color: var(--ink-40, #8a8a8a); overflow: hidden; text-overflow: ellipsis; }
.mv-info__dim { flex: none; font-family: ui-monospace, monospace; }
.mv-info__tri { flex: none; color: var(--ink-40, #8a8a8a); }

.mv-tip {
    position: absolute;
    pointer-events: none;
    background: rgba(28, 28, 28, 0.92);
    color: #fff;
    border-radius: 4px;
    padding: 4px 8px;
    font-size: 12px;
    line-height: 1.3;
    white-space: nowrap;
    z-index: 2;
}
.mv-tip b { display: block; }
.mv-tip span { color: #bcd0f0; font-size: 11px; }
.mv-tip[hidden] { display: none; }

.mv-hint {
    position: absolute;
    right: 8px;
    top: 40px;
    padding: 3px 7px;
    font-size: 9px;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: #fff;
    background: rgba(26, 26, 26, 0.62);
    border-radius: 3px;
    pointer-events: none;
    opacity: 0;
    transition: opacity 0.15s;
}
.mv-stage:hover .mv-hint { opacity: 1; }

/* Loading + failure, over the stage. */
.mv-load {
    position: absolute;
    inset: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 10px;
    background: var(--mv-stage-bg);
    font-size: 12px;
    color: var(--ink-60, #4a4a4a);
    z-index: 3;
}
.mv-load[hidden] { display: none; }
.mv-load__bar { width: 180px; height: 4px; background: var(--paper-deep, #ddd); border-radius: 2px; overflow: hidden; }
.mv-load__bar i { display: block; height: 100%; width: 0; background: var(--accent, #C8531C); transition: width 0.1s; }
.mv-load__bar--indeterminate i { width: 40%; animation: mv-slide 1.1s ease-in-out infinite; }
@keyframes mv-slide { 0% { transform: translateX(-100%); } 100% { transform: translateX(350%); } }
.mv-fail {
    position: absolute;
    inset: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 8px;
    padding: 12px 16px;
    text-align: center;
    background: var(--mv-stage-bg);
    z-index: 3;
}
.mv-fail[hidden] { display: none; }
/* Nothing behind this side yet — said plainly, in the stage's own tone. */
.mv-none {
    position: absolute;
    inset: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 6px;
    background: var(--mv-stage-bg);
    color: var(--ink-40, #8a8a8a);
    z-index: 3;
}
.mv-none[hidden] { display: none; }
.mv-none svg { width: 28px; height: 28px; color: var(--ink-20, #ccc); margin-bottom: 4px; }
.mv-none__msg { font-size: 12px; font-weight: 600; color: var(--ink-60, #4a4a4a); }
.mv-none__sub { font-size: 11px; max-width: 70%; text-align: center; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.mv-modal--none .mv-bar, .mv-modal--none .mv-info, .mv-modal--none .mv-hint, .mv-modal--none .mv-tip, .mv-modal--none .mv-load { display: none; }
.mv-tree__empty { margin: 8px 12px; font-size: 12px; color: var(--ink-40, #8a8a8a); }
.mv-fail__tag { font-size: 9.5px; font-weight: 700; letter-spacing: 0.14em; padding: 3px 8px; background: var(--ink, #1a1a1a); color: var(--surface, #fff); }
.mv-fail__msg { font-size: 12px; color: var(--ink-80, #4a4a4a); max-width: 60%; }

@media (max-width: 900px) {
    .mv-modal__panel { width: 96vw; height: 90vh; }
    .mv-tree { width: 200px; }
}

/* THE 3D | PARTS PILL — the 2D | 3D pick's shape, drawn only on a phone. */
.mv-pane { display: none; border: 1px solid var(--line, #d9d6cf); border-radius: var(--mv-pill-radius, 4px); overflow: hidden; flex: none; }
.mv-pane__b { border: 0; background: transparent; font: inherit; font-size: 12px; font-weight: 600; padding: 5px 12px; cursor: pointer; color: var(--ink-60, #4a4a4a); }
.mv-pane__b + .mv-pane__b { border-left: 1px solid var(--line, #d9d6cf); }
.mv-pane__b--on { background: var(--accent, #C8531C); color: var(--surface, #fff); cursor: default; }

/* A PHONE (Jack, 2026-09-28: "it doesnt fit on the phone ... a pill to change
   between the viewer and the parts"): the panel fills the screen less a
   margin, and ONE pane shows at a time — the model, or the parts at full
   width. The expand toggle and the mouse hint mean nothing here. */
@media (max-width: 700px) {
    .mv-modal__panel {
        top: 8px; left: 8px; right: 8px; bottom: 8px;
        transform: none; width: auto; height: auto; min-width: 0; min-height: 0;
    }
    .mv-modal--large .mv-modal__panel { width: auto; height: auto; }
    /* two rows: the title and ✕, then the pills (a zero-height break item) */
    .mv-modal__head { flex-wrap: wrap; row-gap: 8px; }
    .mv-modal__head::after { content: ''; order: 2; flex-basis: 100%; height: 0; }
    .mv-modal__title { flex: 1 1 0; min-width: 0; }
    .mv-modal__sub, [data-mv-expand], .mv-hint { display: none; }
    .mv-hbtn[data-mv-close] { order: 1; margin-left: 4px; }
    .mv-pane { display: inline-flex; order: 3; margin-left: 0; }
    .mv-mode { order: 4; margin-left: auto; }
    .mv-body { position: relative; }
    .mv-tree { width: 100%; border-right: 0; }
    .mv-modal:not(.mv-modal--parts) .mv-tree { display: none; }
    .mv-modal--parts .mv-stage { display: none; }
    .mv-modal--2d .mv-pane { display: none; }
}

/* THE BILL ON THE LEFT (2026-09-18): Bill | Model switch above the finder;
   a SKU row and its item rows reuse the tree row's own classes. */
.mv-tree__mode { display: flex; gap: 4px; padding: 8px 10px 0; }
.mv-tree__mode[hidden] { display: none; }
.mv-tree__mb { flex: 1; font: 500 11px/22px 'IBM Plex Sans', system-ui, sans-serif; height: 22px; padding: 0 8px; border-radius: var(--mv-pill-radius, 0);
    background: var(--surface, #fff); border: 1px solid var(--line-strong, #8a8a8a); color: var(--ink-60, #555); cursor: pointer; }
.mv-tree__mb:hover { color: var(--ink, #222); }
.mv-tree__mb--on { background: var(--accent, #C8531C); border-color: var(--accent, #C8531C); color: #fff; }
.mv-b--band > .mv-n__kind { background: #d8e8ff; color: #0b3d91; }
.mv-b--sku > .mv-n__kind { background: #f3e3d6; color: #7a3410; }
.mv-b--item > .mv-n__kind { background: #e6f4e6; color: #1e5e1e; }
