:root {
  --cell: 140px;
  --bg-base: #0F172A; --bg-surface: #1E293B; --bg-empty: #0B1220;
  --border: #334155; --text-primary: #F1F5F9; --text-secondary: #94A3B8;
  --accent: #3B82F6; --positive: #22C55E; --positive-bg: #052E16;
  --negative: #EF4444; --negative-bg: #2D0A0A;
}
html.light {
  --bg-base: #F0F4F8; --bg-surface: #FFFFFF; --bg-empty: #E7ECF2;
  --border: #CBD5E1; --text-primary: #0F172A; --text-secondary: #475569;
  --accent: #2563EB; --positive: #16A34A; --positive-bg: #DCFCE7;
  --negative: #DC2626; --negative-bg: #FEE2E2;
}
* { transition: background-color 200ms ease, border-color 200ms ease, color 200ms ease; }
html, body {
  background: var(--bg-base);
  color: var(--text-primary);
  font-family: -apple-system, "Segoe UI", Roboto, sans-serif;
  margin: 0;
  height: 100%;
  touch-action: none;
}
/* App shell: header + collapsible sidebar + main content area. The
   sidebar lists apps — Dash is the only one today, but this is the shell
   any future app page reuses; a new app just adds a .sidebar-item plus
   its own <main> content. */
.app-shell { display: flex; flex-direction: column; height: 100vh; overflow: hidden; }

.app-header {
  flex-shrink: 0; height: 56px; display: flex; align-items: center; justify-content: space-between;
  padding: 0 16px; background: var(--bg-surface); border-bottom: 1px solid var(--border);
  box-shadow: 0 4px 16px rgba(0,0,0,.15); position: relative; z-index: 1100;
}
.app-header-left { display: flex; align-items: center; gap: 12px; }
.app-header-right { display: flex; align-items: center; gap: 10px; }

.sidebar-toggle {
  width: 34px; height: 34px; border-radius: 8px; flex-shrink: 0;
  background: var(--bg-empty); border: 1px solid var(--border); color: var(--text-primary);
  font-size: 16px; cursor: pointer; display: flex; align-items: center; justify-content: center;
}
.sidebar-toggle:hover { border-color: var(--accent); color: var(--accent); }

.app-logo { display: flex; align-items: center; gap: 6px; }

/* Two logo files — logo.png (black wordmark) for the light theme,
   logo-dark.png (white wordmark) for the dark theme. Only one is ever
   shown; toggled by the html.light class theme.js already applies. */
.logo-for-light { display: none; }
html.light .logo-for-dark { display: none; }
html.light .logo-for-light { display: inline-block; }

.app-logo-img { height: 26px; width: auto; }
.login-logo-img { height: 34px; width: auto; }

.app-body { flex: 1; display: flex; min-height: 0; }

.app-sidebar {
  flex-shrink: 0; width: 180px; overflow: hidden; box-sizing: border-box;
  background: var(--bg-surface); border-right: 1px solid var(--border);
  display: flex; flex-direction: column; padding: 10px 8px; gap: 2px;
  transition: width .2s ease, padding .2s ease;
}
.app-sidebar.collapsed { width: 0; padding-left: 0; padding-right: 0; border-right: none; }

.sidebar-item {
  display: flex; align-items: center; gap: 10px; padding: 9px 10px; border-radius: 8px;
  background: none; border: none; color: var(--text-secondary); font-size: 13px; font-weight: 600;
  cursor: pointer; text-align: left; white-space: nowrap; text-decoration: none;
}
.sidebar-item:hover { background: var(--bg-empty); }
.sidebar-item.active { background: rgba(59,130,246,.15); color: var(--accent); }
.sidebar-icon { font-size: 16px; flex-shrink: 0; }

.app-main { flex: 1; min-width: 0; position: relative; overflow: auto; }

.canvas {
  position: relative;
  width: 100%;
  min-height: 100%;
  box-sizing: border-box;
}
.cell {
  position: absolute;
  box-sizing: border-box;
}

/* Empty cells: visibility controlled via JS (.reveal class on #canvas) */
.cell.empty {
  display: flex; align-items: center; justify-content: center;
  font-size: 34px; color: var(--text-secondary);
  background: transparent;
  border: 1px solid transparent;
}
#canvas.reveal .cell.empty {
  background: var(--bg-empty);
  border-color: var(--border);
}
.plus-btn {
  background: none; border: none; color: inherit; font-size: 34px; line-height: 1;
  cursor: pointer; padding: 0; opacity: 0; pointer-events: none;
}
#canvas.reveal .plus-btn { opacity: 1; pointer-events: auto; }

.cell.filled { background: var(--bg-surface); border: 1px solid var(--border); }
.cell.drop-ok { outline: 2px solid var(--positive); outline-offset: -2px; background: var(--positive-bg); }
.cell.drop-bad { outline: 2px solid var(--negative); outline-offset: -2px; background: var(--negative-bg); }

/* Locked (default): tile is view-only — controls hidden, no interaction, no grab cursor.
   Todos and Note are the exception: they stay fully usable (check/add/
   edit/remove items, typing) even when locked, so they work as demo-able
   quick-capture widgets without making people unlock edit mode first.
   Resizing/removing the whole tile still requires edit mode via
   .tile-controls below. */
.tile { cursor: default; }
.tile-controls { opacity: 0; pointer-events: none; }
.clock-city, .weather-city, .news-manage-btn, .news-feed-remove, .news-done-btn { pointer-events: none; }
#canvas.reveal .tile { cursor: grab; }
#canvas.reveal .tile-controls { opacity: 1; pointer-events: auto; }
#canvas.reveal .clock-city, #canvas.reveal .weather-city,
#canvas.reveal .news-manage-btn, #canvas.reveal .news-feed-remove, #canvas.reveal .news-done-btn { pointer-events: auto; }
/* News headlines (read-only preview popup) stay clickable regardless of
   lock state, same reasoning as Todos/Note — only feed management above
   requires unlocking. */
/* Barometer edit button: always clickable when shown — it only renders at
   all for admins (IS_ADMIN check in app.js), so no extra lock-state gate
   is needed on top of that. */
.barometer-edit-btn { cursor: pointer; }

.tile {
  position: relative; width: 100%; height: 100%;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  text-align: center; padding: 10px; cursor: grab; box-sizing: border-box;
}
.tile.dragging-source { opacity: .25; }
.tile .label { font-size: 11px; text-transform: uppercase; letter-spacing: .04em; color: var(--text-secondary); margin-bottom: 4px; }
.tile .value { font-size: 18px; font-weight: 700; color: var(--text-primary); }
.tile .delta { font-size: 11px; font-weight: 600; margin-top: 4px; padding: 1px 6px; border-radius: 999px; }
.tile .delta.up { background: var(--positive-bg); color: var(--positive); }
.tile .delta.down { background: var(--negative-bg); color: var(--negative); }

.tile-controls { position: absolute; top: 6px; right: 6px; display: flex; gap: 4px; z-index: 2; }
.tile-btn {
  width: 20px; height: 20px; border-radius: 50%;
  background: var(--bg-empty); border: 1px solid var(--border); color: var(--text-secondary);
  font-size: 11px; line-height: 1; display: flex; align-items: center; justify-content: center; cursor: pointer;
}
.tile-btn:hover, .tile-btn:active { background: var(--negative-bg); border-color: var(--negative); color: var(--negative); }
.tile-btn.gear:hover, .tile-btn.gear:active { background: rgba(59,130,246,.15); border-color: var(--accent); color: var(--accent); }

/* Popups */
.popup-menu {
  position: fixed; background: var(--bg-surface); border: 1px solid var(--border); border-radius: 10px;
  box-shadow: 0 12px 32px rgba(0,0,0,.5); z-index: 1000; overflow: hidden; display: none; visibility: hidden;
}
.popup-menu.open { display: block; }
#addMenuPopup { width: 200px; }
#sizeMenuPopup { min-width: 90px; }
#newsPreviewPopup { width: 320px; border-radius: 14px; }
.news-preview { padding: 20px 22px 18px; display: flex; flex-direction: column; gap: 10px; }
.news-preview-title { font-size: 15px; font-weight: 700; color: var(--text-primary); line-height: 1.4; }
.news-preview-source {
  font-size: 10px; text-transform: uppercase; letter-spacing: .05em; color: var(--text-secondary);
  padding-bottom: 10px; border-bottom: 1px solid var(--border);
}
.news-preview-summary { font-size: 13px; color: var(--text-primary); line-height: 1.6; }
.news-preview-link {
  font-size: 12px; font-weight: 700; color: #fff; text-decoration: none; margin-top: 6px;
  background: var(--accent); border-radius: 8px; padding: 9px 14px; text-align: center;
}
.news-preview-link:hover { filter: brightness(1.08); }
.menu-item { padding: 12px 16px; font-size: 14px; color: var(--text-primary); cursor: pointer; border-bottom: 1px solid var(--border); }
.menu-item:last-child { border-bottom: none; }
.menu-item:hover, .menu-item:active { background: var(--bg-empty); }
.size-item { padding: 8px 14px; font-size: 13px; color: var(--text-primary); cursor: pointer; white-space: nowrap; border-bottom: 1px solid var(--border); }
.size-item:last-child { border-bottom: none; }
.size-item:hover, .size-item:active { background: var(--bg-empty); }
.size-item.current { color: var(--accent); font-weight: 700; }

/* Todos */
.todos-tile { align-items: stretch; justify-content: flex-start; padding: 10px 8px 8px; }
.todo-list { display: flex; flex-direction: column; gap: 4px; margin-top: 4px; overflow-y: auto; }
.todo-item { display: flex; align-items: center; gap: 6px; cursor: pointer; padding: 2px 0; }
.todo-check { width: 14px; height: 14px; min-width: 14px; border-radius: 4px; border: 1.5px solid var(--text-secondary); display: flex; align-items: center; justify-content: center; font-size: 10px; color: var(--bg-base); background: transparent; }
.todo-item.done .todo-check { background: var(--positive); border-color: var(--positive); }
.todo-text { font-size: 11px; text-align: left; color: var(--text-primary); line-height: 1.25; flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.todo-item.done .todo-text { text-decoration: line-through; color: var(--text-secondary); }
.todo-item-remove { font-size: 9px; color: var(--text-secondary); padding: 2px 3px; margin-left: auto; flex-shrink: 0; }
.todo-item-remove:hover, .todo-item-remove:active { color: var(--negative); }
.todo-add { font-size: 11px; color: var(--accent); cursor: pointer; padding: 3px 0 1px; text-align: left; }
.todo-input { width: 100%; background: var(--bg-base); border: 1px solid var(--accent); border-radius: 4px; color: var(--text-primary); font-size: 11px; padding: 2px 5px; box-sizing: border-box; }
.todo-input:focus { outline: none; }

/* World clock */
.clock-tile { align-items: stretch; justify-content: flex-start; padding: 10px 8px 8px; }
.clock-list { display: flex; flex-direction: column; gap: 6px; margin-top: 4px; overflow-y: auto; }
.clock-row { display: flex; align-items: center; justify-content: space-between; gap: 6px; padding: 2px 0; }
.clock-city { font-size: 11px; color: var(--text-primary); cursor: pointer; text-align: left; }
.clock-city:hover { color: var(--accent); }
.clock-time { font-size: 13px; font-weight: 700; color: var(--text-primary); font-variant-numeric: tabular-nums; }
.clock-select { font-size: 11px; background: var(--bg-base); border: 1px solid var(--accent); border-radius: 4px; color: var(--text-primary); padding: 1px 4px; }
.clock-select:focus { outline: none; }

/* Weather */
.weather-tile { align-items: stretch; justify-content: flex-start; padding: 10px 8px 8px; }
.weather-city { font-size: 11px; color: var(--accent); cursor: pointer; text-align: left; margin-top: 2px; }
.weather-city:hover { text-decoration: underline; }
.weather-main { display: flex; align-items: center; gap: 6px; margin-top: 6px; }
.weather-emoji { font-size: 22px; }
.weather-temp { font-size: 20px; font-weight: 700; color: var(--text-primary); }
.weather-desc { font-size: 11px; color: var(--text-secondary); margin-top: 2px; }
.weather-loading { font-size: 11px; color: var(--text-secondary); margin-top: 6px; }
.weather-search-wrap { display: flex; flex-direction: column; gap: 4px; width: 100%; }
.weather-search-input { width: 100%; background: var(--bg-base); border: 1px solid var(--accent); border-radius: 4px; color: var(--text-primary); font-size: 11px; padding: 3px 6px; box-sizing: border-box; }
.weather-search-input:focus { outline: none; }
.weather-search-results { display: flex; flex-direction: column; gap: 2px; max-height: 80px; overflow-y: auto; }
.weather-result { font-size: 10px; color: var(--text-primary); cursor: pointer; padding: 2px 4px; border-radius: 3px; text-align: left; }
.weather-result:hover { background: var(--bg-empty); }
.weather-result-empty { font-size: 10px; color: var(--text-secondary); padding: 2px 4px; }

/* Logo */
.logo-tile { justify-content: center; align-items: center; gap: 8px; }
.logo-display { display: flex; align-items: center; justify-content: center; width: 100%; height: 100%; min-height: 0; }
.logo-default { max-width: 85%; box-sizing: border-box; }
.logo-default-img { height: 44px; max-width: 100%; object-fit: contain; }
.logo-img { max-width: 100%; max-height: 100%; object-fit: contain; }
.logo-actions { position: absolute; bottom: 6px; right: 6px; display: flex; gap: 4px; opacity: 0; pointer-events: none; }
#canvas.reveal .logo-actions { opacity: 1; pointer-events: auto; }
.logo-upload-btn, .logo-reset-btn {
  width: 20px; height: 20px; border-radius: 50%;
  background: var(--bg-empty); border: 1px solid var(--border); color: var(--text-secondary);
  font-size: 11px; line-height: 1; display: flex; align-items: center; justify-content: center; cursor: pointer;
}
.logo-upload-btn:hover, .logo-reset-btn:hover { background: rgba(59,130,246,.15); border-color: var(--accent); color: var(--accent); }
.logo-file-input { display: none; }

/* News */
.news-tile { align-items: stretch; justify-content: flex-start; padding: 10px 8px 8px; }
.news-label { display: flex; justify-content: space-between; align-items: center; width: 100%; }
.news-manage-btn { font-size: 12px; color: var(--text-secondary); cursor: pointer; }
.news-manage-btn:hover { color: var(--accent); }
.news-list { display: flex; flex-direction: column; gap: 6px; margin-top: 4px; overflow-y: auto; }
.news-item { display: flex; flex-direction: column; text-decoration: none; padding: 3px 0; border-bottom: 1px solid var(--border); cursor: pointer; }
.news-item:last-child { border-bottom: none; }
.news-item-title { font-size: 11px; color: var(--text-primary); line-height: 1.25; text-align: left; }
.news-item-source { font-size: 9px; color: var(--text-secondary); margin-top: 1px; text-transform: uppercase; letter-spacing: .03em; text-align: left; }
.news-empty { font-size: 11px; color: var(--text-secondary); margin-top: 6px; }
.news-feed-list { display: flex; flex-direction: column; gap: 4px; margin-top: 4px; overflow-y: auto; }
.news-feed-row { display: flex; align-items: center; justify-content: space-between; gap: 6px; padding: 2px 0; }
.news-feed-name { font-size: 10px; color: var(--text-primary); text-align: left; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.news-feed-remove { font-size: 9px; color: var(--text-secondary); cursor: pointer; flex-shrink: 0; }
.news-feed-remove:hover { color: var(--negative); }
.news-add-row { margin-top: 6px; display: flex; flex-direction: column; gap: 2px; }
.news-add-input { width: 100%; background: var(--bg-base); border: 1px solid var(--accent); border-radius: 4px; color: var(--text-primary); font-size: 10px; padding: 3px 6px; box-sizing: border-box; }
.news-add-input:focus { outline: none; }
.news-add-error { font-size: 9px; color: var(--negative); min-height: 12px; }
.news-done-btn { font-size: 11px; color: var(--accent); cursor: pointer; text-align: center; margin-top: 4px; }

/* Roadwork / Trafikverket map */
.roadwork-tile { align-items: stretch; justify-content: flex-start; padding: 8px; }
.roadwork-search-row { margin-bottom: 6px; }
.roadwork-search-input { width: 100%; background: var(--bg-base); border: 1px solid var(--border); border-radius: 6px; color: var(--text-primary); font-size: 12px; padding: 6px 10px; box-sizing: border-box; }
.roadwork-search-input:focus { outline: none; border-color: var(--accent); }
.roadwork-map { flex: 1; width: 100%; min-height: 0; border-radius: 8px; overflow: hidden; background: var(--bg-empty); }
.roadwork-updated { flex-shrink: 0; margin-top: 4px; text-align: center; }

/* Trafikkamera */
.roadcamera-tile { align-items: stretch; justify-content: flex-start; padding: 8px; }
.roadcamera-search-row { position: relative; margin-bottom: 6px; }
.roadcamera-search-input { width: 100%; background: var(--bg-base); border: 1px solid var(--border); border-radius: 6px; color: var(--text-primary); font-size: 11px; padding: 5px 8px; box-sizing: border-box; }
.roadcamera-search-input:focus { outline: none; border-color: var(--accent); }
.roadcamera-search-results { position: absolute; top: 100%; left: 0; right: 0; z-index: 5; background: var(--bg-surface); border: 1px solid var(--border); border-radius: 6px; margin-top: 2px; max-height: 120px; overflow-y: auto; }
.roadcamera-search-results:empty { border: none; margin-top: 0; }
.roadcamera-result { font-size: 10px; color: var(--text-primary); padding: 4px 8px; cursor: pointer; text-align: left; }
.roadcamera-result:hover { background: var(--bg-empty); }
.roadcamera-result-empty { font-size: 10px; color: var(--text-secondary); padding: 4px 8px; }
.roadcamera-view { flex: 1; display: flex; flex-direction: column; min-height: 0; }
.roadcamera-img { width: 100%; flex: 1; min-height: 0; object-fit: cover; border-radius: 8px; background: var(--bg-empty); }
.roadcamera-caption { font-size: 10px; color: var(--text-secondary); margin-top: 4px; text-align: center; }
.roadcamera-empty { font-size: 11px; color: var(--text-secondary); margin-top: 8px; }

/* Note */
.note-tile { align-items: stretch; justify-content: flex-start; padding: 10px 8px 8px; }
.note-textarea {
  flex: 1; width: 100%; min-height: 0; resize: none;
  background: var(--bg-base); border: 1px solid var(--border); border-radius: 6px;
  color: var(--text-primary); font-size: 12px; line-height: 1.4; padding: 8px;
  box-sizing: border-box; font-family: inherit; margin-top: 4px;
}
.note-textarea:focus { outline: none; border-color: var(--accent); }

/* Färja */
.ferry-tile { align-items: stretch; justify-content: flex-start; padding: 10px 8px 8px; }
.ferry-search-row { position: relative; margin-bottom: 6px; }
.ferry-search-input { width: 100%; background: var(--bg-base); border: 1px solid var(--border); border-radius: 6px; color: var(--text-primary); font-size: 11px; padding: 5px 8px; box-sizing: border-box; }
.ferry-search-input:focus { outline: none; border-color: var(--accent); }
.ferry-search-results { position: absolute; top: 100%; left: 0; right: 0; z-index: 5; background: var(--bg-surface); border: 1px solid var(--border); border-radius: 6px; margin-top: 2px; max-height: 120px; overflow-y: auto; }
.ferry-search-results:empty { border: none; margin-top: 0; }
.ferry-result { font-size: 10px; color: var(--text-primary); padding: 4px 8px; cursor: pointer; text-align: left; }
.ferry-result:hover { background: var(--bg-empty); }
.ferry-result-empty { font-size: 10px; color: var(--text-secondary); padding: 4px 8px; }
.ferry-view { flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center; text-align: center; }
.ferry-route { font-size: 12px; font-weight: 700; color: var(--text-primary); }
.ferry-next-label { font-size: 10px; text-transform: uppercase; letter-spacing: .04em; color: var(--text-secondary); margin-top: 8px; }
.ferry-next-time { font-size: 22px; font-weight: 700; color: var(--text-primary); font-variant-numeric: tabular-nums; }
.ferry-status { font-size: 11px; color: var(--positive); margin-top: 4px; }
.ferry-empty { font-size: 11px; color: var(--text-secondary); margin-top: 8px; text-align: center; }

/* Transportbarometer */
.barometer-tile { align-items: stretch; justify-content: flex-start; padding: 10px 8px 8px; }
.barometer-relations { display: flex; flex-direction: column; gap: 10px; margin-top: 6px; overflow-y: auto; flex: 1; min-height: 0; }
.barometer-relation-label { display: flex; justify-content: space-between; align-items: center; font-size: 10px; font-weight: 700; text-transform: uppercase; letter-spacing: .03em; color: var(--text-primary); }
.barometer-edit-btn { font-size: 11px; color: var(--text-secondary); cursor: pointer; }
.barometer-edit-btn:hover { color: var(--accent); }
.barometer-bar { display: flex; height: 14px; border-radius: 7px; overflow: hidden; margin-top: 4px; }
.barometer-segment { height: 100%; }
.barometer-frakt { background: var(--accent); }
.barometer-lastrum { box-sizing: border-box; } /* background set inline per status color */
.barometer-values { display: flex; justify-content: space-between; margin-top: 3px; font-size: 10px; font-weight: 700; color: var(--text-primary); }
.barometer-status { display: flex; align-items: center; gap: 4px; font-size: 9px; font-weight: 700; color: var(--text-secondary); margin-top: 3px; }
.barometer-status-dot { width: 6px; height: 6px; border-radius: 50%; flex-shrink: 0; }
.barometer-updated { font-size: 8px; color: var(--text-secondary); margin-top: 2px; }
.barometer-empty { font-size: 10px; color: var(--text-secondary); margin-top: 4px; }
.barometer-source { font-size: 9px; color: var(--text-secondary); margin-top: auto; padding-top: 8px; text-align: center; text-decoration: none; }
.barometer-source:hover { color: var(--accent); text-decoration: underline; }
.barometer-edit-input { width: 56px; background: var(--bg-base); border: 1px solid var(--accent); border-radius: 4px; color: var(--text-primary); font-size: 11px; padding: 2px 4px; box-sizing: border-box; }
.barometer-edit-input:focus { outline: none; }

.diesel-sparkline { width: 80px; height: 20px; color: var(--accent); margin-top: 4px; }

/* Fokustimer — urgency colors override the tile's own background (not the
   cell's), so only this tile is affected. Contrast-checked: white text vs
   each of these two is 4.9:1+ (verified against WCAG, not eyeballed).
   Only yellow/red on purpose — no green — and the yellow-to-red switch is
   proportional to the chosen duration (see updateTimerColorTier), not a
   fixed absolute cutoff. */
.timer-tile { align-items: center; justify-content: center; gap: 4px; padding: 8px; transition: background-color .4s ease; }
.timer-tile-yellow { background: #a16207; }
.timer-tile-red { background: #b91c1c; }
.timer-tile-yellow .label, .timer-tile-red .label,
.timer-tile-yellow .timer-display, .timer-tile-red .timer-display,
.timer-tile-yellow .timer-slider-value, .timer-tile-red .timer-slider-value {
  color: #fff;
}
.timer-display { font-size: 28px; font-weight: 800; font-variant-numeric: tabular-nums; color: var(--text-primary); line-height: 1; }
.timer-controls { display: flex; gap: 6px; margin-top: 2px; }
.timer-btn {
  width: 24px; height: 24px; border-radius: 50%;
  background: var(--bg-empty); border: 1px solid var(--border); color: var(--text-secondary);
  font-size: 11px; cursor: pointer; display: flex; align-items: center; justify-content: center; padding: 0;
}
.timer-btn:hover { background: rgba(59,130,246,.15); border-color: var(--accent); color: var(--accent); }
/* On the saturated yellow/red backgrounds, the default theme-colored button
   would have poor contrast — flip to a translucent white treatment there. */
.timer-tile-yellow .timer-btn, .timer-tile-red .timer-btn {
  background: rgba(255,255,255,.25); border-color: rgba(255,255,255,.5); color: #fff;
}
.timer-tile-yellow .timer-btn:hover, .timer-tile-red .timer-btn:hover { background: rgba(255,255,255,.4); }
.timer-slider-row { display: flex; flex-direction: column; align-items: center; width: 100%; margin-top: 4px; gap: 2px; }
.timer-slider { width: 80%; height: 4px; cursor: pointer; }
.timer-slider-value { font-size: 10px; font-weight: 700; color: var(--text-primary); }

/* Drag ghost */
.ghost-tile {
  position: fixed; background: var(--bg-surface); border: 1px solid var(--accent); border-radius: 8px;
  display: flex; flex-direction: column; align-items: center; justify-content: center; text-align: center; padding: 8px;
  pointer-events: none; z-index: 1000; box-shadow: 0 12px 32px rgba(0,0,0,.5); opacity: .9;
}
.ghost-tile .label { font-size: 11px; text-transform: uppercase; letter-spacing: .04em; color: var(--text-secondary); margin-bottom: 4px; }
.ghost-tile .value { font-size: 18px; font-weight: 700; color: var(--text-primary); }

/* Greeting: now an in-flow header child (see .app-header), not
   independently fixed-positioned — that's what used to make it visually
   collide with widgets in the corner. */
.greeting {
  height: 34px; display: flex; align-items: center;
  padding: 0 16px; border-radius: 17px;
  background: var(--bg-empty); border: 1px solid var(--border); color: var(--text-primary);
  font-size: 13px; font-weight: 700;
}

/* Refresh timer: a circular progress wipe, one full sweep per 60s cycle —
   mirrors the actual auto-refresh cadence for weather/camera/roadwork.
   No number inside on purpose, just the wipe. */
.refresh-timer-wrap { display: flex; flex-direction: column; align-items: center; gap: 3px; cursor: help; }
.refresh-timer-label { font-size: 9px; text-transform: uppercase; letter-spacing: .04em; color: var(--text-secondary); white-space: nowrap; }
.refresh-timer {
  position: relative; width: 22px; height: 22px; flex-shrink: 0;
  border-radius: 50%; overflow: hidden;
  background: var(--bg-empty);
  border: 1px solid var(--border);
}
.rt-half { position: absolute; top: 0; left: 0; width: 50%; height: 100%; overflow: hidden; }
.rt-half-2 { transform-origin: 100% 50%; transform: rotate(180deg); }
.rt-mask {
  position: absolute; top: 0; left: -100%; width: 200%; height: 100%;
  background: var(--accent);
  transform-origin: 100% 50%;
}
.rt-mask-1 { animation: rt-rotate-1 60s linear infinite; }
.rt-mask-2 { animation: rt-rotate-2 60s linear infinite; }
@keyframes rt-rotate-1 {
  0%, 50% { transform: rotate(0deg); }
  100% { transform: rotate(180deg); }
}
@keyframes rt-rotate-2 {
  0% { transform: rotate(0deg); }
  50%, 100% { transform: rotate(180deg); }
}

/* Header icon buttons (theme/lock/logout) — in-flow now, sized to match
   .sidebar-toggle for a consistent header. */
.theme-toggle, .visibility-toggle, .logout-btn {
  width: 34px; height: 34px; border-radius: 50%; flex-shrink: 0;
  background: var(--bg-empty); border: 1px solid var(--border); color: var(--text-primary);
  font-size: 15px; cursor: pointer; display: flex; align-items: center; justify-content: center;
}
.visibility-toggle.forced-hidden { border-color: var(--negative); color: var(--negative); }
.logout-btn:hover { border-color: var(--negative); color: var(--negative); }

/* Standalone floating icon button — only used on login.html, which has no
   header/shell of its own to sit inside. */
.standalone-icon-btn {
  position: fixed; top: 14px; right: 14px; z-index: 1100;
  width: 38px; height: 38px; border-radius: 50%;
  background: var(--bg-surface); border: 1px solid var(--border); color: var(--text-primary);
  font-size: 16px; cursor: pointer; display: flex; align-items: center; justify-content: center;
  box-shadow: 0 4px 16px rgba(0,0,0,.3);
}

/* Login */
.login-wrap { min-height: 100vh; display: flex; align-items: center; justify-content: center; padding: 24px; box-sizing: border-box; }
.login-card { width: 100%; max-width: 340px; background: var(--bg-surface); border: 1px solid var(--border); border-radius: 14px; padding: 28px 24px; box-shadow: 0 12px 32px rgba(0,0,0,.3); box-sizing: border-box; }
.login-logo { display: flex; align-items: center; justify-content: center; margin-bottom: 18px; }
.login-title { font-size: 16px; font-weight: 700; text-align: center; margin: 0 0 18px; color: var(--text-primary); }
.login-label { display: block; font-size: 11px; text-transform: uppercase; letter-spacing: .04em; color: var(--text-secondary); margin: 12px 0 4px; }
.login-input { width: 100%; background: var(--bg-base); border: 1px solid var(--border); border-radius: 8px; color: var(--text-primary); font-size: 14px; padding: 9px 10px; box-sizing: border-box; }
.login-input:focus { outline: none; border-color: var(--accent); }
.login-error { font-size: 12px; color: var(--negative); min-height: 16px; margin-top: 10px; }
.login-hint { font-size: 13px; color: var(--text-secondary); text-align: center; line-height: 1.5; }
.login-submit { width: 100%; margin-top: 14px; padding: 10px; border: none; border-radius: 8px; background: var(--accent); color: #fff; font-size: 14px; font-weight: 700; cursor: pointer; }
.login-submit:disabled { opacity: .6; cursor: default; }
.login-submit:hover:not(:disabled) { filter: brightness(1.08); }
.login-toggle { text-align: center; margin-top: 16px; font-size: 12px; color: var(--text-secondary); }
.login-toggle a { color: var(--accent); text-decoration: none; margin-left: 4px; cursor: pointer; }
.login-toggle a:hover { text-decoration: underline; }
.login-optional { text-transform: none; letter-spacing: 0; font-weight: 400; color: var(--text-secondary); }
