﻿/* ============================================================
   CSiBridge — Modeler shell (post "Generate Model")
   Ribbon + Explorer tree + contextual Property panel + 3D view.
   Fluent tokens re-declared under .mdl-app (same values as the other
   overlays); theme follows the WebView color scheme.
   ============================================================ */

.mdl-app {
  --radius-control: 4px;
  --radius-card: 6px;

  --font: "Segoe UI Variable Text", "Segoe UI Variable", "Segoe UI",
    -apple-system, system-ui, "Helvetica Neue", Arial, sans-serif;
  --font-display: "Segoe UI Variable Display", "Segoe UI Variable",
    "Segoe UI", -apple-system, system-ui, sans-serif;

  position: fixed;
  inset: 0;
  z-index: 1000;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  font-family: var(--font);
  color: var(--text-primary);
  font-size: 12px;
  line-height: 1.35;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

.mdl-app *,
.mdl-app *::before,
.mdl-app *::after {
  box-sizing: border-box;
}

/* ---------- LIGHT ---------- */
.mdl-app {
    /* Theme native form controls (the <select> dropdown popup, scrollbars) to
     match — without this the dropdown list renders white in dark mode. */
    color-scheme: light;
    --accent: #0067c0;
    --accent-hover: #1975c5;
    --accent-pressed: #3183cb;
    --accent-fill-text: #ffffff;
    --border: 1px solid #CCC;
    --text-primary: rgba(0, 0, 0, 0.90);
    --text-secondary: rgba(0, 0, 0, 0.80);
    --text-tertiary: rgba(0, 0, 0, 0.65);
    --text-disabled: rgba(0, 0, 0, 0.50);
    --text-mute: #838b95;

    --mica-base: #edeaf1;
    --layer: #ffffff;
    --card: #ffffff;
    --card-secondary: #fbfbfb;
    --card-head: #f3f3f3;
    --card-stroke: #CCC;
    --control-fill: rgba(255, 255, 255, 0.7);
    --control-fill-hover: rgba(249, 249, 249, 0.5);
    --control-fill-pressed: rgba(249, 249, 249, 0.3);
    --control-stroke: rgba(0, 0, 0, 0.0578);
    --control-stroke-bottom: rgba(0, 0, 0, 0.1622);
    --subtle-hover: rgba(0, 0, 0, 0.0373);
    --subtle-pressed: rgba(0, 0, 0, 0.0241);
    --subtle-selected: rgba(0, 0, 0, 0.0606);
    --divider: rgba(0, 0, 0, 0.0803);
    --flyout: #fcfcfc;
    --flyout-stroke: rgba(0, 0, 0, 0.0578);
    --shadow-card: 0 1px 3px rgba(0, 0, 0, 0.08), 0 0.3px 0.9px rgba(0, 0, 0, 0.06);
    --th-bg: #f7f7f7;
    --canvas2d-bg: #ffffff;
    /* Explorer selected-row highlight (accent tint). */
    --tree-sel-bg: rgba(0, 103, 192, 0.13);
    --tree-sel-bg-hover: rgba(0, 103, 192, 0.20);
    --shadow: 0 8px 28px rgba(20, 30, 50, .15);
}

/* ---------- DARK ----------
   Two triggers, because the two hosts change theme by different means.

   The desktop WebView is told to follow (or override) the OS scheme by the
   native shell — WebBridge.ApplyTheme — so prefers-color-scheme is the whole
   story there and the media query below is what has always run.

   A browser cannot be told what the OS prefers. Settings ▸ UI Theme instead
   stamps data-theme="light"/"dark" on <html> (BridgeHost.setTheme, index.html)
   and removes it for "System". Nothing here used to read that attribute, which
   is exactly why the dropdown appeared dead in the web viewer: it set a flag no
   stylesheet was listening for.

   So: the media query now yields to an explicit Light choice, and an explicit
   Dark choice gets its own copy of the palette below. The token list is
   duplicated verbatim — CSS has no way to share one declaration block between a
   media query and a selector, and the same trade-off is already made on the
   Open Model page (OpenModel.razor.css). Edit both copies together.

   On the desktop nothing is ever stamped, so :not([data-theme="light"]) always
   matches and [data-theme="dark"] never does — the behaviour there is unchanged. */
@media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) .mdl-app {
        color-scheme: dark;
        --accent: #4cc2ff;
        --accent-hover: #47b1e8;
        --accent-pressed: #42a1d2;
        --accent-fill-text: #00131f;
        --border: 1px solid #555555;
        --text-primary: #ffffff;
        --text-secondary: rgba(255, 255, 255, 0.786);
        --text-tertiary: rgba(255, 255, 255, 0.5442);
        --text-disabled: rgba(255, 255, 255, 0.3628);
        --text-mute: #7c838d;

        --mica-base: #202020;
        --layer: #272727;
        --card: #2b2b2b;
        --card-secondary: #2d2d2d;
        --card-head: #333333;
        --card-stroke: rgba(255, 255, 255, 0.0837);
        --control-fill: rgba(255, 255, 255, 0.0605);
        --control-fill-hover: rgba(255, 255, 255, 0.0837);
        --control-fill-pressed: rgba(255, 255, 255, 0.0326);
        --control-stroke: rgba(255, 255, 255, 0.0698);
        --control-stroke-bottom: rgba(255, 255, 255, 0.0954);
        --subtle-hover: rgba(255, 255, 255, 0.0605);
        --subtle-pressed: rgba(255, 255, 255, 0.0419);
        --subtle-selected: rgba(255, 255, 255, 0.0837);
        --divider: rgba(255, 255, 255, 0.0837);
        --flyout: #2c2c2c;
        --flyout-stroke: rgba(255, 255, 255, 0.0698);
        --shadow-card: 0 1px 3px rgba(0, 0, 0, 0.28), 0 0.3px 0.9px rgba(0, 0, 0, 0.22);
        --th-bg: #2f2f2f;
        --canvas2d-bg: #1e1e1e;
        --tree-sel-bg: rgba(76, 194, 255, 0.22);
        --tree-sel-bg-hover: rgba(76, 194, 255, 0.30);
        --shadow: 0 8px 28px rgba(20, 30, 50, .15);
    }
}

/* Explicit Dark (Settings ▸ UI Theme) — a verbatim copy of the block above.
   See the comment there before editing either one. */
:root[data-theme="dark"] .mdl-app {
    color-scheme: dark;
    --accent: #4cc2ff;
    --accent-hover: #47b1e8;
    --accent-pressed: #42a1d2;
    --accent-fill-text: #00131f;
    --border: 1px solid #555555;
    --text-primary: #ffffff;
    --text-secondary: rgba(255, 255, 255, 0.786);
    --text-tertiary: rgba(255, 255, 255, 0.5442);
    --text-disabled: rgba(255, 255, 255, 0.3628);
    --text-mute: #7c838d;

    --mica-base: #202020;
    --layer: #272727;
    --card: #2b2b2b;
    --card-secondary: #2d2d2d;
    --card-head: #333333;
    --card-stroke: rgba(255, 255, 255, 0.0837);
    --control-fill: rgba(255, 255, 255, 0.0605);
    --control-fill-hover: rgba(255, 255, 255, 0.0837);
    --control-fill-pressed: rgba(255, 255, 255, 0.0326);
    --control-stroke: rgba(255, 255, 255, 0.0698);
    --control-stroke-bottom: rgba(255, 255, 255, 0.0954);
    --subtle-hover: rgba(255, 255, 255, 0.0605);
    --subtle-pressed: rgba(255, 255, 255, 0.0419);
    --subtle-selected: rgba(255, 255, 255, 0.0837);
    --divider: rgba(255, 255, 255, 0.0837);
    --flyout: #2c2c2c;
    --flyout-stroke: rgba(255, 255, 255, 0.0698);
    --shadow-card: 0 1px 3px rgba(0, 0, 0, 0.28), 0 0.3px 0.9px rgba(0, 0, 0, 0.22);
    --th-bg: #2f2f2f;
    --canvas2d-bg: #1e1e1e;
    --tree-sel-bg: rgba(76, 194, 255, 0.22);
    --tree-sel-bg-hover: rgba(76, 194, 255, 0.30);
    --shadow: 0 8px 28px rgba(20, 30, 50, .15);
}

/* ============================================================
   Ribbon
   ============================================================ */
.mdl-ribbon {
  flex: 0 0 auto;
  background: var(--mica-base);
  border-bottom: 1px solid var(--divider);
}

/* While Results ▸ Animation is playing, the ribbon (tabs + body) is
   read-only except the Play/Stop button itself, so Stop always stays
   reachable. A dimming overlay (rather than opacity on the ribbon itself)
   is used so the Stop button — raised above it via z-index — stays fully
   legible and clickable instead of inheriting the parent's faded alpha.
   See .mdl-explorer.mdl-locked below for the matching Explorer lockout. */
.mdl-ribbon.mdl-locked {
  position: relative;
  pointer-events: none;
}

.mdl-ribbon.mdl-locked::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 5;
  background: var(--mica-base);
  opacity: 0.55;
  pointer-events: none;
}

.mdl-ribbon.mdl-locked .mdl-anim-toggle {
  position: relative;
  z-index: 6;
  pointer-events: auto;
}

.mdl-tabs {
  display: flex;
  align-items: stretch;
  height: 34px;
  padding: 0 6px;
  gap: 2px;
}

.mdl-tab {
  position: relative;
  border: 0;
  background: transparent;
  cursor: pointer;
  padding: 0 12px;
  font-family: inherit;
  font-size: 13px;
  color: var(--text-secondary);
}

.mdl-tab:hover {
  color: var(--text-primary);
  background: var(--subtle-hover);
  border-radius: var(--radius-control);
}

.mdl-tab.active {
  color: var(--text-primary);
  font-weight: 600;
}

.mdl-tab.active::after {
  content: "";
  position: absolute;
  left: 10px;
  right: 10px;
  bottom: 0;
  height: 2.5px;
  border-radius: 2px;
  background: var(--accent);
}

/* Contextual tab (Mesh/Results): only shown while its FE view is active. */
.mdl-tab-ctx {
  color: var(--accent);
}

.mdl-tab-ctx.active::after {
  background: var(--accent);
}

.mdl-ribbon-body {
  background-color: var(--layer);
  border: var(--border);
  border-radius: 8px;
  display: flex;
  align-items: stretch;
  gap: 0;
  height: 102px;
  margin: 4px;
  padding: 2px 6px 2px;
  /* overflow must stay visible so the Visibility flyouts can drop below the
     100px ribbon without being clipped. (overflow-x:auto would force
     overflow-y to auto too, re-clipping the flyout.) */
  overflow: visible;
}

.mdl-rgroup {
  display: flex;
  flex-direction: column;
  padding: 0 8px;
}

.mdl-rgroup+.mdl-rgroup {
  border-left: 1px solid var(--divider);
}

.mdl-rgroup-tools {
  flex: 1 1 auto;
  display: flex;
  gap: 4px;
}

/* Groups whose tools stack vertically (Home ▸ 3D Display, Visibility). A class
   rather than the inline style this used to be, so .mdl-ribbon-slim can flip
   them back to a single row — inline styles win over every stylesheet rule. */
.mdl-rgroup-tools.mdl-rtools-col {
  flex-direction: column;
  justify-content: center;
  gap: 8px;
}

/* Visibility's rows are .mdl-rfield, which already carries its own height. */
.mdl-rgroup-tools.mdl-rtools-col.mdl-rtools-tight {
  gap: 0;
}

.mdl-rgroup-label {
  text-align: center;
  font-size: 11px;
  color: var(--text-tertiary);
}

/* Ribbon overflow — "More" menu (see ribbon-overflow.js). #mdl-ribbon-measure is
   an always-complete, off-screen copy of the active tab's groups that the JS
   measures against; it never paints and never affects layout. */
.mdl-ribbon-measure {
  position: absolute;
  top: -9999px;
  left: 0;
  visibility: hidden;
  display: flex;
  align-items: stretch;
  pointer-events: none;
}

.mdl-ribbon-more {
  position: relative;
}

.mdl-ribbon-more-pop {
  position: absolute;
  top: 100%;
  right: 0;
  z-index: 91;
  display: flex;
  flex-wrap: wrap;
  align-content: flex-start;
  max-width: 520px;
  padding: 4px;
  background: var(--flyout);
  border: 1px solid var(--flyout-stroke);
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-card);
}

/* Large ribbon button (icon over label) */
.mdl-rbtn-lg {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: flex-start;
  gap: 4px;
  min-width: 60px;
  height: 72px;
  padding: 6px 8px;
  border: 1px solid transparent;
  border-radius: var(--radius-control);
  background: transparent;
  cursor: pointer;
  color: var(--text-primary);
  font-family: inherit;
  font-size: 11.5px;
}

.mdl-rbtn-lg svg {
  width: 30px;
  height: 30px;
}

.mdl-rbtn-lg .lbl {
  max-width: 72px;
  text-align: center;
  line-height: 1.1;
}

.mdl-rbtn-lg:hover {
  background: var(--subtle-hover);
  border-color: var(--card-stroke);
}

.mdl-rbtn-lg:active {
  background: var(--subtle-pressed);
}

.mdl-rbtn-lg.disabled {
  color: var(--text-disabled);
  pointer-events: none;
}

.mdl-rbtn-lg.disabled svg {
  color: var(--text-disabled);
}

.mdl-rbtn-lg.is-on {
  background: var(--subtle-selected);
  border-color: var(--card-stroke);
}

/* Vertical column of combos / sliders / small buttons within a ribbon group */
.mdl-rfields {
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
  gap: 2px;
  justify-content: center;
}

.mdl-color-swatch {
  width: 26px;
  height: 18px;
  border-radius: 3px;
  border: 1px solid var(--control-stroke-bottom);
  background: linear-gradient(135deg, #9db8d8, #c9b6d6);
}

/* Small ribbon button (icon + label, stacked rows in a column) */
.mdl-rcol {
  display: flex;
  flex-direction: column;
  gap: 2px;
  justify-content: center;
}

/* A group's big button with a secondary small button stacked underneath it
   (Run Analysis / Unlock Model, Analysis ▸ Run) — unlike .mdl-rcol, this pairs
   one .mdl-rbtn-lg with one .mdl-rbtn-sm rather than stacking small buttons alone. */
.mdl-rstack {
  display: flex;
  flex-direction: column;
  gap: 4px;
  justify-content: center;
}

/* Primary/CTA ribbon button (Run Analysis, and Unlock Model once analysed) —
   filled with the accent color so it reads as the next action to take. */
.mdl-rbtn-lg.mdl-rbtn-accent,
.mdl-rbtn-sm.mdl-rbtn-accent {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--accent-fill-text);
  padding: 6px 8px;
  height: 50px;
}

.mdl-rbtn-lg.mdl-rbtn-accent svg,
.mdl-rbtn-sm.mdl-rbtn-accent svg {
  color: var(--accent-fill-text);
}

.mdl-rbtn-lg.mdl-rbtn-accent:hover,
.mdl-rbtn-sm.mdl-rbtn-accent:hover {
  background: var(--accent-hover);
  border-color: var(--accent-hover);
}

.mdl-rbtn-lg.mdl-rbtn-accent:active,
.mdl-rbtn-sm.mdl-rbtn-accent:active {
  background: var(--accent-pressed);
  border-color: var(--accent-pressed);
}

.mdl-rbtn-sm {
  display: flex;
  align-items: center;
  gap: 7px;
  height: 26px;
  padding: 0 8px 0 6px;
  border: 1px solid transparent;
  border-radius: var(--radius-control);
  background: transparent;
  cursor: pointer;
  color: var(--text-primary);
  font-family: inherit;
  font-size: 12px;
  text-align: left;
  white-space: nowrap;
}

.mdl-rbtn-sm svg {
  width: 16px;
  height: 16px;
  flex: 0 0 16px;
  color: var(--text-secondary);
}

.mdl-rbtn-sm:hover {
  background: var(--subtle-hover);
}

.mdl-rbtn-sm:active {
  background: var(--subtle-pressed);
}

.mdl-rbtn-sm.is-on {
  background: var(--subtle-selected);
}

.mdl-rbtn-sm.disabled {
  color: var(--text-disabled);
  pointer-events: none;
}

.mdl-rbtn-sm.disabled svg {
  color: var(--text-disabled);
}

/* Labeled dropdown control inside the ribbon (Visible Layers, Color By, …) */
.mdl-rfield {
  display: flex;
  align-items: center;
  gap: 8px;
  height: 26px;
  padding-left: 6px;
}

.mdl-rfield>svg {
  width: 16px;
  height: 16px;
  color: var(--text-secondary);
}

.mdl-rfield .rf-label {
  font-size: 12px;
  min-width: 92px;
  white-space: nowrap;
}

/* Data-driven ribbon groups (Options tab): fixed-width label column so the
   dropdowns/controls in a group line up regardless of label length. */
.mdl-rfield .rf-label.rf-label-wide {
  flex: 0 0 100px;
  min-width: 100px;
  white-space: nowrap;
}

.mdl-rselect {
  /* Extra right padding so the native drop arrow doesn't touch the border. */
  height: 24px;
  min-width: 132px;
  padding: 0 12px 0 8px;
  background: var(--control-fill);
  border: 1px solid var(--control-stroke);
  border-bottom-color: var(--control-stroke-bottom);
  border-radius: var(--radius-control);
  color: var(--text-primary);
  font-family: inherit;
  font-size: 12px;
}

/* Ribbon range sliders (Transparency, Lane Discretization, …) — restyled to
   match the section-clipping card's dual-handle sliders (.bridge-clip-track/
   -rail/-fill/-thumb in the block above) so every slider in the app reads as
   one control: a rounded track, an accent-colored fill up to the thumb, and a
   filled circular thumb with an accent border. Native <input type="range">
   only exposes styling through vendor pseudo-elements — WebView2 is
   Chromium-based so -webkit- is what actually renders, -moz- is included for
   parity if this ever runs in a browser host. The "filled" portion (blue up
   to the thumb) needs a live percentage, so callers set `--range-pct` inline
   (see RangeStyle/RangeBackground helpers) rather than this stylesheet trying
   to compute it from min/max/value, which CSS can't do on its own. */
.mdl-range {
  -webkit-appearance: none;
  appearance: none;
  height: 16px;
  background: transparent;
  cursor: pointer;
  --range-pct: 0%;
}

.mdl-range::-webkit-slider-runnable-track {
  height: 8px;
  border-radius: 8px;
  background: linear-gradient(to right, var(--accent) 0%, var(--accent) var(--range-pct), var(--text-disabled) var(--range-pct), var(--text-disabled) 100%);
}

.mdl-range::-webkit-slider-thumb {
  -webkit-appearance: none;
  width: 12px;
  height: 12px;
  margin-top: -2px;
  border-radius: 50%;
  background: var(--layer);
  border: 2px solid var(--accent);
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.3);
  cursor: grab;
}

.mdl-range::-webkit-slider-thumb:active {
  cursor: grabbing;
}

.mdl-range::-moz-range-track {
  height: 8px;
  border-radius: 8px;
  background: var(--text-disabled);
}

.mdl-range::-moz-range-progress {
  height: 8px;
  border-radius: 8px;
  background: var(--accent);
}

.mdl-range::-moz-range-thumb {
  width: 12px;
  height: 12px;
  border-radius: 50%;
  background: var(--layer);
  border: 2px solid var(--accent);
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.3);
  cursor: grab;
}

.mdl-range:focus-visible::-webkit-slider-thumb {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

.mdl-range:focus-visible::-moz-range-thumb {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

/* The open dropdown popup paints from the <option> background/color, not the
   translucent control fill — give them a SOLID surface so dark mode isn't
   white-on-white. */
.mdl-rselect option,
.mdl-select option {
  background: var(--flyout);
  color: var(--text-primary);
}

/* Native <select> dropdowns: the built-in drop arrow sits hard against the
   border and ignores padding-right, so swap in our own chevron positioned with
   a gap. Scoped to `select` so the buttons that merely reuse .mdl-rselect
   (Visible Layers/Objects, Bridge Colors) keep their own SVG caret. */
select.mdl-rselect,
select.mdl-select {
  -webkit-appearance: none;
  appearance: none;
  /* Chevron stroke ≈ --text-secondary (light theme) so it matches the SVG
     carets on the flyout buttons; dark-theme variant below. */
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%23333333' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 8px center;
  background-size: 13px 13px;
  padding-right: 30px;
}

/* Dark chevron — both theme triggers, as at the top of this file. */
@media (prefers-color-scheme: dark) {

  :root:not([data-theme="light"]) select.mdl-rselect,
  :root:not([data-theme="light"]) select.mdl-select {
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%23c9c9c9' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
  }
}

:root[data-theme="dark"] select.mdl-rselect,
:root[data-theme="dark"] select.mdl-select {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%23c9c9c9' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
}

/* ============================================================
   Slim ribbon — viewer hosts only (.mdl-ribbon-slim, set from Modeler.razor
   when AppCapabilities.ViewerOnly)
   ============================================================
   The desktop ribbon body is 102px because it stacks three rows of small
   buttons, or an icon over a label, inside every group. A viewer's command set
   is a fraction of that and purely about display, so it collapses to a single
   36px row in the style of Office on the web: icon BESIDE label, groups laid
   out left to right separated by the existing .mdl-rgroup divider, and no
   group caption — the caption sits under the tools, which is the third row
   this layout no longer has.

   Everything below is a re-layout, not a re-skin: the same markup renders in
   both hosts, so the desktop rules stay exactly as they are above and nothing
   here applies unless the slim class is present. Scoped to the ribbon so the
   Analysis-tab "More" flyout (.mdl-ribbon-more-pop, which hangs OUTSIDE the
   36px strip and can afford to stack) is unaffected — it is a descendant of
   .mdl-ribbon, so it inherits these too, but a viewer never shows that tab. */
.mdl-ribbon-slim .mdl-ribbon-body {
  height: 36px;
  align-items: center;
  padding: 0 4px;
}

.mdl-ribbon-slim .mdl-rgroup {
  flex-direction: row;
  align-items: center;
  gap: 4px;
  padding: 0 6px;
}

.mdl-ribbon-slim .mdl-rgroup-label {
  display: none;
}

/* Every vertical stack inside a group becomes horizontal. .mdl-rgroup-tools
   also loses its `flex: 1 1 auto` — that existed to push the caption to the
   bottom of a 102px column, and the caption is gone. The doubled
   .mdl-rtools-tight selector outweighs its own gap:0 rule above. */
.mdl-ribbon-slim .mdl-rgroup-tools,
.mdl-ribbon-slim .mdl-rgroup-tools.mdl-rtools-col,
.mdl-ribbon-slim .mdl-rgroup-tools.mdl-rtools-col.mdl-rtools-tight,
.mdl-ribbon-slim .mdl-rcol,
.mdl-ribbon-slim .mdl-rfields,
.mdl-ribbon-slim .mdl-rstack {
  flex: 0 0 auto;
  flex-direction: row;
  align-items: center;
  gap: 4px;
}

/* Large button: icon-over-label tile (72px) → icon + label on one line. */
.mdl-ribbon-slim .mdl-rbtn-lg {
  flex-direction: row;
  align-items: center;
  justify-content: center;
  gap: 7px;
  min-width: 0;
  height: 28px;
  padding: 0 8px;
  font-size: 12px;
}

.mdl-ribbon-slim .mdl-rbtn-lg svg {
  width: 16px;
  height: 16px;
}

.mdl-ribbon-slim .mdl-rbtn-lg .lbl {
  max-width: none;
  white-space: nowrap;
}

/* The accent CTA sets its own 50px height, which does not fit either. */
.mdl-ribbon-slim .mdl-rbtn-lg.mdl-rbtn-accent,
.mdl-ribbon-slim .mdl-rbtn-sm.mdl-rbtn-accent {
  height: 28px;
  padding: 0 8px;
}

.mdl-ribbon-slim .mdl-rbtn-sm {
  height: 26px;
}

/* Labeled dropdowns (Visible Layers, Color By, Panel Style, …). Side by side
   there is nothing left to align, so the fixed label column that made stacked
   rows line up only wastes width — the labels shrink to their text. */
.mdl-ribbon-slim .mdl-rfield {
  height: 26px;
  gap: 6px;
  padding-left: 0;
}

.mdl-ribbon-slim .mdl-rfield .rf-label,
.mdl-ribbon-slim .mdl-rfield .rf-label.rf-label-wide {
  flex: 0 0 auto;
  min-width: 0;
}

.mdl-ribbon-slim .mdl-rselect {
  min-width: 112px;
}

/* Bridge Colors palette picker (Options ▸ Bridge Colors) */
.mdl-colors-wrap {
  position: relative;
  display: inline-flex;
}

.mdl-colors-btn {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  cursor: pointer;
  text-align: left;
}

.mdl-colors-name {
  flex: 1 1 auto;
}

.mdl-colors-btn .mdl-vis-caret {
  width: 13px;
  height: 13px;
  flex: 0 0 auto;
  color: var(--text-secondary);
}

/* Swatch strip — a thin row of the palette's colours. */
.mdl-colors-strip {
  display: inline-flex;
  height: 14px;
  flex: 0 0 auto;
  border-radius: 2px;
  overflow: hidden;
}

.mdl-colors-strip span {
  width: 8px;
  height: 100%;
}

.mdl-colors-pop {
  /* Above .mdl-vis-backdrop (z-index 90), which this flyout reuses to close —
     otherwise the transparent backdrop eats the palette clicks. */
  position: absolute;
  top: calc(100% + 4px);
  right: 0;
  z-index: 91;
  min-width: 200px;
  padding: 4px;
  background: var(--flyout);
  border: 1px solid var(--flyout-stroke);
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-card);
}

.mdl-colors-item {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  padding: 5px 8px;
  border: 0;
  background: transparent;
  cursor: pointer;
  border-radius: var(--radius-control);
  color: var(--text-primary);
  font-family: inherit;
  font-size: 12px;
}

.mdl-colors-item:hover {
  background: var(--subtle-hover);
}

.mdl-colors-item.active {
  background: var(--subtle-selected);
}

.mdl-colors-item .mdl-colors-strip {
  height: 16px;
}

.mdl-colors-item .mdl-colors-strip span {
  width: 14px;
}

.mdl-colors-item .mdl-colors-name {
  flex: 1 1 auto;
}

/* Multi-select visibility flyout (Visible Layers / Visible Objects) */
.mdl-vis-wrap {
  position: relative;
  display: inline-flex;
}

.mdl-vis-btn {
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: space-between;
  gap: 6px;
  padding-right: 6px;
}

.mdl-vis-btn-text {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.mdl-vis-caret {
  width: 13px;
  height: 13px;
  flex: 0 0 13px;
  color: var(--text-secondary);
}

.mdl-vis-backdrop {
  position: fixed;
  inset: 0;
  z-index: 90;
  background: transparent;
}

.mdl-vis-pop {
  position: absolute;
  top: calc(100% + 4px);
  left: 0;
  z-index: 91;
  min-width: 210px;
  display: flex;
  flex-direction: column;
  padding: 8px;
  background: var(--flyout);
  border: 1px solid var(--flyout-stroke);
  border-radius: var(--radius-control);
  box-shadow: var(--shadow-card);
}

.mdl-vis-head,
.mdl-vis-item {
  display: flex;
  align-items: center;
  gap: 9px;
  padding: 5px 6px;
  font-size: 12px;
  color: var(--text-primary);
  border-radius: 4px;
  cursor: pointer;
}

.mdl-vis-head:hover,
.mdl-vis-item:hover {
  background: var(--control-fill-hover);
}

.mdl-vis-head {
  font-weight: 600;
}

.mdl-vis-item {
  padding-left: 14px;
}

.mdl-vis-group {
  font-size: 12px;
  font-weight: 700;
  color: var(--text-primary);
  padding: 7px 6px 2px;
}

.mdl-vis-sep {
  height: 1px;
  background: var(--divider);
  margin: 6px 2px;
}

.mdl-vis-pop input[type=checkbox] {
  width: 16px;
  height: 16px;
  accent-color: var(--accent);
  margin: 0;
}

.mdl-vis-apply {
  margin-top: 6px;
  height: 30px;
  border-radius: var(--radius-control);
  border: 1px solid var(--control-stroke);
  background: var(--control-fill);
  color: var(--text-primary);
  font-family: inherit;
  font-size: 12px;
  cursor: pointer;
}

.mdl-vis-apply:hover {
  background: var(--control-fill-hover);
}

/* ============================================================
   Workspace — three panes
   ============================================================ */
.mdl-workspace {
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  background: var(--mica-base);
}

/* min-width: 0 is essential: without it a flex item's default min-width:auto
   lets wide content (e.g. the 2D section canvas, whose size the renderer sets
   from its measured container) override the flex-basis and expand the pane —
   which then feeds the canvas ResizeObserver into an ever-growing width loop. */
.mdl-pane {
  display: flex;
  flex-direction: column;
  min-height: 0;
  min-width: 0;
  background: var(--layer);
}

.mdl-pane+.mdl-pane {
  border-left: 1px solid var(--divider);
}

.mdl-explorer {
  border: var(--border);
  flex: 0 0 300px;
  margin: 0 0 4px 4px;
}

/* Locked while Results ▸ Animation is playing — see .mdl-ribbon.mdl-locked. */
.mdl-explorer.mdl-locked {
  pointer-events: none;
  opacity: 0.6;
}

.mdl-prop {
  border: var(--border);
  flex: 0 0 560px;
  margin: 0 0 4px 0;
}

/* Viewer layout: the Property pane docks to the RIGHT of the 3D view (see
   Modeler.PropertyDocksRight). Its gutter margin swaps sides — 4px off the window
   edge, mirroring the Explorer's on the left — and it starts narrower, since a
   read-out of values needs far less room than the editing panel's input columns. */
.mdl-prop.mdl-prop--right {
  flex: 0 0 420px;
  margin: 0 4px 4px 0;
}

.mdl-view {
  border: var(--border);
  flex: 1 1 auto;
  min-width: 0;
  margin: 0;
}

/* Collapsed panes tab onto a single left rail bar (Visual Studio auto-hide):
   each collapsed pane is a stacked vertical tab (icon + rotated label) that
   clicks to expand. */
.mdl-railbar {
  flex: 0 0 30px;
  width: 30px;
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding: 4px 0;
  background: var(--layer);
  border: var(--border);
  margin: 0 0 4px 4px;
}

/* Right-docked panes (Help) tab onto the right edge instead of the left. */
.mdl-railbar-right {
  margin: 0 4px 4px 0;
}

.mdl-rail-tab {
  flex: 0 0 auto;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  padding: 9px 0;
  background: transparent;
  border: 0;
  border-radius: var(--radius-control);
  color: var(--text-secondary);
  cursor: pointer;
  font-family: inherit;
}

.mdl-rail-tab:hover {
  background: var(--subtle-hover);
  color: var(--text-primary);
}

.mdl-rail-tab:active {
  background: var(--subtle-pressed);
}

.mdl-rail-icon {
  flex: 0 0 auto;
  display: grid;
  place-items: center;
}

.mdl-rail-icon svg {
  width: 16px;
  height: 16px;
}

.mdl-rail-label {
  writing-mode: vertical-rl;
  /* read top → bottom */
  font-size: 12.5px;
  font-weight: 600;
  letter-spacing: 0.3px;
  white-space: nowrap;
}

/* Pushpin (auto-hide) button — the pinned/vertical pin means "click to collapse",
   matching Visual Studio's tool-window pin. Filled glyph, so no stroke. */
.mdl-pin-btn svg {
  fill: currentColor;
}

/* Drag-to-resize splitter between panes (provides the divider line too). */
.mdl-splitter {
  flex: 0 0 4px;
  position: relative;
  z-index: 2;
  cursor: e-resize;
  background: transparent;
}

.mdl-splitter::before {
  content: "";
  position: absolute;
  top: 0;
  bottom: 0;
  left: 50%;
  width: 1px;
  transform: translateX(-50%);
  background: var(--divider);
  transition: background 0.12s ease, width 0.12s ease;
}

.mdl-splitter:hover::before,
.mdl-splitter.is-dragging::before {
  width: 2px;
  background: var(--accent);
}

/* Horizontal twin of .mdl-splitter: resizes the pane BELOW it in a flex column
   (the Analysis Log docked under the 3D view). */
.mdl-hsplitter {
  flex: 0 0 4px;
  position: relative;
  z-index: 2;
  cursor: n-resize;
  background: transparent;
}

.mdl-hsplitter::before {
  content: "";
  position: absolute;
  left: 0;
  right: 4px;
  top: 50%;
  height: 1px;
  transform: translateY(-50%);
  background: var(--divider);
  transition: background 0.12s ease, height 0.12s ease;
}

.mdl-hsplitter:hover::before,
.mdl-hsplitter.is-dragging::before {
  height: 2px;
  background: var(--accent);
}

.mdl-pane-head {
  flex: 0 0 auto;
  height: 36px;
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 0 10px;
  border-bottom: 1px solid var(--divider);
  font-weight: 600;
  font-size: 12.5px;
  color: var(--text-primary);
}

.mdl-pane-head .ph-icon {
  color: var(--text-secondary);
  display: grid;
  place-items: center;
}

.mdl-pane-head .ph-icon svg {
  width: 16px;
  height: 16px;
}

.mdl-pane-head .ph-spacer {
  flex: 1 1 auto;
}

/* Explorer's Model / Results tabs — a lightweight underline pair, distinct from
   the top ribbon's .mdl-tab (this sits inside a docked/floating tool pane). */
.mdl-explorer-tabs {
  flex: 0 0 auto;
  display: flex;
  gap: 4px;
  padding: 6px 10px 0;
  border-bottom: 1px solid var(--divider);
}

.mdl-explorer-tab {
  padding: 6px 4px 8px;
  background: transparent;
  border: 0;
  border-bottom: 2px solid transparent;
  color: var(--text-secondary);
  cursor: pointer;
  font-family: inherit;
  font-size: 12px;
  font-weight: 600;
}

.mdl-explorer-tab:hover {
  color: var(--text-primary);
}

.mdl-explorer-tab.active {
  color: var(--accent);
  border-bottom-color: var(--accent);
}

.mdl-explorer-empty {
  padding: 16px 14px;
  color: var(--text-secondary);
  font-size: 12.5px;
  line-height: 1.5;
}

.mdl-pane-body {
  flex: 1 1 auto;
  min-height: 0;
  overflow: auto;
}

.mdl-pane-body::-webkit-scrollbar {
  width: 10px;
  height: 10px;
}

.mdl-pane-body::-webkit-scrollbar-thumb {
  background: var(--text-disabled);
  border-radius: 5px;
  border: 3px solid transparent;
  background-clip: padding-box;
}

.mdl-pane-body::-webkit-scrollbar-track {
  background: transparent;
}

/* Small header button (Update Model, Excel export) */
.mdl-head-btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  height: 26px;
  padding: 0 10px;
  background: var(--control-fill);
  border: 1px solid var(--control-stroke);
  border-bottom-color: var(--control-stroke-bottom);
  border-radius: var(--radius-control);
  color: var(--text-primary);
  cursor: pointer;
  font-family: inherit;
  font-size: 12px;
  font-weight: 600;
}

.mdl-head-btn:hover {
  background: var(--control-fill-hover);
}

.mdl-head-btn svg {
  width: 15px;
  height: 15px;
}

.mdl-head-iconbtn {
  width: 28px;
  height: 26px;
  display: grid;
  place-items: center;
  background: transparent;
  border: 1px solid transparent;
  border-radius: var(--radius-control);
  color: var(--text-secondary);
  cursor: pointer;
}

.mdl-head-iconbtn:hover {
  background: var(--subtle-hover);
  color: var(--text-primary);
}

.mdl-head-iconbtn svg {
  width: 16px;
  height: 16px;
}

/* ============================================================
   Explorer tree
   ============================================================ */
.mdl-tree {
  padding: 4px 4px 12px;
}

.tree-row {
  position: relative;
  display: flex;
  align-items: center;
  gap: 2px;
  width: 100%;
  height: 26px;
  min-height: 26px;
  padding-right: 8px;
  border: 0;
  background: transparent;
  cursor: pointer;
  text-align: left;
  color: var(--text-primary);
  font-family: inherit;
  font-size: 12px;
  border-radius: var(--radius-control);
}

.tree-row:hover {
  background: var(--subtle-hover);
}

/* Selected row: an accent-tinted pill with a left accent bar + bold label, so
   the current node reads clearly (the old --subtle-selected was ≈ hover). */
.tree-row.selected {
  background: var(--tree-sel-bg);
}

.tree-row.selected:hover {
  background: var(--tree-sel-bg-hover);
}

.tree-row.selected::before {
  content: "";
  position: absolute;
  left: 1px;
  top: 4px;
  bottom: 4px;
  width: 3px;
  border-radius: 2px;
  background: var(--accent);
}

.tree-row.selected .tree-label {
  font-weight: 600;
}

.tree-caret,
.tree-caret-empty {
  width: 18px;
  flex: 0 0 18px;
  display: grid;
  place-items: center;
  color: var(--text-secondary);
}

.tree-caret svg {
  width: 11px;
  height: 11px;
  transition: transform 0.15s ease;
}

.tree-caret.open svg {
  transform: rotate(90deg);
}

.tree-label {
  flex: 1 1 auto;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Stage-3 / roadmap node (Explorer architecture preview, not yet wired up). */
.tree-row.dim .tree-label {
  color: var(--text-disabled);
  font-style: italic;
}

.tree-row.dim .tree-caret {
  color: var(--text-disabled);
}

/* Selected FE element: recursive read-only property tree. */
.fe-tree {
  padding: 6px 4px 12px;
}

.fe-prop-children {
  padding-left: 14px;
  border-left: 1px solid var(--divider);
  margin-left: 7px;
}

.fe-prop-head {
  display: flex;
  align-items: center;
  gap: 2px;
  width: 100%;
  height: 24px;
  border: 0;
  background: transparent;
  cursor: pointer;
  text-align: left;
  color: var(--text-primary);
  font-family: inherit;
  font-size: 12px;
  font-weight: 600;
  border-radius: var(--radius-control);
}

.fe-prop-head:hover {
  background: var(--subtle-hover);
}

.fe-prop-row {
  display: flex;
  align-items: center;
  gap: 8px;
  min-height: 24px;
  padding: 1px 6px 1px 20px;
  font-size: 12px;
}

.fe-prop-row .fe-prop-label {
  flex: 0 0 44%;
  color: var(--text-secondary);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.fe-prop-value {
  flex: 1 1 auto;
  color: var(--text-primary);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.fe-prop-unit {
  margin-left: 4px;
  color: var(--text-tertiary);
}

/* Analysis Model tree: element-visibility checkbox + count badge. */
.tree-check {
  width: 14px;
  height: 14px;
  flex: 0 0 14px;
  margin: 0 4px 0 0;
  accent-color: var(--accent);
  cursor: pointer;
}

/* Component Libraries usage markers: whether anything still references the component.
   Deliberately quiet — they sit on most rows of a working model, so they read at a glance
   without competing with the label. The tooltip on each names the first user. */
.tree-use {
  flex: 0 0 auto;
  display: grid;
  place-items: center;
  width: 14px;
  height: 14px;
  margin-left: 4px;
  opacity: 0.75;
}

.tree-use svg {
  width: 12px;
  height: 12px;
}

/* Placed in the bridge — the accent, same as the selected row's bar. */
.tree-use-model {
  color: var(--accent);
}

/* Used by another component — a step back, so a component that is only a building block
   does not read as strongly as one that is actually in the bridge. */
.tree-use-comp {
  color: var(--text-secondary);
}

.tree-row:hover .tree-use,
.tree-row.selected .tree-use {
  opacity: 1;
}

.tree-count {
  flex: 0 0 auto;
  margin-left: 6px;
  padding: 0 6px;
  height: 16px;
  line-height: 16px;
  font-size: 10.5px;
  color: var(--text-secondary);
  background: var(--subtle-selected);
  border-radius: 8px;
}

/* ============================================================
   Property panel (cards / fields / tables)
   ============================================================ */
.mdl-prop-body {
  padding: 8px;
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.app-viewer .mdl-prop-body {
    padding: 8px 0;
}

.mdl-card {
  flex: 0 0 auto;
  background: var(--card);
  border: var(--border);
  border-radius: var(--radius-card);
  overflow: hidden;
}

.app-viewer .mdl-card {
    border: none;
    border-radius: 0;
}

.mdl-card-head {
  background: var(--mica-base);
  width: 100%;
  height: 28px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0 14px;
  border: 0;
  cursor: pointer;
  color: var(--text-primary);
  font-family: inherit;
  text-align: left;
}

.app-viewer .mdl-card-head {
    border-bottom: var(--border);
    color: var(--text-mute);
    text-transform: uppercase;
    padding-bottom: 8px;
}

.mdl-card-head:hover {
  background: var(--subtle-hover);
}

/* Viewer: card headers drop their fill and read as plain headings. Keyed off the
   body/#app class the browser host stamps from AppMode, so the desktop shell —
   which never carries it — is untouched. */
.app-viewer .mdl-card-head {
  background: none;
}

/* Non-collapsible card header (Analysis Model read-only property cards). */
.mdl-card-head--static {
  cursor: default;
}

.mdl-card-head--static:hover {
  background: var(--card-head);
}

.mdl-card-title {
  font-family: var(--font-display);
  font-size: 13px;
  font-weight: bold;
}

.app-viewer .mdl-card-title {
    font-size: 12px;
    font-weight: normal;
}

.mdl-card-chevron {
  color: var(--text-secondary);
  display: grid;
  place-items: center;
  transition: transform 0.18s ease;
}

.mdl-card-chevron svg {
  width: 13px;
  height: 13px;
}

.mdl-card.collapsed .mdl-card-chevron {
  transform: rotate(-90deg);
}

/* Top-level cards: chevron points up when open, down when collapsed (reference). */
.mdl-prop-body>.mdl-card>.mdl-card-head .mdl-card-chevron {
  transform: rotate(180deg);
}

.mdl-prop-body>.mdl-card.collapsed>.mdl-card-head .mdl-card-chevron {
  transform: rotate(0deg);
}

.mdl-card-body {
  overflow: hidden;
  max-height: 2000px;
  padding: 0;
  transition: max-height 0.22s ease;
}

.mdl-card.collapsed .mdl-card-body {
  max-height: 0;
}

.mdl-card-inner {
  padding: 8px 16px 8px;
}

.mdl-subhead {
  font-family: var(--font-display);
  font-size: 12px;
  font-weight: bold;
  font-style: italic;
  color: var(--text-secondary);
  margin: 12px 0 6px;
  padding-bottom: 3px;
  border-bottom: 1px solid var(--divider);
}

/* Nested expanders (parameter sub-groups + the section preview): flat italic
   section headers with a left chevron and an underline rule — like .mdl-subhead
   but collapsible — rather than inset cards (matches the reference). */
.mdl-card .mdl-card:first {
  margin: 0;
}

.mdl-card .mdl-card {
  box-shadow: none;
  border: 0;
  border-radius: 0;
  overflow: visible;
  margin: 10px 0 0;
  background: transparent;
}

.mdl-card .mdl-card .mdl-card-head {
  height: 30px;
  padding: 0 2px;
  gap: 8px;
  justify-content: flex-start;
  background: transparent;
  border-bottom: 1px solid var(--divider);
}

.mdl-card .mdl-card .mdl-card-head:hover {
  background: var(--subtle-hover);
}

.mdl-card .mdl-card .mdl-card-title {
  font-family: var(--font-display);
  font-size: 12px;
  font-weight: bold;
  font-style: italic;
  color: var(--text-secondary);
}

/* Chevron sits to the LEFT of the title (down when open, right when collapsed). */
.mdl-card .mdl-card .mdl-card-chevron {
  order: -1;
  color: var(--text-tertiary);
}

.mdl-card .mdl-card .mdl-card-inner {
  padding: 8px 4px 6px 22px;
}

.app-viewer .mdl-card .mdl-card .mdl-card-inner {
    padding-left: 4px;
}

.mdl-subhead:first-child {
  margin-top: 4px;
}

/* ============================================================
   Panel Style (Options ▸ Panel Style) — how the Property-panel cards/expanders
   render. Class lives on .mdl-prop-body. "Mixed" is the baseline (no class):
   top-level cards have a filled header + border; inner cards are flat with a
   header rule.
     • Default           — Mixed, plus inner cards become full cards
                           (border + filled header), like the top-level ones.
     • Plain             — no card border/shadow/fill, no header fill or rule.
     • Plain With Border — Plain, but each header keeps a bottom rule.
   ============================================================ */
.mdl-prop-body.ps-plain .mdl-card,
.mdl-prop-body.ps-plain-border .mdl-card {
  background: transparent;
  border: 0;
  box-shadow: none;
  border-radius: 0;
}

.mdl-prop-body.ps-plain .mdl-card-head,
.mdl-prop-body.ps-plain-border .mdl-card-head {
  background: transparent;
}

.mdl-prop-body.ps-plain .mdl-card-head {
  border-bottom: 0;
}

.mdl-prop-body.ps-plain-border .mdl-card-head {
  border-bottom: 1px solid var(--divider);
}

/* Default: inner (nested) cards render as full cards — border + filled header —
   matching the top-level cards (overrides the flat nested baseline). */
.mdl-prop-body.ps-default .mdl-card .mdl-card {
  background: var(--card);
  border: 1px solid var(--card-stroke);
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-card);
  overflow: hidden;
}

.mdl-prop-body.ps-default .mdl-card .mdl-card .mdl-card-head {
  background: var(--mica-base);
  border-bottom: 0;
  justify-content: space-between;
  padding: 0 14px;
}

/* Full inner cards: chevron sits on the RIGHT (like the top-level cards),
   not to the left of the title as in the flat nested baseline. */
.mdl-prop-body.ps-default .mdl-card .mdl-card .mdl-card-chevron {
  order: 0;
}

.mdl-field {
  display: grid;
  grid-template-columns: 1fr 150px;
  align-items: center;
  gap: 10px;
  min-height: 32px;
  padding: 3px 0;
}

.mdl-card-inner .mdl-field {
  margin-left: 0;
}

.mdl-field-label {
  font-size: 12px;
  color: var(--text-primary);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.mdl-input,
.mdl-select {
  width: 100%;
  height: 28px;
  padding: 0 8px;
  background: var(--control-fill);
  border: 1px solid var(--control-stroke);
  border-bottom-color: var(--control-stroke-bottom);
  border-radius: var(--radius-control);
  color: var(--text-primary);
  font-family: inherit;
  font-size: 12px;
}

.mdl-input:focus,
.mdl-select:focus {
  outline: none;
  border-bottom: 2px solid var(--accent);
  padding-bottom: 0;
}

.mdl-input-wrap {
  position: relative;
  display: flex;
  align-items: center;
}

.mdl-input-wrap .mdl-input {
  padding-right: 26px;
}

.mdl-unit {
  position: absolute;
  right: 8px;
  font-size: 11px;
  color: var(--text-tertiary);
  pointer-events: none;
}

/* The Bridge Components panel uses type="number" inputs (the VB panel uses plain text ones).
   Chromium's spin buttons would sit exactly where .mdl-unit is drawn, so suppress them inside a
   unit wrap — the unit label is the more useful thing in that corner. */
.mdl-input-wrap input[type="number"] {
  -moz-appearance: textfield;
  appearance: textfield;
}

.mdl-input-wrap input[type="number"]::-webkit-outer-spin-button,
.mdl-input-wrap input[type="number"]::-webkit-inner-spin-button {
  -webkit-appearance: none;
  margin: 0;
}

.mdl-readonly {
  font-size: 12px;
  color: var(--text-secondary);
  /* Grows rather than fixed: the value column is 150px, so anything longer than a couple of
     words - a note explaining a card, say - used to overflow a 28px box and paint over the
     rows above and below it. */
  min-height: 28px;
  display: flex;
  align-items: center;
  padding: 4px;
  white-space: normal;
  overflow-wrap: anywhere;
  line-height: 1.35;
}

.mdl-prop-empty {
  padding: 18px 14px;
  font-size: 12px;
  color: var(--text-secondary);
}

/* ============================================================
   Viewer property sheet — .mdl-prop-body.is-viewer

   Same cards, subheads and tables as the modeler panel, but every value is TEXT
   (PropertyPanel / PropertyCard render a .mdl-value instead of an input when
   AppCapabilities.ViewerOnly). The styling follows: label left in secondary ink,
   value right-aligned in primary, one hairline per row. A grid of disabled inputs
   reads as "a form you are locked out of"; this reads as a datasheet, which is
   what a viewer's property panel is.
   ============================================================ */

/* "Read-only" badge in the pane header — says once, quietly, why nothing here
   takes a keystroke, so the panel itself doesn't have to keep saying it. */
.mdl-prop-ro {
  flex: 0 0 auto;
  padding: 1px 7px;
  border: 1px solid var(--card-stroke);
  border-radius: 9px;
  background: var(--mica-base);
  color: var(--text-tertiary);
  font-size: 10.5px;
  font-weight: 600;
  letter-spacing: 0.3px;
  text-transform: uppercase;
}

.mdl-prop-body.is-viewer .mdl-field {
  grid-template-columns: minmax(0, 1fr) minmax(0, auto);
  align-items: baseline;
  gap: 14px;
  min-height: 0;
  /* Negative margin so the hover band spans the card's full inner width while
     the text still lines up with the subheads above it. */
  padding: 5px 6px;
  margin: 0 -6px;
  border-radius: 3px;
  border-bottom: 1px solid var(--divider);
}

.mdl-prop-body.is-viewer .mdl-field:last-child {
  border-bottom: 0;
}

.mdl-prop-body.is-viewer .mdl-field:hover {
  background: var(--subtle-hover);
}

.mdl-prop-body.is-viewer .mdl-field-label {
    color: var(--text-primary);
}

.app-viewer .mdl-prop-body.is-viewer .mdl-field-label {
    color: var(--text-mute);
}

/* Value + unit. Tabular figures so a column of numbers reads down cleanly, and
   selectable — copying a value out is the one "edit" a viewer does (the app
   turns selection off globally; see app.css). */
.mdl-value {
  display: flex;
  align-items: baseline;
  justify-content: flex-end;
  gap: 5px;
  min-width: 0;
}

.mdl-value-text {
  font-size: 12px;
  font-weight: 600;
  color: var(--text-primary);
  font-variant-numeric: tabular-nums;
  text-align: right;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  -webkit-user-select: text;
  user-select: text;
}

.mdl-value-unit {
  flex: 0 0 auto;
  font-size: 11px;
  color: var(--text-tertiary);
}

/* Values the panel ALREADY rendered as text (analysis-model props, Label
   parameters, engine-computed vendor fields) join the same right-hand column
   instead of sitting where an input's left edge used to be. */
.mdl-prop-body.is-viewer .mdl-input-wrap {
  justify-content: flex-end;
}

.mdl-prop-body.is-viewer .mdl-readonly {
  height: auto;
  padding: 0;
  justify-content: flex-end;
  text-align: right;
  color: var(--text-primary);
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  -webkit-user-select: text;
  user-select: text;
}

/* Tables lose their editing affordances too: no cell borders to hover, zebra
   banding to track a row across, figures aligned. */
.mdl-prop-body.is-viewer .mdl-table {
  font-variant-numeric: tabular-nums;
}

.mdl-prop-body.is-viewer .mdl-table td {
  padding: 5px 8px;
  -webkit-user-select: text;
  user-select: text;
}

.mdl-prop-body.is-viewer .mdl-table tbody tr:nth-child(even) {
  background: var(--subtle-pressed);
}

.app-viewer .mdl-prop-body.is-viewer .mdl-table tbody tr:nth-child(even) {
    background: none;
}

.mdl-prop-body.is-viewer .mdl-table tbody tr:hover {
  background: var(--subtle-hover);
}

.mdl-prop-body.is-viewer .mdl-cell-text {
  padding: 0;
  line-height: 18px;
}

/* Group expanders — the flat nested headers inside a card ("General",
   "Beam/Girders") — carry their chevron on the LEFT of the title in the modeler.
   In the read-out sheet everything actionable or scannable is already on the
   right edge (the card chevrons above them, the whole value column below), so
   these join it: one column of controls down the right, one of labels down the
   left, nothing in between. */
.mdl-prop-body.is-viewer .mdl-card .mdl-card .mdl-card-head {
  justify-content: space-between;
}

.mdl-prop-body.is-viewer .mdl-card .mdl-card .mdl-card-chevron {
  order: 0;
}

/* The few controls that survive into the viewer are view settings, not model
   edits (Unit Setup's dimension/decimal pickers, the Results case + scale). They
   keep a control's width rather than collapsing onto the value column. */
.mdl-prop-body.is-viewer .mdl-field>.mdl-select,
.mdl-prop-body.is-viewer .mdl-field>.mdl-input,
.mdl-prop-body.is-viewer .mdl-field>.mdl-input-wrap:has(.mdl-input) {
  min-width: 150px;
}

/* Tables (Bridge Spans / Bents / Abutments) */
.mdl-table {
  width: 100%;
  border-collapse: separate;
  border-spacing: 0;
  font-size: 12px;
}

.mdl-table th {
  position: sticky;
  top: 0;
  z-index: 2;
  background: var(--th-bg);
  color: var(--text-secondary);
  font-weight: 600;
  text-align: left;
  padding: 7px 8px;
  border-bottom: 1px solid var(--divider);
  white-space: nowrap;
}

.mdl-table td {
  padding: 4px 6px;
  border-bottom: 1px solid var(--divider);
  color: var(--text-primary);
}

.mdl-table tr:last-child td {
  border-bottom: 0;
}

.mdl-table .mdl-input,
.mdl-table .mdl-select {
  height: 26px;
}

.mdl-table .rownum {
  width: 26px;
  color: var(--text-tertiary);
  text-align: center;
}

/* Name column: keep the object name on one line (e.g. "Span-2" must not wrap). */
.mdl-table .mdl-col-name {
  white-space: nowrap;
  width: 1%;
}

/* Read-only cell in an otherwise editable panel table (a disabled parameter, a label,
   or a table the engine marks Readonly / AllowEdit = False). Sits on the same baseline
   as the editable cells next to it. */
.mdl-cell-text {
  display: inline-block;
  padding: 0 4px;
  line-height: 24px;
  white-space: nowrap;
}

/* Table that has no rows yet but accepts new ones (the user Load Patterns table before
   the first pattern is created) — the Add button below it is the point. */
.mdl-table-empty {
  padding: 6px 4px;
  font-size: 12px;
  color: var(--text-tertiary);
}

/* A checkbox cell keeps the check centred in the column. */
.mdl-table td>.np-check {
  justify-content: center;
}

/* Unit Setup tables — fixed 4-column layout (label | unit 1 | unit 2 | Decimal)
   so the input dropdowns line up across every table. Groups with a single unit
   leave the middle column empty; the Decimal column stays in the same place. */
.mdl-units-table {
  table-layout: fixed;
}

.mdl-units-table th:nth-child(1),
.mdl-units-table td:nth-child(1) {
  width: 28%;
}

.mdl-units-table th:nth-child(2),
.mdl-units-table td:nth-child(2) {
  width: 27%;
}

.mdl-units-table th:nth-child(3),
.mdl-units-table td:nth-child(3) {
  width: 27%;
}

.mdl-units-table th:nth-child(4),
.mdl-units-table td:nth-child(4) {
  width: 18%;
}

.mdl-units-table th:nth-child(1) {
  font-weight: bold;
}

.mdl-units-table td:first-child {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Inline-editable table cell (Bridge Spans): a borderless control that fills
   the cell and only reveals its border on hover/focus. */
.mdl-table td:has(> .mdl-cell-input) {
  padding: 1px 2px;
}

.mdl-cell-input {
  width: 100%;
  height: 26px;
  padding: 0 6px;
  background: transparent;
  border: 1px solid transparent;
  border-radius: var(--radius-control);
  color: var(--text-primary);
  font-family: inherit;
  font-size: 12px;
}

.mdl-cell-input:hover {
  border-color: var(--control-stroke);
  background: var(--control-fill);
}

.mdl-cell-input:focus {
  outline: none;
  border-color: var(--accent);
  background: var(--control-fill);
  border-bottom-width: 2px;
}

select.mdl-cell-input {
  cursor: pointer;
}

/* Row-actions button in the ⋯ cell (opens the insert/delete menu). */
.mdl-table td.rownum {
  padding: 1px 2px;
}

.mdl-rowbtn {
  width: 22px;
  height: 22px;
  display: grid;
  place-items: center;
  margin: 0 auto;
  border: 1px solid transparent;
  border-radius: var(--radius-control);
  background: transparent;
  color: var(--text-tertiary);
  cursor: pointer;
  font-size: 14px;
  line-height: 1;
}

.mdl-rowbtn:hover {
  background: var(--subtle-hover);
  color: var(--text-primary);
}

.mdl-rowbtn:active {
  background: var(--subtle-pressed);
}

/* "Add Span" action under the table. */
.mdl-table-actions {
  display: flex;
}

.mdl-add-btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  height: 28px;
  padding: 0 10px 0 8px;
  border: 1px solid var(--control-stroke);
  border-bottom-color: var(--control-stroke-bottom);
  border-radius: var(--radius-control);
  background: var(--control-fill);
  color: var(--text-primary);
  font-family: inherit;
  font-size: 12px;
  cursor: pointer;
}

.mdl-add-btn:hover {
  background: var(--subtle-hover);
}

.mdl-add-btn:active {
  background: var(--subtle-pressed);
}

.mdl-add-btn svg {
  width: 14px;
  height: 14px;
  color: var(--accent);
}

/* Row-actions popup menu (click-positioned, like the File Explorer context menu). */
.mdl-rowmenu-catch {
  position: fixed;
  inset: 0;
  z-index: 1900;
}

.mdl-rowmenu {
  position: fixed;
  z-index: 1901;
  min-width: 190px;
  padding: 4px;
  background: var(--flyout);
  color: var(--text-primary);
  border: 1px solid var(--flyout-stroke);
  border-radius: 8px;
  box-shadow: var(--shadow-flyout, 0 8px 24px rgba(0, 0, 0, 0.28));
  animation: mdl-rowmenu-pop 100ms ease-out;
}

.mdl-rowmenu-item {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  height: 32px;
  padding: 0 10px;
  border: 0;
  background: transparent;
  color: var(--text-primary);
  text-align: left;
  cursor: pointer;
  border-radius: 4px;
  font-family: inherit;
  font-size: 12px;
}

.mdl-rowmenu-item:hover {
  background: var(--subtle-hover);
}

.mdl-rowmenu-item:active {
  background: var(--subtle-pressed);
}

.mdl-rowmenu-item:disabled {
  color: var(--text-disabled);
  cursor: default;
  background: transparent;
}

.mdl-rowmenu-item:disabled .mdl-rowmenu-icon {
  color: var(--text-disabled);
}

.mdl-rowmenu-icon {
  flex: 0 0 auto;
  display: grid;
  place-items: center;
  line-height: 0;
  color: var(--text-secondary);
}

.mdl-rowmenu-icon svg {
  width: 15px;
  height: 15px;
}

/* Section caption inside a flyout ("New Girder" above the type list in the Explorer's
   Component Libraries menu). Not a button — it labels the group below it. */
.mdl-rowmenu-head {
  padding: 6px 10px 4px;
  color: var(--text-secondary);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.02em;
}

.mdl-rowmenu-sep {
  height: 1px;
  margin: 4px 6px;
  background: var(--divider);
}

.mdl-rowmenu-danger {
  color: var(--error, #c42b1c);
}

.mdl-rowmenu-danger .mdl-rowmenu-icon {
  color: var(--error, #c42b1c);
}

.mdl-rowmenu-danger:hover:not(:disabled) {
  background: color-mix(in srgb, var(--error, #c42b1c) 8%, transparent);
}

@keyframes mdl-rowmenu-pop {
  from {
    opacity: 0;
    transform: scale(0.97);
  }

  to {
    opacity: 1;
    transform: scale(1);
  }
}

/* Library catalog tables (Material / Section libraries): keep the first column
   (the Name) pinned while the remaining columns scroll horizontally. */
/* Honor the real line breaks produced from the label's "\n" escapes (see
   HeaderOf), while still not wrapping on spaces. */
.mdl-table--freeze1 th {
  white-space: pre;
}

.mdl-table--freeze1 th:first-child,
.mdl-table--freeze1 td:first-child {
  position: sticky;
  left: 0;
  white-space: nowrap;
}

.mdl-table--freeze1 td:first-child {
  z-index: 1;
  background: var(--card);
}

.mdl-table--freeze1 th:first-child {
  z-index: 3;
}

.mdl-table-wrap {
  border: 1px solid var(--card-stroke);
  border-radius: var(--radius-control);
  overflow: auto;
  margin-bottom: 8px;
}

.app-viewer .mdl-table-wrap {
    border: none;
    border-top: 1px solid var(--card-stroke);
    border-bottom: 1px solid var(--card-stroke);
    border-radius: 0;
}

/* Row-selectable table (Vehicle Library "Settings"): click a row to pick a
   vehicle; the selected row is accent-highlighted (incl. the frozen first cell). */
.mdl-table--selectable tbody tr {
    cursor: pointer;
}

.mdl-table--selectable tbody tr:hover td {
  background: var(--subtle-hover);
}

.mdl-table--selectable tbody tr:hover td:first-child {
  background: var(--subtle-hover);
}

.mdl-table--selectable tbody tr.selected td {
  background: var(--tree-sel-bg);
}

.mdl-table--selectable tbody tr.selected td:first-child {
  background: var(--tree-sel-bg);
}

/* Selected-vehicle diagram shown under the Settings table. */
.mdl-vehicle-fig {
  border: 1px solid var(--card-stroke);
  border-radius: var(--radius-control);
  margin: 10px 0;
  text-align: center;
}

.mdl-vehicle-img {
  max-width: 100%;
  height: auto;
}

.mdl-vehicle-cap {
  margin-top: 8px;
  font-size: 12px;
  color: var(--text-secondary);
}

/* 2D canvas preview (PanelMesh / PanelChart / PanelKeyPlan). The renderer
   (BridgeViewport.mount2D) appends a .drw-canvas and observes this box for
   resize, so it just needs a definite size. */
.mdl-canvas2d {
  position: relative;
  width: 100%;
  height: 300px;
  border: 1px solid var(--card-stroke);
  border-radius: var(--radius-control);
  background: var(--canvas2d-bg);
  overflow: hidden;
}

.mdl-canvas2d .drw-canvas {
  display: block;
  width: 100%;
  height: 100%;
  cursor: grab;
}

.mdl-canvas2d .drw-canvas.is-panning {
  cursor: grabbing;
}

/* Hover toolbars over the 2D preview. Hidden until the wrap is hovered. */
.mdl-canvas2d-wrap {
  position: relative;
}

/* Key plan placeholder — the engine generates the drawing on a background thread, so the
   card exists briefly before its geometry does. */
.mdl-canvas2d-pending {
  display: grid;
  place-items: center;
  height: 120px;
  font-size: 12px;
  color: var(--text-tertiary);
  background: var(--subtle-hover);
  border: 1px dashed var(--divider);
}

.mdl-c2d-tools {
  position: absolute;
  z-index: 5;
  display: flex;
  gap: 3px;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.12s ease;
}

.mdl-canvas2d-wrap:hover .mdl-c2d-tools,
.mdl-c2d-tools:focus-within {
  opacity: 1;
  pointer-events: auto;
}

.mdl-c2d-tools.left {
  top: 8px;
  left: 8px;
  flex-direction: column;
}

.mdl-c2d-tools.right {
  top: 8px;
  right: 8px;
  flex-direction: row;
}

/* The 2D preview's export flyout. Same look as the row menu, but it can be
   raised from the EXPANDED preview, which is a z-index:3000 overlay — so both
   the menu and its click-catcher have to outrank that. */
.mdl-c2d-exportmenu {
  z-index: 3010;
}

/* While its menu is open the hover toolbar must stay put: the pointer has left
   the canvas for the flyout, which would otherwise fade the toolbar out from
   under the button the user just clicked. */
.mdl-canvas2d-wrap.menu-open .mdl-c2d-tools {
  opacity: 1;
  pointer-events: auto;
}

/* Lock toggle: always visible (bottom-right) so the preview can be un/locked. */
.mdl-c2d-tools.lock {
  bottom: 8px;
  right: 8px;
  flex-direction: row;
  opacity: 1;
  pointer-events: auto;
}

/* Locked preview: keep the pan/zoom + dimension tool groups hidden even on hover,
   and stop the canvas from receiving mouse input (no pan/zoom). */
.mdl-canvas2d-wrap.locked .mdl-c2d-tools.left,
.mdl-canvas2d-wrap.locked .mdl-c2d-tools.right {
  opacity: 0;
  pointer-events: none;
}

.mdl-canvas2d-wrap.locked .mdl-canvas2d {
  pointer-events: none;
}

.mdl-c2d-btn {
  width: 28px;
  height: 28px;
  flex: 0 0 28px;
  display: grid;
  place-items: center;
  border: 1px solid var(--card-stroke);
  border-radius: var(--radius-control);
  background: var(--layer);
  color: var(--text-secondary);
  font-family: var(--font-display);
  font-size: 12px;
  font-weight: 600;
  cursor: pointer;
  box-shadow: var(--shadow-card);
  padding: 0;
}

.mdl-c2d-btn:hover {
  background: var(--subtle-hover);
  color: var(--text-primary);
}

.mdl-c2d-btn:active {
  background: var(--subtle-pressed);
}

.mdl-c2d-btn.on {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--accent-fill-text);
}

.mdl-c2d-btn svg {
  width: 16px;
  height: 16px;
}

/* Expand overlay: a large copy of the drawing for closer inspection, pinned over
   the 3D view pane (BridgeViewport.anchorOverlay sets the fixed rect to match
   .mdl-view) rather than a full-screen modal — so the explorer + property panes
   stay visible and interactive. No backdrop for the same reason. */
.mdl-c2d-modal {
  position: fixed;
  z-index: 3000;
  display: flex;
  /* left/top/width/height set inline by anchorOverlay over .mdl-view */
}

.mdl-c2d-dialog {
  width: 100%;
  height: 100%;
  display: flex;
  flex-direction: column;
  background: var(--card);
  border: 1px solid var(--card-stroke);
  overflow: hidden;
}

.mdl-c2d-dialog-head {
  flex: 0 0 auto;
  height: 44px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0 10px 0 14px;
  border-bottom: 1px solid var(--divider);
}

.mdl-c2d-dialog-body {
  flex: 1 1 auto;
  min-height: 0;
}

.mdl-c2d-dialog-body .mdl-canvas2d {
  width: 100%;
  height: 100%;
  border: 0;
  border-radius: 0;
}

/* Standard Libraries catalog tables: cap height so long lists scroll within the
   table (the sticky header/first column stay pinned) instead of growing the panel. */
.mdl-table-wrap--capped {
  max-height: 480px;
}

.mdl-add-row {
  margin-top: 8px;
  width: 30px;
  height: 26px;
  display: grid;
  place-items: center;
  background: var(--control-fill);
  border: 1px solid var(--control-stroke);
  border-bottom-color: var(--control-stroke-bottom);
  border-radius: var(--radius-control);
  color: var(--text-secondary);
  cursor: pointer;
}

.mdl-add-row:hover {
  background: var(--control-fill-hover);
  color: var(--text-primary);
}

/* ============================================================
   Help pane (right-docked, toggled from Home > View > Help)
   ============================================================ */
.mdl-help {
  flex: 0 0 360px;
}

.mdl-help-toolbar {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  gap: 4px;
  padding: 5px 8px;
  border-bottom: 1px solid var(--divider);
  background: var(--card-secondary);
}

.mdl-help-crumb {
  font-size: 13px;
  font-weight: 600;
  margin-left: 4px;
}

/* Help document — styles the HTML help fragments served from wwwroot/help
   (loaded by HelpPanel.load). The fragments use h1 section titles, .subtopic /
   .collapsibleTitle headings, .collapsible figure blocks (.image-alt images +
   .image-caption), and ul / ul.note lists. */
.mdl-help-doc {
  padding: 8px 18px 28px;
  color: var(--text-secondary);
  font-size: 13px;
  line-height: 1.55;
}

.mdl-help-doc h1 {
  font-family: var(--font-display);
  font-size: 18px;
  font-weight: 600;
  color: var(--text-primary);
  letter-spacing: -0.2px;
  margin: 14px 0 10px;
  padding-bottom: 6px;
  border-bottom: 1px solid var(--divider);
}

.mdl-help-doc h1:first-child {
  margin-top: 2px;
}

.mdl-help-doc h2,
.mdl-help-doc h3 {
  font-family: var(--font-display);
  font-weight: 600;
  color: var(--text-primary);
  margin: 16px 0 6px;
}

.mdl-help-doc h2 {
  font-size: 15px;
}

.mdl-help-doc h3 {
  font-size: 14px;
}

.mdl-help-doc p {
  margin: 6px 0;
}

.mdl-help-doc b,
.mdl-help-doc strong {
  color: var(--text-primary);
  font-weight: 600;
}

.mdl-help-doc i,
.mdl-help-doc em {
  font-style: italic;
}

.mdl-help-doc ul,
.mdl-help-doc ol {
  margin: 6px 0;
  padding-left: 20px;
}

.mdl-help-doc li {
  margin: 4px 0;
}

/* .subtopic / .collapsibleTitle — section groupings; the leading <span> of a
   collapsibleTitle is its heading. (No JS expander here, so all content shows.) */
.mdl-help-doc .subtopic {
  margin: 8px 0 4px;
}

.mdl-help-doc .collapsibleTitle {
  margin: 12px 0;
}

.mdl-help-doc .collapsibleTitle>span:first-child {
  display: block;
  font-family: var(--font-display);
  font-size: 14px;
  font-weight: 600;
  color: var(--text-primary);
  margin: 10px 0 6px;
}

/* Note callout. */
.mdl-help-doc ul.note {
  list-style: none;
  padding: 8px 12px;
  margin: 10px 0;
  background: var(--subtle-hover);
  border-left: 3px solid var(--accent);
  border-radius: 4px;
}

.mdl-help-doc ul.note>b,
.mdl-help-doc ul.note>li:first-child {
  color: var(--accent);
  font-weight: 600;
}

.mdl-help-doc ul.note ul {
  margin-top: 4px;
}

/* Figures: images + captions. */
.mdl-help-doc .collapsible {
  margin: 10px 0;
}

.mdl-help-doc img,
.mdl-help-doc .image-alt {
  display: block;
  max-width: 100%;
  height: auto;
  margin: 8px auto 2px;
  border: 1px solid var(--card-stroke);
  border-radius: 4px;
  cursor: zoom-in;
}

/* Hover affordance: help-panel.js wraps each figure in .mdl-help-zoom so a
   magnify badge can fade in on hover, signalling "click to enlarge". */
.mdl-help-zoom {
  position: relative;
  display: block;
  width: fit-content;
  max-width: 100%;
  margin: 8px auto 2px;
  cursor: zoom-in;
}

.mdl-help-zoom img {
  margin: 0;
  cursor: zoom-in;
}

.mdl-help-zoom::after {
  content: "";
  position: absolute;
  top: 8px;
  right: 8px;
  width: 28px;
  height: 28px;
  border-radius: 50%;
  pointer-events: none;
  background: rgba(0, 0, 0, 0.55) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='18' height='18' viewBox='0 0 24 24' fill='none' stroke='%23ffffff' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='7'/%3E%3Cpath d='M21 21l-4.3-4.3M11 8v6M8 11h6'/%3E%3C/svg%3E") no-repeat center / 18px 18px;
  opacity: 0;
  transform: scale(0.85);
  transition: opacity 120ms ease, transform 120ms ease;
}

.mdl-help-zoom:hover::after {
  opacity: 1;
  transform: scale(1);
}

.mdl-help-zoom:hover img {
  filter: brightness(0.93);
}

/* Full-screen lightbox for an enlarged help figure (appended to <body> by
   help-panel.js, so it sits at the top level — not scoped to .mdl-app). */
.mdl-help-lightbox {
  position: fixed;
  inset: 0;
  z-index: 3000;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
  background: rgba(0, 0, 0, 0.8);
  cursor: zoom-out;
  animation: mdl-help-lb-fade 120ms ease-out;
}

.mdl-help-lightbox img {
  max-width: 96vw;
  max-height: 92vh;
  object-fit: contain;
  border-radius: 4px;
  box-shadow: 0 16px 48px rgba(0, 0, 0, 0.55);
}

@keyframes mdl-help-lb-fade {
  from {
    opacity: 0;
  }

  to {
    opacity: 1;
  }
}

.mdl-help-doc .image-caption {
  font-size: 11.5px;
  font-style: italic;
  color: var(--text-tertiary);
  text-align: center;
  margin: 0 0 10px;
}

.mdl-help-doc table {
  border-collapse: collapse;
  width: 100%;
  margin: 10px 0;
  font-size: 12.5px;
}

.mdl-help-doc th,
.mdl-help-doc td {
  border: 1px solid var(--divider);
  padding: 5px 8px;
  text-align: left;
}

.mdl-help-doc th {
  background: var(--th-bg);
  color: var(--text-primary);
  font-weight: 600;
}

/* Empty/placeholder hint. */
.mdl-help-doc .mdl-help-hint {
  color: var(--text-tertiary);
  font-style: italic;
  padding: 14px 2px;
}

/* ============================================================
   3D view pane
   ============================================================ */
.mdl-view-toolbar {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  gap: 2px;
  flex-wrap: wrap;
  padding: 5px 8px;
  border-bottom: 1px solid var(--divider);
}

.mdl-view-toolbar .sep {
  width: 1px;
  height: 20px;
  background: var(--divider);
  margin: 0 4px;
}

.mdl-vbtn {
  width: 30px;
  height: 28px;
  display: grid;
  place-items: center;
  background: transparent;
  border: 1px solid transparent;
  border-radius: var(--radius-control);
  color: var(--text-secondary);
  cursor: pointer;
}

.mdl-vbtn:hover {
  background: var(--subtle-hover);
  color: var(--text-primary);
}

.mdl-vbtn:active {
  background: var(--subtle-pressed);
}

.mdl-vbtn.is-on {
  background: var(--subtle-selected);
  color: var(--accent);
}

.mdl-vbtn svg {
  width: 18px;
  height: 18px;
}

/* Segmented toggle (e.g. Perspective / Orthographic) — a rounded pill of
   buttons with the active segment filled. */
.mdl-seg {
  display: inline-flex;
  align-items: stretch;
  height: 28px;
  border: 1px solid var(--control-stroke);
  border-radius: var(--radius-control);
  background: var(--control-fill);
  overflow: hidden;
}

.mdl-seg-btn {
  display: inline-flex;
  align-items: center;
  border: 0;
  background: transparent;
  cursor: pointer;
  padding: 0 11px;
  font-family: inherit;
  font-size: 12px;
  color: var(--text-secondary);
  white-space: nowrap;
}

.mdl-seg-btn+.mdl-seg-btn {
  border-left: 1px solid var(--control-stroke);
}

.mdl-seg-btn:hover:not(.active) {
  background: var(--subtle-hover);
  color: var(--text-primary);
}

.mdl-seg-btn.active {
  background: var(--text-primary);
  color: var(--card);
  font-weight: 600;
}

/* Standard-views dropdown trigger: wider so the cube + caret fit side by side. */
.mdl-vbtn-wide {
  width: auto;
  padding: 0 4px;
  display: inline-flex;
  align-items: center;
  gap: 1px;
}

.mdl-vbtn-wide .mdl-caret {
  width: 13px;
  height: 13px;
  color: var(--text-secondary);
}

.mdl-viewmenu-wrap {
  position: relative;
  display: inline-flex;
}

.mdl-viewmenu-backdrop {
  position: fixed;
  inset: 0;
  z-index: 19;
}

.mdl-viewmenu {
  position: absolute;
  top: calc(100% + 4px);
  left: 0;
  z-index: 20;
  min-width: 130px;
  padding: 4px;
  background: var(--flyout);
  border: 1px solid var(--flyout-stroke);
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-card);
}

.mdl-viewmenu-item {
  display: flex;
  align-items: center;
  gap: 9px;
  width: 100%;
  height: 28px;
  padding: 0 10px;
  border: 0;
  background: transparent;
  color: var(--text-primary);
  text-align: left;
  cursor: pointer;
  border-radius: var(--radius-control);
  font-family: inherit;
  font-size: 12px;
}

.mdl-viewmenu-item:hover {
  background: var(--subtle-hover);
}

.mdl-viewmenu-item:active {
  background: var(--subtle-pressed);
}

.mdl-viewmenu-icon {
  flex: 0 0 auto;
  display: grid;
  place-items: center;
  color: var(--text-secondary);
}

.mdl-viewmenu-icon svg {
  width: 15px;
  height: 15px;
}

.mdl-viewmenu-sep {
  height: 1px;
  margin: 4px 6px;
  background: var(--divider);
}

.mdl-canvas-host {
  flex: 1 1 auto;
  min-height: 0;
  position: relative;
}

.mdl-canvas {
  position: absolute;
  inset: 0;
}

.mdl-canvas canvas {
  display: block;
  width: 100% !important;
  height: 100% !important;
}

/* Viewport toolbar overlay injected by Viewport3D.ts */
.mdl-app .viewport-toolbar {
  position: absolute;
  top: 10px;
  left: 10px;
  display: flex;
  flex-direction: column;
  gap: 4px;
  z-index: 5;
  pointer-events: auto;
}

.mdl-app .viewport-toolbar button {
  width: 32px;
  height: 32px;
  display: grid;
  place-items: center;
  background: var(--flyout);
  border: 1px solid var(--flyout-stroke);
  border-radius: var(--radius-control);
  box-shadow: var(--shadow-card);
  color: var(--text-secondary);
  cursor: pointer;
}

.mdl-app .viewport-toolbar button:hover {
  background: var(--control-fill-hover);
  color: var(--text-primary);
}

.mdl-app .viewport-toolbar button.is-active {
  color: var(--accent);
  border-color: var(--accent);
}

.mdl-app .viewport-toolbar svg {
  width: 18px;
  height: 18px;
}

/* HUD reused from the viewport */
.mdl-app .bridge-hud {
  position: absolute;
  right: 10px;
  bottom: 10px;
  z-index: 6;
  pointer-events: none;
  -webkit-user-select: none;
  user-select: none;
  white-space: nowrap;
  font-family: "Cascadia Code", ui-monospace, Consolas, monospace;
  font-size: 11px;
  line-height: 1;
  color: var(--text-secondary);
  background: var(--flyout);
  border: 1px solid var(--flyout-stroke);
  border-radius: var(--radius-control);
  box-shadow: var(--shadow-card);
  padding: 5px 9px;
}

/* Results "Disp. Color Dir." contour legend — bottom-center of the 3D canvas.
   Structure: title, then a bar+ticks stack (barwrap) holding the gradient bar,
   its hover tooltip, and a row of tick marks + value labels below it. */
.mdl-app .bridge-colorscale {
  position: absolute;
  left: 50%;
  bottom: 14px;
  transform: translateX(-50%);
  z-index: 6;
  -webkit-user-select: none;
  user-select: none;
  white-space: nowrap;
  pointer-events: none;
  font-family: "Cascadia Code", ui-monospace, Consolas, monospace;
  font-size: 11px;
  line-height: 1;
  color: var(--text-secondary);
  background: var(--flyout);
  border: 1px solid var(--flyout-stroke);
  border-radius: var(--radius-control);
  box-shadow: var(--shadow-card);
  padding: 8px 16px 6px;
}

.mdl-app .bridge-colorscale.hidden {
  display: none;
}

.mdl-app .bridge-colorscale-title {
  font-weight: 600;
  color: var(--text-primary);
  text-align: center;
  margin-bottom: 6px;
}

.mdl-app .bridge-colorscale-barwrap {
  position: relative;
  width: 360px;
}

.mdl-app .bridge-colorscale-bar {
  width: 100%;
  height: 16px;
  border-radius: 3px;
  border: 1px solid var(--flyout-stroke);
  cursor: crosshair;
  pointer-events: auto;
}

.mdl-app .bridge-colorscale-ticks {
  position: relative;
  width: 100%;
  height: 15px;
  margin-top: 4px;
}

.mdl-app .bridge-colorscale-tickmark {
  position: absolute;
  top: 0;
  width: 1px;
  height: 4px;
  background: var(--flyout-stroke);
  transform: translateX(-0.5px);
}

.mdl-app .bridge-colorscale-tick {
  position: absolute;
  top: 5px;
  transform: translateX(-50%);
  white-space: nowrap;
  font-size: 10px;
  color: var(--text-tertiary);
}

.mdl-app .bridge-colorscale-tooltip {
  position: absolute;
  bottom: calc(100% + 5px);
  transform: translateX(-50%);
  background: var(--text-primary);
  color: var(--layer);
  padding: 2px 7px;
  border-radius: 4px;
  font-size: 10.5px;
  font-weight: 600;
  pointer-events: none;
  white-space: nowrap;
}

.mdl-app .bridge-colorscale-tooltip.hidden {
  display: none;
}

/* Section-clipping card — bottom-center of the 3D canvas (ClippingPanel.ts).
   A dark vertical "CLIPPING" tab beside three X/Y/Z dual-handle range rows;
   dragging a handle installs axis-aligned crop planes on the renderer. */
.mdl-app .bridge-clip {
  position: absolute;
  bottom: 8px;
  left: 50%;
  transform: translate(-50%);
  z-index: 21;
  display: flex;
  flex-direction: row;
  align-items: stretch;
  width: min(520px, calc(100% - 40px));
  background: var(--flyout);
  border: 1px solid var(--flyout-stroke);
  border-radius: 8px;
  box-shadow: var(--shadow-card);
  overflow: hidden;
  pointer-events: auto;
}

.mdl-app .bridge-clip.hidden {
  display: none;
}

.mdl-app .bridge-clip-tab {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  justify-content: center;
  writing-mode: vertical-rl;
  transform: rotate(180deg);
  padding: 4px 8px;
  font-weight: 700;
  font-size: 10px;
  letter-spacing: 1.5px;
  background: var(--text-primary);
  color: var(--layer);
}

.mdl-app .bridge-clip-body {
  position: relative;
  flex: 1 1 auto;
  display: flex;
}

.mdl-app .bridge-clip-rows {
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
  gap: 5px;
  padding: 8px 28px 8px 12px;
}

.mdl-app .bridge-clip-close {
  background: var(--subtle-selected);
  position: absolute;
  top: 5px;
  right: 5px;
  width: 20px;
  height: 20px;
  display: grid;
  place-items: center;
  padding: 0;
  border: none;
  border-radius: 4px;
  color: var(--text-secondary);
  cursor: pointer;
}

.mdl-app .bridge-clip-close:hover {
  background: var(--subtle-hover);
  color: var(--text-primary);
}

.mdl-app .bridge-clip-row {
  display: flex;
  align-items: center;
  gap: 8px;
}

.mdl-app .bridge-clip-axis {
  flex: 0 0 auto;
  width: 10px;
  font-weight: 700;
  color: var(--text-secondary);
}

.mdl-app .bridge-clip-value {
  flex: 0 0 auto;
  width: 40px;
  color: var(--text-secondary);
  font-variant-numeric: tabular-nums;
}

.mdl-app .bridge-clip-value-min {
  text-align: right;
}

.mdl-app .bridge-clip-value-max {
  text-align: left;
}

.mdl-app .bridge-clip-track {
  position: relative;
  flex: 1 1 auto;
  min-width: 140px;
  height: 16px;
  margin: 0 8px;
  touch-action: none;
}

.mdl-app .bridge-clip-rail {
  position: absolute;
  top: 50%;
  left: 0;
  right: 0;
  height: 8px;
  transform: translateY(-50%);
  border-radius: 8px;
  background: var(--text-disabled);
}

.mdl-app .bridge-clip-fill {
  position: absolute;
  top: 50%;
  height: 8px;
  transform: translateY(-50%);
  border-radius: 8px;
  background: var(--accent);
}

.mdl-app .bridge-clip-thumb {
  position: absolute;
  top: 50%;
  width: 12px;
  height: 12px;
  transform: translate(-50%, -50%);
  border-radius: 50%;
  background: var(--layer);
  border: 2px solid var(--accent);
  cursor: grab;
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.3);
}

.mdl-app .bridge-clip-thumb:active {
  cursor: grabbing;
}

.mdl-app .bridge-clip-thumb:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

/* ============================================================
   Analysis Log — pane docked under the 3D view (inside .mdl-viewstack,
   below .mdl-views, resized by the #mdl-split-log gutter). Streams the
   VB-engine status (xApp.Event_ShowStatus) and SAP-solver monitor
   messages during Run Analysis; reopen via Analysis > Analysis Logs.
   ============================================================ */
.mdl-app .mdl-log {
  /* position + z-index keep it painting above the busy overlay (z-index 2000),
     so the log stays visible and streams live while Run Analysis holds the
     overlay up. .mdl-workspace / .mdl-viewstack create no stacking context, so
     this competes directly with the overlay inside .mdl-app. */
  position: relative;
  z-index: 2001;
  flex: 0 0 200px;
  min-height: 88px;
  max-height: 60%;
  display: flex;
  flex-direction: column;
  margin: 0 4px 4px 0;
  background: var(--flyout);
  border: var(--border);
  box-shadow: var(--shadow-card);
  overflow: hidden;
}

.mdl-log-head {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  gap: 8px;
  height: 34px;
  padding: 0 6px 0 12px;
  background: var(--card-head);
  border-bottom: 1px solid var(--divider);
}

/* Push Clear / Close to the far right of the header. */
.mdl-log-head .ph-spacer {
  flex: 1 1 auto;
}

.mdl-log-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  flex: 0 0 8px;
  background: var(--accent);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 22%, transparent);
}

.mdl-log-title {
  font-size: 12px;
  font-weight: 600;
  color: var(--text-primary);
}

.mdl-log-count {
  font-size: 11px;
  color: var(--text-tertiary);
}

.mdl-log-body {
  flex: 1 1 auto;
  overflow-y: auto;
  padding: 8px 12px;
  background: var(--canvas2d-bg);
  font-family: "Cascadia Code", ui-monospace, Consolas, monospace;
  font-size: 11.5px;
  line-height: 1.5;
  color: var(--text-secondary);
  white-space: pre-wrap;
  word-break: break-word;
}

.mdl-log-line {
  padding: 0;
}

.mdl-log-line:last-child {
  color: var(--text-primary);
}

.mdl-log-empty {
  color: var(--text-tertiary);
  font-style: italic;
}

/* The bottom info bar left this file: it is now the app-wide <AppInfoBar>
   (Components/Shared/AppInfoBar.razor + .razor.css) — centred rather than
   window-wide, shared by every screen, and self-dismissing. */

/* ============================================================
   Torn-off tool-panel window
   A panel (Explorer / Property / Help) undocked into its own native OS window
   (see PanelWindowRoot / PanelWindowService). The single pane fills the window;
   its docking margins/borders/fixed widths are dropped.
   ============================================================ */
.mdl-panel-window {
  position: fixed;
  inset: 0;
  display: flex;
  flex-direction: column;
  background: var(--mica-base);
}

.mdl-panel-window .mdl-pane,
.mdl-panel-window .mdl-pane.mdl-explorer,
.mdl-panel-window .mdl-pane.mdl-prop,
.mdl-panel-window .mdl-pane.mdl-help {
  flex: 1 1 auto;
  width: 100%;
  min-width: 0;
  min-height: 0;
  margin: 0;
  border: 0;
}

.mdl-panel-window-empty {
  padding: 20px;
  font-size: 13px;
  color: var(--text-secondary);
}

/* ============================================================
   Additional 3D views (multiple / side-by-side / undockable)
   ============================================================ */
/* Each extra view is a peer .mdl-view pane (flex:1 1 auto → shares the row). */
.mdl-secondary-view {
  min-width: 0;
}

/* Focused-view highlight (only shown when more than one view is open). */
.mdl-view.is-active-view {
  outline: 2px solid var(--accent, #2a6fd6);
}

/* "+ New View" button in the primary view header. */
.mdl-newview-btn svg {
  width: 16px;
  height: 16px;
}

/* ============================================================
   3D view tiling (Snap layouts) + layout picker
   ============================================================ */
/* Grid container holding the primary + additional docked views. */
/* Column that holds the tiled 3D views plus the Analysis Log docked beneath them
   (log + its gutter are absent while the log is closed, so views take the lot). */
.mdl-viewstack {
  flex: 1 1 auto;
  min-width: 0;
  min-height: 0;
  display: flex;
  flex-direction: column;
}

.mdl-views {
  flex: 1 1 auto;
  min-width: 0;
  min-height: 0;
  display: grid;
  gap: 4px;
  padding-bottom: 4px;
  padding-right: 4px;
}

.app-viewer .mdl-views {
    padding-right: 0;
}

.mdl-views>.mdl-pane {
  min-width: 0;
  min-height: 0;
}

.mdl-views-columns {
  grid-auto-flow: column;
  grid-auto-columns: 1fr;
  grid-template-rows: 1fr;
}

.mdl-views-rows {
  grid-auto-flow: row;
  grid-auto-rows: 1fr;
  grid-template-columns: 1fr;
}

.mdl-views-grid {
  grid-template-columns: 1fr 1fr;
  grid-auto-rows: 1fr;
}

/* Layout picker flyout (Windows-Snap style). */
.mdl-layout-wrap {
  position: relative;
  display: inline-flex;
}

.mdl-layout-backdrop {
  position: fixed;
  inset: 0;
  z-index: 90;
}

.mdl-layout-pop {
  position: absolute;
  top: calc(100% + 4px);
  right: 0;
  z-index: 91;
  display: flex;
  flex-direction: column;
  padding: 10px;
  background: var(--flyout);
  border: 1px solid var(--flyout-stroke);
  border-radius: var(--radius-control);
  box-shadow: var(--shadow-card);
}

.mdl-layout-title {
  font-size: 11px;
  color: var(--text-secondary);
  margin: 0 2px 8px;
}

.mdl-layout-grid {
  display: flex;
  gap: 6px;
}

.mdl-layout-opt {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
  padding: 8px;
  border: 1px solid transparent;
  border-radius: var(--radius-control);
  background: transparent;
  cursor: pointer;
  color: var(--text-secondary);
}

.mdl-layout-opt:hover {
  background: var(--subtle-hover);
}

.mdl-layout-opt.active {
  border-color: var(--accent, #2a6fd6);
  background: var(--subtle-hover);
}

.mdl-layout-lbl {
  font-size: 11px;
}

.mdl-layout-dia {
  width: 46px;
  height: 34px;
  display: grid;
  gap: 3px;
  padding: 3px;
  border-radius: 4px;
  background: var(--divider);
}

.mdl-layout-dia i {
  background: var(--text-tertiary);
  border-radius: 2px;
}

.mdl-layout-dia.dia-cols {
  grid-template-columns: 1fr 1fr;
  grid-template-rows: 1fr;
}

.mdl-layout-dia.dia-rows {
  grid-template-columns: 1fr;
  grid-template-rows: 1fr 1fr;
}

.mdl-layout-dia.dia-grid {
  grid-template-columns: 1fr 1fr;
  grid-template-rows: 1fr 1fr;
}

/* ============================================================
   BOQ pane — covers the 3D view stack while a node in the
   Explorer's BOQ tab is selected (Modeler.Boq.cs).

   Same overlay geometry as the report pane below, but the content is
   ordinary scrollable tables rather than an iframe: this view exists to
   be read against a drawing and checked, not to be printed. Tables reuse
   .mdl-table so a figure here looks like a figure anywhere else in the
   Modeler.
   ============================================================ */
.mdl-app .mdl-boq {
  position: absolute;
  inset: 0;
  z-index: 2002;
  display: flex;
  flex-direction: column;
  margin: 0 4px 4px 0;
  background: var(--flyout);
  border: var(--border);
  box-shadow: var(--shadow-card);
  overflow: hidden;
}

/* A scrolling card stack. The padding, gap, card and sub-head styling all come from
   .mdl-prop-body, which the element also carries — this only adds the scrolling. */
.mdl-boq-body {
  flex: 1 1 auto;
  min-height: 0;
  overflow: auto;
}

/* Cards span the pane, as they do in the Property panel — sizing each to its own table left a
   ragged right edge. The TABLES inside stay content-sized, so figures still sit in tight columns
   rather than being spread across the card. */
.mdl-boq-body .mdl-card {
  align-self: stretch;
}

/* Consecutive tables inside one card need air between them (a sub-head provides it above, but the
   last table in a card has nothing below it). */
.mdl-boq-body .mdl-card-inner > .mdl-boq-scroll + .mdl-subhead {
  margin-top: 12px;
}

/* A wide table scrolls inside its own box rather than pushing the pane sideways. */
.mdl-boq-scroll {
  overflow-x: auto;
}

/* Figures right, everything else left (BoqTable.RightAligned decides which is which), and a
   figure never wraps — a broken "7,186.52" is unreadable. */
.mdl-boq-scroll .mdl-table th.is-figures,
.mdl-boq-scroll .mdl-table td.is-figures {
  text-align: right;
  white-space: nowrap;
}

/* Text columns take the width their content needs and give the rest away, so the label column
   stops stretching to half the pane with its content stranded at the far edge. `width: 1%` on an
   auto-layout table means "shrink to fit"; nowrap is what makes that fit ONE LINE rather than the
   narrowest possible column — without it "Concrete Surface/Wearing Course" came out three lines
   tall. */
.mdl-boq-scroll .mdl-table th:not(.is-figures),
.mdl-boq-scroll .mdl-table td:not(.is-figures) {
  text-align: left;
  white-space: nowrap;
}

/* The last column absorbs the slack, and is the one column allowed to wrap: it is where the long
   prose lives (the Checks table's Basis), and forcing that onto one line would put every table
   into horizontal scroll. */
.mdl-boq-scroll .mdl-table th:last-child:not(.is-figures),
.mdl-boq-scroll .mdl-table td:last-child:not(.is-figures) {
  white-space: normal;
}

/* Sized to its content, not stretched to the pane. `min-width: 100%` was what spread a
   three-column bar list across the full width and stranded every figure at the right edge of its
   own oversized column; `width: auto` did not fix it either, because percentage cell widths on an
   auto-width table are circular and browsers resolve them by expanding the table. max-content
   sizes each column to its longest cell, and the max-width caps a wide table at the pane, where
   the wrapping last column gives way first. */
.mdl-boq-scroll .mdl-table {
  width: max-content;
  max-width: 100%;
}

/* Total rows carry the weight of a footer. Marked by the table itself (BoqTable.TotalRows),
   not by position: most of these tables do not end on a total. */
.mdl-boq-scroll .mdl-table tbody tr.is-total td {
  font-weight: 600;
}

/* ============================================================
   Report pane — covers the 3D view stack while a report node is
   selected in the Explorer (Bill of Quantities, Design Report,
   Analysis Result Summary, Location Details, User Reports…).

   The report itself renders inside an iframe (wwwroot/report/report.html)
   that carries the Xplore/XReport renderer ported from the WinUI report
   app; it stays mounted once created so the bundle loads only once, and
   is hidden rather than removed when leaving report mode.
   ============================================================ */
.mdl-app .mdl-report {
  /* Overlays .mdl-views inside the (non-positioned) .mdl-viewstack, and paints
     above the busy overlay for the same reason .mdl-log does. */
  position: absolute;
  inset: 0;
  z-index: 2002;
  display: flex;
  flex-direction: column;
  margin: 0 4px 4px 0;
  background: var(--flyout);
  border: var(--border);
  box-shadow: var(--shadow-card);
  overflow: hidden;
}

.mdl-app .mdl-report.is-hidden {
  display: none;
}

.mdl-viewstack {
  position: relative;
}

.mdl-report-body {
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  flex-direction: column;
}

.mdl-report-frame {
  flex: 1 1 auto;
  width: 100%;
  min-height: 0;
  border: 0;
  background: #fff;
}

.mdl-report-note {
  flex: 0 0 auto;
  padding: 8px 12px;
  font-size: 12px;
  color: var(--text-secondary);
  background: var(--subtle-hover);
  border-bottom: 1px solid var(--divider);
}

.mdl-report-busy {
  font-size: 11px;
  font-weight: 400;
  color: var(--text-tertiary);
  margin-right: 6px;
}

/* ============================================================
   AI assistant panel (AiPanel.razor)
   ============================================================
   A right-docked tool pane like Help, but laid out as a transcript over a fixed
   composer, so the body is the only thing that scrolls. */
.mdl-ai { flex: 0 0 420px; display: flex; flex-direction: column; min-height: 0; }

.mdl-ai-body { display: flex; flex-direction: column; gap: 8px; padding: 10px 12px; }

/* --- Empty state --- */
.mdl-ai-empty { padding: 8px 2px; color: var(--text-secondary); }
.mdl-ai-empty-title { margin: 0 0 6px; font-size: 13px; font-weight: 600; color: var(--text-primary); }
.mdl-ai-empty-note { margin: 0 0 14px; font-size: 12px; line-height: 1.5; }
.mdl-ai-suggestions { display: flex; flex-direction: column; align-items: flex-start; gap: 6px; }
.mdl-ai-suggestion {
  max-width: 100%; text-align: left; font: inherit; font-size: 12px; cursor: pointer;
  padding: 6px 10px; border: 1px solid var(--control-stroke); border-radius: var(--radius-control);
  background: var(--control-fill); color: var(--text-secondary);
}
.mdl-ai-suggestion:hover:not(:disabled) { background: var(--control-fill-hover); color: var(--text-primary); }
.mdl-ai-suggestion:disabled { opacity: .5; cursor: default; }

/* --- Transcript --- */
.mdl-ai-msg { font-size: 13px; line-height: 1.55; white-space: pre-wrap; overflow-wrap: anywhere; }
.mdl-ai-user {
  align-self: flex-end; max-width: 88%; padding: 7px 11px;
  border-radius: 12px 12px 3px 12px; background: var(--accent); color: var(--accent-fill-text);
}
.mdl-ai-assistant { color: var(--text-primary); }

.mdl-ai-thinking { font-size: 12px; color: var(--text-tertiary); }
.mdl-ai-thinking > summary { cursor: pointer; user-select: none; padding: 2px 0; }
.mdl-ai-thinking-body {
  margin-top: 4px; padding-left: 9px; border-left: 2px solid var(--divider);
  white-space: pre-wrap; line-height: 1.5; overflow-wrap: anywhere;
}

/* Tool activity: a compact chip per call, so a long turn stays readable. */
.mdl-ai-tool {
  display: flex; align-items: baseline; gap: 7px; font-size: 11.5px;
  color: var(--text-tertiary); padding: 3px 0;
}
.mdl-ai-tool-name {
  flex: 0 0 auto; font-family: var(--font-mono); font-size: 11px;
  padding: 1px 6px; border-radius: 4px; background: var(--card-secondary); color: var(--text-secondary);
}
.mdl-ai-tool-args { min-width: 0; overflow-wrap: anywhere; }
.mdl-ai-tool.is-pending .mdl-ai-tool-name { animation: mdl-ai-pulse 1.2s ease-in-out infinite; }
.mdl-ai-tool.is-failed .mdl-ai-tool-name { background: color-mix(in srgb, var(--error) 18%, transparent); color: var(--error); }

.mdl-ai-note, .mdl-ai-error {
  font-size: 12px; line-height: 1.5; padding: 6px 9px; border-radius: var(--radius-control);
  overflow-wrap: anywhere;
}
.mdl-ai-note { background: var(--card-secondary); color: var(--text-secondary); }
.mdl-ai-error { background: color-mix(in srgb, var(--error) 12%, transparent); color: var(--error); }

.mdl-ai-working { display: flex; align-items: center; gap: 7px; font-size: 12px; color: var(--text-tertiary); }
.mdl-ai-dot { width: 7px; height: 7px; border-radius: 50%; background: var(--accent); animation: mdl-ai-pulse 1.2s ease-in-out infinite; }
@keyframes mdl-ai-pulse { 0%, 100% { opacity: 1; } 50% { opacity: .3; } }

/* --- Composer --- */
.mdl-ai-composer {
  flex: 0 0 auto; display: flex; align-items: flex-end; gap: 8px;
  padding: 8px 10px; border-top: 1px solid var(--divider); background: var(--card-secondary);
}
.mdl-ai-input {
  flex: 1 1 auto; min-width: 0; resize: none; font: inherit; font-size: 13px; line-height: 1.45;
  padding: 7px 9px; border: 1px solid var(--control-stroke); border-radius: var(--radius-control);
  background: var(--control-fill); color: var(--text-primary);
}
.mdl-ai-input:focus { outline: none; border-color: var(--accent); }
.mdl-ai-input:disabled { opacity: .6; }
.mdl-ai-send {
  flex: 0 0 auto; font: inherit; font-size: 12px; cursor: pointer; padding: 7px 14px;
  border: 1px solid transparent; border-radius: var(--radius-control);
  background: var(--accent); color: var(--accent-fill-text);
}
.mdl-ai-send:hover:not(:disabled) { background: var(--accent-hover); }
.mdl-ai-send:disabled { opacity: .45; cursor: default; }
.mdl-ai-stop { background: var(--control-fill); color: var(--text-primary); border-color: var(--control-stroke); }
.mdl-ai-stop:hover { background: var(--control-fill-hover); }

/* --- API key flyout --- */
.mdl-ai-key {
  flex: 0 0 auto; padding: 10px 12px;
  border-bottom: 1px solid var(--divider); background: var(--card-secondary);
}
.mdl-ai-key-label { display: block; font-size: 11px; color: var(--text-secondary); margin-bottom: 5px; }
.mdl-ai-key-input {
  width: 100%; box-sizing: border-box; font: inherit; font-size: 12px; font-family: var(--font-mono);
  padding: 6px 8px; border: 1px solid var(--control-stroke); border-radius: var(--radius-control);
  background: var(--control-fill); color: var(--text-primary);
}
.mdl-ai-key-input:focus { outline: none; border-color: var(--accent); }
.mdl-ai-key-row { display: flex; gap: 6px; margin-top: 7px; }
.mdl-ai-key-clear {
  font: inherit; font-size: 12px; cursor: pointer; padding: 5px 12px;
  border: 1px solid var(--control-stroke); border-radius: var(--radius-control);
  background: var(--control-fill); color: var(--text-primary);
}
.mdl-ai-key-clear:disabled { opacity: .45; cursor: default; }
.mdl-ai-key-note { margin: 8px 0 0; font-size: 11px; line-height: 1.45; color: var(--text-tertiary); }

/* Header icon buttons have no disabled style of their own. */
.mdl-head-iconbtn:disabled { opacity: .35; cursor: default; }
.mdl-head-iconbtn:disabled:hover { background: transparent; }

/* ============================================================
   Canvas toolbar ▸ rebar span filter
   ============================================================
   Lives in the BridgeViewport3D toolbar's trailing slot, so it has to match the
   .bv3d-btn row (28px tall, --text-secondary icon) rather than the ribbon's
   .mdl-rselect. Authored in Modeler.razor, so it is styled here and not in the
   viewport component's scoped sheet. */
.mdl-rebarspan {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  height: 28px;
  padding: 0 2px 0 5px;
  color: var(--text-secondary);
}
.mdl-rebarspan svg { width: 17px; height: 17px; flex: 0 0 auto; }
.mdl-rebarspan:has(select:disabled) { opacity: .4; }

.mdl-rebarspan-select {
  height: 24px;
  min-width: 104px;
  padding: 0 26px 0 7px;
  background: var(--control-fill);
  border: 1px solid var(--control-stroke);
  border-bottom-color: var(--control-stroke-bottom);
  border-radius: var(--radius-control);
  color: var(--text-primary);
  font-family: inherit;
  font-size: 12px;
  cursor: pointer;
  -webkit-appearance: none;
  appearance: none;
  /* Same chevron as select.mdl-select — light theme stroke; dark below. */
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%23333333' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 7px center;
  background-size: 13px 13px;
}
.mdl-rebarspan-select:disabled { cursor: default; }

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) select.mdl-rebarspan-select {
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%23c9c9c9' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
  }
}

:root[data-theme="dark"] select.mdl-rebarspan-select {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%23c9c9c9' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
}

/* ============================================================
   Explorer ▸ Drawing — the sheet coverage card
   ============================================================
   Shown in the Property panel for a sheet or one of its views (see
   Modeler.Drawings.cs / PropertyPanel.razor). Not a form and not a drawing:
   a list of statements about what this app can generate, so it is styled as
   prose with a status pill rather than as label/value fields. */
.mdl-dwg-summary {
  padding: 4px 0 10px;
  color: var(--text-secondary);
  font-size: 12.5px;
  line-height: 1.5;
}

.mdl-dwg-row {
  padding: 8px 0;
  border-top: 1px solid var(--divider);
}

.mdl-dwg-row-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
}

.mdl-dwg-name {
  color: var(--text-primary);
  font-size: 12.5px;
  font-weight: 600;
}

/* Fixed width so the pills line up down the right edge — the column of statuses
   is the thing being scanned, and ragged pills make it unreadable. */
.mdl-dwg-pill {
  flex: 0 0 auto;
  min-width: 82px;
  padding: 1px 8px;
  border: 1px solid currentColor;
  border-radius: 9px;
  font-size: 10.5px;
  font-weight: 600;
  text-align: center;
  white-space: nowrap;
}

.mdl-dwg-pill.is-ready { color: #0f7b0f; }
.mdl-dwg-pill.is-partial { color: #9d5d00; }
.mdl-dwg-pill.is-missing { color: #c42b1c; }

.mdl-dwg-detail {
  padding-top: 3px;
  color: var(--text-tertiary);
  font-size: 12px;
  line-height: 1.5;
}

.mdl-dwg-note {
  margin-top: 10px;
  padding: 8px 10px;
  background: var(--subtle-hover);
  border-radius: var(--radius-control);
  color: var(--text-secondary);
  font-size: 12px;
  line-height: 1.5;
}

/* The drawings pane itself — same geometry as the BOQ pane: absolutely positioned over
   the 3D views inside .mdl-viewstack, so closing it uncovers the view rather than
   relaying it. */
.mdl-app .mdl-drawing {
  position: absolute;
  inset: 0;
  z-index: 2002;
  display: flex;
  flex-direction: column;
  margin: 0 4px 4px 0;
  background: var(--flyout);
  border: var(--border);
  box-shadow: var(--shadow-card);
  overflow: hidden;
}

.mdl-drawing-body {
  flex: 1 1 auto;
  min-height: 0;
  overflow: auto;
  padding: 8px;
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.mdl-viewstack .mdl-drawing-body {
    padding: 0;
}

/* A sheet is several views seen TOGETHER, which is the whole reason these moved out of the
   Property panel's column. Tiled, with a floor wide enough that a dimensioned section stays
   readable; one drawing on a narrow window still spans it. */
.mdl-drawing-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(420px, 1fr));
    gap: 8px;
    align-items: start;
}

/* Taller than the 300px the Property panel gives a preview — this pane exists to make the
   drawings big enough to read. */
.mdl-drawing .mdl-canvas2d {
  height: 380px;
}

/* The composed sheet is one canvas, so it takes the whole pane and as much height as it can
   get — a sheet of a dozen views at one scale is unreadable in a 380px strip. */
.mdl-drawing-sheet {
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
}

.mdl-drawing-sheet > .mdl-card {
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
  min-height: 0;
}

.mdl-drawing-sheet .mdl-card-body,
.mdl-drawing-sheet .mdl-card-inner,
.mdl-drawing-sheet .mdl-canvas2d-wrap {
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  flex-direction: column;
}

.mdl-drawing-sheet .mdl-canvas2d {
  flex: 1 1 auto;
  height: auto;
  min-height: 420px;
}

/* A card that IS the panel: no frame, no padding, nothing between the drawing and the
   surface it sits on. The card element is kept so the body/inner structure and the
   collapse transition stay intact - only its chrome goes. */
.mdl-card.mdl-card--bare {
  background: transparent;
  border: 0;
  border-radius: 0;
}

.mdl-card.mdl-card--bare > .mdl-card-body {
  max-height: none;
}

.mdl-card.mdl-card--bare .mdl-card-inner {
  padding: 0;
}

/* Sheet / Views switch in the pane header. A segmented pair rather than two buttons, so it
   reads as one choice. */
.mdl-dwg-layout {
  display: inline-flex;
  margin-right: 6px;
  border: 1px solid var(--control-stroke);
  border-radius: var(--radius-control);
  overflow: hidden;
}

.mdl-dwg-layout-btn {
  padding: 3px 9px;
  border: 0;
  background: var(--control-fill);
  color: var(--text-secondary);
  cursor: pointer;
  font-family: inherit;
  font-size: 11px;
  font-weight: 600;
}

.mdl-dwg-layout-btn + .mdl-dwg-layout-btn {
  border-left: 1px solid var(--control-stroke);
}

.mdl-dwg-layout-btn:hover { background: var(--control-fill-hover); color: var(--text-primary); }

.mdl-dwg-layout-btn.active {
  background: var(--accent);
  color: var(--accent-fill-text);
}

/* The coverage card spans the pane rather than sitting in the tile grid: it is prose about
   the sheet, not one of its drawings. */
.mdl-dwg-card {
  max-width: 900px;
}

.mdl-dwg-count {
  margin-right: 6px;
  font-size: 11px;
  font-weight: 400;
  color: var(--text-tertiary);
}

/* Dark. Two selectors for the two ways dark is reached — see the token blocks
   above; the same pairing, kept in step. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .mdl-dwg-pill.is-ready { color: #6ccb5f; }
  :root:not([data-theme="light"]) .mdl-dwg-pill.is-partial { color: #fce100; }
  :root:not([data-theme="light"]) .mdl-dwg-pill.is-missing { color: #ff99a4; }
}

:root[data-theme="dark"] .mdl-dwg-pill.is-ready { color: #6ccb5f; }
:root[data-theme="dark"] .mdl-dwg-pill.is-partial { color: #fce100; }
:root[data-theme="dark"] .mdl-dwg-pill.is-missing { color: #ff99a4; }
