/* Page styles: dashboard-konto - loaded by views/partials/header.ejs after
   Bootstrap and public/style/panel.css. Plain CSS, panel.css tokens only.
   Only what Bootstrap utilities and panel.css components cannot express
   (hooks set by scripts, few shared patterns of this page group). */

/* ---------------------------------------------------------------------------
   DASHBOARD: HEADER ROW (views/dash/dashboard.ejs)

   Key figures and news as two equal cards (.kopf-karte). scripts/check-
   dashboard.js guards the declarations this depends on - read it before
   changing anything here.
   --------------------------------------------------------------------------- */

/* The grid stretches both cards to the same height (no align-items: start -
   the shorter card would hang at the top again). 5/7 from lg when the news
   card is shown. */
.kopf-zeile { display: grid; gap: var(--z-gap); }
@media (min-width: 992px) {
  .kopf-zeile.mit-news { grid-template-columns: 5fr 7fr; }
}
.kopf-karte { min-width: 0; }

/* The key figure tiles. On the phone stacked: side by side "Offene Tickets"
   wraps and the tiles differ in height. Columns only from 576px (sm), and
   counted with 1fr as the upper bound of minmax() - a fixed upper bound
   makes the browser count fewer columns and the third tile drops into a
   second row although there is room. Overrides .raster-kpi from panel.css. */
.raster.kopf-kennzahlen { grid-template-columns: minmax(0, 1fr); gap: .75rem; max-width: 880px; }
@media (min-width: 576px) {
  .raster.kopf-kennzahlen { grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); }
  .kopf-kennzahlen > .kennzahl { max-width: 280px; }
}

/* News items: one line each, title cut with an ellipsis */
.news-raster { display: grid; gap: .5rem; }
@media (min-width: 576px) {
  .news-raster { grid-template-columns: repeat(auto-fit, minmax(235px, 1fr)); }
}
.news-item-modern {
  padding: .5rem .75rem;
  border: 1px solid var(--z-border);
  border-radius: var(--z-radius-sm);
  transition: background-color .15s ease;
}
.news-item-modern:hover { background: var(--z-hover); }

/* ---------------------------------------------------------------------------
   DASHBOARD: WIDGET GRID

   The width steps come from routes/userRoutes.js (WIDGET_BREITEN) and carry
   Bootstrap's column names; the dashboard script swaps them on the holder
   when the width button is pressed. Here they become spans of a
   twelve-column grid, at Bootstrap's breakpoints (md 768px, xxl 1400px).
   Bootstrap's own .col-* rules (flex/width) do nothing in a grid; the span
   rules below are what counts.
   --------------------------------------------------------------------------- */
.widget-ablage {
  display: grid;
  grid-template-columns: repeat(12, minmax(0, 1fr));
  gap: 1rem;
  min-height: 60px;
  border-radius: var(--z-radius);
  outline: 2px dashed transparent;
  outline-offset: 4px;
  transition: background-color .15s ease, outline-color .15s ease;
}
.widget-ablage > * { grid-column: 1 / -1; width: auto; max-width: none; }
@media (min-width: 768px) {
  .widget-ablage > .col-md-6 { grid-column: span 6 / span 6; }
  .widget-ablage > .col-md-12 { grid-column: span 12 / span 12; }
}
@media (min-width: 1400px) {
  .widget-ablage > .col-xxl-4 { grid-column: span 4 / span 4; }
  .widget-ablage > .col-xxl-6 { grid-column: span 6 / span 6; }
}
.widget-ablage > .col-12 { grid-column: 1 / -1; }

/* Only visible during a drag - otherwise the border is distracting */
.widget-ablage.zielbereit {
  background: rgba(var(--z-neutral-rgb), .05);
  outline-color: var(--user-accent, var(--z-accent));
}

.widget-halter { position: relative; min-width: 0; }

/* EDIT MODE. Everything depends on .bearbeiten on the widget area; only
   the side panel ("Widgets" button) sets it. Without it: no tools, no
   dragging, no grab cursor - a pure view. The tools must not catch clicks
   while hidden either. */
.widget-werkzeuge {
  position: absolute;
  top: .6rem;
  right: .6rem;
  z-index: 3;
  display: flex;
  gap: .25rem;
  opacity: 0;
  pointer-events: none;
  transition: opacity .15s ease;
}
/* Solid background: the tools lie over the card header */
.widget-werkzeuge .btn { --bs-btn-bg: var(--z-surface); --bs-btn-disabled-bg: var(--z-surface); }
.widget-ablage.bearbeiten .widget-halter:hover .widget-werkzeuge,
.widget-ablage.bearbeiten .widget-halter:focus-within .widget-werkzeuge {
  opacity: 1;
  pointer-events: auto;
}
.widget-ablage.bearbeiten .widget-halter {
  cursor: grab;
  border-radius: var(--z-radius);
  outline: 1px dashed rgba(var(--z-neutral-rgb), .3);
  outline-offset: 3px;
}
.widget-ablage.bearbeiten .widget-halter:active { cursor: grabbing; }
/* Drag and drop is hard to hit on a phone - there the arrow buttons are
   permanently visible, but still ONLY in edit mode. */
@media (max-width: 576px) {
  .widget-ablage.bearbeiten .widget-werkzeuge { opacity: 1; pointer-events: auto; }
}

/* The dragged widget / picker tile stays faded in its place */
.widget-halter.wird-gezogen,
.widget-kachel.wird-gezogen { opacity: .4; }

/* Where the widget would land: a bar in the gap before or after the tile */
.widget-halter.einfuegen-davor::before,
.widget-halter.einfuegen-danach::after {
  content: '';
  position: absolute;
  top: .25rem;
  bottom: .25rem;
  z-index: 4;
  width: 4px;
  border-radius: 2px;
  background: var(--user-accent, var(--z-accent));
}
.widget-halter.einfuegen-davor::before { left: calc(-.5rem - 2px); }
.widget-halter.einfuegen-danach::after { right: calc(-.5rem - 2px); }

/* Loading veil while a newly added widget is fetched (set by the script) */
.widget-laden {
  position: fixed;
  inset: 0;
  z-index: 2000;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: .75rem;
  background: rgba(15, 18, 24, .7);
  color: var(--z-text);
  font-size: var(--z-fs-small);
  backdrop-filter: blur(4px);
}

/* Inside the widgets: the user's accent colour on the title icon, rows
   with a small icon square, separated by lines */
.card-header .card-title > .bi.nutzer-akzent,
.nutzer-akzent { color: var(--user-accent, var(--z-accent)); }
.widget-liste > * + * { border-top: 1px solid var(--z-border); }
.widget-symbol {
  display: grid;
  flex: none;
  place-items: center;
  width: 2rem;
  height: 2rem;
  border: 1px solid var(--z-border);
  border-radius: var(--z-radius-sm);
  background: var(--z-hover);
  color: var(--z-muted);
}
.widget-link { color: var(--z-text); text-decoration: none; }
.widget-link:hover { color: var(--user-accent, var(--z-soft-primary)); text-decoration: underline; }

/* Density "compact" from the dashboard settings */
.is-compact .card {
  --bs-card-spacer-y: .7rem;
  --bs-card-spacer-x: .8rem;
  --bs-card-cap-padding-y: .55rem;
  --bs-card-cap-padding-x: .8rem;
}
.is-compact .card-header { min-height: 2.6rem; }

/* ---------------------------------------------------------------------------
   WIDGET PICKER (side panel)
   Deliberately an offcanvas without a backdrop: the picker sits next to the
   dashboard, not in front of it. Bootstrap's .offcanvas-end slides it in
   from the right; only the width is ours.
   --------------------------------------------------------------------------- */
.widget-seitenfenster { --bs-offcanvas-width: min(340px, 92vw); }

/* The flash messages sit at the bottom right and would lie over the panel.
   Instead of fiddling with layers they move aside while it is open; the
   dashboard script sets the class on <body>. */
body.widgets-offen .meldungen {
  right: calc(min(340px, 92vw) + 1rem);
  transition: right .3s ease;
}

.widget-kachel {
  display: flex;
  flex-direction: column;
  gap: .5rem;
  padding: .75rem;
  border: 1px solid var(--z-border);
  border-radius: var(--z-radius);
  background: var(--z-surface);
  cursor: grab;
  user-select: none;
  transition: background-color .15s ease, border-color .15s ease;
}
.widget-kachel:hover { background: var(--z-hover); border-color: var(--user-accent, var(--z-accent)); }
.widget-kachel:active { cursor: grabbing; }
/* Widgets already on the dashboard are set apart in the picker
   (server-rendered class, the drag script checks it) */
.widget-kachel.liegt-schon { opacity: .45; cursor: default; }
.widget-kachel.liegt-schon:hover { border-color: var(--z-border); background: var(--z-surface); }

/* Schematic preview in a picker tile: a list, a map, number tiles */
.vorschau {
  position: relative;
  display: block;
  height: 4rem;
  width: 100%;
  overflow: hidden;
  padding: .375rem;
  border: 1px solid var(--z-border);
  border-radius: var(--z-radius-sm);
  background: rgba(var(--z-neutral-rgb), .04);
}
.vorschau-kopf { display: block; height: .375rem; width: 42%; margin-bottom: .5rem; border-radius: 99px; background: rgba(255, 255, 255, .2); }
.vorschau-zeilen { display: flex; flex-direction: column; gap: .375rem; }
.vorschau-zeile { display: flex; align-items: center; gap: .375rem; }
.vorschau-strich { display: block; height: .375rem; border-radius: 99px; background: rgba(255, 255, 255, .15); }
.vorschau-marke { flex: none; width: .375rem; height: .375rem; border-radius: 2px; background: var(--user-accent, var(--z-accent)); }
.vorschau-rund { flex: none; width: .375rem; height: .375rem; border-radius: 50%; background: rgba(255, 255, 255, .3); }
.vorschau-frist { flex: none; margin-left: auto; width: 1.25rem; height: .5rem; border-radius: 99px; background: rgba(var(--z-warning-rgb), .6); }
.vorschau-karte { position: relative; display: block; height: 2.5rem; }
.vorschau-land { position: absolute; top: 12%; left: 8%; height: 74%; width: 66%; border-radius: 42% 58% 36% 64% / 54% 38% 62% 46%; background: rgba(255, 255, 255, .1); }
.vorschau-ort { position: absolute; width: .5rem; height: .5rem; margin: -.25rem 0 0 -.25rem; border-radius: 50%; background: var(--user-accent, var(--z-accent)); box-shadow: 0 0 0 2px rgba(255, 255, 255, .2); }
.vorschau-weg { position: absolute; top: 58%; left: 26%; height: 1px; width: 52%; transform-origin: top left; transform: rotate(-26deg); background: repeating-linear-gradient(90deg, var(--user-accent, var(--z-accent)) 0 4px, transparent 4px 7px); opacity: .8; }

/* ---------------------------------------------------------------------------
   LOCATION MAP (views/dash/widget-map.ejs, drawn by public/js/map.js)

   Stroke widths and font size come as variables from the script
   (--karte-strich etc.). They depend on the zoom: if they were fixed, lines
   and labels would grow when zooming in and plaster over the map.
   The dots and the route take the user's accent colour (--user-accent).
   --------------------------------------------------------------------------- */

/* THE HEIGHT COMES FROM THE LOCATIONS, NOT FROM A FIXED NUMBER.
   public/js/map.js computes the aspect ratio of the point cloud and sets it
   as `--karte-verhaeltnis` (limited to 1.2 … 2.2). min-height/max-height catch
   the extremes: on a phone the tile would otherwise be flat as a line, on a
   wide screen taller than half the screen. */
.karte-behaelter {
  position: relative;
  width: 100%;
  flex: 0 0 auto;
  aspect-ratio: var(--karte-verhaeltnis, 1.4);
  min-height: 260px;
  max-height: 500px;
  border-radius: var(--z-radius-sm);
  border: 1px solid var(--z-border);
  background: var(--z-bg);
  overflow: hidden;
}

/* In the dialog the map takes whatever the window offers - the point cloud's
   ratio doesn't apply here, because here you can drag and zoom. */
.karte-behaelter-gross {
  aspect-ratio: auto;
  min-height: min(66vh, 620px);
  max-height: none;
  flex: 1 1 auto;
}

/* The enlarge button inside the small map, bottom right */
.karte-vergroessern {
  position: absolute;
  right: .5rem;
  bottom: .5rem;
  z-index: 2;
  --bs-btn-bg: rgba(21, 26, 34, .9);
}

/* Wide, but not fullscreen. Bootstrap reads the width from this variable. */
.karte-dialog { --bs-modal-width: min(1600px, 88vw); }

.karte-svg { display: block; width: 100%; height: 100%; }
.karte-beweglich .karte-svg { cursor: grab; touch-action: none; }
.karte-zieht .karte-svg { cursor: grabbing; }

/* The graticule. The meridians are curves drawn as <path>; a <path> without
   a fill is FILLED BLACK in SVG, so fill: none is the essential part. */
.karte-netz line,
.karte-netz path {
  fill: none;
  stroke: rgba(255, 255, 255, .05);
  stroke-width: var(--karte-strich, 0.25);
}

/* Land understated, borders visible. Fixed width with non-scaling-stroke:
   it is in screen pixels, --karte-strich would make it a tenth of a pixel. */
.karte-land path {
  fill: rgba(255, 255, 255, .05);
  stroke: rgba(255, 255, 255, .38);
  stroke-width: 0.8;
  stroke-linejoin: round;
  vector-effect: non-scaling-stroke;
}

/* Dashed: not a measured route but the order of the locations west to east */
.karte-weg line {
  stroke: var(--user-accent, #6f42c1);
  stroke-width: calc(var(--karte-strich, 0.25) * 1.6);
  stroke-dasharray: calc(var(--karte-strich, 0.25) * 4) calc(var(--karte-strich, 0.25) * 3);
  opacity: .8;
}

/* Leader line from the dot to its displaced name */
.karte-fuehrung line {
  stroke: rgba(255, 255, 255, .45);
  stroke-width: var(--karte-strich, 0.25);
}

.karte-punkt {
  r: var(--karte-punkt, 1.1);
  fill: var(--user-accent, #6f42c1);
  stroke: rgba(255, 255, 255, .9);
  stroke-width: var(--karte-strich, 0.25);
}
.karte-hof {
  r: var(--karte-hof, 2.4);
  fill: var(--user-accent, #6f42c1);
  opacity: .2;
}

.karte-beschriftung {
  fill: rgba(250, 250, 250, .92);
  font-family: var(--z-font);
  font-size: var(--karte-schrift, 2.6px);
  font-weight: 600;
  paint-order: stroke;
  stroke: rgba(9, 9, 11, .7);
  stroke-width: calc(var(--karte-strich, 0.25) * 2.5);
  stroke-linejoin: round;
  /* Otherwise the text catches mouse events and the dot's title doesn't show */
  pointer-events: none;
}
.karte-punkte g { cursor: help; }

/* If the outline file doesn't load, the map stays usable with grid and dots */
.karte-ohne-umrisse::after {
  content: 'Umrisse konnten nicht geladen werden';
  position: absolute;
  left: .6rem;
  bottom: .5rem;
  font-size: var(--z-fs-xs);
  color: var(--z-muted);
}

@media (prefers-reduced-motion: reduce) {
  .karte-weg line { stroke-dasharray: none; }
}

/* ---------------------------------------------------------------------------
   SETTINGS (views/dash/settings.ejs)
   --------------------------------------------------------------------------- */

/* Tab panes: a column with gap, but only while shown */
.tab-content > .einstellungen-pane.active { display: flex; flex-direction: column; gap: var(--z-gap); }

/* Expandable entries (<details>) for hosters and notifications */
.hoster-eintrag { border: 1px solid var(--z-border); border-radius: var(--z-radius-sm); overflow: hidden; }
.hoster-eintrag[open] { background: rgba(255, 255, 255, .015); }
.hoster-eintrag > summary { display: flex; align-items: center; gap: .75rem; padding: .7rem 1rem; cursor: pointer; list-style: none; }
.hoster-eintrag > summary::-webkit-details-marker { display: none; }
.hoster-eintrag > summary:hover { background: var(--z-hover); }
.hoster-eintrag-symbol { flex: none; width: 1.5rem; text-align: center; font-size: 1rem; color: var(--z-muted); }
.hoster-eintrag-pfeil { flex: none; font-size: .75rem; color: var(--z-muted); transition: transform .15s ease; }
.hoster-eintrag[open] .hoster-eintrag-pfeil { transform: rotate(180deg); }
.hoster-eintrag-inhalt { border-top: 1px solid var(--z-border); padding: 1rem; }
.hoster-logo { flex: none; width: 1.5rem; height: 1.5rem; padding: .125rem; border-radius: var(--z-radius-xs); background: #fff; object-fit: contain; }
.hoster-logo-sm { width: 1.25rem; height: 1.25rem; }

/* State badge in the head of an expandable entry. The page script toggles
   "an" and the text when the switch (or the Discord address) changes. */
.hoster-marke {
  display: inline-flex;
  flex: none;
  align-items: center;
  gap: .4rem;
  white-space: nowrap;
  padding: .1rem .5rem;
  border: 1px solid var(--z-border);
  border-radius: var(--z-radius-xs);
  color: var(--z-muted);
  font-size: var(--z-fs-xs);
  font-weight: 500;
}
.hoster-marke::before {
  content: '';
  width: .375rem;
  height: .375rem;
  border-radius: 50%;
  background: var(--z-soft-neutral);
}
.hoster-marke.an { color: var(--z-text); }
.hoster-marke.an::before { background: var(--z-success); }

/* Secret field with the eye button inside */
.feld-mit-auge { position: relative; }
.feld-mit-auge > .form-control { padding-right: 2.5rem; }
.feld-mit-auge > .hoster-auge { position: absolute; top: 50%; right: .25rem; transform: translateY(-50%); }

/* Hetzner project rows */
.hetzner-projekt-zeile { display: grid; gap: .5rem; align-items: start; }
@media (min-width: 768px) { .hetzner-projekt-zeile { grid-template-columns: 2fr 3fr auto auto; } }
.hetzner-projekt-zeile > .projekt-stand { grid-column: 1 / -1; }

/* Proxmox card header: the button toggles a Bootstrap collapse */
.ausklapp-knopf { display: flex; width: 100%; align-items: center; justify-content: space-between; gap: .75rem; padding: 0; border: 0; background: none; color: inherit; text-align: left; }
.ausklapp-pfeil { color: var(--z-muted); transition: transform .15s ease; }
.ausklapp-knopf[aria-expanded="true"] .ausklapp-pfeil { transform: rotate(180deg); }

/* The guest picker is a Bootstrap dropdown as wide as its button */
.dropdown-menu.gast-menu { width: 100%; min-width: 0; padding: 0; overflow: hidden; }
.gast-liste { max-height: 17rem; }
.gast-zeile { display: flex; align-items: center; gap: .6rem; padding: .35rem .5rem; border-radius: var(--z-radius-xs); cursor: pointer; }
.gast-zeile:hover { background: var(--z-hover); }
.gast-typ { width: 2rem; justify-content: center; font-size: .68rem; font-weight: 700; letter-spacing: .03em; }
.gast-id { min-width: 2.6rem; }

/* "Beenden" full width on the phone */
@media (max-width: 575.98px) { .geraet-beenden, .geraet-beenden .btn { width: 100%; } }

@media (prefers-reduced-motion: reduce) {
  .hoster-eintrag-pfeil, .ausklapp-pfeil { transition: none; }
}
