:root {
  --color-bg: #0b0f14;
  --color-surface: #141a21;
  --color-surface-raised: #1c242d;
  --color-border: #2a3440;
  --color-text-primary: #f5f7fa;
  --color-text-secondary: #9aa5b1;
  --color-accent: #ffa000;
  --color-accent-contrast: #1a1200;
  --color-danger: #ff6b6b;

  /* Houle : une teinte à elle, pour ne pas la confondre avec la marée, qui garde
     l'orange d'accent. Le vent, lui, n'a pas de couleur propre — il prend celle
     de sa qualité (offshore / de travers / onshore). */
  --color-wave: #38bdf8;
  --color-offshore: #4ade80;
  --color-cross: #ffa000;
  --color-onshore: #ff6b6b;

  --gap: 1.2vh;
  --radius: 12px;

  /* Tailles pensées pour une lecture à distance (canapé / TV) */
  --font-size-base: 2.1vh;
  --font-size-header: 2.6vh;
  --font-size-large: 4vh;
  --font-size-small: 1.7vh;
}

* {
  box-sizing: border-box;
}

html, body {
  margin: 0;
  padding: 0;
  width: 100vw;
  height: 100vh;
  overflow: hidden;
  background: var(--color-bg);
  color: var(--color-text-primary);
  font-family: 'Segoe UI', Roboto, Arial, sans-serif;
  font-size: var(--font-size-base);
}

/* Scrollbars thémées (ex : défilement horizontal des heures météo) plutôt
   que la barre grise par défaut du navigateur, qui détonne sur fond sombre. */
* {
  scrollbar-width: thin;
  scrollbar-color: var(--color-border) var(--color-surface-raised);
}

*::-webkit-scrollbar {
  width: 0.8vh;
  height: 0.8vh;
}

*::-webkit-scrollbar-track {
  background: var(--color-surface-raised);
}

*::-webkit-scrollbar-thumb {
  background: var(--color-border);
  border-radius: 4px;
}

*::-webkit-scrollbar-thumb:hover {
  background: var(--color-accent);
}

.dashboard-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  grid-template-rows: 1fr 1fr;
  gap: var(--gap);
  width: 100vw;
  height: 100vh;
  padding: var(--gap);
}

.widget {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  padding: 1.5vh 1.5vw;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  min-width: 0;
  min-height: 0;
}

.widget-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.6vw;
  font-size: var(--font-size-header);
  font-weight: 700;
  letter-spacing: 0.02em;
  margin-bottom: 1vh;
  color: var(--color-text-primary);
  flex: 0 0 auto;
}

.widget-header-actions {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  gap: 0.6vw;
}

.widget-fullscreen-btn {
  flex: 0 0 auto;
  width: 3.4vh;
  height: 3.4vh;
  border-radius: 6px;
  border: 2px solid var(--color-border);
  background: var(--color-surface-raised);
  color: var(--color-text-secondary);
  font-size: 1.8vh;
  line-height: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: border-color 0.12s ease, transform 0.12s ease;
}

.widget-fullscreen-btn:hover,
.widget-fullscreen-btn:focus-visible {
  border-color: var(--color-accent);
  transform: scale(1.08);
}

/* Un seul quadrant visible, agrandi pour occuper toute la grille. Les
   autres widgets restent en vie dans le DOM (pas de re-render), juste
   masqués — sauf la webcam dont le lecteur unique n'est de toute façon
   jamais dupliqué (voir js/widgets/webcam.js). */
.dashboard-grid.has-fullscreen .widget {
  display: none;
}

.dashboard-grid.has-fullscreen .widget.is-fullscreen {
  display: flex;
  grid-column: 1 / -1;
  grid-row: 1 / -1;
}

.widget-stale {
  margin-top: auto;
  padding-top: 0.6vh;
  color: var(--color-danger);
  font-size: var(--font-size-small);
  flex: 0 0 auto;
}

/* État de focus télécommande : bien visible, contraste fort */
:focus-visible,
.is-focused {
  outline: 3px solid var(--color-accent);
  outline-offset: 2px;
}

button {
  font-family: inherit;
  color: inherit;
  cursor: pointer;
}

/* ------------------------------------------------------------- téléphone */

/* Sous ce seuil, l'écran est trop étroit pour la grille 2x2 pensée pour la TV :
   un widget n'y occuperait qu'un quart d'écran, illisible (voir les bandes du
   widget surf ou les heures du widget météo). On passe à un empilement
   vertical défilant, chaque widget retrouvant une hauteur proche de son état
   "plein écran" habituel plutôt que d'un quadrant. Le reste du CSS (thème,
   plein écran par quadrant...) s'applique tel quel par-dessus, sans dédoubler
   quoi que ce soit. Seuil dupliqué dans fullscreen.js (COMPACT_QUERY) : les
   deux doivent rester alignés. */
@media (max-width: 820px) {
  html, body {
    height: auto;
    min-height: 100vh;
    min-height: 100dvh;
    overflow-y: auto;
    overflow-x: hidden;
  }

  .dashboard-grid {
    grid-template-columns: 1fr;
    grid-template-rows: none;
    height: auto;
    min-height: 100vh;
    min-height: 100dvh;
  }

  /* Pas de hauteur forcée ici : chaque widget se dimensionne à son contenu
     (voir la règle mobile de chacun dans son propre fichier CSS — webcam.css,
     meteo.css, surf.css, tele.css — sans quoi elle perdrait la bataille de
     cascade face à la règle non conditionnelle du même sélecteur, chargée
     après base.css). Un widget plus court que les autres (météo) ne traîne
     plus une bande vide géante ; un widget qui a vraiment besoin de place
     (surf) la réclame lui-même. */

  /* Plein écran natif du navigateur (voir fullscreen.js) : le widget devenu
     l'élément plein écran doit occuper tout l'écran, quelle que soit sa
     hauteur naturelle dans l'empilement normal. Sert aussi de repli si le
     plein écran natif est refusé (WebView, permissions) : la grille CSS
     existante prend le relais avec la même règle. */
  .dashboard-grid.has-fullscreen .widget.is-fullscreen {
    min-height: 100vh;
    min-height: 100dvh;
  }

  /* Les boutons de tête (modes d'affichage, plein écran) peuvent être plus
     nombreux que ce qu'une largeur de téléphone permet sur une seule ligne :
     passer à la ligne plutôt que déborder hors du widget. */
  .widget-header {
    flex-wrap: wrap;
    row-gap: 0.6vh;
  }

  .widget-header-actions {
    flex-wrap: wrap;
    justify-content: flex-end;
  }
}
