/* ======================================================================================
   FrameLab — mobile-first, dark, deliberately quiet chrome so the structure is the loudest
   thing on the screen. One accent colour, one warm colour for loads, and the diagram
   colours are reserved strictly for diagrams.
   ====================================================================================== */

:root {
  --bg:        #0b1220;
  --bg-2:      #0e1626;
  --panel:     #111a2b;
  --panel-2:   #16223a;
  --panel-3:   #1b2942;
  --line:      #22304d;
  --line-2:    #2c3d61;
  --text:      #e8eefc;
  --text-2:    #c2d0e8;
  --muted:     #8ea3c8;
  --accent:    #22d3ee;
  --accent-2:  #0e7490;
  --accent-ink: #04222b;
  --tpl-bg:   rgba(34,211,238,.055);
  --tpl-line: rgba(34,211,238,.38);
  --tpl-tag:  #67e8f9;      /* text on a filled accent control */
  --amber:     #fbbf24;
  --danger:    #f87171;
  --good:      #34d399;
  --diag-M:    #f87171;
  --diag-V:    #60a5fa;
  --diag-D:    #34d399;
  --diag-N:    #a78bfa;
  --diag-R:    #fbbf24;
  --r:         14px;
  --r-sm:      10px;
  --tap:       44px;
  --shadow:    0 10px 30px rgba(0,0,0,.45);
  --bar-bg:    rgba(11,18,32,.94);
  --float-bg:  rgba(17,26,43,.94);
  --mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
  --sans: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Inter, system-ui, sans-serif;
}

/* A bright daylight palette for the same layout. Chosen deliberately, not an inversion. */
html[data-theme="light"] {
  --bg:        #eef2f8;
  --bg-2:      #ffffff;
  --panel:     #ffffff;
  --panel-2:   #f4f7fc;
  --panel-3:   #e9eff8;
  --line:      #dbe3ef;
  --line-2:    #c2cee0;
  --text:      #0f1a2b;
  --text-2:    #2b3a52;
  --muted:     #5f7089;
  --accent:    #0e7490;
  --accent-2:  #22d3ee;
  --accent-ink: #ffffff;
  --tpl-bg:   rgba(14,116,144,.055);
  --tpl-line: rgba(14,116,144,.45);
  --tpl-tag:  #0a566b;      /* 6.8:1 on the tinted card; #0e7490 only managed 4.4:1 */      /* text on a filled accent control */
  --amber:     #b45309;
  --danger:    #dc2626;
  --good:      #047857;
  --bar-bg:    rgba(255,255,255,.94);
  --float-bg:  rgba(255,255,255,.96);
  --shadow:    0 8px 26px rgba(15,26,43,.14);
}
html[data-theme="light"] .gate {
  background: radial-gradient(1100px 500px at 15% -10%, rgba(14,116,144,.10), transparent 60%), var(--bg);
}
html[data-theme="light"] {
  /* the tab colours follow the canvas palette: #34d399 on white is unreadable, #059669 is not */
  --diag-M: #b91c1c;
  --diag-V: #1d4ed8;
  --diag-D: #047857;
  --diag-N: #6d28d9;
  --diag-R: #92400e;
}
html[data-theme="light"] .btn.primary { color: #ffffff; }

* { box-sizing: border-box; -webkit-tap-highlight-color: transparent; }
html, body { height: 100%; }
body {
  margin: 0; background: var(--bg); color: var(--text); font-family: var(--sans);
  font-size: 15px; line-height: 1.45; overflow: hidden;
  -webkit-font-smoothing: antialiased;
}
body.gate-open { overflow: auto; }
h1, h2, h3 { margin: 0; font-weight: 650; letter-spacing: -.01em; }
.h2 { font-size: 1.15rem; }
p { margin: 0 0 8px; }
code { font-family: var(--mono); font-size: .82em; background: var(--panel-2); padding: 2px 6px; border-radius: 6px; }
.muted { color: var(--muted); }
.tiny { font-size: .78rem; }
[hidden] { display: none !important; }

/* ------------------------------------------------------------------ sign in ---- */
.gate {
  position: fixed; inset: 0; z-index: 60; display: flex; align-items: center; justify-content: center;
  padding: 20px; overflow: auto;
  background:
    radial-gradient(1100px 500px at 15% -10%, rgba(34,211,238,.10), transparent 60%),
    radial-gradient(900px 500px at 110% 10%, rgba(96,165,250,.08), transparent 55%),
    var(--bg);
}
.gate-card {
  width: 100%; max-width: 400px; background: var(--panel); border: 1px solid var(--line);
  border-radius: 20px; padding: 22px 20px 18px; box-shadow: var(--shadow);
}
.gate-brand { display: flex; align-items: center; gap: 12px; margin-bottom: 18px; }
.gate-logo { width: 46px; height: 46px; color: var(--accent); flex: 0 0 auto; }
.gate-logo circle { fill: var(--accent); stroke: none; }
.gate-brand h1 { font-size: 1.5rem; letter-spacing: -.02em; }
.gate-brand p { margin: 0; }
.gate-note { font-size: .8rem; color: var(--muted); background: var(--panel-2); border: 1px solid var(--line);
  border-radius: var(--r-sm); padding: 9px 11px; margin-bottom: 14px; }
.gate-foot { margin-top: 12px; text-align: center; }
.gate-err { margin: 12px 0 0; padding: 9px 11px; border-radius: var(--r-sm); font-size: .82rem;
  background: rgba(248,113,113,.12); border: 1px solid rgba(248,113,113,.35); color: var(--danger); }
html[data-theme="dark"] .gate-err { color: #ffd7d7; }

label { display: block; font-size: .78rem; color: var(--muted); margin-bottom: 11px; }
label input, label select {
  display: block; width: 100%; margin-top: 5px; min-height: var(--tap);
  padding: 11px 13px; font-size: 1rem; font-family: inherit; color: var(--text);
  background: var(--bg-2); border: 1px solid var(--line-2); border-radius: var(--r-sm);
}
label input:focus, label select:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px rgba(34,211,238,.15); }

.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 7px;
  min-height: var(--tap); padding: 0 15px; font-size: .92rem; font-weight: 600; font-family: inherit;
  color: var(--text); background: var(--panel-3); border: 1px solid var(--line-2);
  border-radius: var(--r-sm); cursor: pointer;
}
.btn svg { width: 18px; height: 18px; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
.btn.primary { background: linear-gradient(180deg, #22d3ee, #0891b2); border-color: #0891b2; color: #04222b; }
.btn.ghost { background: transparent; }
.btn.block { width: 100%; margin-top: 4px; }
.btn:active { transform: translateY(1px); }

/* -------------------------------------------------------------------- app ------ */
#app { display: flex; flex-direction: column; height: 100%; }
.topbar {
  flex: 0 0 auto; display: flex; align-items: center; gap: 6px; padding: 10px 12px;
  padding-top: calc(10px + env(safe-area-inset-top));
  background: var(--bar-bg); backdrop-filter: blur(12px);
  border-bottom: 1px solid var(--line); z-index: 20;
}
.tb-title { flex: 1; min-width: 0; display: flex; flex-direction: column; }
.tb-brand { font-weight: 700; letter-spacing: -.02em; font-size: 1.02rem; }
.tb-sub { font-size: .74rem; color: var(--muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.tb-btn {
  flex: 0 0 auto; width: var(--tap); height: var(--tap); display: grid; place-items: center;
  background: transparent; border: 0; color: var(--text-2); border-radius: 12px; cursor: pointer;
}
.tb-btn svg { width: 22px; height: 22px; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
.tb-btn:active { background: var(--panel-2); }

.view { flex: 1; min-height: 0; display: flex; flex-direction: column; }
.view[hidden] { display: none !important; }
.wrap { flex: 1; overflow-y: auto; -webkit-overflow-scrolling: touch; padding: 14px 14px calc(20px + env(safe-area-inset-bottom)); }
#viewResults .result-pane {
  flex: 0 0 auto; height: 40vh; min-height: 74px; max-height: 78vh;
  background: var(--bg-2); overflow-y: auto;
  /* this pane is also a .wrap, so it was inheriting 14px of top padding — a visible strip of
     background between the handle and the controls, which the reader spotted straight away */
  padding-top: 0;
}
/* the controls stay put while the panels below scroll, even with the pane dragged right down */
.pane-controls { position: sticky; top: 0; z-index: 2; background: var(--bg-2); border-bottom: 1px solid var(--line); }
.pane-grab {
  flex: 0 0 auto; height: 22px; display: flex; align-items: center; justify-content: center;
  background: var(--panel-2); border-top: 1px solid var(--line); cursor: ns-resize; touch-action: none;
}
.pane-grip { width: 46px; height: 4px; border-radius: 999px; background: var(--line-2); transition: background .15s, width .15s; }
.pane-grab.active .pane-grip, .pane-grab:focus-visible .pane-grip { background: var(--accent); width: 66px; }
.pane-grab:focus-visible { outline: none; }
/* a switch for the label settings */
.sheet-item .sw {
  margin-left: auto; flex: 0 0 auto; width: 44px; height: 26px; border-radius: 999px;
  background: var(--panel-3); border: 1px solid var(--line-2); position: relative;
}
.sheet-item .sw::after {
  content: ''; position: absolute; top: 2px; left: 2px; width: 20px; height: 20px; border-radius: 50%;
  background: var(--muted); transition: transform .16s ease, background .16s ease;
}
.sheet-item .sw.on { background: rgba(34,211,238,.18); border-color: var(--accent); }
.sheet-item .sw.on::after { transform: translateX(18px); background: var(--accent); }
#viewReport .wrap { padding-bottom: calc(40px + env(safe-area-inset-bottom)); }

.rowline { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin-bottom: 12px; }
.rowline h2 { min-width: 0; }

/* ---------------------------------------------------------------- projects ---- */
.templates { display: flex; gap: 8px; overflow-x: auto; padding: 2px 2px 12px; scrollbar-width: none; }
.templates::-webkit-scrollbar { display: none; }
/* A template is a starting point, not one of your structures: a dashed edge, a tinted card and a tag
   say so before you read a word of it. */
.tpl {
  flex: 0 0 auto; min-height: 64px; padding: 9px 13px; display: flex; flex-direction: column; gap: 2px;
  background: var(--tpl-bg); border: 1px dashed var(--tpl-line); border-radius: var(--r); cursor: pointer;
  text-align: left; color: var(--text); font-family: inherit;
}
.tpl b { font-size: .86rem; font-weight: 650; }
.tpl span { font-size: .72rem; color: var(--muted); white-space: nowrap; }
html[data-theme="light"] .tpl span { color: #33475a; }   /* 7.9:1 on the tinted card */
.tpl-tag { font-style: normal; font-size: .58rem; font-weight: 700; text-transform: uppercase;
  letter-spacing: .1em; color: var(--tpl-tag); }
.tpl:active { background: var(--panel-2); border-style: solid; }
#projCount { font-weight: 600; font-size: .78rem; color: var(--muted); margin-left: 8px; }

.plist { display: flex; flex-direction: column; gap: 9px; }
.pcard {
  display: flex; align-items: center; gap: 12px; padding: 12px 13px;
  background: var(--panel); border: 1px solid var(--line); border-radius: var(--r); cursor: pointer;
}
.pcard:active { background: var(--panel-2); }
.pthumb { flex: 0 0 auto; width: 46px; height: 46px; border-radius: var(--r-sm); background: var(--bg-2); border: 1px solid var(--line); }
.pmain { flex: 1; min-width: 0; }
.pname { font-weight: 600; font-size: .95rem; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.pmeta { font-size: .75rem; color: var(--muted); }
.pdel { flex: 0 0 auto; width: 38px; height: 38px; display: grid; place-items: center; background: transparent;
  border: 0; border-radius: 10px; color: var(--muted); cursor: pointer; }
.pdel svg { width: 19px; height: 19px; fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; }
.pdel:active { background: rgba(220, 80, 80, .16); color: #e05252; }
.pgo { flex: 0 0 auto; color: var(--muted); }
.pgo svg { width: 20px; height: 20px; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; }
.empty { padding: 26px 16px; text-align: center; color: var(--muted); font-size: .88rem;
  border: 1px dashed var(--line-2); border-radius: var(--r); }

/* ------------------------------------------------------------------ editor ---- */
.canvas-host { position: relative; flex: 1; min-height: 0; background: var(--bg-2); overflow: hidden; touch-action: none; }
.canvas-host canvas { display: block; width: 100%; height: 100%; }
.cv-hint {
  position: absolute; left: 50%; bottom: 18px; transform: translateX(-50%);
  background: var(--float-bg); border: 1px solid var(--line-2); color: var(--text-2);
  padding: 8px 13px; border-radius: 999px; font-size: .78rem; white-space: nowrap; pointer-events: none;
}
.cv-badge {
  position: absolute; right: 10px; top: 10px; background: var(--float-bg); border: 1px solid var(--line);
  color: var(--muted); font-family: var(--mono); font-size: .7rem; padding: 3px 8px; border-radius: 999px;
}
.toolbar {
  flex: 0 0 auto; display: grid; grid-template-columns: repeat(5, 1fr); gap: 4px;
  padding: 7px 8px; background: var(--bar-bg); border-top: 1px solid var(--line);
  backdrop-filter: blur(12px); z-index: 20;
}
.tool {
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 3px;
  min-height: 54px; padding: 6px 2px; font-size: .68rem; font-weight: 600; font-family: inherit;
  color: var(--muted); background: transparent; border: 1px solid transparent; border-radius: var(--r-sm); cursor: pointer;
}
.tool svg { width: 21px; height: 21px; fill: none; stroke: currentColor; stroke-width: 1.9; stroke-linecap: round; stroke-linejoin: round; }
/* The tool you are holding down has to be obvious at a glance: a filled accent control, not a
   slightly different shade of panel. */
.tool.primary {
  color: var(--accent-ink); background: var(--accent); border-color: var(--accent);
  font-weight: 700; box-shadow: 0 2px 12px rgba(34, 211, 238, .30);
}
html[data-theme="light"] .tool.primary { box-shadow: 0 2px 12px rgba(14, 116, 144, .32); }
.tool.primary svg { stroke-width: 2.4; }
.tool:not(.primary):active { background: var(--panel-2); }
.actionbar {
  flex: 0 0 auto; display: flex; align-items: center; justify-content: space-between; gap: 8px;
  padding: 4px 10px calc(8px + env(safe-area-inset-bottom)); background: var(--bar-bg);
}
.act {
  width: 46px; height: 42px; display: grid; place-items: center; border-radius: var(--r-sm);
  background: var(--panel); border: 1px solid var(--line); color: var(--text-2); cursor: pointer;
}
.act svg { width: 20px; height: 20px; fill: none; stroke: currentColor; stroke-width: 1.9; stroke-linecap: round; stroke-linejoin: round; }
.act:disabled { opacity: .4; }
#btnSolve { width: auto; min-width: 116px; padding: 0 18px; gap: 8px; display: inline-flex;
  background: linear-gradient(180deg, #22d3ee, #0891b2); border-color: #0891b2; color: #04222b; font-weight: 700; font-size: .92rem; }
#btnSolve::after { content: "Solve"; }
/* Fit and Labels wear the SAME glyph and the SAME word on the input pad and on the results screen:
   the results chips carry the icon, and these two carry the word — one action, one appearance. The
   text comes from CSS, which is how the Solve button already labels itself. */
#btnFit, #btnEditLabels { width: auto; min-width: 72px; padding: 0 11px; gap: 7px;
  display: inline-flex; align-items: center; justify-content: center; }
#btnFit::after { content: "Fit"; }
#btnEditLabels::after { content: "Labels"; }
#btnFit::after, #btnEditLabels::after { font-size: .8rem; font-weight: 700; }
.chip { display: inline-flex; align-items: center; gap: 6px; }
.chip svg { width: 14px; height: 14px; fill: none; stroke: currentColor; stroke-width: 2;
  stroke-linecap: round; stroke-linejoin: round; }

/* ----------------------------------------------------------------- results ---- */
.diagram-tabs { flex: 0 0 auto; display: flex; gap: 7px; overflow-x: auto; padding: 9px 10px;
  border-bottom: 1px solid var(--line); scrollbar-width: none; }
.diagram-tabs::-webkit-scrollbar { display: none; }
.dtab {
  flex: 0 0 auto; min-height: 36px; padding: 0 13px; border-radius: 999px; font-size: .8rem; font-weight: 600;
  font-family: inherit; background: var(--panel); border: 1px solid var(--line); color: var(--text-2); cursor: pointer;
}
.dtab.on { color: var(--text); border-color: currentColor; }
.dtab[data-diag="M"].on { color: var(--diag-M); border-color: var(--diag-M); background: rgba(248,113,113,.12); }
.dtab[data-diag="V"].on { color: var(--diag-V); border-color: var(--diag-V); background: rgba(96,165,250,.12); }
.dtab[data-diag="D"].on { color: var(--diag-D); border-color: var(--diag-D); background: rgba(52,211,153,.12); }
.dtab[data-diag="N"].on { color: var(--diag-N); border-color: var(--diag-N); background: rgba(167,139,250,.12); }
.dtab[data-diag="R"].on { color: var(--diag-R); border-color: var(--diag-R); background: rgba(251,191,36,.12); }
/* Wrapping matters: on a 390px screen the last control was pushed past the right edge and simply
   could not be tapped. A control nobody can reach is a control that does not exist. */
.scale-row { flex: 0 0 auto; display: flex; flex-wrap: wrap; align-items: center; gap: 8px 10px;
  padding: 8px 14px 10px; }
.scale-row input[type=range] { min-width: 88px; }
.scale-row input[type=range] { flex: 1; accent-color: var(--accent); }
.chip { min-height: 32px; padding: 0 12px; border-radius: 999px; font-size: .76rem; font-weight: 600;
  font-family: inherit; background: var(--panel); border: 1px solid var(--line); color: var(--text-2); cursor: pointer; }
.chip.on { background: rgba(34,211,238,.14); border-color: var(--accent); color: var(--accent); }

.stat-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; margin: 10px 0 14px; }
.stat { background: var(--panel); border: 1px solid var(--line); border-radius: var(--r); padding: 10px 12px; }
.stat b { display: block; font-size: 1.12rem; font-family: var(--mono); letter-spacing: -.02em; }
.stat span { font-size: .72rem; color: var(--muted); }
.tbl { width: 100%; border-collapse: collapse; font-size: .8rem; }
.tbl th, .tbl td { padding: 7px 9px; text-align: right; border-bottom: 1px solid var(--line); white-space: nowrap; }
.tbl th { color: var(--muted); font-weight: 600; font-size: .72rem; text-transform: uppercase; letter-spacing: .04em; }
.tbl td:first-child, .tbl th:first-child { text-align: left; }
.tbl tbody tr:last-child td { border-bottom: 0; }
.tbl-wrap { overflow-x: auto; border: 1px solid var(--line); border-radius: var(--r); background: var(--panel); }
/* The heading of each block on a sheet. Inverted against the panel — a solid bar with the theme's text
   colour as the background — so the eye can find where the next section starts at a glance, which is
   what the muted grey label failed to do. --text/--bg swap with the theme, so it stays inverted on
   both screens. */
.sec-h { font-size: .74rem; text-transform: uppercase; letter-spacing: .06em;
  color: var(--bg); background: var(--text);
  padding: 6px 10px; border-radius: 6px;
  margin: 18px 0 10px; font-weight: 700; }

/* ------------------------------------------------------------------ sheets ---- */
/* The balance warning: a bar under the topbar that does NOT fade. A toast took the message away before
   it could be read, and this is the one message that must not be missed. It sits below the sheet in the
   stacking order, so an open panel still covers it, and its text wraps rather than running off screen. */
/* In the flow, not floating: a fixed bar landed on top of the results tabs. As a flex item under the
   topbar it takes its own height and the views shift down, which is what "on top" should look like.
   [hidden] has to be spelled out — an author display rule beats the attribute's own display:none. */
.badge-warn {
  flex: 0 0 auto;
  display: flex; align-items: center; gap: 8px;
  padding: 6px 10px;
  background: rgba(251,191,36,.15);
  border-bottom: 1px solid rgba(251,191,36,.5);
  color: var(--text); font-size: .74rem; line-height: 1.35;
  /* It can never eat a click, whatever it ends up sitting near: only the dismiss button takes pointers.
     "Staying on top, but never blocking a button" is a property of the markup, not a hope. */
  pointer-events: none;
}
/* The same warning inside the printed report. The on-screen banner is hidden by @media print, so the
   report carries its own — a warning that disappears at the moment of printing is no warning. */
.rep-warn { border: 1.5px solid #b91c1c; border-radius: 10px; padding: 9px 12px; margin: 10px 0 14px;
  background: rgba(185,28,28,.07); color: #7f1d1d; font-size: .82rem; line-height: 1.45; }
.rep-warn b { display: block; margin-bottom: 3px; font-size: .88rem; }
.rep-warn span { display: block; }
html[data-theme="dark"] .rep-warn { color: #fecaca; background: rgba(185,28,28,.18); }

.badge-warn[hidden] { display: none !important; }
.badge-warn svg { flex: 0 0 auto; width: 15px; height: 15px; fill: none;
  stroke: #fbbf24; stroke-width: 1.9; stroke-linejoin: round; stroke-linecap: round; }
.badge-warn span { flex: 1 1 auto; min-width: 0; overflow-wrap: anywhere; }
.badge-x { flex: 0 0 auto; width: 28px; height: 24px; background: none; color: var(--text);
  border: 1px solid rgba(251,191,36,.55); border-radius: 7px; font: inherit; cursor: pointer;
  pointer-events: auto; }
.badge-x:active { background: rgba(251,191,36,.2); }
@media print { .badge-warn { display: none !important; } }

:root { --sheet-w: 400px; }      /* the floating panel's width on a large screen; set from JS */

.scrim { position: fixed; inset: 0; background: rgba(4,8,16,.62); z-index: 40; }
/* The drawer drops from the TOP. A bottom sheet loses its fields behind the on-screen keyboard
   the moment you tap one, which is exactly when you need to see it. */
.sheet {
  position: fixed; left: 0; right: 0; top: 0; z-index: 50;
  max-height: 88vh;
  max-height: 88dvh;                      /* shrinks with the keyboard on modern browsers */
  display: flex; flex-direction: column;
  background: var(--panel); border-bottom: 1px solid var(--line-2); border-radius: 0 0 20px 20px;
  box-shadow: 0 14px 40px rgba(0,0,0,.5);
  padding-top: env(safe-area-inset-top);  /* clear the notch */
  animation: sheet-in .17s ease-out;
}
@keyframes sheet-in { from { transform: translateY(-14px); opacity: .6; } to { transform: none; opacity: 1; } }
@media (prefers-reduced-motion: reduce) { .sheet { animation: none; } }
/* the handle sits at the foot of a top drawer: tap it to put the drawer away */
.sheet-grab { order: 3; width: 40px; height: 4px; border-radius: 999px; background: var(--line-2);
  margin: 2px auto calc(8px + env(safe-area-inset-bottom)); flex: 0 0 auto; }
.sheet-head { order: 1; display: flex; align-items: center; justify-content: space-between; gap: 8px; padding: 12px 10px 4px 16px; flex: 0 0 auto; }
.sheet-head h3 { font-size: 1.02rem; }
.sheet-body { order: 2; flex: 1 1 auto; min-height: 0; overflow-y: auto; padding: 6px 16px 14px; }
/* A row of fields must never push a control past the right edge of a phone: it wraps instead, and
   every field can shrink (min-width:0) rather than forcing the row wider than the screen. */
.sheet-row { display: flex; flex-wrap: wrap; gap: 9px; }
.sheet-row > * { flex: 1 1 84px; min-width: 0; }

/* One card per load. A column of bare inputs with nothing between them reads as a single blur,
   especially on a phone, and the wrong field gets edited. */
.load-card { border: 1px solid var(--line-2); border-radius: var(--r-sm); background: var(--panel-2);
  padding: 8px 10px 2px; margin-bottom: 10px; }
.load-head { display: flex; align-items: center; gap: 8px; margin-bottom: 7px; }
.load-head b { font-size: .78rem; letter-spacing: .01em; }
.load-head > span { flex: 1; min-width: 0; }
.load-head .btn { flex: 0 0 auto; min-width: 40px; min-height: 34px; padding: 0 8px; }
.load-card .sheet-row { margin-bottom: 6px; }
.load-card .seg-row { margin-bottom: 8px; }

.copyright { text-align: center; font-size: .72rem; color: var(--muted); margin: 22px 0 0; line-height: 1.5; }

/* The listing is one screen: the templates at the top and the copyright at the foot hold their place
   while the list of structures scrolls between them, instead of the whole page carrying the templates
   and the footer away with it. */
#viewProjects .wrap { display: flex; flex-direction: column; overflow: hidden; }
#viewProjects .sec-h, #viewProjects .templates, #viewProjects .rowline { flex: 0 0 auto; }
#viewProjects .plist { flex: 1 1 auto; min-height: 0; overflow-y: auto; -webkit-overflow-scrolling: touch; }
#viewProjects .copyright { flex: 0 0 auto; margin: 10px 0 0; }

/* The pencil beside a structure's name: rename it from the list. */
.prow { display: flex; align-items: center; gap: 6px; }
.pname { flex: 1 1 auto; min-width: 0; }
.pren { flex: 0 0 auto; width: 40px; height: 34px; display: grid; place-items: center;
  background: none; border: 1px solid var(--line); border-radius: 9px; color: var(--muted); cursor: pointer; }
.pren svg { width: 16px; height: 16px; fill: none; stroke: currentColor; stroke-width: 1.8;
  stroke-linecap: round; stroke-linejoin: round; }
.pren:active { background: var(--panel-2); color: var(--text); }
/* A thin rule between menu groups: what you produce, how the pad behaves, help, the account. */
.sheet-sep { flex: 0 0 auto; height: 1px; background: var(--line); margin: 7px 4px; }
/* The duplicate button sits beside the bin on every card: copying a structure belongs with the card. */
.pdup { flex: 0 0 auto; width: 40px; height: 34px; display: grid; place-items: center;
  background: none; border: 1px solid var(--line); border-radius: 9px; color: var(--muted); cursor: pointer; }
.pdup svg { width: 16px; height: 16px; fill: none; stroke: currentColor; stroke-width: 1.8;
  stroke-linecap: round; stroke-linejoin: round; }
.pdup:active { background: var(--panel-2); color: var(--text); }
@media print { #viewProjects .wrap { overflow: visible !important; display: block !important; } }
/* .gate is a flex row: anything else placed directly in it becomes a column beside the card and
   squeezes the form to half width. Keep the card first and let it hold its own width. */
.gate > .gate-card { flex: 0 0 auto; }
/* On a large screen the edit panel does not have to own the whole width. It floats over the right of
   the drawing like a properties palette: the canvas stays visible, and — the important part — stays
   LIVE, because the scrim stops catching clicks. Only the panel's own ✕ (or Escape) closes it, and a
   tap on another node or member simply swaps the panel's contents. */
@media (min-width: 900px) {
  .scrim { background: none; pointer-events: none; }
  .sheet {
    left: auto; right: 22px; top: 100px; bottom: auto;
    width: var(--sheet-w, 400px);
    max-height: calc(100dvh - 168px);
    border: 1px solid var(--line-2);
    border-radius: 16px;
    padding-top: 0;
    animation: sheet-float .16s ease-out;
  }
  .sheet-grab { display: none; }         /* a drag handle makes no sense on a floating card */
  .sheet-head { cursor: grab; touch-action: none; user-select: none; }
  .sheet-head.dragging { cursor: grabbing; }
  @keyframes sheet-float {
    from { opacity: 0; transform: translateY(6px); }
    to   { opacity: 1; transform: none; }
  }
}

.seg-row { display: flex; gap: 7px; flex-wrap: wrap; margin-bottom: 12px; }
/* The support buttons carry the same little symbol the canvas draws, so the two roller supports can
   be told apart at a glance instead of by a word that reads two ways. */
.seg svg { width: 15px; height: 15px; vertical-align: -3px; margin-right: 5px; fill: none;
           stroke: currentColor; stroke-width: 1.7; stroke-linejoin: round; stroke-linecap: round; }
.seg svg circle { fill: currentColor; }

.seg {
  flex: 1 1 auto; min-height: 40px; padding: 0 12px; border-radius: var(--r-sm); font-size: .82rem; font-weight: 600;
  font-family: inherit; background: var(--bg-2); border: 1px solid var(--line-2); color: var(--text-2); cursor: pointer;
}
.seg.on { border-color: var(--accent); background: rgba(34,211,238,.14); color: var(--text); }
.danger { color: var(--danger) !important; border-color: rgba(248,113,113,.4) !important; }
.sheet-list { display: flex; flex-direction: column; gap: 6px; }
.sheet-item {
  display: flex; align-items: center; gap: 10px; padding: 11px 12px; background: var(--bg-2);
  border: 1px solid var(--line); border-radius: var(--r-sm); cursor: pointer; color: var(--text); font-family: inherit;
  font-size: .88rem; text-align: left; width: 100%;
}
.sheet-item svg { width: 19px; height: 19px; fill: none; stroke: var(--muted); stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; flex: 0 0 auto; }
.sheet-item b { font-weight: 600; }
.sheet-item span { color: var(--muted); font-size: .76rem; }

.toast {
  /* Sits clear of the toolbars, is small enough to ignore, and takes no taps at all — a message must
     never be the reason a tool cannot be pressed. */
  position: fixed; left: 50%; transform: translateX(-50%);
  bottom: calc(128px + env(safe-area-inset-bottom));
  z-index: 70; background: var(--panel-3); border: 1px solid var(--line-2); color: var(--text);
  padding: 6px 12px; border-radius: 999px; font-size: .72rem; line-height: 1.25; text-align: center;
  box-shadow: var(--shadow); max-width: 86vw; pointer-events: none;
}
.grid-row { display: flex; gap: 10px; margin-bottom: 10px; }
.grid-row label { flex: 1; display: flex; flex-direction: column; gap: 4px; font-size: .74rem; color: var(--muted); }
.grid-row input { font-family: var(--mono); font-size: 1rem; padding: 9px 10px; }
.chip-row { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 12px; }
/* the padlock on the canvas */
.cv-lock {
  position: absolute; right: 10px; top: 42px; width: 40px; height: 40px; display: grid; place-items: center;
  background: var(--float-bg); border: 1px solid var(--line); border-radius: 12px;
  color: var(--muted); cursor: pointer; z-index: 3;
}
.cv-lock svg { width: 19px; height: 19px; fill: none; stroke: currentColor; stroke-width: 1.8;
  stroke-linecap: round; stroke-linejoin: round; }
.cv-lock.on { background: var(--accent); border-color: var(--accent); color: var(--accent-ink);
  box-shadow: 0 2px 12px rgba(34, 211, 238, .30); }
.toast.bad { background: rgba(248,113,113,.16); border-color: rgba(248,113,113,.45); }

/* ------------------------------------------------------------------ report ---- */
.rep-head { border-bottom: 2px solid var(--line-2); padding-bottom: 10px; margin-bottom: 14px; }
.rep-head h2 { font-size: 1.3rem; }
.rep-head .muted { font-size: .8rem; }
.rep-canvas { width: 100%; background: #fff; border-radius: var(--r); border: 1px solid var(--line); margin-bottom: 6px; }

@media print {
  /* real sheet margins, so nothing sits against the paper edge or under a printer's unprintable
     border */
  @page { margin: 13mm 11mm; }
  :root { --bg: #fff; --bg-2: #fff; --panel: #fff; --panel-2: #fff; --panel-3: #fff;
          --line: #d5dae4; --line-2: #b9c2d2; --text: #101820; --text-2: #24303f; --muted: #5b6a80; }
  body { overflow: visible; background: #fff; color: #101820; }
  .topbar, .toolbar, .actionbar, .diagram-tabs, .scale-row, .scrim, .sheet, .toast, .gate,
  #btnPrint { display: none !important; }        /* a button on paper is no use to anyone */
  /* The app shell is a phone layout: html/body/#app are pinned to 100% height with scrolling
     wrappers inside. On paper that means the report is squeezed into exactly one page and everything
     past the first screenful — the later diagrams and both tables — is silently dropped. Release the
     height chain and let the report flow onto as many pages as it needs. */
  html, body { height: auto !important; min-height: 0 !important; overflow: visible !important; }
  #app { display: block !important; height: auto !important; min-height: 0 !important; overflow: visible !important; }
  .view { display: block !important; flex: none !important; height: auto !important;
          min-height: 0 !important; overflow: visible !important; }
  .wrap { display: block !important; flex: none !important; height: auto !important;
          max-height: none !important; overflow: visible !important; padding: 0 !important; }
  #viewReport { display: block !important; }
  #viewReport .wrap { max-height: none !important; overflow: visible !important; padding: 0 !important; }
  .rep-head, .sec-h { break-after: avoid; page-break-after: avoid; }
  .rep-canvas { border-color: #c8ceda; break-inside: avoid; page-break-inside: avoid;
                -webkit-print-color-adjust: exact; print-color-adjust: exact; }
  .stat, .tbl-wrap { background: #fff; }
  .sec-h { color: #333; background: transparent; padding: 0; border-radius: 0; }
  .tbl th, .tbl td { border-color: #dfe4ec; }
}

/* the moment side is a real choice, so it gets a labelled two-state control */
.side-row { padding: 0 14px 6px; margin-bottom: 0; align-items: center; }
.side-row .seg-lead { font-size: .74rem; color: var(--muted); margin-right: 2px; }
.seg-btn {
  min-height: 34px; padding: 0 12px; border-radius: 999px; font-size: .78rem; font-weight: 600;
  font-family: inherit; background: var(--panel); border: 1px solid var(--line); color: var(--text-2); cursor: pointer;
}
.seg-btn.on { background: rgba(34,211,238,.14); border-color: var(--accent); color: var(--accent); }
.pad-note { padding: 0 14px 8px; margin: 0; }

/* the instance overview on the admin screen */
.stat-row { display: grid; grid-template-columns: repeat(auto-fit, minmax(96px, 1fr)); gap: 8px; }
.stat-row .stat {
  background: var(--bg-2); border: 1px solid var(--line); border-radius: var(--r-sm);
  padding: 9px 10px; display: flex; flex-direction: column; gap: 2px;
}
.stat-row .stat b { font-size: 1.12rem; font-family: var(--mono); color: var(--text); }
.stat-row .stat span { font-size: .7rem; color: var(--muted); line-height: 1.25; }

/* the running version, beside the title */
.tb-line { display: flex; align-items: baseline; gap: 5px; min-width: 0; }
.tb-ver { font-family: var(--mono); font-size: .64rem; color: var(--muted); font-weight: 600;
  letter-spacing: .02em; }
.act.on { color: var(--text); border-color: var(--accent, var(--line)); background: var(--panel-2, var(--panel)); }
.gate-ver { font-family: var(--mono); font-size: .72rem; color: var(--muted); font-weight: 600; }

/* One colour per section: a two-column grid of swatches, thumb-sized so it works on a phone. */
.seccol-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }
.seccol { display: flex; align-items: center; gap: 9px; min-height: 44px; padding: 4px 8px;
  border: 1px solid var(--line); border-radius: 10px; background: var(--panel); }
.seccol input[type="color"] { width: 34px; height: 30px; padding: 0; border: 0; background: none;
  flex: 0 0 auto; cursor: pointer; }
.seccol span { font-size: 12px; line-height: 1.25; color: var(--text); }

/* The section library: one row per section, with the property line under the name. */
.sec-list { display: flex; flex-direction: column; gap: 7px; }
.sec-row { display: flex; align-items: center; gap: 9px; padding: 7px 9px; border: 1px solid var(--line);
  border-radius: 10px; background: var(--panel); }
.sec-row.builtin { opacity: .92; }
.sec-chip { width: 16px; height: 16px; border-radius: 5px; flex: 0 0 auto; border: 1px solid var(--line); }
.sec-info { flex: 1 1 auto; min-width: 0; }
.sec-info b { display: block; font-size: 13px; color: var(--text); }
.sec-info span { display: block; font-size: 10.5px; line-height: 1.3; color: var(--muted); }
.sec-row .btn { flex: 0 0 auto; padding: 6px 10px; font-size: 12px; min-height: 32px; }
.fld { display: block; font-size: 10.5px; color: var(--muted); margin: 8px 0 0; }
.fld input, .fld select { width: 100%; }
.sec-props { margin-top: 10px; padding: 8px 10px; border-radius: 10px; background: var(--panel);
  border: 1px solid var(--line); }
.sec-props b { display: block; font-size: 14px; color: var(--text); }
.sec-props span { display: block; font-size: 11px; color: var(--muted); margin-top: 2px; }
#secPad { width: 100%; height: auto; max-width: 340px; margin: 0 auto; display: block;
  border-radius: 10px; touch-action: none; }

/* ------------------------------------------------------------------ wide screens
   The pad is built for a phone first, and on a desktop the same layout was simply stretched: cards ran
   the full width of the window, text ran to 2000px, and the drawing sat in a short strip. These rules
   give a wide screen a layout of its own — cards in a grid, a readable measure for the text views, more
   of the sheet for the panels — and change nothing a phone can see. */
@media (min-width: 900px) {
  .templates, .plist {
    display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 10px; align-content: start; align-items: stretch;
  }
  .templates { margin-bottom: 6px; }
  .plist { margin-top: 10px; }
  #viewProjects .wrap, #viewPeople .wrap, #viewAccount .wrap {
    max-width: 1100px; margin: 0 auto; width: 100%;
  }
  #viewReport .wrap { max-width: 1040px; margin: 0 auto; width: 100%; }
  .tpl { text-align: left; }
  .stat-grid { grid-template-columns: repeat(4, minmax(0, 1fr)); }
  .stat-row { grid-template-columns: repeat(auto-fit, minmax(124px, 1fr)); }
  .seccol-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .gate-card { max-width: 460px; }
  .sheet { --sheet-w: 420px; }
}

@media (min-width: 1400px) {
  .templates, .plist { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  #viewProjects .wrap, #viewPeople .wrap, #viewAccount .wrap { max-width: 1320px; }
  #viewReport .wrap { max-width: 1120px; }
  .stat-grid { grid-template-columns: repeat(6, minmax(0, 1fr)); }
  .seccol-grid { grid-template-columns: repeat(4, minmax(0, 1fr)); }
  .gate-card { max-width: 500px; }
}

/* A phone has to hold the whole action row: undo, redo, copy, cut, paste, then Fit, Labels and Solve.
   The three worded buttons drop to their glyphs and everything gives up a little width — Solve falling
   off the right-hand end of the bar is worse than Fit losing its word. This sits last on purpose: the
   base rules above set the same ids and a media query earlier in the file would lose to them. */
@media (max-width: 520px) {
  .actionbar { gap: 4px; padding-left: 5px; padding-right: 5px; }
  .act { width: 36px; height: 40px; }
  .act svg { width: 17px; height: 17px; }
  #btnFit, #btnEditLabels, #btnSolve {
    width: 36px; min-width: 36px; padding: 0; gap: 0; display: grid; place-items: center;
  }
  #btnFit::after, #btnEditLabels::after, #btnSolve::after { content: none; }
}
