/* =============================================================
   WebTec Energy Server — site chrome
   ============================================================= */

.wts {
  background: var(--wt-page);
  color: var(--wt-ink);
  font-family: var(--wt-font-sans);
  font-size: 14px;
  line-height: 1.5;
  width: 100%;
  min-height: 100%;
  display: flex;
  flex-direction: column;
  -webkit-font-smoothing: antialiased;
}
.wts *, .wts *::before, .wts *::after { box-sizing: border-box; }
.wts h1, .wts h2, .wts h3, .wts h4 { margin: 0; font-weight: 700; letter-spacing: -0.015em; color: var(--wt-ink); }
.wts p { margin: 0; }
.wts a { color: var(--wt-brand-strong); text-decoration: none; }
.wts a:hover { text-decoration: underline; text-underline-offset: 3px; }
.wts code, .wts .mono { font-family: var(--wt-font-mono); }

/* Header --------------------------------------------------------*/
.wts-header {
  height: 64px;
  padding: 0 32px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  border-bottom: 1px solid var(--wt-border);
  background: var(--wt-surface);
  flex-shrink: 0;
}
.wts-brand {
  display: inline-flex; align-items: center; gap: 12px;
  font-weight: 800; letter-spacing: -0.02em;
  font-size: 20px; color: var(--wt-ink);
}
.wts-brand .logo {
  width: 36px; height: 36px;
  display: block; object-fit: contain;
  border-radius: var(--wt-r-md);
  flex-shrink: 0;
}
.wts-brand .name { line-height: 1.05; }
.wts-brand .name .sub {
  display: block; font-size: 10.5px; color: var(--wt-ink-muted);
  font-family: var(--wt-font-mono); font-weight: 500;
  letter-spacing: 0; margin-top: 4px; text-transform: uppercase;
}
.wts-nav { display: flex; gap: 6px; align-items: center; }
.wts-nav a {
  padding: 8px 14px; border-radius: var(--wt-r-md);
  font-size: 13.5px; font-weight: 500; color: var(--wt-ink-soft);
}
.wts-nav a:hover { background: var(--wt-surface-2); color: var(--wt-ink); text-decoration: none; }
.wts-nav a.is-active { color: var(--wt-ink); }
.wts-nav .nav-cta {
  margin-left: 6px;
  padding: 8px 16px; background: var(--wt-brand); color: var(--wt-ink-on-brand);
  border-radius: var(--wt-r-md); font-weight: 600;
}
.wts-nav .nav-cta:hover { background: var(--wt-brand-strong); text-decoration: none; }
.wts-nav .nav-user {
  display: inline-flex; align-items: center; gap: 8px;
  padding: 6px 12px 6px 6px; border-radius: var(--wt-r-full);
  background: var(--wt-surface-2); border: 1px solid var(--wt-border);
  font-size: 13px; color: var(--wt-ink);
}
.wts-nav .nav-user .avatar {
  width: 24px; height: 24px; border-radius: 50%;
  background: var(--wt-brand); color: var(--wt-ink-on-brand);
  display: grid; place-items: center;
  font-size: 11px; font-weight: 700;
}

/* Footer --------------------------------------------------------*/
.wts-footer {
  margin-top: auto;
  padding: 24px 32px 20px;
  border-top: 1px solid var(--wt-border);
  background: var(--wt-surface);
  display: flex; align-items: center; justify-content: space-between;
  font-size: 12.5px; color: var(--wt-ink-muted);
  flex-shrink: 0;
}
.wts-footer .links { display: flex; gap: 18px; }
.wts-footer .links a { color: var(--wt-ink-soft); font-weight: 500; }
/* Build identifier — present so a support call can name what it sees, quiet
   enough not to compete with the copyright line it sits next to. */
.wts-version { opacity: .55; font-variant-numeric: tabular-nums; margin-left: 6px; }

/* Settings sidebar ---------------------------------------------*/
.wts-shell { display: grid; grid-template-columns: 240px 1fr; flex: 1; min-height: 0; }
.wts-side {
  background: var(--wt-surface);
  border-right: 1px solid var(--wt-border);
  padding: 24px 16px;
  display: flex; flex-direction: column; gap: 4px;
}
.wts-side h4 {
  font-size: 11px; letter-spacing: 0.1em; text-transform: uppercase;
  color: var(--wt-ink-muted); font-weight: 700;
  padding: 0 10px; margin-bottom: 8px;
}
.wts-side a {
  display: flex; align-items: center; gap: 10px;
  padding: 9px 10px; border-radius: var(--wt-r-md);
  font-size: 14px; color: var(--wt-ink-soft); font-weight: 500;
}
.wts-side a:hover { background: var(--wt-surface-2); color: var(--wt-ink); text-decoration: none; }
.wts-side a.is-active { background: var(--wt-brand-soft); color: var(--wt-brand-strong); }
.wts-side a .ic { width: 18px; height: 18px; flex-shrink: 0; }

/* Settings main area -------------------------------------------*/
.wts-main { padding: 32px 36px; overflow: hidden; min-width: 0; }
.wts-main h2.page-title { font-size: 26px; letter-spacing: -0.02em; }
.wts-main .page-sub { color: var(--wt-ink-soft); margin-top: 4px; font-size: 14px; }
.wts-toolbar {
  display: flex; align-items: center; gap: 12px; margin-top: 18px;
  padding: 12px 14px; background: var(--wt-surface); border: 1px solid var(--wt-border);
  border-radius: var(--wt-r-md);
}

/* Dashboard hero ------------------------------------------------*/
.wts-hero {
  padding: 40px 32px 28px;
  display: grid; grid-template-columns: 1fr auto;
  gap: 32px; align-items: end;
  background: linear-gradient(180deg, var(--wt-surface) 0%, var(--wt-page) 100%);
  border-bottom: 1px solid var(--wt-border);
}
.wts-hero .eyebrow {
  font-size: 12px; font-weight: 700; letter-spacing: 0.1em; text-transform: uppercase;
  color: var(--wt-brand-strong); margin-bottom: 8px;
}
.wts-hero h1 {
  font-size: 40px; line-height: 1.1; letter-spacing: -0.025em; font-weight: 800;
}
.wts-hero h1 .accent { color: var(--wt-brand-strong); }
.wts-hero p { color: var(--wt-ink-soft); font-size: 16px; max-width: 56ch; margin-top: 8px; }
.wts-hero .live-pill {
  display: inline-flex; align-items: center; gap: 8px;
  padding: 6px 12px 6px 8px;
  background: var(--wt-success-soft); color: var(--wt-success);
  border-radius: var(--wt-r-full);
  font-size: 12.5px; font-weight: 600;
}
.wts-hero .live-pill .pulse {
  width: 8px; height: 8px; border-radius: 50%;
  background: var(--wt-success);
  box-shadow: 0 0 0 0 var(--wt-success);
  animation: wts-pulse 1.6s infinite;
}
@keyframes wts-pulse {
  0% { box-shadow: 0 0 0 0 color-mix(in oklab, var(--wt-success) 60%, transparent); }
  70% { box-shadow: 0 0 0 10px color-mix(in oklab, var(--wt-success) 0%, transparent); }
  100% { box-shadow: 0 0 0 0 color-mix(in oklab, var(--wt-success) 0%, transparent); }
}

/* Tile row ------------------------------------------------------*/
.wts-tile-row {
  display: grid; grid-template-columns: repeat(3, 1fr); gap: 16px;
  padding: 24px 32px;
}
.wts-tile {
  background: var(--wt-surface);
  border: 1px solid var(--wt-border);
  border-radius: var(--wt-r-xl);
  padding: 24px;
  display: flex; flex-direction: column; gap: 14px;
  min-height: 280px;
}
.wts-tile h3 {
  font-size: 13px; font-weight: 600; color: var(--wt-ink-muted);
  text-transform: uppercase; letter-spacing: 0.08em;
}
.wts-tile .figure { font-family: var(--wt-font-mono); font-size: 34px; font-weight: 700; letter-spacing: -0.025em; color: var(--wt-ink); }
.wts-tile .figure small { font-size: 18px; color: var(--wt-ink-muted); margin-left: 4px; font-weight: 500; }

.wts-stat-list { display: flex; flex-direction: column; gap: 14px; }
.wts-stat-list .row {
  display: flex; align-items: baseline; justify-content: space-between;
  padding-bottom: 14px; border-bottom: 1px dashed var(--wt-border);
}
.wts-stat-list .row:last-child { border-bottom: 0; padding-bottom: 0; }
.wts-stat-list .label {
  font-size: 13px; color: var(--wt-ink-soft);
  display: inline-flex; align-items: center; gap: 8px;
}
.wts-stat-list .label .dot { width: 8px; height: 8px; border-radius: 50%; display: inline-block; }
.wts-stat-list .value {
  font-family: var(--wt-font-mono); font-weight: 600; font-size: 19px;
  color: var(--wt-ink);
}
.wts-stat-list .value small { font-size: 12px; color: var(--wt-ink-muted); margin-left: 4px; font-weight: 500; }

/* Donut ---------------------------------------------------------*/
/* chart.js sizes its canvas from this box, so the box must be square and must
   be allowed to shrink - the 180px is a cap, not a width. */
.wts-donut { display: grid; place-items: center; min-width: 0; }
.wts-donut canvas { max-width: 100%; }
.wts-donut-legend {
  display: flex; justify-content: space-between; flex-wrap: wrap; gap: 4px 8px;
  font-size: 12.5px; color: var(--wt-ink-muted); margin-top: 4px;
}
.wts-donut-legend > span { display: inline-flex; align-items: center; gap: 6px; }
/* JS recolours these from the same tokens the wedges use. */
.wts-donut-legend .dot { width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0; }

/* Map -----------------------------------------------------------*/
/* The map only takes the wheel and the pointer once it has been clicked; until
   then the page scrolls straight over it. .is-active is set by setMapInteractive
   in index.js.

   The active state is deliberately quiet: the same 2px/--wt-border-medium the
   Stammdaten rows use, not a brand colour or a focus ring. The map is a large
   surface and a bright outline around it dominates the whole dashboard. What
   actually tells the user the map is live is the "Karte verlassen" button
   appearing and the cursor turning into a grab hand.
   The 1px the box gains is absorbed by the content, so nothing around it moves. */
.wts-map {
  margin: 0 32px 32px;
  border: 1px solid var(--wt-border);
  border-radius: var(--wt-r-xl);
  background: var(--wt-surface);
  overflow: hidden;
  transition: border-color .15s ease;
}
.wts-map.is-active {
  border: 2px solid var(--wt-border-medium);
}
.wts-map-head-right { display: flex; align-items: center; gap: 12px; }

/* Exit control. Display is driven entirely by the parent's state class, so no
   [hidden] attribute to be overridden by this rule's own display. */
.wts-map-exit {
  display: none;
  align-items: center;
  gap: 6px;
  padding: 5px 12px;
  font: 600 12.5px var(--wt-font-sans);
  color: var(--wt-brand-strong);
  background: var(--wt-brand-soft);
  border: 1px solid var(--wt-brand);
  border-radius: var(--wt-r-full);
  cursor: pointer;
}
.wts-map.is-active .wts-map-exit { display: inline-flex; }

/* Same state-driven display as the exit button. */
.wts-map-toggle {
  display: none;
  align-items: center;
  gap: 6px;
  font: 600 12.5px var(--wt-font-sans);
  color: var(--wt-ink-soft);
  cursor: pointer;
  user-select: none;
}
.wts-map.is-active .wts-map-toggle { display: inline-flex; }
.wts-map-toggle input { accent-color: var(--wt-brand); cursor: pointer; margin: 0; }
/* The count spinner is only meaningful while min/max is on; it stays in the flow
   greyed out rather than disappearing, so the header does not reflow on toggle. */
.wts-map-count input[type="number"] {
  width: 52px;
  padding: 3px 6px;
  font: 600 12.5px var(--wt-font-mono);
  color: var(--wt-ink);
  background: var(--wt-surface);
  border: 1px solid var(--wt-border-medium);
  border-radius: var(--wt-r-sm);
}
.wts-map-count.is-disabled { opacity: .45; pointer-events: none; }
.wts-map-exit:hover { background: var(--wt-brand); color: var(--wt-ink-on-brand); }
.wts-map-exit:focus-visible { outline: 2px solid var(--wt-focus); outline-offset: 2px; }

/* Hint. pointer-events:none matters: this sits over the canvas, and if it took
   the click the map could never be activated by clicking the middle of it. */
.wts-map-hint {
  position: absolute;
  left: 50%;
  bottom: 14px;
  transform: translateX(-50%);
  pointer-events: none;
  padding: 6px 14px;
  border-radius: var(--wt-r-full);
  background: var(--wt-overlay);
  color: #fff;
  font: 600 12.5px var(--wt-font-sans);
  opacity: 0;
  transition: opacity .15s ease;
}
.wts-map:not(.is-active) .wts-map-body:hover .wts-map-hint { opacity: 1; }
.wts-map:not(.is-active) #canvasMapData { cursor: zoom-in; }
.wts-map.is-active #canvasMapData { cursor: grab; touch-action: none; }
.wts-map.is-active #canvasMapData:active { cursor: grabbing; }

@media (prefers-reduced-motion: reduce) {
  .wts-map, .wts-map-hint { transition: none; }
}
.wts-map-header { padding: 14px 20px; display: flex; align-items: center; justify-content: space-between; border-bottom: 1px solid var(--wt-border); }
.wts-map-header h3 { font-size: 15px; }
/* Holds the real map: the <img> sizes the box, the canvas draws over it.
   The redesign's mock dots and caption lived here - they sat on top of the
   actual map once one existed, so they are gone. */
.wts-map-body {
  background: var(--wt-surface-sunken);
  position: relative;
}

/* Map row + eco tiles ------------------------------------------*/
/* The map and the two eco tiles ("Baeume gepflanzt" / "CO2 vermieden") are one
   row: map on the left, tiles in a fixed right column. The page margin moved
   here from .wts-map, which is why .wts-map zeroes its own inside the row.

   .is-stacked drops the tiles into their own row under the map. It is set from
   two places and they must not contradict each other: the 820px query below
   (phones, works with JS off) and setEcoLayout() in index.js, which compares the
   width the map WOULD get beside the tiles against the height it would then
   take. That check is deliberately run on the hypothetical geometry and never on
   the measured box - stacking widens the map, so measuring the result would
   unstack it again on the next observation, and back. */
.wts-map-row {
  display: grid;
  /* The side column is exactly the third dashboard tile's column. .wts-tile-row is
     three 1fr tracks with two 16px gaps inside the same content width this row has
     (its margin equals that row's horizontal padding), so one column is
     (100% - 2*16px)/3. Keep the 32px in step with .wts-tile-row's gap, and with
     ECO_GAP_PX / ecoColWidth() in index.js, which mirror this arithmetic to decide
     whether the map still fits beside the tiles. */
  grid-template-columns: minmax(0, 1fr) calc((100% - 32px) / 3);
  gap: 16px;
  margin: 0 32px 32px;
}
.wts-map-row > .wts-map { margin: 0; }
.wts-map-row.is-stacked { grid-template-columns: minmax(0, 1fr); }

/* Side by side the column is as tall as the map and the two tiles split that height
   between them (the row's default align-items:stretch does the first half, the two
   1fr tracks the second). The tracks are 1fr and not minmax(0,1fr) on purpose: a
   tile whose content needs more room may grow the row rather than be clipped.
   Stacked, the column sits under the map and takes its natural height again. */
.wts-eco { display: grid; grid-template-columns: minmax(0, 1fr); gap: 16px; min-width: 0; }
.wts-map-row:not(.is-stacked) .wts-eco { grid-template-rows: 1fr 1fr; }
.wts-map-row.is-stacked .wts-eco { grid-template-columns: repeat(2, minmax(0, 1fr)); }

/* min-height:0 because .wts-tile's 280px is meant for the three dashboard tiles;
   here the row decides the height. The art is the flexible part, so the extra
   height a tall map hands down goes into the illustration and the figures stay
   put. */
.wts-eco-tile { min-height: 0; gap: 10px; }
.wts-eco-art { display: grid; place-items: center; padding: 2px 0; flex: 1 1 auto; min-height: 0; }
.wts-eco-art svg { display: block; width: 100%; max-width: 172px; max-height: 100%; height: auto; }

/* Header: title left, info button hard right. position:relative anchors the popover. */
.wts-eco-head {
  position: relative;
  display: flex; align-items: center; justify-content: space-between; gap: 8px;
}
.wts-eco-info {
  flex: 0 0 auto;
  display: inline-flex; align-items: center; justify-content: center;
  width: 20px; height: 20px; padding: 0;
  color: var(--wt-ink-muted);
  background: none; border: 0; border-radius: 50%;
  cursor: pointer;
}
.wts-eco-info svg { width: 15px; height: 15px; display: block; }
.wts-eco-info:hover { color: var(--wt-brand-strong); background: var(--wt-brand-soft); }
.wts-eco-info:focus-visible { outline: 2px solid var(--wt-focus); outline-offset: 2px; }
.wts-eco-info[aria-expanded="true"] { color: var(--wt-brand-strong); background: var(--wt-brand-soft); }

/* Anchored to the header's right edge so it can never reach past the tile, which
   matters because .wts-main clips horizontally. */
.wts-eco-pop {
  position: absolute; top: calc(100% + 8px); right: 0; z-index: 30;
  width: max-content; max-width: min(300px, 100%);
  padding: 10px 12px;
  background: var(--wt-surface);
  border: 1px solid var(--wt-border-medium);
  border-radius: var(--wt-r-md);
  box-shadow: var(--wt-shadow-md);
  font: 400 11.5px/1.5 var(--wt-font-sans);
  color: var(--wt-ink-soft);
  text-transform: none; letter-spacing: normal;
}
/* [hidden] is the CLICK state, which index.js toggles - it is what makes the panel
   sticky and what makes it work on a touch screen at all. Hover is layered on top
   with a higher specificity than the [hidden] rule, so pointing at the button shows
   the panel even while it is attributed hidden, without JS and without disturbing
   the click state.
   .wts-eco-pop:hover plus the ::before bridge keep it open while the pointer travels
   the 8px gap from the button into the panel - otherwise the text could be shown but
   never read. */
.wts-eco-pop p { margin: 0; }
.wts-eco-pop p + p { margin-top: 7px; }
.wts-eco-pop[hidden] { display: none; }
.wts-eco-info:hover + .wts-eco-pop,
.wts-eco-info:focus-visible + .wts-eco-pop,
.wts-eco-pop:hover { display: block; }
.wts-eco-pop::before {
  content: ""; position: absolute;
  left: 0; right: 0; top: -10px; height: 10px;
}

.wts-eco-figure {
  font-family: var(--wt-font-mono); font-size: 32px; font-weight: 700;
  letter-spacing: -0.025em; color: var(--wt-ink); line-height: 1.05;
}
.wts-eco-figure small { font-size: 16px; color: var(--wt-ink-muted); margin-left: 4px; font-weight: 500; }
.wts-eco-caption { font-size: 12.5px; color: var(--wt-ink-muted); margin-top: -6px; }

/* Decorative grove under the figure. index.js fills it with <use> copies of
   #icoTree; the partially grown one is scaled from its base, hence the origin. */
.wts-grove { display: flex; flex-wrap: wrap; align-items: flex-end; gap: 3px; min-height: 22px; }
.wts-grove svg { flex: 0 0 auto; display: block; width: 16px; height: 21px; transform-origin: 50% 100%; }

/* Same dot as the hero live pill, which scopes its own .pulse to .live-pill. */
.wts-eco-tile .pulse {
  width: 7px; height: 7px; border-radius: 50%; display: inline-block;
  background: var(--wt-success);
  animation: wts-pulse 1.6s infinite;
}
@media (prefers-reduced-motion: reduce) {
  .wts-eco-tile .pulse { animation: none; }
}

/* Content + rail split (profile page). Was an inline grid-template-columns,
   which no media query could reach - keep it a class so it can collapse. */
.wts-split { margin-top: 24px; display: grid; grid-template-columns: 1fr 280px; gap: 20px; }

/* Generic panel -------------------------------------------------*/
.wts-panel {
  background: var(--wt-surface); border: 1px solid var(--wt-border);
  border-radius: var(--wt-r-lg);
  padding: 20px;
}
.wts-panel + .wts-panel { margin-top: 12px; }
.wts-panel .panel-head {
  display: flex; align-items: center; justify-content: space-between;
  margin-bottom: 12px;
}
.wts-panel .panel-head h4 { font-size: 15px; }

/* Form rows -----------------------------------------------------*/
.wts-field { display: flex; flex-direction: column; gap: 6px; }
.wts-field label { font-size: 13px; font-weight: 600; color: var(--wt-ink); }
.wts-field .help { font-size: 12px; color: var(--wt-ink-muted); }
.wts-input {
  height: 40px; padding: 0 14px;
  border: 1px solid var(--wt-border-strong); background: var(--wt-surface);
  border-radius: var(--wt-r-md);
  font: 500 14px var(--wt-font-sans);
  color: var(--wt-ink); width: 100%;
}
.wts-input:focus { outline: none; border-color: var(--wt-brand); box-shadow: 0 0 0 4px var(--wt-focus); }
.wts-input[readonly], .wts-input[disabled] { background: var(--wt-surface-sunken); color: var(--wt-ink-soft); }
textarea.wts-input { height: auto; min-height: 72px; padding: 10px 14px; line-height: 1.5; resize: vertical; font-family: var(--wt-font-mono); font-size: 12.5px; }
.wts-select { appearance: none; padding-right: 32px;
  background:
    linear-gradient(45deg, transparent 50%, var(--wt-ink-soft) 50%) no-repeat right 18px top 18px / 5px 5px,
    linear-gradient(135deg, var(--wt-ink-soft) 50%, transparent 50%) no-repeat right 13px top 18px / 5px 5px,
    var(--wt-surface);
}
.wts-input-group { display: flex; }
.wts-input-group .wts-input { border-top-right-radius: 0; border-bottom-right-radius: 0; border-right: 0; }
.wts-input-group .wts-btn { border-top-left-radius: 0; border-bottom-left-radius: 0; }

.wts-btn {
  display: inline-flex; align-items: center; gap: 7px;
  height: 40px; padding: 0 16px;
  border-radius: var(--wt-r-md);
  font: 600 13.5px var(--wt-font-sans);
  border: 1px solid transparent; cursor: pointer;
  white-space: nowrap;
}
.wts-btn--primary { background: var(--wt-brand); color: var(--wt-ink-on-brand); }
.wts-btn--secondary { background: var(--wt-surface); color: var(--wt-ink); border-color: var(--wt-border-strong); }
.wts-btn--ghost { background: transparent; color: var(--wt-ink-soft); }
.wts-btn--ghost:hover { background: var(--wt-surface-2); color: var(--wt-ink); }
.wts-btn--danger { background: var(--wt-danger); color: white; }
.wts-btn--sm { height: 32px; padding: 0 12px; font-size: 12.5px; }
.wts-btn--icon {
  width: 36px; height: 36px; padding: 0; justify-content: center;
}
.wts-btn .ic { width: 16px; height: 16px; stroke-width: 1.75; }
/* A disabled button was indistinguishable from an enabled one - it kept the
   pointer cursor and the full contrast, and only did nothing when clicked. */
.wts-btn:disabled { opacity: 0.45; cursor: not-allowed; }
.wts-btn--ghost:disabled:hover { background: transparent; color: var(--wt-ink-soft); }

/* Switches/checkboxes ------------------------------------------*/
.wts-switch { position: relative; width: 36px; height: 22px; flex-shrink: 0; }
.wts-switch input { opacity: 0; width: 0; height: 0; }
.wts-switch .track { position: absolute; inset: 0; background: var(--wt-border-strong); border-radius: var(--wt-r-full); transition: background 0.18s; }
.wts-switch .thumb { position: absolute; left: 3px; top: 3px; width: 16px; height: 16px; border-radius: 50%; background: white; box-shadow: var(--wt-shadow-sm); transition: transform 0.18s; }
.wts-switch input:checked + .track { background: var(--wt-brand); }
.wts-switch input:checked + .track .thumb { transform: translateX(14px); }

/* User accordion (Stammdaten / OCPP) ----------------------------*/
.wts-acc-list { display: flex; flex-direction: column; gap: 10px; }
.wts-acc {
  background: var(--wt-surface);
  border: 1px solid var(--wt-border);
  border-radius: var(--wt-r-lg);
  overflow: hidden;
}
.wts-acc-head {
  display: grid;
  grid-template-columns: 28px 1fr auto auto auto;
  gap: 12px; padding: 12px 16px;
  align-items: center;
  cursor: pointer;
  background: var(--wt-surface);
}
.wts-acc[data-state="open"] .wts-acc-head { background: var(--wt-surface-2); border-bottom: 1px solid var(--wt-border); }
.wts-acc-head .caret {
  width: 24px; height: 24px;
  display: grid; place-items: center;
  border-radius: 6px; color: var(--wt-ink-soft);
  background: transparent;
  transition: transform 0.16s ease;
}
/* .ic is sized per context (button, sidebar); the caret had no rule of its own,
   so its svg fell back to the 300x150 default of a replaced element. */
.wts-acc-head .caret .ic { width: 16px; height: 16px; }
.wts-acc[data-state="open"] .wts-acc-head .caret { transform: rotate(90deg); color: var(--wt-brand-strong); }
/* The open state was styled but the closed one never hid anything, so the
   component could not actually collapse. data-state is set by the page. */
.wts-acc:not([data-state="open"]) .wts-acc-body { display: none; }
.wts-acc-head .who { font-weight: 600; font-size: 14.5px; color: var(--wt-ink); }
.wts-acc-head .who .sub { font-size: 12.5px; color: var(--wt-ink-muted); font-weight: 500; margin-left: 6px; font-family: var(--wt-font-mono); }
.wts-acc-head .badge-set { display: flex; gap: 6px; }
.wts-acc-body { padding: 18px 20px 20px; display: flex; flex-direction: column; gap: 12px; }
.wts-form-row {
  display: grid; grid-template-columns: repeat(4, 1fr); gap: 12px;
}
.wts-form-row.col-2 { grid-template-columns: repeat(2, 1fr); }
.wts-form-row.col-3 { grid-template-columns: repeat(3, 1fr); }
.wts-form-row .field-h {
  display: flex; align-items: center; gap: 8px;
}
.wts-form-row .field-h label { font-size: 12.5px; color: var(--wt-ink-soft); font-weight: 500; flex-shrink: 0; }
.wts-form-row .field-h .wts-input { font-size: 13px; height: 36px; }
.wts-form-row .field-h.toggle-row { justify-content: space-between; background: var(--wt-surface-2); padding: 8px 12px; border-radius: var(--wt-r-md); }
.wts-divider { height: 1px; background: var(--wt-border); margin: 4px 0; }

/* Status badges -------------------------------------------------*/
.wts-badge {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 3px 10px; border-radius: var(--wt-r-full);
  font: 600 11px var(--wt-font-sans); letter-spacing: 0.02em;
  background: var(--wt-surface-2); color: var(--wt-ink-soft);
  border: 1px solid var(--wt-border);
}
.wts-badge .led { width: 6px; height: 6px; border-radius: 50%; background: currentColor; }
.wts-badge--success { background: var(--wt-success-soft); color: var(--wt-success); border-color: transparent; }
.wts-badge--warning { background: var(--wt-warning-soft); color: var(--wt-accent-strong); border-color: transparent; }
.wts-badge--danger { background: var(--wt-danger-soft); color: var(--wt-danger); border-color: transparent; }
.wts-badge--info { background: var(--wt-info-soft); color: var(--wt-info); border-color: transparent; }
.wts-badge--brand { background: var(--wt-brand-soft); color: var(--wt-brand-strong); border-color: transparent; }

/* Server status row --------------------------------------------*/
.wts-srv-row {
  display: grid; grid-template-columns: 220px 1fr auto;
  gap: 18px; align-items: start;
  padding: 18px 20px;
  background: var(--wt-surface);
  border: 1px solid var(--wt-border);
  border-radius: var(--wt-r-lg);
}
.wts-srv-row + .wts-srv-row { margin-top: 12px; }
.wts-srv-row .srv-label { display: flex; flex-direction: column; gap: 4px; }
.wts-srv-row .srv-label h4 { font-size: 14.5px; }
.wts-srv-row .srv-label .hint { font-size: 12px; color: var(--wt-ink-muted); }
.wts-srv-row textarea.wts-input { font-size: 12px; min-height: 70px; }

/* Auth card -----------------------------------------------------*/
.wts-auth-card {
  width: min(420px, 100%);
  background: var(--wt-surface);
  border: 1px solid var(--wt-border);
  border-radius: var(--wt-r-xl);
  padding: 36px 32px;
  box-shadow: var(--wt-shadow-md);
}
.wts-auth-card .head {
  display: flex; flex-direction: column; align-items: center; gap: 8px;
  margin-bottom: 22px;
}
.wts-auth-card .head h2 { font-size: 22px; }
.wts-auth-card .head p { font-size: 13px; color: var(--wt-ink-muted); }

/* Legal pages ---------------------------------------------------*/
.wts-legal {
  display: grid;
  grid-template-columns: 240px 1fr;
  gap: 40px;
  padding: 40px 48px 64px;
}
.wts-legal-toc {
  position: sticky; top: 24px; align-self: start;
  font-size: 13px;
}
.wts-legal-toc h4 {
  font-size: 11px; letter-spacing: 0.1em; text-transform: uppercase;
  color: var(--wt-ink-muted); margin-bottom: 10px; font-weight: 700;
}
.wts-legal-toc ul { list-style: none; padding: 0; margin: 0; display: flex; flex-direction: column; gap: 2px; }
.wts-legal-toc a {
  display: block; padding: 4px 10px; border-radius: 6px;
  color: var(--wt-ink-soft); font-size: 13px;
}
.wts-legal-toc a:hover { background: var(--wt-surface-2); text-decoration: none; }
.wts-legal-toc a.is-current { background: var(--wt-brand-soft); color: var(--wt-brand-strong); }

.wts-legal-body { max-width: 640px; }
.wts-legal-body h1 { font-size: 32px; letter-spacing: -0.025em; }
.wts-legal-body h2 { font-size: 18px; margin-top: 28px; }
.wts-legal-body h3 { font-size: 14.5px; margin-top: 22px; color: var(--wt-ink); }
.wts-legal-body p, .wts-legal-body li { color: var(--wt-ink-soft); font-size: 14px; line-height: 1.65; }
.wts-legal-body p + p { margin-top: 12px; }
.wts-legal-body ul { padding-left: 18px; }
.wts-legal-body .summary {
  background: var(--wt-brand-soft);
  border-left: 3px solid var(--wt-brand);
  padding: 14px 16px;
  border-radius: 0 var(--wt-r-md) var(--wt-r-md) 0;
  margin-top: 12px;
}
.wts-legal-body .summary strong { color: var(--wt-brand-strong); }
.wts-legal-body .meta-row {
  display: grid; grid-template-columns: 130px 1fr;
  font-size: 13px;
  padding: 6px 0;
  border-bottom: 1px dashed var(--wt-border);
}
.wts-legal-body .meta-row dt { color: var(--wt-ink-muted); }

/* Masks an admin-list password field without making it type="password" - see
   setPwdMaskedElement in indexBase.js for why those fields must stay text. */
.wts-pw-mask {
  -webkit-text-security: disc;
  text-security: disc;
}

/* Password show/hide eye ----------------------------------------
   Drawn in CSS, no icon font: a rounded lens rotated 45 degrees with a round
   pupil. It used to be styled in indexBase.css, which no template has loaded
   since the redesign, so the toggle rendered as an empty div. currentColor here
   so it takes the tint of whatever button it sits in, in either theme. */
.clsHideShowPwd {
  width: 13px; height: 13px;
  border: 1px solid currentColor;
  border-radius: 75% 15%;
  transform: rotate(45deg);
  position: relative;
  flex-shrink: 0;
}
.clsHideShowPwd::before {
  content: "";
  position: absolute;
  left: 3px; top: 3px;
  width: 5px; height: 5px;
  border: 1px solid currentColor;
  border-radius: 50%;
}

/* Helpers -------------------------------------------------------*/
.wts-row { display: flex; align-items: center; gap: 12px; }
.wts-spacer { flex: 1; }
.wts-text-muted { color: var(--wt-ink-muted); }
.wts-mono { font-family: var(--wt-font-mono); }

/* Search + filter bar ------------------------------------------*/
.wts-filterbar {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
}
.wts-filterbar .search {
  display: flex; align-items: center; gap: 8px;
  background: var(--wt-surface); border: 1px solid var(--wt-border-strong);
  border-radius: var(--wt-r-md); padding: 0 12px;
  min-width: 240px; height: 38px;
}
.wts-filterbar .search input {
  border: 0; outline: 0; background: transparent; flex: 1;
  font: 500 13.5px var(--wt-font-sans); color: var(--wt-ink);
}
.wts-filterbar .search svg { width: 14px; height: 14px; color: var(--wt-ink-muted); }

/* Tables (used in some settings) -------------------------------*/
.wts-table { width: 100%; border-collapse: separate; border-spacing: 0; font-size: 13px; }
.wts-table th, .wts-table td { text-align: left; padding: 10px 14px; border-bottom: 1px solid var(--wt-border); }
.wts-table th { background: var(--wt-surface-2); color: var(--wt-ink-muted); font: 700 11px var(--wt-font-sans); letter-spacing: 0.06em; text-transform: uppercase; }

/* Responsive ----------------------------------------------------*/
/* The redesign shipped without a single media query, which is why every page
   scrolled sideways on a phone. Two causes, fixed separately below.

   1. Grid and flex children default to min-width:auto, so an item wider than
      its track (a mono figure, the map canvas, a long meter id) pushes the
      track past the viewport instead of shrinking. min-width:0 is what lets
      the 1fr tracks actually behave like 1fr.
   2. Rigid track counts and fixed gutters. Everything below only drops column
      counts and padding - no rule here may introduce a new fixed px width. */

.wts-shell, .wts-main, .wts-tile-row, .wts-tile, .wts-hero, .wts-legal,
.wts-srv-row, .wts-form-row, .wts-acc, .wts-acc-head, .wts-panel { min-width: 0; }
.wts-tile-row > *, .wts-hero > *, .wts-srv-row > *,
.wts-form-row > *, .wts-acc-head > *, .wts-shell > * { min-width: 0; }

/* German compounds in the hero and the legal pages are long enough to overflow
   on their own; the templates already carry soft hyphens, this is the backstop. */
.wts-hero h1, .wts-hero p, .wts-legal-body, .wts-tile h3 { overflow-wrap: break-word; }

/* The three dashboard tiles stay side by side at every width - the row is meant
   to be read as one comparison, so it compacts instead of stacking. Everything
   in it has to survive a ~90px column at 320px: hence the type ramp below, and
   the point where each stat label moves above its value instead of beside it. */
@media (max-width: 1100px) {
  .wts-form-row { grid-template-columns: repeat(2, 1fr); }
  .wts-legal { grid-template-columns: 1fr; gap: 24px; padding: 32px 24px 48px; }
  .wts-legal-toc { position: static; }
}

@media (max-width: 820px) {
  .wts-shell { grid-template-columns: 1fr; }
  .wts-side {
    border-right: 0; border-bottom: 1px solid var(--wt-border);
    flex-direction: row; flex-wrap: wrap; padding: 12px 16px;
  }
  .wts-side h4 { width: 100%; margin-bottom: 4px; padding: 0; }
  .wts-main { padding: 20px 16px; }

  .wts-hero {
    grid-template-columns: 1fr; gap: 16px;
    padding: 28px 20px 22px; align-items: start;
  }
  .wts-hero h1 { font-size: 30px; }
  .wts-hero p { font-size: 15px; }

  .wts-tile-row { gap: 10px; padding: 16px 16px; }
  .wts-tile { min-height: 0; padding: 16px 13px; gap: 11px; }
  .wts-tile h3 { font-size: 10.5px; letter-spacing: 0.05em; }
  .wts-stat-list { gap: 11px; }
  .wts-stat-list .row { padding-bottom: 11px; }
  .wts-stat-list .value { font-size: 16px; }
  .wts-donut-legend { font-size: 11px; }
  .wts-map { margin: 0 20px 20px; }
  /* No-JS baseline for the stack: below this the side column cannot hold a tile
     and the map at the same time. setEcoLayout only ever ADDS .is-stacked, so it
     can never fight this rule. */
  .wts-map-row { margin: 0 20px 20px; grid-template-columns: minmax(0, 1fr); }
  .wts-eco { gap: 10px; }
  .wts-eco-tile { padding: 16px 13px; }
  .wts-eco-figure { font-size: 27px; }

  .wts-split { grid-template-columns: 1fr; }
  .wts-srv-row { grid-template-columns: 1fr; gap: 12px; }
  /* Button rows are nowrap by default, so a 3-button toolbar runs off under
     .wts-main's overflow:hidden and the buttons become unreachable. The inner
     groups are inline display:flex, hence the child selector. */
  .wts-row, .wts-toolbar, .wts-filterbar { flex-wrap: wrap; }
  .wts-row > div { flex-wrap: wrap; }
  /* Let the badges wrap onto their own line instead of widening the head. */
  .wts-acc-head { grid-template-columns: 24px 1fr; row-gap: 8px; }
  .wts-acc-head .badge-set { grid-column: 1 / -1; flex-wrap: wrap; }
}

@media (max-width: 620px) {
  /* Below this a stat label and its value no longer fit on one line, and the
     three legend entries no longer fit across the donut. */
  .wts-stat-list .row { flex-direction: column; align-items: flex-start; gap: 3px; }
  .wts-stat-list .label { font-size: 11.5px; gap: 6px; }
  .wts-stat-list .value { font-size: 15px; }
  .wts-stat-list .value small { font-size: 10.5px; margin-left: 3px; }
  .wts-donut-legend { flex-direction: column; align-items: flex-start; gap: 4px; }
}

@media (max-width: 560px) {
  .wts-header {
    height: auto; padding: 10px 16px;
    flex-wrap: wrap; gap: 10px;
  }
  .wts-brand { font-size: 17px; }
  .wts-nav { flex-wrap: wrap; gap: 4px; }
  .wts-nav a { padding: 7px 10px; font-size: 13px; }
  .wts-nav .nav-cta { margin-left: 0; }

  .wts-footer {
    flex-direction: column; align-items: flex-start; gap: 10px;
    padding: 20px 16px 18px;
  }
  .wts-footer .links { flex-wrap: wrap; gap: 12px; }

  .wts-main { padding: 16px 12px; }
  .wts-tile-row { gap: 7px; padding: 12px 10px; }
  .wts-tile { padding: 13px 10px; gap: 9px; border-radius: var(--wt-r-lg); }
  .wts-tile h3 { font-size: 9.5px; letter-spacing: 0.03em; }
  .wts-stat-list .label { font-size: 10.5px; gap: 5px; }
  .wts-stat-list .value { font-size: 13.5px; }
  .wts-donut-legend { font-size: 10.5px; }
  .wts-map { margin: 0 12px 16px; }
  .wts-map-row { margin: 0 12px 16px; gap: 10px; }
  .wts-eco-pop { max-width: min(260px, 86vw); }
  /* Two eco tiles no longer fit across a phone. */
  .wts-map-row.is-stacked .wts-eco { grid-template-columns: minmax(0, 1fr); }
  .wts-eco { gap: 7px; }
  .wts-eco-tile { padding: 13px 10px; gap: 8px; }
  .wts-eco-figure { font-size: 23px; }
  .wts-eco-figure small { font-size: 13px; }
  .wts-eco-art svg { max-width: 140px; }
  .wts-hero { padding: 24px 16px 20px; }
  .wts-hero h1 { font-size: 26px; }

  .wts-form-row,
  .wts-form-row.col-2,
  .wts-form-row.col-3 { grid-template-columns: 1fr; }
  /* The label sits above the input here - side by side there is no room. */
  .wts-form-row .field-h { flex-direction: column; align-items: stretch; gap: 4px; }
  .wts-form-row .field-h.toggle-row { flex-direction: row; align-items: center; }

  .wts-legal { padding: 24px 16px 40px; }
  .wts-legal-body h1 { font-size: 26px; }

  .wts-filterbar .search { min-width: 0; width: 100%; }
  .wts-auth-card { padding: 28px 20px; }
}

/* Floating scroll-to-top ------------------------------------------------
   Sits below bootstrap's modal layer (1055) on purpose, so an open dialog
   covers it instead of the button floating over the backdrop.
   Visibility is a class rather than the [hidden] attribute: this rule sets
   display:flex, which would win over [hidden]'s display:none, and a class
   also lets the appearance animate. Logic is wtsToTop* in indexBase.js. */
.wts-to-top {
  position: fixed;
  right: 20px;
  bottom: 20px;
  width: 44px;
  height: 44px;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  border: 1px solid var(--wt-border);
  border-radius: var(--wt-r-full);
  background: var(--wt-surface);
  color: var(--wt-ink-soft);
  box-shadow: var(--wt-shadow-md);
  cursor: pointer;
  z-index: 1030;
  opacity: 0;
  visibility: hidden;
  transform: translateY(8px);
  transition: opacity .18s ease, transform .18s ease, visibility .18s,
              background-color .15s ease, color .15s ease, border-color .15s ease;
}
.wts-to-top.is-visible { opacity: 1; visibility: visible; transform: none; }
.wts-to-top:hover {
  background: var(--wt-brand-soft);
  border-color: var(--wt-brand);
  color: var(--wt-brand-strong);
}
.wts-to-top:active { transform: translateY(1px); }
.wts-to-top:focus-visible { outline: 2px solid var(--wt-focus); outline-offset: 2px; }

@media (max-width: 620px) {
  /* Clear of the footer links and a thumb's reach on a phone. */
  .wts-to-top { right: 12px; bottom: 12px; width: 40px; height: 40px; }
}

@media (prefers-reduced-motion: reduce) {
  .wts-to-top { transition: opacity .01s, visibility .01s; transform: none; }
  .wts-to-top:active { transform: none; }
}
