:root {
  color-scheme: light dark;
  --bg: #f2f2f2;
  --surface: #ffffff;
  --surface-rgb: 255, 255, 255;
  --fg: #1a1a1a;
  --fg-muted: #6b6b6b;
  --border: #e0e0e0;
  --home-header-bg: #1A5276;
  --home-header-fg: #ffffff;
  --clock-bg: #000000;
  --clock-fg: #ffffff;
  --clock-analog-day: #ffffff;
  --clock-analog-night: #c9c9c9;
  --action-go-bg: #c8f2c0;
  --action-go-fg: #14531f;
  --action-stop-bg: #f7c9c9;
  --action-stop-fg: #6b1414;
}

:root[data-theme="dark"] {
  --bg: #14181c;
  --surface: #1e2328;
  --surface-rgb: 30, 35, 40;
  --fg: #e8e8e8;
  --fg-muted: #9aa0a6;
  --border: #2c3238;
  --clock-analog-day: #8a8a8a;
  --clock-analog-night: #4a4a4a;
  --action-go-bg: #1f3d24;
  --action-go-fg: #a3e8a3;
  --action-stop-bg: #3d1f1f;
  --action-stop-fg: #e8a3a3;
}

* { box-sizing: border-box; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--fg);
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
}

.pinned-header {
  position: sticky;
  top: 0;
  z-index: 100;
  background: var(--bg);
  border-bottom: 1px solid var(--border);
}

.site-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 12px 16px;
}

.site-title {
  flex: 1;
  text-align: center;
  font-size: 1.3rem;
  margin: 0;
}

.theme-toggle {
  position: relative;
  border: none;
  background: var(--border);
  border-radius: 999px;
  width: 52px;
  height: 28px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 3px 6px;
  cursor: pointer;
}

.theme-toggle-thumb {
  position: absolute;
  top: 2px;
  left: 2px;
  background: var(--surface);
  border-radius: 50%;
  width: 24px;
  height: 24px;
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.25);
  transition: transform 0.2s ease;
}

:root[data-theme="dark"] .theme-toggle-thumb {
  transform: translateX(24px);
}

.theme-toggle-icon {
  position: relative;
  font-size: 13px;
  opacity: 0.35;
  filter: grayscale(1);
  transition: opacity 0.2s ease, filter 0.2s ease;
}

.theme-toggle-icon[data-theme-icon="light"] {
  opacity: 1;
  filter: none;
}

:root[data-theme="dark"] .theme-toggle-icon[data-theme-icon="light"] {
  opacity: 0.35;
  filter: grayscale(1);
}

:root[data-theme="dark"] .theme-toggle-icon[data-theme-icon="dark"] {
  opacity: 1;
  filter: none;
}

.header-icons {
  display: flex;
  gap: 8px;
}

.icon-btn {
  border: none;
  background: var(--border);
  color: var(--fg);
  width: 32px;
  height: 32px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  font-weight: 600;
}

.search-row {
  display: flex;
  gap: 6px;
  padding: 0 16px 12px;
}

.search-engine {
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--surface);
  color: var(--fg);
  padding: 0 6px;
}

.search-input {
  flex: 1;
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 8px 12px;
  background: var(--surface);
  color: var(--fg);
  font-size: 1rem;
  min-width: 0;
}

.search-submit {
  border: 1px solid var(--border);
  background: var(--surface);
  color: var(--fg);
  border-radius: 8px;
  width: 40px;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
}

main {
  max-width: 900px;
  margin: 0 auto;
  padding-bottom: 32px;
}

.category {
  border-bottom: 1px solid var(--border);
}

.category:last-child {
  border-bottom: none;
}

/* .category-header is now a plain (non-button) container so it can hold two independently
   clickable controls side by side — .category-header-main (opens the category, matches the old
   header's full styling) and .category-collapse-btn (closes just this level, shown only while
   this category/subcategory is the currently open leaf). A <button> can't contain another
   <button>, which is why this moved off the header element itself — same pattern already used by
   .category-header--home's .home-header-actions. */
.category-header {
  width: 100%;
  display: flex;
  align-items: stretch;
  background: var(--surface);
  border-top: 3px solid var(--stripe-color, transparent);
}

.category-header-main {
  flex: 1;
  min-width: 0;
  display: flex;
  align-items: center;
  /* flex-start, not space-between — a leftover from when this button also held a chevron icon on
     the right (long gone). Its only two possible children now are the selection checkmark and the
     name; space-between shoved them to opposite far edges the instant the checkmark became
     visible, instead of sitting them side by side. */
  justify-content: flex-start;
  background: transparent;
  border: none;
  padding: 6px 14px 10px;
  cursor: pointer;
  font-size: 1rem;
  color: var(--fg);
  text-align: left;
}

.category-name {
  font-weight: 600;
  font-size: 1rem;
  margin: 0;
  /* --depth is set per-header (on .category-header, the wrapper both this and .category-collapse-btn
     live under) from script.js — a real DOM ancestor count, not a CSS self-incrementing custom
     property (that looked like the obvious approach but Chromium resolves a custom property
     referencing its own name to nothing, even meaning "the inherited value", treating it as
     circular). Only the title text indents — the header row itself (stripe, background, touch
     target, collapse button) stays full width at every depth, so neither shrinks no matter how
     deep the nesting goes. */
  padding-left: calc(var(--depth, 0) * 2ch);
}

.category-collapse-btn {
  flex-shrink: 0;
  border: none;
  background: transparent;
  color: var(--fg-muted);
  cursor: pointer;
  font-size: 0.8rem;
  padding: 6px 12px;
  /* Outdents on subcategories, mirroring .category-name's indent in the opposite direction, so a
     deeply-nested open subcategory's collapse button visually sets itself apart the same way its
     indented title already does. */
  margin-right: calc(var(--depth, 0) * 2ch);
}

.category-collapse-btn:hover,
.category-collapse-btn:focus-visible {
  color: var(--fg);
}

.category-collapse-btn[hidden] {
  display: none;
}

.category-header--home {
  /* Tappable/long-pressable across the whole bar now (select-Home-as-destination, long-press for
     Home Settings) — the +/▲ buttons in .home-header-actions keep their own cursor via
     .home-header-action-btn, a more specific selector than this one. */
  cursor: pointer;
  -webkit-touch-callout: none;
  -webkit-user-select: none;
  user-select: none;
  /* --home-color-bg/-fg (set inline, script.js) are Home's own user-pickable colors — distinct
     from --home-header-bg/-fg, which stay fixed defaults also reused as the app's general accent
     color elsewhere (buttons, borders). Falls back to those defaults until the user picks. */
  background: var(--home-color-bg, var(--home-header-bg));
  color: var(--home-color-fg, var(--home-header-fg));
  border-top: none;
  padding: 10px 14px;
  /* Anchored just below .pinned-header (also fixed, at top: 0) rather than the rest of Home's
     tiles, which keep scrolling away normally. --pinned-header-height is kept in sync by a
     ResizeObserver (script.js) since the pinned header's real height varies (alert ticker,
     hourly-forecast content, window resize) — a hardcoded pixel offset would drift out of sync
     with any of those. z-index sits below .pinned-header's (100) so that one stays on top when
     both are visible, but above ordinary scrolling content beneath it.
     position: fixed, not sticky — sticky only stays stuck within its own containing block
     (.category--home), and that section is exactly the header's own height plus Home's short
     tile-grid tall, so the header gets pushed off the moment that box's bottom scrolls past the
     sticky offset (i.e. the instant the next category, News, touches it). Fixed has no such
     containing-block edge case: it's anchored to the viewport, full stop. Left/width/max-width
     mirror main's own centered 900px column (main { max-width:900px; margin:0 auto }) so the
     header lines up with the content below it instead of stretching edge-to-edge on wide
     screens — on phone widths (this is mobile-first) that column is the full viewport anyway,
     so this is a no-op there. Removed from flow, so .category--home .tile-grid below reserves
     the matching space via padding-top: var(--home-header-height). */
  position: fixed;
  top: var(--pinned-header-height, 0px);
  left: 50%;
  transform: translateX(-50%);
  width: 100%;
  max-width: 900px;
  box-sizing: border-box;
  z-index: 90;
}

.category--home .tile-grid {
  /* Reserves the space .category-header--home used to occupy in normal flow before it became
     position: fixed (see that rule's comment) — kept live by the same ResizeObserver pattern
     as --pinned-header-height (script.js), not a hardcoded value. */
  padding-top: var(--home-header-height, 0px);
}

.category--home .category-header--home .category-name {
  color: var(--home-color-fg, var(--home-header-fg));
}

.home-header-actions {
  display: flex;
  gap: 2px;
  /* .category-header lost justify-content: space-between in Build 42's restructuring; regular
     category headers still push their collapse button to the right edge by coincidence
     (.category-header-main's flex: 1 fills the row regardless), but Home's plain <h2> + this div
     has nothing to do that — margin-left: auto pushes just this element over instead, without
     touching the (already-correct) regular category headers. */
  margin-left: auto;
}

.home-header-action-btn {
  border: none;
  background: transparent;
  color: var(--home-color-fg, var(--home-header-fg));
  opacity: 0.75;
  cursor: pointer;
  font-size: 0.8rem;
  line-height: 1;
  padding: 6px;
  border-radius: 4px;
}

.home-header-action-btn:hover,
.home-header-action-btn:focus-visible {
  opacity: 1;
  background: rgba(255, 255, 255, 0.15);
}

/* #create-btn only — collapse-all-btn (the header's other .home-header-action-btn) keeps the
   plain transparent icon-button look above, untouched. ID selector wins over the shared class
   rules (including its :hover) with no !important and regardless of source order, so this reads
   as a small green tile-like chip instead: same border-radius as a real .tile, the Cut/Paste
   action bar's existing green tokens (Build 47) rather than a third green being introduced. */
#create-btn {
  font-size: 1.6rem;
  line-height: 1;
  padding: 2px 12px;
  border-radius: 8px;
  background: var(--action-go-bg);
  color: var(--action-go-fg);
  opacity: 1;
}

#create-btn:hover,
#create-btn:focus-visible {
  opacity: 0.85;
  background: var(--action-go-bg);
}

.home-widgets {
  display: grid;
  /* 2fr/3fr reproduces the original 2-of-5 / 3-of-5 column split the widgets used when they
     still lived inside Home's 5-column tile-grid. */
  grid-template-columns: 2fr 3fr;
  gap: 3px;
  padding: 3px;
  background: var(--surface);
  /* Establishes this grid as the containing block for .hourly-panel's position:absolute +
     explicit grid-column placement — without this, an absolutely-positioned grid item falls
     back to the viewport as its containing block, ignoring the grid entirely. */
  position: relative;
}

.tile-grid {
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  gap: 3px;
  padding: 3px;
  background: var(--surface);
}

.tile-grid[hidden] {
  display: none;
}

.category-content[hidden] {
  display: none;
}

/* --depth itself is set per .category-name element from script.js (a real DOM ancestor count,
   not a CSS self-incrementing custom property — that looked like the obvious approach but
   Chromium resolves a custom property referencing its own name to nothing, even when the intent
   is "the inherited value", treating it as circular). A top-level category's --depth is 0 (no
   indent); each level of nesting adds another 2ch, to any depth. Supersedes Build 41's
   margin-left/margin-right on `.category-content > .category`, which shrank the entire header
   (stripe, touch target, and all) by 4ch per level — unusable at ~5 levels deep. The header row
   itself stays full width now; only the title text indents. */

.tile {
  position: relative;
  aspect-ratio: 1 / 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 2px;
  text-decoration: none;
  color: var(--fg);
  background: var(--surface);
  border: 1px solid var(--home-header-bg);
  border-radius: 8px;
  overflow: hidden;
  padding: 2px;
  touch-action: manipulation;
  -webkit-touch-callout: none;
  -webkit-user-select: none;
  user-select: none;
}

/* Info Blurb Management: ℹ️ badge, bottom-left corner — bottom-right is reserved for the
   Brazil-flag badge (Build Planner, not yet built), so the two never collide on the same tile. */
.tile-info-icon {
  position: absolute;
  right: 2px;
  bottom: 2px;
  font-size: 0.6rem;
  line-height: 1;
  background: var(--bg);
  border-radius: 50%;
  padding: 1px;
}

/* Visual Grouping Headers: a cosmetic divider inside one category's tile grid — spans the full
   grid width (not a grid cell of its own) so it reads as a section break, not a tile. Per the
   user: "basically just a line with a text description, followed by another line after it." */
.tile-divider {
  grid-column: 1 / -1;
  padding: 6px 2px 4px;
  touch-action: manipulation;
  -webkit-touch-callout: none;
  -webkit-user-select: none;
  user-select: none;
}

.tile-divider-label {
  display: block;
  font-size: 0.75rem;
  font-weight: 600;
  color: var(--fg-muted);
  padding-bottom: 4px;
  border-bottom: 1px solid var(--border);
}

/* Long-pressed and selected (Organize Mode's grouping kind) — same blue-outline treatment as a
   selected tile/reorg row, so it reads as one consistent "selected" language across the app. */
.tile-divider.tile-divider-selected {
  outline: 2px solid var(--stripe-color, #3B82C4);
  outline-offset: 2px;
  border-radius: 4px;
}

/* Replaces .tile-divider-label in place during inline rename (✏️ on the select-action-bar, or
   dropped straight into after ➕/creating one) — same type size/weight/color as the label it's
   standing in for, styled as a real input rather than plain text. */
.tile-divider-input {
  display: block;
  width: 100%;
  box-sizing: border-box;
  font: inherit;
  font-size: 0.75rem;
  font-weight: 600;
  color: var(--fg);
  background: var(--surface);
  border: none;
  border-bottom: 1px solid var(--stripe-color, #3B82C4);
  padding-bottom: 4px;
  margin-bottom: -1px;
}

.tile-divider-input:focus {
  outline: none;
}

.tile img {
  width: 75%;
  height: 75%;
  object-fit: contain;
  pointer-events: none;
  -webkit-touch-callout: none;
}

.tile span {
  font-size: 0.6rem;
  line-height: 1.2;
  text-align: center;
  overflow: hidden;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  max-width: 100%;
  color: var(--fg-muted);
}

.tile span.tile-name-wrap {
  font-size: 0.475rem;
  line-height: 0.595rem;
}

.tile-fallback span {
  font-size: 0.75rem;
  -webkit-line-clamp: 3;
}

/* --- Phase 2 Editing System, Part 2: Organize Mode (select + drag-and-drop, merged) ---
   touch-action: none applies for the whole select-mode session, not just once a drag has
   actually started — a real touchscreen can otherwise claim the gesture as a native scroll
   during the threshold-watching phase before a drag is detected as such. */

.tile-grid.select-mode .tile {
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.35);
  touch-action: none;
}

.tile.move-grabbed {
  box-shadow: 0 4px 14px rgba(0, 0, 0, 0.45), 0 0 0 2px var(--stripe-color, #3B82C4);
  transform: rotate(-3deg) scale(1.05);
  z-index: 10;
}

.tile.move-dragging {
  transition: none;
}

.widget {
  border-radius: 8px;
  overflow: hidden;
}

.clock-widget {
  aspect-ratio: 1 / 1;
  touch-action: manipulation;
  -webkit-touch-callout: none;
  -webkit-user-select: none;
  user-select: none;
  position: relative;
  border: 1px solid var(--home-header-bg);
}

.weather-widget {
  /* No explicit height: default grid align-items:stretch matches it to clock-widget's
     aspect-ratio-driven height, same as when both shared a row-span in the old 5-column grid. */
}

/* Popover, not a pushed-down block: anchored via grid placement to row 2 (the row right below
   the clock+weather widgets, which together span the full grid width), but taken out of grid
   flow via position:absolute so it floats over content beneath rather than displacing it.
   A grid container is the containing block for its own absolutely-positioned children with
   explicit grid-column placement, so no extra positioned wrapper is needed. */
.hourly-panel {
  grid-column: 1 / 3;
  /* Explicit grid-row is required here, not left to auto-placement: an absolutely-positioned
     grid item doesn't participate in normal collision-avoidance auto-placement (it's out of
     flow), so without this it defaults to row 1 and overlaps clock/weather instead of landing
     in row 2, right below them. */
  grid-row: 2;
  position: absolute;
  inset: 0 0 auto 0;
  z-index: 20;
  background: var(--surface);
  border: 1px solid var(--home-header-bg);
  border-radius: 0 0 10px 10px;
  box-shadow: 0 8px 16px rgba(0, 0, 0, 0.18);
  max-height: 0;
  opacity: 0;
  overflow: hidden;
  transition: max-height 0.28s ease, opacity 0.22s ease;
  pointer-events: none;
}

.hourly-panel.open {
  max-height: 190px;
  opacity: 1;
  pointer-events: auto;
}

/* Single scroll container: alert/time/graph/precip all stack vertically inside it and scroll
   horizontally together as one unit, so nothing needs manual scroll-position syncing. */
.hourly-strip {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: 8px 6px 6px;
  overflow-x: auto;
  overflow-y: hidden;
  -webkit-overflow-scrolling: touch;
}

.hourly-row {
  display: flex;
  gap: 0;
}

.hourly-cell {
  flex: 0 0 32px;
  width: 32px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 1px;
  font-size: 0.6rem;
  color: var(--fg-muted);
}

.hourly-cell.now {
  background: rgba(59, 130, 246, 0.14);
}

.hourly-row-alert .hourly-cell {
  height: 16px;
  flex-direction: row;
  gap: 2px;
}

.hourly-alert-icon {
  font-size: 0.54rem;
  line-height: 1;
}

.hourly-alert-dot {
  width: 5px;
  height: 5px;
  border-radius: 50%;
  flex: 0 0 auto;
}

.hourly-alert-dot.red { background: #dc2626; }
.hourly-alert-dot.orange { background: #f97316; }
.hourly-alert-dot.yellow { background: #eab308; }

.hourly-row-time .hourly-cell {
  height: 16px;
  font-size: 0.55rem;
  font-weight: 600;
}

.hourly-row-time .hourly-cell.now {
  color: var(--fg);
}

.hourly-temp-graph {
  display: block;
  height: 80px;
}

.hourly-graph-now-bg {
  fill: rgba(59, 130, 246, 0.14);
}

.hourly-graph-line {
  fill: none;
  stroke: #94a3b8;
  stroke-width: 1.5;
}

.hourly-graph-icon {
  font-size: 17.5px;
  text-anchor: middle;
  dominant-baseline: central;
}

.hourly-graph-label {
  font-size: 11.25px;
  font-weight: 600;
  text-anchor: middle;
  fill: var(--fg);
}

.hourly-row-precip .hourly-cell {
  height: 14px;
  color: #3b82f6;
  font-size: 0.55rem;
}

.clock-inner {
  display: flex;
  align-items: center;
  width: 100%;
  height: 100%;
  background: var(--clock-bg);
  text-decoration: none;
}

.clock-face {
  flex: 0 0 auto;
  height: 78%;
  aspect-ratio: 1 / 1;
  position: relative;
  font-variant-numeric: tabular-nums;
}

.clock-face[data-scheme="red-black"] { background: #000; color: #e6293f; }
.clock-face[data-scheme="blue-black"] { background: #000; color: #3b82f6; }
.clock-face[data-scheme="black-white"] { background: #000; color: #fff; }
.clock-face[data-scheme="white-black"] { background: #000; color: #fff; }
.clock-face[data-scheme="green-black"] { background: #000; color: #22c55e; }
.clock-face[data-scheme="orange-black"] { background: #000; color: #f97316; }
.clock-face[data-mode="analog"] { background: var(--clock-bg); }

.clock-face[data-scheme="black-white"] .clock-digits {
  background: #fff;
  color: #000;
  border-radius: 6px;
  padding: 0 8px;
}

.clock-digital {
  width: 100%;
  height: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  position: relative;
}

.clock-digital[hidden] {
  display: none;
}

.clock-digits {
  display: flex;
  flex-direction: column;
  align-items: center;
}

.clock-analog {
  width: 100%;
  height: 100%;
  display: block;
}

.clock-analog[hidden] {
  display: none;
}

.clock-ampm {
  position: absolute;
  top: 8%;
  left: 8%;
  font-size: 0.7rem;
  opacity: 0.8;
}

.clock-hour, .clock-minute {
  font-size: 3rem;
  line-height: 1.05;
  font-weight: 600;
}

.clock-tz-pill {
  position: absolute;
  bottom: 6px;
  right: 8px;
  color: var(--clock-fg);
  border: 1px solid currentColor;
  border-radius: 999px;
  padding: 1px 6px;
  font-size: 0.7rem;
  opacity: 0.85;
}

.clock-date {
  flex: 0 0 auto;
  margin-left: auto;
  padding-right: 6px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  color: var(--clock-fg);
  background: var(--clock-bg);
  font-size: 0.75rem;
  font-weight: 600;
  white-space: nowrap;
}

.clock-date-stack {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
  margin-top: 12px;
}

.weather-widget {
  background: var(--surface);
  border: 1px solid var(--home-header-bg);
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  padding: 6px 8px;
  font-size: 0.7rem;
  touch-action: manipulation;
  -webkit-touch-callout: none;
  -webkit-user-select: none;
  user-select: none;
  position: relative;
  z-index: 0;
}

.weather-skin {
  position: absolute;
  inset: 0;
  z-index: -1;
  overflow: hidden;
  pointer-events: none;
}

/* Explicit z-index layering, not DOM append order — stars < cloud tint overlay < precipitation
   < floating clouds < lightning flash. This lets renderWeatherSkin() leave untouched layers
   (especially the CSS-animated clouds) alone in the DOM on every call instead of re-appending
   them just to keep them visually on top; re-appending an already-connected element turned out
   to disturb its running animation-delay-based position. */
.weather-skin-stars {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
  z-index: 1;
}

.weather-skin-overlay {
  position: absolute;
  inset: 0;
  background: #4b5563;
  pointer-events: none;
  z-index: 2;
}

.weather-skin-precip {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
  z-index: 3;
}

.wx-skin-cloud {
  position: absolute;
  left: calc(-1 * var(--cloud-w, 40px));
  font-size: 1rem;
  animation-name: wx-cloud-drift;
  animation-timing-function: linear;
  animation-iteration-count: infinite;
  pointer-events: none;
  opacity: 0.9;
  z-index: 4;
}

.weather-skin-flash {
  position: absolute;
  inset: 0;
  background: #eaf2ff;
  opacity: 0;
  pointer-events: none;
  z-index: 5;
}

@keyframes wx-cloud-drift {
  from { left: calc(-1 * var(--cloud-w, 40px)); }
  to { left: calc(100% + var(--cloud-w, 40px)); }
}

.weather-widget.no-white-bg {
  background: transparent;
}

.weather-widget.test-text-stroke * {
  -webkit-text-stroke: 0.5px #808080;
  text-stroke: 0.5px #808080;
  paint-order: stroke fill;
}

.weather-top {
  display: flex;
  align-items: flex-start;
}

.weather-extras {
  flex: 0 0 50%;
  display: flex;
  justify-content: space-between;
  color: var(--wx-text-color, var(--fg-muted));
}

.wx-stack {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1px;
}

.wx-stack[hidden] {
  display: none;
}

.weather-location {
  flex: 0 0 50%;
  text-align: right;
  color: var(--wx-text-color, var(--fg-muted));
}

.wx-icon {
  font-size: 1.2em;
}

.weather-middle {
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.weather-temp,
.weather-emoji {
  border: none;
  background: none;
  padding: 0;
  cursor: pointer;
  color: var(--fg);
  font-family: inherit;
}

.weather-temp {
  font-size: 3.6rem;
  font-weight: 600;
  color: var(--wx-text-color, var(--fg-muted));
}

.weather-unit {
  font-size: 1.4rem;
  font-weight: 400;
  color: var(--wx-text-color, var(--fg-muted));
}

.weather-emoji {
  font-size: 3.6rem;
}

.weather-bottom {
  display: flex;
  align-items: baseline;
  color: var(--wx-text-color, var(--fg-muted));
}

.weather-hilo {
  flex: 0 0 50%;
}

.weather-desc {
  flex: 0 0 50%;
  text-align: right;
}

.weather-hilo .hi {
  color: #d0342c;
}

.weather-hilo .lo {
  color: #2563eb;
}

.weather-footer-row {
  min-height: 1.5em;
  display: flex;
  align-items: center;
}

.weather-footer {
  flex: 1;
  display: flex;
  justify-content: space-between;
  color: var(--wx-text-color, var(--fg-muted));
}

.weather-footer[hidden] {
  display: none;
}

.weather-alert-ticker {
  flex: 1;
  width: 100%;
  overflow: hidden;
  background: #b91c1c;
  border: none;
  border-radius: 4px;
  padding: 2px 0;
  cursor: pointer;
}

.weather-alert-ticker[hidden] {
  display: none;
}

.weather-alert-track {
  display: inline-block;
  white-space: nowrap;
  padding-left: 100%;
  color: #fff;
  font-size: 0.7rem;
  font-weight: 600;
  animation-name: wx-alert-scroll;
  /* animation-duration is set inline by applyAlertTicker() (script.js), computed from the
     track's actual rendered width so every message scrolls at the same constant px/sec
     regardless of length — a fixed duration here would scale on-screen speed with message
     length instead (translateX(-100%) is relative to this element's own width, not the
     container's). This value only matters for the instant before that JS ever runs. */
  animation-duration: 14s;
  animation-timing-function: linear;
  animation-iteration-count: infinite;
}

@keyframes wx-alert-scroll {
  from { transform: translateX(0); }
  to { transform: translateX(-100%); }
}

.uv-badge.uv-low { color: #2e8b3d; }
.uv-badge.uv-moderate { color: #d4a017; }
.uv-badge.uv-veryhigh { color: #d0342c; }
.uv-badge.uv-extreme { color: #9b30c9; }

.help-overlay {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.5);
  align-items: flex-start;
  justify-content: center;
  padding: 20px;
  /* Anchored flush to the very top of the screen instead of vertically centered — an on-screen
     keyboard covers the bottom of the viewport, which used to hide a centered (or lower) popup
     entirely. Deliberately NOT reserving space for the pinned header (theme/title/icons + search
     bar): the dimmed backdrop already makes everything behind the popup unusable, so there's no
     reason to leave room above it for controls nobody can reach anyway — just the same flat 20px
     as every other edge. */
  /* Above .pinned-header (100) so popups render on top of it rather than behind it. */
  z-index: 200;
}

.help-overlay:not([hidden]) {
  display: flex;
}

.help-panel {
  background: var(--surface);
  color: var(--fg);
  border-radius: 12px;
  padding: 24px;
  max-width: 480px;
  width: 100%;
  position: relative;
  max-height: 80vh;
  overflow-y: auto;
  touch-action: manipulation;
  -webkit-touch-callout: none;
  -webkit-user-select: none;
  user-select: none;
}

/* Testing Panel docks to the bottom half of the screen instead of covering it fully, so the
   weather widget stays visible above it while picking a testing option — Settings/Help stay
   full-screen centered modals via the shared .help-overlay rules above. */
#testing-panel-overlay {
  align-items: flex-end;
  justify-content: stretch;
  padding: 0;
}

#testing-panel-overlay .help-panel {
  max-width: none;
  width: 100%;
  height: 50vh;
  max-height: 50vh;
  border-radius: 12px 12px 0 0;
}

.help-close {
  position: absolute;
  top: 10px;
  right: 10px;
  border: none;
  background: none;
  font-size: 1.4rem;
  cursor: pointer;
  color: var(--fg);
}

.options-section {
  margin-top: 18px;
}

.testing-panel-trigger {
  display: block;
  margin: 24px auto;
  padding: 8px 16px;
  border: 1px dashed var(--fg-muted);
  border-radius: 8px;
  background: var(--surface);
  color: var(--fg-muted);
  font-size: 0.85rem;
  cursor: pointer;
}

.testing-note {
  font-size: 0.8rem;
  color: var(--fg-muted);
  margin: 8px 0 0;
}

.testing-swatch-row {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-top: 6px;
  font-size: 0.8rem;
  color: var(--fg-muted);
}

.testing-swatch {
  display: inline-block;
  width: 20px;
  height: 20px;
  border-radius: 4px;
  border: 1px solid var(--border);
}

.testing-reset-btn {
  margin-top: 20px;
  width: 100%;
  padding: 10px;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--bg);
  color: var(--fg);
  font-size: 0.9rem;
  cursor: pointer;
}

.testing-debug-output {
  width: 100%;
  margin-top: 8px;
  padding: 8px;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--surface);
  color: var(--fg);
  font-family: monospace;
  font-size: 0.75rem;
  white-space: pre;
  resize: vertical;
  box-sizing: border-box;
}

#test-time-input {
  border: 1px solid var(--border);
  border-radius: 6px;
  background: var(--surface);
  color: var(--fg);
  padding: 4px 6px;
}

.options-section h3 {
  font-size: 0.8rem;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--fg-muted);
  margin: 0 0 8px;
}

.testing-subhead {
  font-size: 0.72rem;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  color: var(--fg-muted);
  opacity: 0.75;
  margin: 14px 0 4px;
}

.option-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 8px 0;
  border-bottom: 1px solid var(--border);
  font-size: 0.95rem;
}

/* Edit Category dialog's Sort Tiles row — three immediate-action buttons (not a form field),
   each sorting that category's own direct tiles only. Non-destructive/instant per spec, so no
   confirmation and the dialog stays open for trying another order. */
.category-sort-actions {
  display: flex;
  gap: 8px;
}

.category-sort-btn {
  flex: 1;
  padding: 8px 4px;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--bg);
  color: var(--fg);
  font-size: 0.8rem;
  cursor: pointer;
}

.category-sort-btn:hover,
.category-sort-btn:focus-visible {
  border-color: var(--fg-muted);
}

/* Category Color / Home header color pickers — default swatches, a native <input type="color">
   for a wider palette, and a hex field, kept in sync both ways. Doesn't try to match the
   reference mock-up's own "Choose" dropdown pixel-for-pixel, per the user — same capability,
   simpler shape. */
.color-picker-row {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-top: 8px;
  flex-wrap: wrap;
}

.color-swatch-row {
  display: flex;
  gap: 6px;
  flex-wrap: wrap;
}

.color-swatch-btn {
  width: 26px;
  height: 26px;
  border-radius: 50%;
  border: 1px solid var(--border);
  padding: 0;
  cursor: pointer;
}

.color-picker-native {
  width: 32px;
  height: 32px;
  padding: 0;
  border: 1px solid var(--border);
  border-radius: 6px;
  background: none;
  cursor: pointer;
  flex-shrink: 0;
}

.color-picker-hex {
  width: 90px;
  border: 1px solid var(--border);
  border-radius: 6px;
  background: var(--surface);
  color: var(--fg);
  padding: 6px 8px;
  font-size: 0.85rem;
  font-family: monospace;
}

.color-picker-none-btn {
  border: 1px solid var(--border);
  border-radius: 6px;
  background: var(--bg);
  color: var(--fg-muted);
  padding: 6px 10px;
  font-size: 0.8rem;
  cursor: pointer;
}

.option-row:last-child {
  border-bottom: none;
}

.add-category-error {
  color: var(--action-stop-fg);
  background: var(--action-stop-bg);
  border-radius: 8px;
  padding: 8px 10px;
  font-size: 0.85rem;
  margin: 8px 0 0;
}

.add-category-error[hidden] {
  display: none;
}

/* Remove Category's impact count (tile/subcategory/combined total) — neutral, not the error-red
   treatment above, since showing it isn't itself a warning; it's informational and shown even in
   the low-friction (no typed confirmation) tier whenever there's anything nested. */
#tile-confirm-counts {
  color: var(--fg-muted);
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 8px 10px;
  font-size: 0.85rem;
  margin: 8px 0 0;
}

#tile-confirm-type-input {
  border: 1px solid var(--border);
  border-radius: 6px;
  background: var(--surface);
  color: var(--fg);
  padding: 8px 10px;
  font-size: 0.9rem;
  margin-top: 12px;
}

.option-row input[type="checkbox"],
.option-row input[type="radio"] {
  width: 20px;
  height: 20px;
  accent-color: var(--home-header-bg);
}

.segmented {
  display: inline-flex;
  border: 1px solid var(--border);
  border-radius: 8px;
  overflow: hidden;
}

.segmented button {
  border: none;
  background: var(--bg);
  color: var(--fg);
  padding: 4px 10px;
  font-size: 0.85rem;
  cursor: pointer;
}

.segmented button.active {
  background: var(--home-header-bg);
  color: var(--home-header-fg);
}

.scheme-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 10px;
}

.scheme-swatch {
  border: 2px solid var(--border);
  border-radius: 8px;
  padding: 0;
  cursor: pointer;
  overflow: hidden;
  background: none;
}

.scheme-swatch.active {
  border-color: var(--home-header-bg);
}

.mini-clock {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 4px;
  padding: 10px 0;
  font-size: 1rem;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}

.mini-clock[data-scheme="red-black"] { background: #000; color: #e6293f; }
.mini-clock[data-scheme="blue-black"] { background: #000; color: #3b82f6; }
.mini-clock[data-scheme="black-white"] { background: #fff; color: #000; }
.mini-clock[data-scheme="white-black"] { background: #000; color: #fff; }
.mini-clock[data-scheme="green-black"] { background: #000; color: #22c55e; }
.mini-clock[data-scheme="orange-black"] { background: #000; color: #f97316; }

.analog-preview-wrap {
  display: flex;
  justify-content: center;
  padding: 8px 0;
}

.analog-preview-svg {
  width: 140px;
  height: 140px;
}

.analog-style-swatch {
  border: 2px solid var(--border);
  border-radius: 8px;
  padding: 6px;
  cursor: pointer;
  overflow: hidden;
  background: var(--surface);
  display: flex;
  justify-content: center;
}

.analog-style-swatch.active {
  border-color: var(--home-header-bg);
}

.analog-style-swatch[hidden] {
  display: none;
}

.analog-style-preview-svg {
  width: 64px;
  height: 64px;
}

/* --- Tile-style action buttons: originally the tile-menu popup's own styling (Rename/Move/
   Select/Delete), but the popup itself is retired — these classes are still live, shared with
   the "+" Create menu's "+ Tile"/"+ Category" buttons (index.html, #create-menu-overlay). --- */

.tile-menu-actions {
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  gap: 8px;
  margin-top: 16px;
}

.tile-menu-action {
  aspect-ratio: 1 / 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 4px;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--surface);
  color: var(--fg);
  font-family: inherit;
  cursor: pointer;
  padding: 4px;
}

.tile-menu-action:hover,
.tile-menu-action:focus-visible {
  background: var(--home-header-bg);
  color: #fff;
}

.tile-menu-icon {
  font-size: 1.4rem;
  line-height: 1;
}

.tile-menu-action-label {
  font-size: 0.65rem;
  line-height: 1.1;
  text-align: center;
}

/* --- Multi-select batch move --- */

.tile.tile-selected {
  position: relative;
  outline: 3px solid var(--stripe-color, var(--home-header-bg));
  outline-offset: -3px;
  /* Scale/lift feedback, per the spec — reuses .tile.move-grabbed's own scale+shadow treatment
     below, minus its rotate: selection lifts, it doesn't tilt. */
  transform: scale(1.05);
  box-shadow: 0 4px 14px rgba(0, 0, 0, 0.45), 0 0 0 2px var(--stripe-color, #3B82C4);
  z-index: 5;
}

.tile.tile-selected::after {
  content: '\2713';
  position: absolute;
  top: 3px;
  right: 3px;
  width: 16px;
  height: 16px;
  border-radius: 50%;
  background: var(--stripe-color, var(--home-header-bg));
  color: #fff;
  font-size: 0.6rem;
  display: flex;
  align-items: center;
  justify-content: center;
}

.select-action-bar {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 100;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  background: var(--surface);
  border-top: 1px solid var(--border);
  padding: 10px 14px;
  box-shadow: 0 -2px 10px rgba(0, 0, 0, 0.15);
}

.select-action-bar[hidden] {
  display: none;
}

.select-action-status {
  font-size: 0.8rem;
  color: var(--fg-muted);
  flex: 1;
  min-width: 0;
}

.select-action-icons {
  display: flex;
  gap: 6px;
  flex-shrink: 0;
}

/* Icon-only square buttons — Select All, Cut, Rename/Edit, Paste, Delete, Clear, in that order
   (the order chosen for the safety goal: Delete sits at the far end next to Clear, not sandwiched
   between the frequently-tapped Cut/Paste). */
.select-action-icon-btn {
  width: 38px;
  height: 38px;
  display: flex;
  align-items: center;
  justify-content: center;
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 0;
  font-size: 1.1rem;
  line-height: 1;
  cursor: pointer;
  background: var(--surface);
  color: var(--fg);
}

.select-action-icon-btn:disabled {
  opacity: 0.4;
  cursor: default;
}

.select-action-icon-btn.select-action-cut,
.select-action-icon-btn.select-action-paste {
  background: var(--action-go-bg);
  color: var(--action-go-fg);
  border-color: var(--action-go-bg);
}

.select-action-icon-btn.select-action-delete {
  background: var(--action-stop-bg);
  color: var(--action-stop-fg);
  border-color: var(--action-stop-bg);
}

/* --- Phase 2 Part 4: Whole-Structure Reorg Tree Tool ---
   A genuine full-screen replacement view, not a .help-overlay modal — opaque background, no
   dimmed backdrop, covers everything including the pinned header (z-index above both .pinned-
   header's 100 and .help-overlay's 200) since nothing behind it should be reachable while open. */
#reorg-view {
  position: fixed;
  inset: 0;
  z-index: 300;
  background: var(--bg);
  color: var(--fg);
  flex-direction: column;
}

#reorg-view:not([hidden]) {
  display: flex;
}

.reorg-header {
  flex-shrink: 0;
  padding: 16px 16px 8px;
  border-bottom: 1px solid var(--border);
}

.reorg-header h2 {
  margin: 0 0 4px;
}

.reorg-list {
  flex: 1;
  overflow-y: auto;
  padding: 8px 16px;
  position: relative;
}

.reorg-row {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 10px 8px;
  border-radius: 8px;
  background: var(--surface);
  border: 1px solid var(--border);
  margin-bottom: 6px;
  -webkit-user-select: none;
  user-select: none;
  /* Indentation represents nesting depth — set per-row from script.js, same --depth pattern
     .category-name already uses for the live accordion. */
  margin-left: calc(var(--depth, 0) * 2ch);
}

.reorg-row-handle {
  flex-shrink: 0;
  color: var(--fg-muted);
  font-size: 1.1rem;
  cursor: grab;
  /* Dragging is gated on this handle specifically, not the whole row (script.js) — touch-action
     stays scoped to match, so the rest of the row (including the name) keeps its default
     touch-action and scrolls normally instead of every pixel being a drag target. */
  touch-action: none;
  padding: 4px 8px;
  margin: -4px -8px;
}

.reorg-row-name {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.reorg-row.reorg-row-dragging {
  position: relative;
  z-index: 10;
  box-shadow: 0 4px 14px rgba(0, 0, 0, 0.35);
  transition: none;
}

.reorg-row.reorg-row-invalid {
  border-color: var(--action-stop-bg);
  box-shadow: 0 0 0 2px var(--action-stop-bg);
}

/* Home — shown for context but greyed out and non-interactive for every function this tool
   offers (can't be moved, renamed, or nested under; every real top-level category effectively
   sits as its child). */
.reorg-row.reorg-row-home {
  opacity: 0.5;
  cursor: default;
}

.reorg-row.reorg-row-home .reorg-row-handle {
  cursor: default;
}

/* Toolbar (Properties/New Category/New Subcategory/Remove Category) + the row-select model it
   acts on — replaces the old in-list "+ New Category" row entirely, now folded into the New
   Category button here. */
.reorg-toolbar {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-top: 10px;
}

.reorg-toolbar-btn {
  flex: 1 1 calc(50% - 4px);
  padding: 8px 4px;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--bg);
  color: var(--fg);
  font-size: 0.8rem;
  cursor: pointer;
}

.reorg-toolbar-btn:disabled {
  opacity: 0.4;
  cursor: default;
}

.reorg-toolbar-btn-danger:not(:disabled) {
  background: var(--action-stop-bg);
  color: var(--action-stop-fg);
  border-color: var(--action-stop-bg);
}

.reorg-row-arrow {
  flex-shrink: 0;
  width: 20px;
  height: 20px;
  display: flex;
  align-items: center;
  justify-content: center;
  border: none;
  background: none;
  color: var(--fg-muted);
  font-size: 0.7rem;
  padding: 0;
  cursor: pointer;
}

/* A leaf row still reserves the arrow's own width (invisible, non-interactive) so every row's
   name lines up at the same starting column regardless of whether it has children. */
.reorg-row-arrow-empty {
  visibility: hidden;
  cursor: default;
}

.reorg-row.reorg-row-selected {
  border-color: var(--stripe-color, #3B82C4);
  box-shadow: 0 0 0 2px var(--stripe-color, #3B82C4);
}

.reorg-move-row {
  flex-shrink: 0;
  display: flex;
  gap: 10px;
  padding: 8px 16px;
  border-top: 1px solid var(--border);
}

.reorg-move-row .reorg-toolbar-btn {
  flex: 1;
}

.reorg-footer {
  flex-shrink: 0;
  display: flex;
  gap: 10px;
  padding: 12px 16px;
  border-top: 1px solid var(--border);
}

.reorg-footer .testing-reset-btn {
  margin-top: 0;
  flex: 1;
}

#reorg-cancel-btn {
  background: var(--bg);
}

#reorg-save-btn {
  background: var(--action-go-bg);
  color: var(--action-go-fg);
  border-color: var(--action-go-bg);
}

/* Above #reorg-view's own 300, since this dialog needs to appear on top of it while open. */
#reorg-new-category-overlay {
  z-index: 310;
}

/* Visual Grouping Headers: management list in the Edit Category dialog, alongside Sort Tiles. */
.grouping-list {
  margin-bottom: 8px;
}

.grouping-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  padding: 8px 0;
  border-bottom: 1px solid var(--border);
}

.grouping-row-name {
  flex: 1;
  font-size: 0.9rem;
}

.grouping-row-btn {
  border: none;
  background: none;
  font-size: 1rem;
  cursor: pointer;
  padding: 4px;
}

.grouping-add-btn {
  width: 100%;
  margin-top: 4px;
}

/* Reorg Tree Tool's Properties button (script.js) opens this same live Edit Category dialog
   while #reorg-view (z-index 300) is still open behind it — needs to sit above it, since Properties
   was previously only ever reachable from the live page with no full-screen view in the way. */
#add-category-overlay {
  z-index: 320;
}

/* Explicit, not left to DOM-order-at-equal-z-index luck: a confirmation is the most urgent thing
   on screen whenever it's shown, so it always sits above every other overlay — including Reorg's
   own Remove Category confirm (Reorg Tree Tool -> Properties/Edit Category -> confirm) and a
   grouping delete confirm (which briefly hides the Reorg view entirely to reveal the live grid
   underneath, rather than stacking above it — see revealLiveGridForGrouping, script.js). */
#tile-confirm-overlay {
  z-index: 340;
}
