/*
 * Article explainer kit — the shared styles behind every insights widget.
 *
 * The `es-` prefix is EXPLAINER system, not earthing: ~45 of these 71 classes
 * are a generic widget design system (shell, segmented control, sliders, stat
 * tiles, banners, theme-aware figures, glossary) and only the `.es-id__*`
 * wizard family and `.es-flow` animation are topic-flavoured.
 *
 * All classes are es- namespaced and consume the site's CSS custom properties
 * so the dark / light / slate themes all work. No hardcoded theme colours.
 * Modelled on tools/lighting-calc/calc.css (stat tiles, segmented control,
 * badges) so the article and the calculators feel like one product.
 */

/* ---------- shell ---------- */
.es-widget {
  background: var(--bg-surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 1rem;
  margin: 1.75rem 0;
}
.es-widget__head { display: flex; flex-wrap: wrap; gap: 0.5rem; align-items: baseline; justify-content: space-between; margin-bottom: 0.9rem; }
.es-widget__title { font-size: 1.05rem; font-weight: 600; color: var(--text-primary); margin: 0; }
.es-widget__hint { font-size: 0.8rem; color: var(--text-muted); margin: 0; }
.es-widget__fallback { font-size: 0.9rem; color: var(--text-muted); margin: 0; }

/* ---------- segmented controls ---------- */
/* align-self: start is load-bearing. .es-controls__group is a COLUMN flex container, so its
   default align-items: stretch overrides inline-flex and pulls the segmented control out to the
   width of its LABEL. With short buttons under a long label ("SYSTEM EARTHING" over TN | TT)
   that left a 31px empty bordered tail which reads as a third, disabled button. */
.es-seg { display: inline-flex; align-self: start; flex-wrap: wrap; border: 1px solid var(--border); border-radius: var(--radius); overflow: hidden; }
.es-seg__btn {
  font-family: inherit; font-size: 0.8rem; padding: 0.4rem 0.8rem;
  background: var(--bg-elevated); color: var(--text-muted);
  border: none; border-right: 1px solid var(--border);
  cursor: pointer; transition: var(--transition);
}
.es-seg__btn:last-child { border-right: none; }
.es-seg__btn:hover:not(:disabled) { color: var(--accent); }
.es-seg__btn[aria-pressed="true"] { background: var(--accent); color: #fff; }
.es-seg__btn:disabled { opacity: 0.4; cursor: not-allowed; }
.es-seg__btn:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }

.es-controls { display: flex; flex-wrap: wrap; gap: 0.6rem 1rem; align-items: flex-start; margin-bottom: 0.9rem; }
.es-controls__group { display: flex; flex-direction: column; gap: 0.3rem; }
.es-controls__label { font-size: 0.72rem; text-transform: uppercase; letter-spacing: 0.05em; color: var(--text-muted); }

/* ---------- diagram stage ---------- */
.es-stage {
  background: var(--bg-elevated);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 0.6rem;
  overflow-x: auto;
}
/* Five conductor rows need more width before the labels stop being legible —
   below this the stage scrolls horizontally rather than shrinking the text. */
.es-stage svg { min-width: 640px; }

/* Animated current-flow highlight. */
.es-flow {
  stroke-dasharray: 14 10;
  animation: es-dash 1.1s linear infinite;
}
@keyframes es-dash { to { stroke-dashoffset: -48; } }
@media (prefers-reduced-motion: reduce) {
  .es-flow { animation: none; stroke-dasharray: none; }
}

/* ---------- two-column body ---------- */
.es-body { display: grid; grid-template-columns: minmax(220px, 300px) 1fr; gap: 0.9rem; align-items: start; margin-top: 0.9rem; }
@media (max-width: 720px) { .es-body { grid-template-columns: 1fr; } }

.es-panel { background: var(--bg-elevated); border: 1px solid var(--border); border-radius: var(--radius); padding: 0.8rem; }
.es-panel h4 { font-size: 0.82rem; text-transform: uppercase; letter-spacing: 0.05em; color: var(--text-muted); margin: 0 0 0.7rem; font-weight: 600; }

/* ---------- fields ---------- */
.es-field { display: flex; flex-direction: column; gap: 0.25rem; margin-bottom: 0.8rem; }
.es-field:last-child { margin-bottom: 0; }
.es-field__row { display: flex; justify-content: space-between; align-items: baseline; gap: 0.5rem; font-size: 0.8rem; }
.es-field__label { color: var(--text-muted); }
.es-field__value { color: var(--accent); font-weight: 700; font-variant-numeric: tabular-nums; }
.es-field select { font-size: 0.85rem; padding: 0.4rem 2rem 0.4rem 0.6rem; }

/* ---------- range slider (no range styling existed in the repo) ---------- */
.es-range {
  -webkit-appearance: none; appearance: none;
  width: 100%; height: 22px; background: transparent; cursor: pointer; margin: 0;
}
.es-range:focus { outline: none; }
.es-range:focus-visible::-webkit-slider-thumb { box-shadow: 0 0 0 3px rgba(var(--accent-rgb), 0.35); }
.es-range:focus-visible::-moz-range-thumb { box-shadow: 0 0 0 3px rgba(var(--accent-rgb), 0.35); }

.es-range::-webkit-slider-runnable-track {
  height: 5px; border-radius: 3px;
  background: var(--border); border: 1px solid var(--border);
}
.es-range::-webkit-slider-thumb {
  -webkit-appearance: none; appearance: none;
  width: 16px; height: 16px; margin-top: -6px;
  border-radius: 50%; background: var(--accent);
  border: 2px solid var(--bg-surface);
  transition: background var(--transition);
}
.es-range:hover::-webkit-slider-thumb { background: var(--accent-hover); }

.es-range::-moz-range-track {
  height: 5px; border-radius: 3px;
  background: var(--border); border: 1px solid var(--border);
}
.es-range::-moz-range-thumb {
  width: 14px; height: 14px; border-radius: 50%;
  background: var(--accent); border: 2px solid var(--bg-surface);
  transition: background var(--transition);
}
.es-range:hover::-moz-range-thumb { background: var(--accent-hover); }

/* ---------- stat tiles ---------- */
.es-stats { display: grid; grid-template-columns: repeat(auto-fit, minmax(110px, 1fr)); gap: 0.5rem; }
.es-stat { background: var(--bg-surface); border: 1px solid var(--border); border-radius: var(--radius); padding: 0.55rem; text-align: center; }
.es-stat__value { font-size: 1.05rem; font-weight: 700; color: var(--text-primary); line-height: 1.2; font-variant-numeric: tabular-nums; }
.es-stat__value--accent { color: var(--accent); }
.es-stat__value--pass { color: var(--success); }
.es-stat__value--fail { color: var(--danger); }
.es-stat__label { font-size: 0.7rem; color: var(--text-muted); margin-top: 0.15rem; }

/* ---------- verdict banner ---------- */
.es-banner { padding: 0.6rem 0.8rem; border-radius: var(--radius); border: 1px solid var(--border); background: var(--bg-surface); font-size: 0.85rem; margin-top: 0.7rem; color: var(--text-primary); }
.es-banner--pass { border-color: var(--success); background: rgba(46, 204, 113, 0.10); }
.es-banner--fail { border-color: var(--danger); background: rgba(224, 82, 82, 0.10); }
.es-banner--info { border-color: var(--accent); background: rgba(var(--accent-rgb), 0.10); }
.es-banner strong { color: inherit; }
.es-banner__ref { display: block; margin-top: 0.3rem; font-size: 0.76rem; color: var(--text-muted); }

.es-badge { display: inline-block; font-size: 0.7rem; font-weight: 700; padding: 0.1rem 0.45rem; border-radius: 3px; letter-spacing: 0.03em; }
.es-badge--pass { background: rgba(46, 204, 113, 0.16); color: var(--success); }
.es-badge--fail { background: rgba(224, 82, 82, 0.16); color: var(--danger); }
.es-badge--info { background: rgba(var(--accent-rgb), 0.16); color: var(--accent); }

.es-note { font-size: 0.8rem; color: var(--text-muted); line-height: 1.55; margin: 0.7rem 0 0; }
.es-note code { font-size: 0.78rem; color: var(--text-primary); }

/* ---------- identifier widget ---------- */
.es-id__step { margin-bottom: 1rem; }
.es-id__q { font-size: 0.92rem; font-weight: 600; color: var(--text-primary); margin: 0 0 0.3rem; }
.es-id__hint { font-size: 0.8rem; color: var(--text-muted); margin: 0 0 0.55rem; line-height: 1.5; }
.es-id__opts { display: flex; flex-wrap: wrap; gap: 0.4rem; }
.es-id__opt {
  font-family: inherit; font-size: 0.82rem; text-align: left;
  padding: 0.45rem 0.75rem; border-radius: var(--radius);
  background: var(--bg-elevated); color: var(--text-primary);
  border: 1px solid var(--border); cursor: pointer; transition: var(--transition);
}
.es-id__opt:hover { border-color: var(--accent); color: var(--accent); }
.es-id__opt[aria-pressed="true"] { background: var(--accent); border-color: var(--accent); color: #fff; }
.es-id__opt:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

.es-id__result { margin-top: 0.4rem; }
.es-id__verdict { font-size: 1.25rem; font-weight: 700; color: var(--accent); margin: 0 0 0.25rem; }
.es-id__why { font-size: 0.88rem; color: var(--text-primary); margin: 0 0 0.6rem; }
.es-id__checks { margin: 0; padding-left: 1.1rem; font-size: 0.83rem; color: var(--text-muted); line-height: 1.6; }
.es-id__checks li { margin-bottom: 0.25rem; }
.es-id__reset {
  margin-top: 0.8rem;
  font-family: inherit; font-size: 0.8rem; padding: 0.4rem 0.8rem;
  background: var(--bg-elevated); color: var(--text-muted);
  border: 1px solid var(--border); border-radius: var(--radius);
  cursor: pointer; transition: var(--transition);
}
.es-id__reset:hover { border-color: var(--accent); color: var(--accent); }
.es-id__reset:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* ---------- article figures ----------
   Each figure ships as two <img> editions because an <img>-loaded SVG cannot
   read these custom properties. Show the one that matches the active theme:
   default (dark) and slate get the dark edition, light gets the light one. */
.es-fig { margin: 1.5rem 0; }
.es-fig__img { width: 100%; height: auto; border: 1px solid var(--border); border-radius: var(--radius); }
.es-fig__img--dark  { display: block; }
.es-fig__img--light { display: none; }
:root[data-theme="light"] .es-fig__img--dark  { display: none; }
:root[data-theme="light"] .es-fig__img--light { display: block; }
.es-fig figcaption { font-size: 0.83rem; color: var(--text-muted); margin-top: 0.5rem; line-height: 1.55; }

/* ---------- a displayed formula ----------
   Set apart from the prose, monospaced enough to read as an expression without
   pretending to be code. Scrolls rather than pushing the page sideways. */
.es-formula {
  margin: 1.2rem 0;
  padding: 0.9rem 1rem;
  background: var(--bg-elevated);
  border-left: 3px solid var(--accent);
  border-radius: var(--radius);
  font-size: 1.05rem;
  text-align: center;
  overflow-x: auto;
}

/* ---------- reference tables ----------
   Sits alongside the sitewide .cmp-table; these only add what a standards table
   needs — a caption, a footnote marker and figures that line up in columns. */
.es-tbl__cap {
  caption-side: top;
  text-align: left;
  font-size: 0.8rem;
  color: var(--text-muted);
  padding-bottom: 0.5rem;
  line-height: 1.5;
}
.es-tbl__note { color: var(--accent); font-weight: 700; }
.es-tbl--num td { font-variant-numeric: tabular-nums; white-space: nowrap; }

/* ---------- factor stack ----------
   A list of named coefficients, each with its value, what produced it and the
   table it came from. One that equals 1 is dimmed rather than hidden, so the
   reader can see it was considered and cost nothing. */
.es-factors { display: grid; gap: 0.4rem; margin: 0.9rem 0 1.1rem; }
.es-factor {
  display: grid;
  grid-template-columns: 2.2rem 3.2rem 1fr;
  align-items: baseline;
  gap: 0.5rem;
  padding: 0.5rem 0.6rem;
  background: var(--bg-elevated);
  border-radius: var(--radius);
  border-left: 2px solid var(--accent);
  font-size: 0.85rem;
}
.es-factor--inert { border-left-color: var(--border); opacity: 0.62; }
.es-factor__sym { font-weight: 700; color: var(--accent); }
.es-factor--inert .es-factor__sym { color: var(--text-muted); }
.es-factor__val { font-family: 'JetBrains Mono', ui-monospace, monospace; font-variant-numeric: tabular-nums; font-weight: 700; }
.es-factor__body { line-height: 1.5; }
.es-factor__ref { display: block; font-size: 0.78rem; color: var(--text-muted); margin-top: 0.15rem; }

/* ---------- glossary ---------- */
.es-gloss { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: 0.5rem 1.2rem; margin: 1rem 0; }
.es-gloss__item { font-size: 0.87rem; line-height: 1.55; }
/* The term is an inline lead-in immediately followed by a sibling <span> of body text, and with no
   trailing space the two ran together — "521.5.201Electromechanical stresses". This affected every
   explainer using es-gloss (selectivity, xlpe, cleats), not one topic, so the gap belongs here
   rather than in each app.js. */
.es-gloss__term { color: var(--accent); font-weight: 700; margin-right: 0.45em; }

@media print {
  .es-widget { break-inside: avoid; }
}

/* ---------- editable load schedule (diversity explorer) ----------
   Five controls will not fit across a 300 px panel — as a single grid row they
   silently CLIPPED their own contents, so you could not read the description you
   had typed or which category was selected. The description now takes its own
   line and the rest wrap beneath it, which holds at any panel width. */
.es-load {
  display: flex;
  flex-wrap: wrap;
  gap: 0.3rem;
  align-items: center;
  margin-bottom: 0.5rem;
  padding-bottom: 0.5rem;
  border-bottom: 1px solid var(--border);
}
.es-load:last-of-type { border-bottom: none; }
.es-load input, .es-load select {
  font-family: inherit; font-size: 0.8rem; padding: 0.35rem 0.4rem;
  background: var(--bg-elevated); color: var(--text-primary);
  border: 1px solid var(--border); border-radius: var(--radius);
  min-width: 0;
}
.es-load input:focus-visible, .es-load select:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
.es-load__name  { flex: 1 1 100%; }
.es-load__val   { flex: 0 0 4.2rem; }
.es-load__unit  { flex: 0 0 4.6rem; }
.es-load__cat   { flex: 1 1 8rem; }
.es-load__phase { flex: 0 0 4.2rem; }
.es-load__del {
  flex: 0 0 auto; margin-left: auto;
  font-family: inherit; font-size: 1rem; line-height: 1; padding: 0.3rem 0.5rem;
  background: none; color: var(--text-muted); border: 1px solid var(--border);
  border-radius: var(--radius); cursor: pointer; transition: var(--transition);
}
.es-load__del:hover { border-color: var(--danger); color: var(--danger); }
.es-load__del:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* ------------------------------------------------------------------ *
 * Classes the containment-fill widget uses. They were referenced in
 * insights/containment-fill/app.js from the start but never defined here, so
 * that markup rendered unstyled. Defined 2026-08-02 to match the rest of the
 * kit rather than to invent a new look — see INSIGHTS-EXPLAINERS.md §9.
 * ------------------------------------------------------------------ */

/* the results column of a two-panel widget */
.es-output { display: flex; flex-direction: column; gap: 0.75rem; }

/* a plain data table inside a widget — lighter than the sitewide .cmp-table,
   and it must be able to scroll rather than push the page sideways */
.es-table { width: 100%; border-collapse: collapse; font-size: 0.85rem; display: block; overflow-x: auto; }
.es-table th, .es-table td { padding: 0.4rem 0.6rem; text-align: left; border-bottom: 1px solid var(--border); white-space: nowrap; }
.es-table thead th { font-size: 0.72rem; letter-spacing: 0.06em; text-transform: uppercase; color: var(--text-muted); font-weight: 600; }
.es-table tbody tr:last-child th, .es-table tbody tr:last-child td { border-bottom: 0; }

/* A table whose last column is a SENTENCE, not a value. The base is nowrap — correct for the
   short-cell tables, but it makes a prose column run off the page. Opt in per table. */
.es-table--prose td:last-child, .es-table--prose th:last-child { white-space: normal; min-width: 20rem; }
.es-table--prose td, .es-table--prose th { vertical-align: top; }

/* the row the reader is meant to take away */
.es-row--key td, .es-row--key th { background: rgba(var(--accent-rgb), 0.07); font-weight: 600; color: var(--text-primary); }

/* an inline source/standard marker inside a cell */
.es-tag {
  display: inline-block; font-size: 0.68rem; letter-spacing: 0.04em; text-transform: uppercase;
  padding: 0.06rem 0.35rem; margin-left: 0.3rem; border-radius: 3px;
  border: 1px solid var(--border); color: var(--text-muted); white-space: nowrap;
}

/* two flavours of .es-note: a VERIFY caveat, and a quieter aside */
.es-note--verify { border-left: 2px solid var(--accent-warm); padding-left: 0.7rem; }
.es-note--aside { opacity: 0.85; font-size: 0.82rem; }

/* set on the mount once the widget has rendered, so a stylesheet can tell a
   filled widget from an empty placeholder */
.es-widget:not(.es-ready) .es-widget__fallback { display: block; }
.es-ready .es-widget__fallback { display: none; }

/* ---------- es-video: click-to-load embed ---------------------------- *
 * The site has NO client-side tracking and therefore needs no cookie banner (CLAUDE.md). A normal
 * YouTube iframe contacts Google and sets cookies on page LOAD, which would reverse that. So this
 * is a FACADE: a self-hosted poster and a play button, with zero third-party requests until the
 * reader actually clicks. The iframe is only then injected, pointing at youtube-nocookie.com.
 * A test asserts no youtube.com/embed and no iframe ships in the markup — do not "simplify" this. */
.es-video { margin: 1.75rem 0; }
.es-video__frame {
  position: relative; width: 100%; aspect-ratio: 16 / 9; overflow: hidden;
  border: 1px solid var(--border); border-radius: var(--radius); background: var(--bg-elevated);
}
.es-video__frame > iframe { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; }
/* Play affordance centred; the wording pinned to the BOTTOM over a scrim. Centring all three
   stacked the label straight onto the poster artwork and butted the hint into the poster's own
   caption — the fix is to give the text its own band rather than sharing the middle. */
.es-video__btn {
  position: absolute; inset: 0; display: grid; place-items: center;
  grid-template-rows: 1fr auto auto; width: 100%; height: 100%; padding: 0 0 1rem; cursor: pointer;
  background: none; border: 0; color: var(--text-primary); font: inherit; text-align: center;
}
.es-video__btn::after {
  content: ''; position: absolute; inset: auto 0 0 0; height: 45%; pointer-events: none;
  background: linear-gradient(to top, rgba(0, 0, 0, 0.72), rgba(0, 0, 0, 0));
}
.es-video__poster {
  position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover;
  /* the poster is decorative behind the label; dim it so the play affordance reads clearly */
  opacity: 0.55; transition: opacity 0.2s ease;
}
.es-video__btn:hover .es-video__poster,
.es-video__btn:focus-visible .es-video__poster { opacity: 0.75; }
.es-video__play {
  position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%);
  display: grid; place-items: center;
  width: 4.25rem; height: 4.25rem; border-radius: 50%;
  background: var(--accent); color: #fff; font-size: 1.4rem; line-height: 1;
  box-shadow: 0 2px 14px rgba(0, 0, 0, 0.35);
}
.es-video__label {
  position: relative; grid-row: 2; max-width: 34rem; padding: 0 1rem 0.2rem;
  font-size: 0.95rem; font-weight: 600; color: #fff;
}
.es-video__hint {
  position: relative; grid-row: 3; padding: 0 1rem;
  font-size: 0.78rem; color: rgba(255, 255, 255, 0.72);
}
/* the frame is a dark plate in every theme, so the overlay text is white in every theme too */
.es-video__frame { color-scheme: dark; }
.es-video__btn:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
.es-video figcaption { margin-top: 0.6rem; font-size: 0.86rem; color: var(--text-muted); }
@media (prefers-reduced-motion: reduce) { .es-video__poster { transition: none; } }
