/**
 * Thermal Energy Lab styles (v2 workbench layout).
 *
 * Layout thesis: the sealed flask is the experiment, so it gets the wide
 * main column, with Particle Motion inline beside it (not off in the
 * sidebar - the two visuals are read together). Heating and cooling
 * equipment stack in a narrow right-hand frame, each folded into
 * Mild / Moderate / Extreme tier drawers. Everything that is not the live
 * experiment (substance catalog, sample properties, manual temperature)
 * lives behind a drawer so a middle schooler sees one clear thing at a
 * time. Page-local palette per the house lab convention.
 *
 * WCAG 2.1 AA: 0.75rem minimum font size, 44px touch targets on primary
 * controls, phase/state never conveyed by color alone (every color cue is
 * paired with a text label).
 *
 * Compact pass: Heating and Cooling are each a collapsible <details> so a
 * whole side can be tucked away, not just its tiers, with one shared
 * "Turn equipment off" button (.te-equip-off) below both instead of a
 * duplicate nested inside each; and margins/padding throughout are
 * trimmed to keep the whole lab on-screen with less scrolling. Touch
 * targets stay at 44px min-height regardless - only the space AROUND
 * controls shrinks, never the controls themselves.
 *
 * Flask overlay pass (v7): the flask area is a row (.te-flask-row) of the
 * apparatus stage (.te-flask-stage, left, wide) and a right-hand column
 * (.te-flask-rightcol) split into three stacked zones: the K/C/F + phase
 * badge readout up top (.te-corner-status - it's the ONLY state-of-matter
 * badge on the page, it used to also be duplicated in a sidebar status
 * card), Particle Motion in the middle (.te-particles-inline, moved out
 * of the sidebar), and the active-equipment line + closed-system note at
 * the bottom. The old toolbar (speed / pause / reset / sample info / set
 * temperature) is a plain vertical stack of small buttons overlaid on the
 * flask stage's left edge (.te-transport) - a circular dial was tried
 * first but didn't render cleanly, hence the plain stack; it's absolutely
 * positioned against .te-flask-stage so it adds zero height to the stage
 * - the SVG's own height is what drives it. K/C/F are a value + unit grid
 * (.te-temp-row/.te-temp-val/.te-temp-unit) so the digits align instead
 * of a plain right-align anchoring on the differing unit-label lengths.
 * The curve SVG's viewBox was halved to shrink the graph. The apparatus
 * SVG's viewBox is cropped tight to its artwork; the 20px gap above the
 * balloon and below the equipment cue is real CSS padding on
 * .te-apparatus-frame, not viewBox margin (viewBox units don't equal
 * screen pixels once scaled). .te-side and .te-tier use an inset
 * box-shadow instead of a literal border - see the comment at .te-side -
 * because border + border-radius + overflow:hidden renders unreliably at
 * fractional device-pixel-ratios (this was why Heating's outline could
 * look present or missing versus Cooling's despite identical CSS).
 */
:root {
  --bg: #eef3fb;
  --paper: #fff;
  --ink: #15233c;
  --muted: #5c6b85;
  --line: #d7e0ef;
  --grid: rgba(47, 107, 255, .08);

  --heat: #e8590c;
  --heat-bg: #fff4ec;
  --cold: #1971c2;
  --cold-bg: #eaf4ff;
  --accent: #7c3aed;
  --accent-bg: #f5f0ff;
  --good: #2f9e44;
  --warn-bg: #fff9db;
  --warn-border: #f5c518;

  --tier-mild: #2f9e44;
  --tier-moderate: #d9730d;
  --tier-extreme: #e03131;
}

* { box-sizing: border-box; margin: 0; padding: 0; }
html { scroll-behavior: smooth; }
body {
  background:
    linear-gradient(var(--grid) 1px, transparent 1px) 0 0 / 26px 26px,
    linear-gradient(90deg, var(--grid) 1px, transparent 1px) 0 0 / 26px 26px,
    var(--bg);
  color: var(--ink);
  font-family: 'Inter', system-ui, sans-serif;
  line-height: 1.6;
  font-size: 1rem;
}

.te-wrap { max-width: 1220px; margin: 0 auto; padding: 0 16px 24px; }

/* HERO ---------------------------------------------------------------- */
.te-hero { padding: 14px 16px 8px; text-align: center; }
.te-hero-title { display: flex; align-items: center; justify-content: center; gap: 10px; flex-wrap: wrap; }
.te-eyebrow {
  display: inline-block; font-family: 'Space Grotesk', sans-serif; font-weight: 600;
  letter-spacing: .14em; text-transform: uppercase; font-size: .72rem; color: #fff;
  background: var(--accent); padding: 5px 12px; border-radius: 6px;
}
.te-hero h1 {
  font-family: 'Space Grotesk', sans-serif; font-weight: 700;
  font-size: clamp(1.6rem, 4vw, 2.4rem); line-height: 1.02; letter-spacing: -.02em;
}
.te-hero .te-sub { max-width: 640px; margin: 4px auto 0; color: var(--muted); font-size: .88rem; font-weight: 500; }

/* LAB SHELL ----------------------------------------------------------- */
.te-lab {
  background: var(--paper); border: 1px solid var(--line); border-radius: 20px;
  padding: 12px; margin-top: 8px; box-shadow: 0 8px 28px rgba(21, 35, 60, .05);
}

/* SAMPLE BAR ----------------------------------------------------------- */
.te-samplebar {
  display: flex; flex-wrap: wrap; align-items: center; gap: 8px 16px;
  padding: 8px 14px; background: #fbfcfe; border: 1px solid var(--line);
  border-radius: 14px; margin-bottom: 10px;
}
.te-sample-now { min-width: 190px; }
.te-sample-label {
  display: block; font-family: 'Space Grotesk', sans-serif; font-weight: 600;
  font-size: .68rem; letter-spacing: .1em; text-transform: uppercase; color: var(--muted);
}
.te-sample-name { font-family: 'Space Grotesk', sans-serif; font-weight: 700; font-size: 1.3rem; }
.te-sample-formula { color: var(--accent); font-weight: 600; margin-left: 8px; font-size: 1rem; }
.te-sample-points { display: block; color: var(--muted); font-size: .8rem; font-weight: 500; }
.te-massctl { display: flex; align-items: center; gap: 10px; margin-left: auto; flex: 0 1 280px; min-width: 220px; }
.te-massctl label { font-weight: 600; font-size: .84rem; }

/* Substance drawer ----------------------------------------------------- */
.te-drawer {
  border: 1px solid var(--line); border-radius: 14px; background: #fff;
  padding: 12px 14px; margin: 0 0 10px;
}
.te-cat { margin-bottom: 10px; }
.te-cat:last-child { margin-bottom: 0; }
.te-cat-label {
  font-family: 'Space Grotesk', sans-serif; font-weight: 600; font-size: .74rem;
  letter-spacing: .08em; text-transform: uppercase; color: var(--muted); margin-bottom: 6px;
}
.te-subgrid { display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 8px; }
.te-subcard {
  display: flex; flex-direction: column; gap: 1px; text-align: left;
  border: 1px solid var(--line); background: #fff; border-radius: 12px;
  padding: 10px 12px; cursor: pointer; font: inherit; min-height: 44px; transition: .13s;
}
.te-subcard:hover { border-color: var(--accent); box-shadow: 0 3px 10px rgba(124, 58, 237, .12); }
.te-subcard:focus-visible { outline: 3px solid var(--accent); outline-offset: 1px; }
.te-subcard[aria-pressed="true"] { border-color: var(--accent); background: var(--accent-bg); }
.te-subcard-name { font-family: 'Space Grotesk', sans-serif; font-weight: 600; font-size: .9rem; }
.te-subcard-formula { color: var(--accent); font-weight: 600; font-size: .78rem; }
.te-subcard-range { color: var(--muted); font-size: .75rem; font-weight: 500; }

/* STAGE: sealed flask (large) | stacked cooling / particle motion / heating */
.te-stage {
  display: grid; gap: 8px; align-items: start;
  grid-template-columns: minmax(0, 1fr) 220px;
  grid-template-areas: "center side";
}
.te-center { grid-area: center; min-width: 0; display: flex; flex-direction: column; gap: 8px; }
.te-side-right { grid-area: side; display: flex; flex-direction: column; gap: 8px; min-width: 0; }

/* Heating/Cooling are <details> (open by default) so the WHOLE section -
   not just its Mild/Moderate/Extreme tiers - can be collapsed to save
   space, e.g. once a student has picked a tool and moved on.
   The rounded border/background/clip live on .te-side-shell, a plain div
   wrapping the <details> - NOT on the <details> element itself. <details>
   is a native interactive, form-associated element with its own internal
   rendering; combined with border-radius + overflow:hidden (needed to
   clip content to the rounded corners) it can rasterize a border (or an
   inset box-shadow - tried that first) unreliably in Chrome, especially
   at fractional device-pixel-ratios (e.g. 150% Windows display scaling) -
   that's what made Heating's outline disappear even with CSS identical
   to Cooling's. A plain div doesn't have that baggage. */
.te-side-shell {
  border: 1px solid var(--line); border-radius: 12px; background: #fff; overflow: hidden;
}
.te-side > summary {
  display: flex; align-items: center; gap: 8px; min-height: 44px;
  padding: 6px 12px; cursor: pointer; list-style: none;
}
.te-side > summary::-webkit-details-marker { display: none; }
.te-side > summary:focus-visible { outline: 3px solid var(--accent); outline-offset: -3px; }
.te-side > summary::after {
  content: ''; width: 8px; height: 8px; flex: none; margin-left: auto;
  border-right: 2px solid var(--muted); border-bottom: 2px solid var(--muted);
  transform: rotate(45deg); transition: transform .15s; margin-bottom: 3px;
}
.te-side[open] > summary::after { transform: rotate(225deg); margin-bottom: -3px; }
.te-side > div { padding: 0 8px 8px; }
.te-side h2 {
  font-family: 'Space Grotesk', sans-serif; font-weight: 700; font-size: .8rem;
  letter-spacing: .09em; text-transform: uppercase;
}
.te-side-cool h2 { color: var(--cold); }
.te-side-heat h2 { color: var(--heat); }

/* Tier drawers - same .te-tier-shell / <details> split as .te-side above,
   for the same reason. */
.te-tier-shell {
  border: 1px solid var(--line); border-radius: 12px; background: #fff; overflow: hidden;
  margin-bottom: 6px;
}
.te-tier summary {
  display: flex; justify-content: space-between; align-items: center; gap: 8px;
  padding: 8px 12px; cursor: pointer; min-height: 44px; list-style: none;
}
.te-tier summary::-webkit-details-marker { display: none; }
.te-tier summary:focus-visible { outline: 3px solid var(--accent); outline-offset: -3px; }
.te-tier-name { font-family: 'Space Grotesk', sans-serif; font-weight: 600; font-size: .84rem; }
.te-tier-mild .te-tier-name { color: var(--tier-mild); }
.te-tier-moderate .te-tier-name { color: var(--tier-moderate); }
.te-tier-extreme .te-tier-name { color: var(--tier-extreme); }
.te-tier-range { color: var(--muted); font-size: .75rem; font-weight: 600; margin-left: auto; }
.te-tier summary::after {
  content: ''; width: 8px; height: 8px; flex: none;
  border-right: 2px solid var(--muted); border-bottom: 2px solid var(--muted);
  transform: rotate(45deg); transition: transform .15s; margin-bottom: 3px;
}
.te-tier[open] summary::after { transform: rotate(225deg); margin-bottom: -3px; }

.te-tool {
  display: flex; justify-content: space-between; align-items: center; gap: 8px;
  width: 100%; border: none; border-top: 1px solid var(--line); background: #fff;
  padding: 9px 12px; font: inherit; font-size: .82rem; font-weight: 500;
  cursor: pointer; min-height: 44px; text-align: left; transition: background .12s;
}
.te-tool:hover { background: var(--accent-bg); }
.te-tool:focus-visible { outline: 3px solid var(--accent); outline-offset: -3px; }
.te-tool-name { font-weight: 600; }
.te-tool-temp { color: var(--muted); font-size: .75rem; font-weight: 600; white-space: nowrap; }
.te-side-heat .te-tool[aria-pressed="true"] { background: var(--heat); color: #fff; }
.te-side-cool .te-tool[aria-pressed="true"] { background: var(--cold); color: #fff; }
.te-tool[aria-pressed="true"] .te-tool-temp { color: rgba(255, 255, 255, .85); }

/* Shared "Turn equipment off" - one icon button outside both Heating and
   Cooling instead of a duplicate text button nested inside each (only
   one equipment can be active at a time, so one control covers both). */
.te-equip-off {
  width: 100%; min-height: 44px; border-radius: 12px; border: 1px solid var(--line);
  background: #fff; color: var(--ink); cursor: pointer;
  display: flex; align-items: center; justify-content: center; gap: 8px;
  font-family: 'Space Grotesk', sans-serif; font-weight: 600; font-size: .84rem;
}
.te-equip-off[hidden] { display: none; }
.te-equip-off:hover { border-color: var(--accent); color: var(--accent); }
.te-equip-off:focus-visible { outline: 3px solid var(--accent); outline-offset: 1px; }
.te-equip-off svg { width: 18px; height: 18px; flex: none; }

/* Bottom-right flask zone: active-equipment line + closed-system note. */
.te-flask-equip .te-phasebadge { font-size: .8rem; padding: 3px 10px; }
.te-equip-status {
  color: var(--muted); font-size: .75rem; font-weight: 600;
  text-transform: uppercase; letter-spacing: .04em;
}
.te-status-note { color: var(--muted); font-size: .75rem; font-weight: 500; margin-top: 4px; line-height: 1.4; }

/* CENTER: visualization ------------------------------------------------- */
.te-panel { background: #fbfcfe; border: 1px solid var(--line); border-radius: 16px; padding: 10px; transition: border-color .25s; }
.te-heating-active .te-center .te-panel { border-color: rgba(232, 89, 12, .45); }
.te-cooling-active .te-center .te-panel { border-color: rgba(25, 113, 194, .45); }
.te-panel h3 {
  font-family: 'Space Grotesk', sans-serif; font-size: .78rem; font-weight: 600;
  color: var(--muted); text-transform: uppercase; letter-spacing: .06em;
}
.te-panel > h3 { margin-bottom: 4px; }
#te-apparatus, #te-particles, #te-curve { width: 100%; height: auto; display: block; }
.te-caption { color: var(--muted); font-size: .75rem; font-weight: 500; margin-top: 4px; }

/* Flask row: the apparatus stage (left, wide) and a right-hand column
   (.te-flask-rightcol) sit side by side inside the same Sealed Flask
   panel, instead of Particle Motion living in the sidebar. */
.te-flask-row { display: flex; align-items: stretch; gap: 12px; }

/* Flask stage: the SVG needs a positioning context for the transport
   buttons, overlaid on top of it. */
.te-flask-stage { position: relative; flex: 1 1 auto; min-width: 0; }

/* Right column: three stacked zones - state badge + K/C/F up top,
   Particle Motion in the middle, active-equipment status at the bottom.
   space-between pushes the first zone to the top and the last to the
   bottom; the middle zone lands close to vertical center as long as the
   top/bottom zones are roughly similar heights. */
.te-flask-rightcol {
  flex: 0 0 200px; min-width: 0;
  display: flex; flex-direction: column; justify-content: space-between; gap: 10px;
}

/* Upper-right zone: state badge + K/C/F. This is the ONLY state-of-matter
   badge on the page - it used to be duplicated in the sidebar status
   card too. */
.te-corner-status { display: flex; flex-direction: column; align-items: flex-start; gap: 4px; }
/* K/C/F as a two-column grid (value | unit) instead of plain right-aligned
   strings: a bare right-align anchors on the LAST character, which was
   the unit letter (" K" / " °C" / " °F" are different lengths), so the
   digits themselves never lined up. Splitting value/unit into their own
   grid columns, with tabular-nums on the value, aligns the digits and
   decimal points regardless of how many integer digits each reading has. */
.te-corner-temps {
  display: grid; grid-template-columns: auto auto; justify-content: start;
  column-gap: 3px; row-gap: 1px;
  font-family: 'Space Grotesk', sans-serif; font-weight: 700; font-size: .82rem;
}
.te-temp-row { display: contents; }
.te-temp-val { grid-column: 1; text-align: right; font-variant-numeric: tabular-nums; }
.te-temp-unit { grid-column: 2; text-align: left; color: var(--muted); font-weight: 600; }
.te-phasebadge {
  background: var(--accent-bg); color: var(--accent);
  border: 1px solid var(--line); padding: 3px 12px; border-radius: 999px; font-size: .82rem;
}

/* Middle-right zone: Particle Motion, inline beside the flask instead of
   its own boxed panel in the sidebar - a plain sub-column, not a bordered
   card, so it reads as part of the same Sealed Flask panel. */
.te-particles-inline h4 {
  font-family: 'Space Grotesk', sans-serif; font-size: .78rem; font-weight: 600;
  color: var(--muted); text-transform: uppercase; letter-spacing: .06em; margin-bottom: 4px;
}

/* Apparatus frame: 20px of real CSS padding above and below the SVG - the
   "20px from top/bottom of the container" gap around the balloon and the
   equipment cue. The SVG's own viewBox is cropped tight to its artwork
   (see render.js), so this padding is the ONLY source of that gap; a
   viewBox margin would render at a different pixel size depending on how
   wide the panel happens to be, which is why the previous pass missed
   the mark. */
.te-apparatus-frame { padding: 20px 0; }

/* Transport: a plain vertical stack of small buttons on the flask's left
   edge (speed, play/pause, temp, info, reset) - replaces the old toolbar
   row so the controls cost no extra panel height. A circular dial was
   tried first but didn't render cleanly, hence the plain stack. Native
   title + aria-label on every button give both the hover tooltip and the
   accessible name (icon-only buttons have no visible text of their own). */
.te-transport {
  position: absolute; left: 8px; top: 50%; transform: translateY(-50%); z-index: 2;
  display: flex; flex-direction: column; gap: 6px;
}
.te-transport-btn {
  width: 44px; min-height: 44px; border-radius: 10px; border: 1px solid var(--line);
  background: #fff; color: var(--ink); cursor: pointer;
  font-family: 'Space Grotesk', sans-serif; font-weight: 700; font-size: .78rem;
  display: flex; align-items: center; justify-content: center;
  box-shadow: 0 2px 6px rgba(21, 35, 60, .1);
}
.te-transport-btn:hover { border-color: var(--accent); color: var(--accent); }
.te-transport-btn:focus-visible { outline: 3px solid var(--accent); outline-offset: 1px; }
/* Speed segments use aria-pressed (radio-like); the temp/info toggles use
   aria-expanded (their drawer is open/closed) - both need the same
   "this one's active" coloring, so both attributes are covered here. */
.te-transport-btn[aria-pressed="true"], .te-transport-btn[aria-expanded="true"] {
  background: var(--accent); color: #fff; border-color: var(--accent);
}
.te-transport-btn svg { width: 18px; height: 18px; }
.te-transport-play { background: var(--accent); color: #fff; border-color: var(--accent); }
.te-transport-play:hover { background: #6c2bd9; color: #fff; }
.te-transport-play svg { width: 20px; height: 20px; }
.te-transport-play [hidden] { display: none; }

.te-btn {
  font-family: 'Space Grotesk', sans-serif; font-weight: 600; font-size: .84rem;
  border: 1px solid var(--line); background: #fff; color: var(--ink);
  border-radius: 10px; padding: 9px 14px; cursor: pointer; min-height: 44px;
}
.te-btn:hover { border-color: var(--accent); color: var(--accent); }
.te-btn:focus-visible { outline: 3px solid var(--accent); outline-offset: 1px; }
.te-btn-primary { background: var(--accent); color: #fff; border-color: var(--accent); }
/* :hover has higher specificity than a single class, so .te-btn:hover's
   color would otherwise win over the filled variants' white text and make
   the label invisible. Restated for every filled/active variant. */
.te-btn-primary:hover, .te-btn[aria-pressed="true"]:hover { color: #fff; }
.te-btn[aria-pressed="true"] { background: var(--ink); color: #fff; border-color: var(--ink); }
.te-drawerbtn::after {
  content: ''; display: inline-block; width: 7px; height: 7px; margin-left: 8px;
  border-right: 2px solid currentColor; border-bottom: 2px solid currentColor;
  transform: rotate(45deg) translateY(-2px); transition: transform .15s;
}
.te-drawerbtn[aria-expanded="true"]::after { transform: rotate(225deg) translateY(-1px); }

/* Toggle panels under the toolbar (spacing above comes from .te-center's
   flex gap, not a margin here, so it doesn't double up when shown) */
.te-subpanel {
  background: var(--accent-bg); border: 1px solid var(--line); border-radius: 14px;
  padding: 10px 14px;
}
.te-subpanel[hidden] { display: none; }
.te-info-points { font-weight: 600; font-size: .92rem; margin-bottom: 6px; }
.te-notes { margin: 8px 0 0 18px; }
.te-notes li { font-size: .84rem; color: var(--muted); margin: 4px 0; }

.te-manual-row { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; margin-top: 6px; }
.te-manual-row:first-of-type { margin-top: 0; }
.te-manual-row label { font-weight: 600; font-size: .86rem; }
.te-manual-row input[type=number] {
  width: 96px; font-size: .9rem; padding: 8px 10px; border: 1px solid var(--line);
  border-radius: 8px; min-height: 44px; font-family: inherit;
}

/* Ceiling hint (spacing above from .te-center's flex gap, see note above) */
.te-ceiling-hint {
  background: var(--warn-bg); border: 1px solid var(--warn-border); border-radius: 12px;
  padding: 8px 12px; font-size: .88rem; font-weight: 500;
}
.te-ceiling-hint[hidden] { display: none; }

/* Range input */
input[type=range].te-range {
  -webkit-appearance: none; appearance: none; height: 8px; border-radius: 999px;
  background: var(--line); outline: none; flex: 1; min-width: 110px;
}
input[type=range].te-range::-webkit-slider-thumb {
  -webkit-appearance: none; width: 26px; height: 26px; border-radius: 50%;
  background: var(--accent); border: 3px solid #fff; box-shadow: 0 2px 6px rgba(124, 58, 237, .45); cursor: pointer;
}
input[type=range].te-range::-moz-range-thumb {
  width: 22px; height: 22px; border-radius: 50%; background: var(--accent); border: 3px solid #fff; cursor: pointer;
}
input[type=range].te-range:focus-visible { outline: 3px solid var(--accent); outline-offset: 2px; }
.te-val { font-family: 'Space Grotesk', sans-serif; font-weight: 700; min-width: 52px; text-align: right; }

/* CURVE PANEL ----------------------------------------------------------- */
.te-curvepanel { margin-top: 10px; }
.te-curve-actions { display: flex; gap: 8px; margin-top: 6px; }

/* APPARATUS SVG --------------------------------------------------------- */
.te-flask-outline { stroke: var(--ink); stroke-width: 2.5; fill: rgba(255, 255, 255, .35); }
.te-solid { fill: #bcd0e8; stroke: #90a8c8; stroke-width: 1; }
.te-liquid { fill: #6fb3e0; opacity: .85; }
.te-bubble { fill: #fff; opacity: .75; }
.te-melt-dot { fill: #e8590c; opacity: .7; }
.te-freeze-tick { stroke: #1971c2; stroke-width: 2; }
.te-condensate { fill: #4d9fd6; opacity: .9; }
.te-frost-tick { stroke: #9fd8f5; stroke-width: 2.5; }
.te-wisp { fill: #b9c6d8; }
.te-balloon { fill: #f7b8c6; stroke: #d9607f; stroke-width: 2; opacity: .93; }
.te-balloon-flat { fill: #e79cb0; stroke: #d9607f; stroke-width: 1.5; opacity: .85; }
.te-cuff { fill: #d9607f; }
.te-cap { fill: #8a93a6; stroke: #5c6b85; stroke-width: 1.5; }
.te-tube { stroke: #8a93a6; stroke-width: 3; fill: none; }
.te-gauge-dial { fill: #fff; stroke: var(--ink); stroke-width: 2; }
.te-gauge-needle { stroke: #e03131; stroke-width: 2.5; stroke-linecap: round; }
.te-gauge-pin { fill: var(--ink); }
.te-bath { stroke: var(--cold); stroke-width: 3; fill: #dbedff; fill-opacity: .5; }
.te-glow { transition: opacity .3s; }
.te-glow-heat { fill: var(--heat); filter: blur(10px); }
.te-glow-cold { fill: var(--cold); filter: blur(10px); }

/* Equipment-specific art (hot plate, burner + flame, ice, dewar, ...) -
   see buildEquipVisuals() in render.js for which shapes exist and
   EQUIP_VISUALS-style keys in equipment.js for which equipment uses which. */
.te-equip-metal { fill: #b7c0d1; stroke: #5c6b85; stroke-width: 1.5; }
.te-equip-metal-dark { fill: #5c6b85; stroke: #3a4356; stroke-width: 1.5; }
.te-equip-knob { fill: #fff; stroke: #5c6b85; stroke-width: 1; }
.te-equip-heatline { stroke: var(--heat); stroke-width: 2; stroke-linecap: round; fill: none; opacity: .8; }
.te-equip-flame-outer { fill: #e8590c; opacity: .92; }
.te-equip-flame-inner { fill: #ffc93b; }
.te-equip-torch-outer { fill: #1971c2; opacity: .9; }
.te-equip-torch-inner { fill: #cdeeff; }
.te-equip-flame-outer, .te-equip-flame-inner, .te-equip-torch-outer, .te-equip-torch-inner {
  transform-box: fill-box; transform-origin: bottom center;
  animation: te-flame-flicker 1.4s ease-in-out infinite alternate;
}
.te-equip-torch-outer, .te-equip-torch-inner { animation-duration: .9s; }
.te-equip-window { fill: var(--heat); opacity: .85; }
.te-equip-ripple { stroke: var(--cold); stroke-width: 1.5; fill: none; opacity: .55; }
.te-equip-ice { fill: #d8f0fb; stroke: #9fd8f5; stroke-width: 1.2; opacity: .95; }
.te-equip-salt { fill: #fff; stroke: #c7d3e6; stroke-width: .5; }
.te-equip-appliance { fill: #f2f5fa; stroke: #5c6b85; stroke-width: 1.5; }
.te-equip-seam { stroke: #b7c0d1; stroke-width: 1; }
.te-equip-dryice-block { fill: #e7ecf3; stroke: #9aa7bd; stroke-width: 1.2; }
.te-equip-wisp {
  fill: #c7d3e6; opacity: 0; transform-box: fill-box; transform-origin: center;
  animation: te-wisp-rise 2.2s ease-in infinite;
}

@keyframes te-flame-flicker { from { transform: scaleY(1) scaleX(1); } to { transform: scaleY(1.06) scaleX(.96); } }
@keyframes te-wisp-rise {
  0% { opacity: 0; transform: translateY(0); }
  30% { opacity: .6; }
  100% { opacity: 0; transform: translateY(-16px); }
}

/* PARTICLES SVG --------------------------------------------------------- */
.te-particle-box { fill: #fff; stroke: var(--line); }
.te-particle { fill: var(--accent); }
.te-p-solid { fill: #5c7fb8; }
.te-p-liquid { fill: #1971c2; }
.te-p-gas { fill: #7c3aed; }

/* CURVE SVG ------------------------------------------------------------- */
.te-gridline { stroke: var(--line); stroke-dasharray: 3 3; }
.te-axis-label { font: 600 9px 'Inter', sans-serif; fill: var(--muted); }
.te-curve-live { stroke: var(--heat); stroke-width: 2.5; }
.te-curve-snapshot { stroke-width: 2; opacity: .8; stroke-dasharray: 5 3; }
.te-plateau-line { stroke: var(--good); stroke-width: 1.5; stroke-dasharray: 2 3; }
.te-plateau-label { font: 700 9px 'Space Grotesk', sans-serif; fill: var(--good); }

/* NOTEBOOK -------------------------------------------------------------- */
.te-notebook { margin-top: 16px; border-top: 1px solid var(--line); padding-top: 12px; }
.te-section-label {
  font-family: 'Space Grotesk', sans-serif; font-weight: 600; color: var(--accent);
  letter-spacing: .09em; text-transform: uppercase; font-size: .74rem; margin-bottom: 6px;
}
.te-panel-h {
  font-family: 'Space Grotesk', sans-serif; font-weight: 600; font-size: .95rem;
  margin: 12px 0 6px;
}
.te-props { font-size: .9rem; color: var(--ink); }
.te-obs-field { display: block; margin: 8px 0; }
.te-obs-field label { display: block; font-weight: 600; font-size: .88rem; margin-bottom: 6px; }
.te-obs-field textarea {
  width: 100%; min-height: 70px; border: 1px solid var(--line); border-radius: 10px;
  padding: 10px 12px; font-family: inherit; font-size: .92rem;
}
#te-event-log { list-style: none; }
#te-event-log li { padding: 6px 0; border-bottom: 1px dashed var(--line); font-size: .88rem; }
#te-snapshot-list { list-style: none; display: flex; flex-direction: column; gap: 6px; margin-top: 8px; }
#te-snapshot-list li { display: flex; align-items: center; gap: 8px; font-size: .86rem; }
.te-swatch { display: inline-block; width: 14px; height: 14px; border-radius: 3px; }
.te-swatch-remove { margin-left: auto; font-size: .78rem; border: none; background: none; color: var(--muted); cursor: pointer; text-decoration: underline; min-height: 32px; }
#te-save-status { font-size: .8rem; color: var(--muted); margin-left: 8px; }

/* MISC ------------------------------------------------------------------ */
.te-sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0;
}
.te-copyright { text-align: center; font-size: .75rem; color: var(--muted); padding: 12px 0; }

/* RESPONSIVE ------------------------------------------------------------ */
@media (max-width: 1020px) {
  .te-stage {
    grid-template-columns: 1fr;
    grid-template-areas: "center" "side";
  }
  .te-side-right { flex-direction: row; flex-wrap: wrap; }
  .te-side-right > * { flex: 1 1 220px; }
}
@media (max-width: 700px) {
  .te-massctl { margin-left: 0; flex: 1 1 100%; }
  .te-flask-row { flex-direction: column; }
  .te-flask-rightcol { flex: initial; }
}
@media (max-width: 600px) {
  .te-side-right { flex-direction: column; }
  .te-side-right > * { flex: initial; }
}

@media (prefers-reduced-motion: reduce) {
  * { transition-duration: 0.001ms !important; animation-duration: 0.001ms !important; }
}
