/* ---------------------------------------------------------------------------
   Developer site — shared stylesheet.

   No external requests: no web font, no CDN, no framework. The page is the
   product's first performance claim, and a render-blocking font request would
   contradict it before a single number is read. Typography carries the
   personality through scale, weight and tracking instead of through a face
   nobody else has.

   The palette is a temperature scale, because the subject is temperature:
   `--cold` for the archive and heating, `--warm` for heat and cooling. Those
   two are reserved for data that actually means hot or cold. Everything
   structural is ink on chart paper.
--------------------------------------------------------------------------- */

:root {
  --ink: #0d1b21;
  --ink-soft: #4d6069;
  --ink-faint: #7d8f96;
  --paper: #edf0ec;
  --card: #ffffff;
  --line: #d5dad3;
  --line-soft: #e4e8e2;
  --cold: #0b5d7a;
  --cold-soft: #e0ebf0;
  --warm: #c2451b;
  --warm-soft: #f7e6de;
  --ok: #1d6b4f;
  /* Text drawn on top of --cold. Dark mode lightens the accent, so the
     readable foreground flips with it. */
  --on-accent: #ffffff;

  --mono: ui-monospace, "SF Mono", SFMono-Regular, "Cascadia Mono", Menlo,
    Consolas, "Liberation Mono", monospace;
  --sans: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue",
    Arial, sans-serif;

  --shell: 1140px;
  --radius: 10px;
  --shadow: 0 1px 2px rgba(13, 27, 33, .05), 0 8px 24px -16px rgba(13, 27, 33, .35);
}

/* Light is the base, and dark is an override — in two places rather than one.
   The media query is the reader's *system* preference and applies unless they
   picked light explicitly; the attribute is the reader's own choice, set on
   <html> by the header control and remembered in localStorage. A single media
   query cannot express "system says dark but this person said light", which is
   exactly the case a theme switch exists for. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --ink: #e4eae7;
    --ink-soft: #93a5ad;
    --ink-faint: #6d7f88;
    --paper: #0e1417;
    --card: #151c20;
    --line: #263136;
    --line-soft: #1d262a;
    --cold: #62b6d9;
    --cold-soft: #12303c;
    --warm: #f1774a;
    --warm-soft: #35190f;
    --ok: #5cbd95;
    --on-accent: #08191f;
    --shadow: 0 1px 2px rgba(0, 0, 0, .4), 0 8px 24px -16px rgba(0, 0, 0, .8);
  }
}

:root[data-theme="dark"] {
    --ink: #e4eae7;
    --ink-soft: #93a5ad;
    --ink-faint: #6d7f88;
    --paper: #0e1417;
    --card: #151c20;
    --line: #263136;
    --line-soft: #1d262a;
    --cold: #62b6d9;
    --cold-soft: #12303c;
    --warm: #f1774a;
    --warm-soft: #35190f;
    --ok: #5cbd95;
    --on-accent: #08191f;
    --shadow: 0 1px 2px rgba(0, 0, 0, .4), 0 8px 24px -16px rgba(0, 0, 0, .8);
}

* { box-sizing: border-box; }

html {
  scroll-behavior: smooth;
  scroll-padding-top: 5rem;
  -webkit-text-size-adjust: 100%;
}

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font: 17px/1.62 var(--sans);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
  }
}

a { color: var(--cold); text-decoration-thickness: 1px; text-underline-offset: 2px; }
a:hover { color: var(--ink); }

:focus-visible {
  outline: 2px solid var(--cold);
  outline-offset: 3px;
  border-radius: 3px;
}

.skip {
  position: absolute;
  inset-inline-start: -9999px;
  top: .5rem;
  background: var(--card);
  border: 1px solid var(--line);
  padding: .6rem 1rem;
  border-radius: var(--radius);
  z-index: 100;
}
.skip:focus { inset-inline-start: .75rem; }

/* --- shell and rhythm ---------------------------------------------------- */

.shell {
  width: 100%;
  max-width: var(--shell);
  margin: 0 auto;
  padding: 0 1.25rem;
}

.band { padding: 4.5rem 0; }
.band--tight { padding: 3rem 0; }
.band--card { background: var(--card); border-block: 1px solid var(--line-soft); }

@media (max-width: 700px) {
  .band { padding: 3rem 0; }
}

/* --- header -------------------------------------------------------------- */

.site-head {
  position: sticky;
  top: 0;
  z-index: 40;
  background: color-mix(in srgb, var(--paper) 88%, transparent);
  backdrop-filter: saturate(160%) blur(10px);
  border-bottom: 1px solid var(--line);
}

.site-head__in {
  display: flex;
  align-items: center;
  gap: 1.5rem;
  min-height: 60px;
}

.brand {
  display: inline-flex;
  align-items: baseline;
  gap: .5rem;
  font-family: var(--mono);
  font-size: .84rem;
  font-weight: 600;
  letter-spacing: .02em;
  color: var(--ink);
  text-decoration: none;
  white-space: nowrap;
}
.brand b { color: var(--cold); font-weight: 600; }
.brand span {
  font-size: .62rem;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--ink-faint);
}

.site-nav {
  display: flex;
  align-items: center;
  gap: 1.4rem;
  margin-inline-start: 1.6rem;
  font-size: .9rem;
}
.site-nav a { color: var(--ink-soft); text-decoration: none; }
.site-nav a:hover, .site-nav a[aria-current] { color: var(--ink); }
.site-nav a[aria-current] { text-decoration: underline; text-decoration-color: var(--cold); text-decoration-thickness: 2px; }

@media (max-width: 1180px) {
  .site-nav { gap: 1rem; font-size: .86rem; margin-inline-start: 1rem; }
}

/* Les très petits écrans — 320 px, l'iPhone SE de première génération et les
   Android d'entrée de gamme.
   La barre d'en-tête ne se replie pas (`nowrap`, et c'est voulu : un en-tête
   collant sur deux lignes mange un tiers de la hauteur utile d'un tel écran).
   Elle demandait 328 px là où la coquille en offrait 280, et c'est le CORPS de
   chaque page qui défilait alors latéralement de 28 px — sur les quarante-huit
   pages à la fois, puisque l'en-tête est partagé.
   On resserre au lieu de retirer : le sélecteur de langue, le thème et le menu
   restent tous atteignables. Seul le libellé « EN » du sélecteur disparaît, et
   il était redondant — l'icône globe, le `title` et l'`aria-label` disent déjà
   ce que fait le bouton, et la langue courante porte `aria-current` dans le
   panneau. Mesuré : 348 px → 320 px, sans rien perdre d'autre. */
@media (max-width: 400px) {
  .shell { padding: 0 .75rem; }
  .site-head__in { gap: .5rem; }
  .head-tools { gap: .15rem; }
  .brand { font-size: .78rem; }
  .head-tools .pop > summary > span { display: none; }
  .theme button { padding: .25rem .3rem; }
  .tool { padding: .3rem .35rem; }
}

/* --- type ---------------------------------------------------------------- */

.eyebrow {
  font-family: var(--mono);
  font-size: .68rem;
  letter-spacing: .17em;
  text-transform: uppercase;
  color: var(--ink-faint);
  margin: 0 0 .9rem;
}
.eyebrow b { color: var(--cold); font-weight: 600; }

.display {
  font-size: clamp(2.15rem, 5.2vw, 3.5rem);
  line-height: 1.03;
  letter-spacing: -.033em;
  font-weight: 700;
  margin: 0 0 1.1rem;
  max-width: 18ch;
}
.display em { font-style: normal; color: var(--cold); }

h2 {
  font-size: clamp(1.5rem, 3.2vw, 2.05rem);
  line-height: 1.15;
  letter-spacing: -.024em;
  font-weight: 700;
  margin: 0 0 .8rem;
  max-width: 22ch;
}

h3 {
  font-size: 1.08rem;
  line-height: 1.35;
  letter-spacing: -.01em;
  margin: 0 0 .4rem;
}

.lede {
  font-size: clamp(1.05rem, 1.8vw, 1.22rem);
  line-height: 1.55;
  color: var(--ink-soft);
  max-width: 60ch;
  margin: 0 0 1.8rem;
}

/* `break-word` et non `anywhere` : on ne coupe QUE le mot qui ne tiendrait sur
   aucune ligne, jamais un mot ordinaire pour gagner de la place. La différence
   se voit sur les pages légales de la console, qui partagent cette feuille :
   la mention obligatoire de l'Autorité de protection des données porte
   `https://www.autoriteprotectiondonnees.be`, quarante caractères sans une
   espace, et le paragraphe débordait de 27 px sur un écran de 320 px. Une
   mention légale qu'on ne peut pas lire en entier est le mauvais endroit où
   économiser une règle. */
.prose { max-width: 66ch; overflow-wrap: break-word; }
.prose p { margin: 0 0 1rem; }
.prose ul { margin: 0 0 1rem; padding-inline-start: 1.1rem; }
.prose li { margin: .35rem 0; }

.muted { color: var(--ink-soft); }
.small { font-size: .88rem; }

.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
}

/* --- calls to action ----------------------------------------------------- */

.cta-row {
  display: flex;
  flex-wrap: wrap;
  gap: .7rem;
  align-items: center;
}

.cta {
  display: inline-flex;
  align-items: center;
  gap: .5rem;
  padding: .72rem 1.25rem;
  border-radius: var(--radius);
  font-size: .95rem;
  font-weight: 600;
  text-decoration: none;
  border: 1px solid transparent;
  transition: transform .12s ease, background .12s ease, border-color .12s ease;
}
.cta:active { transform: translateY(1px); }

.cta--primary { background: var(--cold); color: var(--on-accent); }
.cta--primary:hover { background: var(--ink); color: var(--paper); }

.cta--ghost { border-color: var(--line); color: var(--ink); background: var(--card); }
.cta--ghost:hover { border-color: var(--cold); color: var(--cold); }

/* Header size: matches the 34px of the controls beside it, so the row has one
   baseline instead of three. */
.cta--sm { height: 34px; padding: 0 .85rem; font-size: .82rem; border-radius: 8px; }

.cta-note {
  font-size: .84rem;
  color: var(--ink-faint);
  margin: .9rem 0 0;
}

/* --- hero ---------------------------------------------------------------- */

/* The hero states the thesis in words; the signature figure gets the full
   column width immediately below it, because at half width its year ticks stop
   being readable and the figure stops being evidence. */
.hero { padding: 3.5rem 0 2rem; }

/* Le haut de page est centré, la figure qui le suit occupe toute la coquille :
   alignés à gauche, le titre et le chapô tenaient sur la moitié gauche et
   laissaient un vide à droite que la figure, elle, ne laisse pas — la page
   avait l'air désaxée alors que les deux blocs partagent la même coquille.
   On centre la boîte (`margin-inline: auto`) SANS toucher aux `max-width` :
   la mesure du titre et du chapô est réglée pour douze langues, et l'élargir
   ici recasserait les césures en arabe ou en allemand pour rien.
   Les quatre pages (accueil, météo, degrés-jours, climat) partagent ce
   gabarit, donc la règle porte sur `.hero` et le générateur ne bouge pas. */
.hero .shell { text-align: center; }
.hero .display,
.hero .lede { margin-inline: auto; }
.hero .cta-row { justify-content: center; }

/* --- the signature figures ----------------------------------------------- */

.figure {
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: 1.1rem 1.1rem .9rem;
}
.figure svg { display: block; width: 100%; height: auto; }
.figure__cap {
  font-family: var(--mono);
  font-size: .68rem;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--ink-faint);
  margin: .8rem 0 0;
  display: flex;
  flex-wrap: wrap;
  gap: .35rem 1rem;
}
.figure__cap b { color: var(--ink-soft); font-weight: 600; }

/* Generated figures. Structure uses currentColor so one figure serves both
   themes; only the two data colours are named. */
.fx { color: var(--ink); overflow: visible; }
.fx-tick {
  font-family: var(--mono);
  font-size: 10px;
  fill: var(--ink-faint);
  letter-spacing: .06em;
}
.fx-now { fill: var(--ink-soft); font-weight: 600; }
.fx-label {
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: .16em;
  text-transform: uppercase;
  fill: var(--ink-faint);
}
.fx-res {
  font-family: var(--mono);
  font-size: 13px;
  font-weight: 600;
  fill: var(--ink);
  letter-spacing: -.01em;
}

.fx-draw {
  stroke-dasharray: var(--len, 2000);
  stroke-dashoffset: var(--len, 2000);
  animation: fx-draw 1.6s cubic-bezier(.2, .7, .3, 1) .2s forwards;
}
@keyframes fx-draw { to { stroke-dashoffset: 0; } }

.fx-fade { opacity: 0; animation: fx-fade 1s ease 1.1s forwards; }
@keyframes fx-fade { to { opacity: 1; } }

@media (prefers-reduced-motion: reduce) {
  .fx-draw { stroke-dashoffset: 0; }
  .fx-fade { opacity: 1; }
}

/* --- cards --------------------------------------------------------------- */

.grid { display: grid; gap: 1.1rem; }
.grid--2 { grid-template-columns: repeat(auto-fit, minmax(290px, 1fr)); }
.grid--3 { grid-template-columns: repeat(auto-fit, minmax(230px, 1fr)); }

.card {
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 1.35rem 1.4rem;
}
.card p { margin: .45rem 0 0; color: var(--ink-soft); font-size: .95rem; }
.card p:first-of-type { margin-top: .5rem; }

.card--link {
  display: flex;
  flex-direction: column;
  text-decoration: none;
  color: inherit;
  transition: border-color .14s ease, transform .14s ease;
}
.card--link:hover { border-color: var(--cold); transform: translateY(-2px); color: inherit; }
.card--link .card__more {
  margin-top: auto;
  padding-top: 1rem;
  font-weight: 600;
  font-size: .92rem;
  color: var(--cold);
}

.card__kicker {
  font-family: var(--mono);
  font-size: .66rem;
  letter-spacing: .15em;
  text-transform: uppercase;
  color: var(--ink-faint);
  margin: 0 0 .55rem;
}

/* --- stats --------------------------------------------------------------- */

.stats {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: 1px;
  background: var(--line);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  overflow: hidden;
}
.stat { background: var(--card); padding: 1.15rem 1.2rem; }
.stat__value {
  font-family: var(--mono);
  font-size: 1.5rem;
  font-weight: 600;
  letter-spacing: -.02em;
  line-height: 1.1;
  color: var(--ink);
  font-variant-numeric: tabular-nums;
}
.stat__value small { font-size: .8rem; color: var(--ink-faint); font-weight: 500; }
.stat__label {
  font-size: .82rem;
  color: var(--ink-soft);
  margin: .35rem 0 0;
  line-height: 1.35;
}

/* --- tables -------------------------------------------------------------- */

.table-wrap {
  overflow-x: auto;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--card);
}
table { width: 100%; border-collapse: collapse; font-size: .9rem; }
th, td {
  text-align: start;
  padding: .62rem .85rem;
  border-bottom: 1px solid var(--line-soft);
  vertical-align: top;
}
tbody tr:last-child td { border-bottom: 0; }
th {
  font-family: var(--mono);
  font-weight: 600;
  font-size: .68rem;
  letter-spacing: .11em;
  text-transform: uppercase;
  color: var(--ink-faint);
  white-space: nowrap;
  border-bottom-color: var(--line);
}
td.num { font-family: var(--mono); font-variant-numeric: tabular-nums; white-space: nowrap; }
tr.is-highlight td { background: var(--cold-soft); }

/* --- code ---------------------------------------------------------------- */

code {
  font-family: var(--mono);
  font-size: .875em;
  background: var(--line-soft);
  padding: .1em .34em;
  border-radius: 4px;
  /* Un identifiant ou une URL n'a pas d'espace où se couper, et le corps de la
     page se mettait alors à défiler LATÉRALEMENT sur mobile : 79 px de trop sur
     /start, à cause du seul `https://api.climatememory.com/v1/forecast/city/
     fr/paris` de la table des formes de ville. `anywhere` et non `break-word`
     parce que seul le premier est pris en compte pour calculer la largeur
     minimale d'une cellule de tableau — et c'est dans une table que le cas
     s'est présenté. */
  overflow-wrap: anywhere;
}
/* Dans un `pre`, non : le bloc défile déjà tout seul, et une ligne de code
   coupée au milieu d'un mot y devient illisible et non copiable. */
pre code { overflow-wrap: normal; }

pre {
  margin: 0;
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 1rem 1.1rem;
  overflow-x: auto;
  font-family: var(--mono);
  font-size: .82rem;
  line-height: 1.6;
}
pre code { background: none; padding: 0; font-size: inherit; }

.tok-key { color: var(--cold); }
.tok-str { color: var(--ok); }
.tok-num { color: var(--warm); }
.tok-dim { color: var(--ink-faint); }

.endpoint {
  display: flex;
  align-items: center;
  gap: .6rem;
  flex-wrap: wrap;
  font-family: var(--mono);
  font-size: .82rem;
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: .6rem .8rem;
  margin: 0 0 .75rem;
  overflow-x: auto;
}
.verb {
  background: var(--cold);
  color: var(--on-accent);
  padding: .1rem .45rem;
  border-radius: 4px;
  font-size: .66rem;
  font-weight: 700;
  letter-spacing: .08em;
}
/* `nowrap` pour les libellés courts de la ligne d'endpoint — l'hôte, les
   pastilles de scope — qui se lisent mal coupés en deux.
   ⚠️ Les deux exceptions ne sont pas courtes : `.path` porte des chemins
   comme `/v1/degree-days?breakdown={daily|weekly|monthly|yearly}` et
   `.pill--cost` une phrase entière. Sur un écran de 390 px elles poussaient la
   page à défiler latéralement de 71 px.
   Les exclure ICI plutôt que rendre les autres règles plus spécifiques :
   `.endpoint span:not(.verb)` pèse (0,2,1) et battait le `.ref .path` (0,2,0)
   qui portait déjà `word-break: break-all` — lequel ne servait donc à rien,
   `nowrap` l'emportant sur lui. */
.endpoint span:not(.verb):not(.path):not(.pill--cost) { white-space: nowrap; }

/* --- tabs (code samples) ------------------------------------------------- */

.tabs { display: flex; gap: .35rem; margin: 0 0 .6rem; flex-wrap: wrap; }
.tab {
  font-family: var(--mono);
  font-size: .72rem;
  letter-spacing: .06em;
  padding: .38rem .75rem;
  border: 1px solid var(--line);
  background: var(--card);
  color: var(--ink-soft);
  border-radius: 6px;
  cursor: pointer;
}
.tab[aria-selected="true"] { border-color: var(--cold); color: var(--cold); }
.tabpanel[hidden] { display: none; }

/* --- notes --------------------------------------------------------------- */

.note {
  border-inline-start: 3px solid var(--cold);
  background: var(--cold-soft);
  border-start-end-radius: var(--radius);
  border-end-end-radius: var(--radius);
  padding: .9rem 1.1rem;
  font-size: .93rem;
}
.note p { margin: 0; }
.note p + p { margin-top: .6rem; }
.note--warm { border-inline-start-color: var(--warm); background: var(--warm-soft); }

/* --- the base-temperature widget ---------------------------------------- */

.dial {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: .8rem 1.4rem;
  margin: .9rem 0 0;
  padding-top: .9rem;
  border-top: 1px solid var(--line-soft);
}
.dial label {
  font-family: var(--mono);
  font-size: .68rem;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--ink-faint);
  display: block;
  margin-bottom: .3rem;
}
.dial__slider { flex: 1 1 260px; min-width: 200px; }
.dial input[type="range"] { width: 100%; accent-color: var(--cold); }
.dial__read { display: flex; gap: 1.4rem; }
.dial__num {
  font-family: var(--mono);
  font-size: 1.25rem;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  line-height: 1.1;
}
.dial__num--cold { color: var(--cold); }
.dial__num--warm { color: var(--warm); }

/* --- faq ----------------------------------------------------------------- */

.faq { border-top: 1px solid var(--line); }
.faq details { border-bottom: 1px solid var(--line); }
.faq summary {
  cursor: pointer;
  padding-block: 1rem;
  padding-inline: 0 2rem;
  font-weight: 600;
  font-size: 1rem;
  list-style: none;
  position: relative;
}
.faq summary::-webkit-details-marker { display: none; }
.faq summary::after {
  content: "+";
  position: absolute;
  inset-inline-end: .25rem;
  top: .95rem;
  font-family: var(--mono);
  color: var(--cold);
  font-size: 1.1rem;
}
.faq details[open] summary::after { content: "\2013"; }
.faq .faq__a { padding-inline: 0 2rem; padding-bottom: 1.1rem; color: var(--ink-soft); max-width: 72ch; }
.faq .faq__a p { margin: 0 0 .7rem; }
.faq .faq__a p:last-child { margin-bottom: 0; }

/* --- pricing strip ------------------------------------------------------- */

.plans { display: grid; gap: 1.1rem; grid-template-columns: repeat(auto-fit, minmax(230px, 1fr)); }
.plan {
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 1.3rem 1.35rem;
  display: flex;
  flex-direction: column;
}
.plan--featured { border-color: var(--cold); box-shadow: var(--shadow); }
.plan__name {
  font-family: var(--mono);
  font-size: .7rem;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--ink-faint);
  margin: 0 0 .6rem;
}
.plan--featured .plan__name { color: var(--cold); }
.plan__price {
  font-size: 2rem;
  font-weight: 700;
  letter-spacing: -.03em;
  line-height: 1;
  font-variant-numeric: tabular-nums;
}
.plan__price small { font-size: .82rem; font-weight: 500; color: var(--ink-faint); letter-spacing: 0; }
.plan__list { list-style: none; margin: 1rem 0 1.2rem; padding: 0; font-size: .9rem; color: var(--ink-soft); }
.plan__list li { padding: .28rem 0; padding-inline-start: 1.25rem; position: relative; }
.plan__list li::before {
  content: "";
  position: absolute;
  inset-inline-start: 0;
  top: .78em;
  width: 7px;
  height: 7px;
  border-radius: 2px;
  background: var(--cold);
}
.plan .cta { margin-top: auto; justify-content: center; }

/* --- footer -------------------------------------------------------------- */

.site-foot {
  border-top: 1px solid var(--line);
  padding: 2.5rem 0 3rem;
  font-size: .88rem;
  color: var(--ink-soft);
}
.site-foot__grid {
  display: grid;
  gap: 1.5rem;
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  margin-bottom: 2rem;
}
.site-foot h4 {
  font-family: var(--mono);
  font-size: .66rem;
  letter-spacing: .15em;
  text-transform: uppercase;
  color: var(--ink-faint);
  margin: 0 0 .6rem;
  font-weight: 600;
}
.site-foot ul { list-style: none; margin: 0; padding: 0; }
.site-foot li { margin: .3rem 0; }
.site-foot a { color: var(--ink-soft); text-decoration: none; }
.site-foot a:hover { color: var(--cold); }
.site-foot__legal { border-top: 1px solid var(--line-soft); padding-top: 1.2rem; font-size: .8rem; color: var(--ink-faint); }
.site-foot__legal p { margin: 0 0 .5rem; max-width: 90ch; }


/* --- utilities the generator emits ---------------------------------------- */

.spaced { margin-top: 1.4rem; }
.measure { max-width: 72ch; }
.h2--wide { max-width: none; margin-inline: auto; }
.lede--center { margin-inline: auto; }
.cta-row--center { justify-content: center; }

/* --- language row --------------------------------------------------------- */
/* Twelve real links. They are the only way a crawler discovers the alternate
   pages, and the only way a reader who landed on the wrong one gets out. */

.site-foot__langs {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: .3rem 1rem;
  margin: 0 0 1.6rem;
  padding-top: 1.2rem;
  border-top: 1px solid var(--line-soft);
  font-size: .84rem;
}
.site-foot__langs a { color: var(--ink-faint); text-decoration: none; }
.site-foot__langs a:hover { color: var(--cold); }
.site-foot__langs a[aria-current] { color: var(--ink); font-weight: 600; }

/* --- right-to-left --------------------------------------------------------- */
/* Arabic mirrors the layout, but never the data: a code block, an endpoint and
   a figure are read left to right in every language, and flipping them would
   turn `lat=36.75` into nonsense. Those carry dir="ltr" in the markup; the rest
   of the page uses logical properties and needs nothing here. */

[dir="rtl"] .card__more,
[dir="rtl"] .site-foot__langs { direction: rtl; }
[dir="rtl"] pre,
[dir="rtl"] .endpoint { text-align: left; }
[dir="rtl"] .stat__value,
[dir="rtl"] .dial__num,
[dir="rtl"] .plan__price { direction: ltr; text-align: start; }

/* Inline identifiers inside Arabic prose. `isolate` is what stops a trailing
   bracket or slash from being dragged to the wrong end of the run — without it
   `/v1/attribution` renders as `attribution/v1/` in the middle of a sentence. */
[dir="rtl"] code { direction: ltr; unicode-bidi: isolate; }


/* --- header controls ------------------------------------------------------ */
/* Language and theme sit in the header because that is where a reader who
   landed on the wrong one looks first. Both are real controls with visible
   state: the picker shows the current language code, the theme group shows
   which of the three modes is active. Nothing here guesses. */

.head-tools {
  display: flex;
  align-items: center;
  gap: .4rem;
  margin-inline-start: auto;
}

.tool {
  display: inline-flex;
  align-items: center;
  gap: .3rem;
  height: 34px;
  padding: 0 .55rem;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: var(--card);
  color: var(--ink-soft);
  font: 600 .78rem/1 var(--mono);
  letter-spacing: .04em;
  cursor: pointer;
  white-space: nowrap;
}
.tool:hover { color: var(--ink); border-color: var(--ink-faint); }
.tool svg { width: 15px; height: 15px; flex: none; }

/* --- disclosure menus (language, mobile nav) ------------------------------ */
/* <details> rather than a scripted dropdown: it opens without JavaScript, it is
   keyboard-operable for free, and a crawler follows the links inside it. */

.pop { position: relative; }
.pop > summary { list-style: none; }
.pop > summary::-webkit-details-marker { display: none; }
.pop__panel {
  position: absolute;
  top: calc(100% + .4rem);
  inset-inline-end: 0;
  min-width: 190px;
  max-height: min(70vh, 420px);
  overflow-y: auto;
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: 10px;
  box-shadow: var(--shadow);
  padding: .35rem;
  z-index: 50;
}
.pop__panel a {
  display: flex;
  align-items: baseline;
  gap: .5rem;
  padding: .42rem .6rem;
  border-radius: 6px;
  color: var(--ink-soft);
  text-decoration: none;
  font-size: .9rem;
}
.pop__panel a:hover { background: var(--cold-soft); color: var(--ink); }
.pop__panel a[aria-current] { color: var(--ink); font-weight: 600; }
.pop__panel a[aria-current]::after { content: "✓"; margin-inline-start: auto; color: var(--cold); }
.pop__head {
  font-family: var(--mono);
  font-size: .64rem;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--ink-faint);
  padding: .5rem .6rem .3rem;
}
.pop__sep { height: 1px; background: var(--line-soft); margin: .35rem .3rem; }

/* --- the language sheet --------------------------------------------------- */
/* Not a dropdown: a sheet as wide as the header, holding the twelve endonyms in
   columns. A 190px panel listing twelve languages is a scrolling list of twelve
   things you read one at a time; the same twelve in four columns are taken in at
   a glance, which is the whole point of a picker.

   It is the same `<details>` as the burger menu, so everything above still
   applies — opens with script off, keyboard-operable, crawlable.

   `position: static` on the <details> is what widens it. The panel's containing
   block then resolves to `.site-head` — sticky, so it qualifies — instead of the
   34px summary, and `inset-inline: 0` + `top: 100%` put the sheet directly under
   the bar at exactly the bar's width. No header height is written down anywhere,
   which matters because that height changes in three media queries below.

   No ✕ on it, deliberately. The globe stays visible above the sheet and closes
   it on a second click; site.js already dismisses on Escape and on a click
   outside. A close button would have needed a thirteenth nav string translated
   into twelve languages to say what the trigger it sits under already says. */

.pop--sheet { position: static; }
/* The chevron — the second of the two SVGs in the summary. It is the only part
   of the trigger that says "this is open", now that the panel it opens is no
   longer visibly attached to it. */
.pop--sheet > summary > svg:last-of-type { transition: transform .18s ease; }
.pop--sheet[open] > summary > svg:last-of-type { transform: rotate(180deg); }

.lang-sheet {
  position: absolute;
  inset-inline: 0;
  top: 100%;
  /* Opaque, unlike the header above it: the sheet sits over body copy, and the
     header's translucency works only because what shows through it is blurred. */
  background: var(--paper);
  border-bottom: 1px solid var(--line);
  box-shadow: var(--shadow);
  padding: 1.4rem 0 1.8rem;
  z-index: 50;
}
.lang-sheet .pop__head { padding: 0 0 1rem; }

/* Multi-column rather than a grid, and that is not a preference: `columns` fills
   down a column before starting the next, so the alphabetical order reads down
   each column the way a printed list does. A grid would fill across, scattering
   the alphabet over four columns. */
.lang-sheet__grid {
  column-count: 4;
  column-gap: 2rem;
}
.lang-sheet__grid a {
  display: block;
  break-inside: avoid;
  padding: .48rem 0;
  color: var(--ink-soft);
  text-decoration: none;
  font-size: 1rem;
  line-height: 1.25;
}
.lang-sheet__grid a:hover { color: var(--cold); }
.lang-sheet__grid a[aria-current] { color: var(--ink); font-weight: 600; }
.lang-sheet__grid a[aria-current]::after {
  content: "✓";
  margin-inline-start: .45rem;
  font-size: .8em;
  color: var(--cold);
}

@media (max-width: 900px) { .lang-sheet__grid { column-count: 3; } }
@media (max-width: 620px) {
  .lang-sheet__grid { column-count: 2; column-gap: 1.25rem; }
  .lang-sheet { padding: 1.1rem 0 1.4rem; }
}

/* --- theme group ---------------------------------------------------------- */

.theme {
  display: inline-flex;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: var(--card);
  overflow: hidden;
  height: 34px;
}
.theme button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  border: 0;
  background: none;
  color: var(--ink-faint);
  cursor: pointer;
  padding: 0;
}
.theme button + button { border-inline-start: 1px solid var(--line-soft); }
.theme button:hover { color: var(--ink); }
.theme button[aria-pressed="true"] { background: var(--cold-soft); color: var(--cold); }
.theme svg { width: 15px; height: 15px; }

/* --- responsive header ---------------------------------------------------- */

.head-menu { display: none; }

/* 1040 and not 980: the inline nav carries five links since the price joined
   it, and the row neither wraps nor scrolls — it just overflows. The widest
   label set is French, and it needs about 60px more than the four did. */
@media (max-width: 1040px) {
  .site-head__in > .site-nav { display: none; }
  .head-menu { display: inline-flex; }
}
@media (max-width: 700px) {
  .site-head__in { gap: .75rem; }
}
@media (max-width: 560px) {
  /* The key can go: it is one tap away inside the menu, and the row has to
     fit. The theme and the language cannot — they are the two controls a
     visitor reaches for on a phone, and burying either defeats the point. */
  .head-tools .tool--key { display: none; }
  .brand span { display: none; }
  .theme button { width: 28px; }
  .tool { padding: 0 .45rem; }
}

/* --- the API reference ---------------------------------------------------
   Four pages share these rules. They used to live in a <style> block inside
   the single hand-written reference, where they aliased the palette instead of
   using it — which is how that page ended up one shade off every other page,
   and how the theme switch worked everywhere except there. Nothing here
   redeclares a colour; it all reads the tokens at the top of this file.        */

main.ref {
  display: grid;
  grid-template-columns: 250px minmax(0, 1fr);
  gap: 3rem;
  max-width: 1180px;
  margin: 0 auto;
  padding: 0 1.5rem 5rem;
}

/* --- the sidebar ---------------------------------------------------------- */

.ref__nav {
  position: sticky;
  top: 64px;
  align-self: start;
  max-height: calc(100vh - 64px);
  overflow-y: auto;
  padding: 2rem 0;
  font-size: .875rem;
}
.ref__nav h4 {
  margin: 1.6rem 0 .5rem;
  font-family: var(--mono);
  font-size: .66rem;
  text-transform: uppercase;
  letter-spacing: .11em;
  color: var(--ink-faint);
}
.ref__nav a {
  display: block;
  padding: .28rem 0 .28rem .7rem;
  margin-inline-start: -.7rem;
  color: var(--ink-soft);
  text-decoration: none;
  border-inline-start: 2px solid transparent;
}
.ref__nav a:hover { color: var(--cold); }
/* Set by the scroll spy in site.js. Without it a 20 kB page gives no clue
   where you are, which was the single worst thing about the old one page. */
.ref__nav a.is-active {
  color: var(--cold);
  border-inline-start-color: var(--cold);
  font-weight: 600;
}

.ref__switch {
  display: grid;
  gap: .1rem;
  padding-bottom: 1rem;
  border-bottom: 1px solid var(--line);
}
.ref__page {
  font-weight: 500;
  color: var(--ink) !important;
  border-radius: 6px;
  padding: .35rem .6rem !important;
  margin-inline-start: 0 !important;
  border-inline-start: 0 !important;
}
.ref__page:hover { background: var(--line-soft); }
.ref__page.is-here { background: var(--cold-soft); color: var(--cold) !important; }

/* --- the body ------------------------------------------------------------- */

.ref__body { padding: 2rem 0 0; min-width: 0; }
.ref__crumb { margin: 0 0 .4rem; font-size: .78rem; }
.ref__crumb a { color: var(--ink-faint); text-decoration: none; }
.ref__crumb a:hover { color: var(--cold); }
.ref__body h1 { margin: 0 0 .5rem; }
.ref__body .lede {
  font-size: 1.06rem;
  color: var(--ink-soft);
  max-width: 64ch;
  margin: 0 0 1rem;
}

.ref__sec { scroll-margin-top: 5rem; }
.ref__sec h2 {
  margin: 3.2rem 0 1rem;
  padding-bottom: .4rem;
  border-bottom: 1px solid var(--line);
  font-size: 1.35rem;
}
.ref__sec h3 { margin: 2.2rem 0 .6rem; font-size: 1.05rem; }
.ref__sec h4 { margin: 1.6rem 0 .5rem; font-size: .92rem; }
.ref__sec p, .ref__sec li { max-width: 72ch; }
.ref__sec table { margin: 1rem 0; display: block; overflow-x: auto; }
.ref__sec pre { margin: 1rem 0; }
.ref__sec .note, .ref__sec .warn { margin: 1.2rem 0; }

/* The permalink beside every heading. Invisible until the heading is hovered
   or the link itself is focused — a reference is read far more often than it
   is linked, and a column of hash marks reads as noise. */
.anchor {
  margin-inline-start: .45rem;
  font-weight: 400;
  color: var(--ink-faint);
  text-decoration: none;
  opacity: 0;
  transition: opacity .12s;
}
h2:hover .anchor, .anchor:focus { opacity: 1; }

.warn {
  border-inline-start: 3px solid var(--warm);
  background: var(--warm-soft);
  border-start-end-radius: var(--radius);
  border-end-end-radius: var(--radius);
  padding: .9rem 1.1rem;
  font-size: .93rem;
}
.warn p { margin: 0; }
.warn p + p { margin-top: .6rem; }

/* --- endpoint cards ------------------------------------------------------- */

/* Overrides the single-line `.endpoint` used on the product pages: here a
   section can document four related paths, and they have to stack. */
.ref .endpoint {
  display: block;
  padding: .9rem 1.1rem;
  margin: 1.1rem 0;
  font-family: inherit;
  font-size: inherit;
  overflow: visible;
}
.ref .endpoint-head {
  display: flex;
  gap: .5rem;
  align-items: center;
  flex-wrap: wrap;
  font-family: var(--mono);
  font-size: .82rem;
}
.ref .endpoint-head + .endpoint-head { margin-top: .7rem; }
/* The host is dimmed but present. Stating a base URL once at the top of a page
   and bare paths thereafter is how half of readers call the wrong host; here,
   selecting the line copies something that resolves. */
.ref .host { color: var(--ink-faint); }
/* ⚠️ `white-space: normal` est indispensable ici, et il n'est pas redondant :
   `.endpoint span:not(.verb)` pose `nowrap` sur ce même élément, et `nowrap`
   ANNULE `break-all` — la règle ci-dessous ne servait donc à rien. Un chemin
   comme `/v1/degree-days?breakdown={daily|weekly|monthly|yearly}` faisait
   déborder la page de 71 px sur un écran de 390 px. */
.ref .path { font-weight: 600; word-break: break-all; }
.ref .endpoint-sum {
  margin: .45rem 0 0;
  font-size: .9rem;
  color: var(--ink-soft);
  max-width: 72ch;
}

.pill {
  display: inline-block;
  background: var(--cold-soft);
  color: var(--cold);
  padding: .08rem .5rem;
  border-radius: 20px;
  font-family: var(--mono);
  font-size: .66rem;
  font-weight: 600;
  white-space: nowrap;
}
.pill code { background: none; padding: 0; font-size: 1em; }
.pill--open { background: var(--line-soft); color: var(--ink-soft); }
/* Les pastilles de prix portent une PHRASE, pas un mot — « (years + 1) ×
   (variables ÷ 2), rounded down, min 1 credits ». Le `nowrap` du `.pill` les
   poussait hors de l'écran. Elles se coupent aux espaces, donc `normal`
   suffit : pas besoin de `break-all`, qui casserait la formule en plein
   milieu. Les autres pastilles restent en `nowrap`, elles tiennent en un mot. */
/* Les pastilles de prix portent une PHRASE, pas un mot — « (years + 1) ×
   (variables ÷ 2), rounded down, min 1 credits ». DEUX règles leur imposaient
   `nowrap` et il fallait lever les deux : `.endpoint span:not(.verb)` plus
   haut, et `.pill` juste au-dessus d'ici. Celle-ci suffit à annuler la seconde
   parce qu'elle la suit dans le fichier, à spécificité égale.
   `normal` et non `break-all` : la formule se coupe très bien aux espaces, et
   `break-all` la casserait en plein milieu d'un opérateur. */
.pill--cost { background: var(--warm-soft); color: var(--warm); white-space: normal; }

/* --- copy buttons --------------------------------------------------------- */

.copywrap { position: relative; }
.copy {
  position: absolute;
  top: .5rem;
  inset-inline-end: .5rem;
  font-family: var(--mono);
  font-size: .66rem;
  letter-spacing: .06em;
  text-transform: uppercase;
  padding: .25rem .5rem;
  border: 1px solid var(--line);
  border-radius: 6px;
  background: var(--paper);
  color: var(--ink-soft);
  cursor: pointer;
  opacity: 0;
  transition: opacity .12s;
}
.copywrap:hover .copy, .copy:focus { opacity: 1; }
.copy.is-done { color: var(--ok); border-color: var(--ok); }

/* --- the hub -------------------------------------------------------------- */

main.hub { padding: 2.5rem 0 5rem; }
main.hub h1 { margin: 0 0 .5rem; }
main.hub .lede { font-size: 1.06rem; color: var(--ink-soft); max-width: 64ch; }
main.hub h2 { margin: 3rem 0 .8rem; font-size: 1.35rem; }
main.hub table { margin-top: 1rem; display: block; overflow-x: auto; }

.refcards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: 1rem;
  margin: 2rem 0;
}
.refcard {
  display: flex;
  flex-direction: column;
  gap: .4rem;
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 1.1rem 1.2rem;
  text-decoration: none;
  color: inherit;
}
.refcard:hover { border-color: var(--cold); }
.refcard h3 { margin: 0; font-size: 1rem; color: var(--cold); }
.refcard p { margin: 0; font-size: .86rem; color: var(--ink-soft); }
.refcard__go {
  margin-top: auto;
  padding-top: .5rem;
  font-family: var(--mono);
  font-size: .7rem;
  color: var(--ink-faint);
}

kbd {
  font-family: var(--mono);
  font-size: .78em;
  border: 1px solid var(--line);
  border-bottom-width: 2px;
  border-radius: 4px;
  padding: .05em .35em;
  background: var(--card);
}

/* --- the search palette --------------------------------------------------- */

.palette[hidden] { display: none; }
.palette {
  position: fixed;
  inset: 0;
  z-index: 60;
  background: rgba(0, 0, 0, .45);
  padding: 10vh 1rem 1rem;
}
.palette__box {
  max-width: 560px;
  margin: 0 auto;
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  overflow: hidden;
  box-shadow: 0 20px 60px rgba(0, 0, 0, .28);
}
.palette input {
  width: 100%;
  border: 0;
  border-bottom: 1px solid var(--line);
  padding: .9rem 1rem;
  font: inherit;
  background: transparent;
  color: var(--ink);
}
.palette input:focus { outline: none; }
.palette ul {
  list-style: none;
  margin: 0;
  padding: .3rem;
  max-height: 46vh;
  overflow-y: auto;
}
.palette a {
  display: flex;
  justify-content: space-between;
  gap: 1rem;
  align-items: baseline;
  padding: .5rem .7rem;
  border-radius: 6px;
  text-decoration: none;
  color: var(--ink);
}
.palette li.is-active a, .palette a:hover { background: var(--cold-soft); color: var(--cold); }
.palette small {
  font-family: var(--mono);
  font-size: .68rem;
  color: var(--ink-faint);
  white-space: nowrap;
}
.palette__empty { padding: 1rem; color: var(--ink-faint); font-size: .9rem; }

/* --- narrow screens ------------------------------------------------------- */

@media (max-width: 980px) {
  main.ref { grid-template-columns: 1fr; gap: 0; padding-inline: 1.25rem; }
  .ref__nav {
    position: static;
    max-height: none;
    padding: 1.25rem 0;
    border-bottom: 1px solid var(--line);
  }
  .ref__switch { grid-template-columns: repeat(2, 1fr); }
  .ref__body { padding-top: 1.5rem; }
  /* The per-section list is long on a phone and sits between the reader and
     the page they asked for. The page switcher above it stays. */
  .ref__nav h4, .ref__nav a:not(.ref__page) { display: none; }
}

/* --- les grands écrans ----------------------------------------------------
   1 140 px de coquille sur un moniteur de 2 000 px, c'est plus d'un tiers de la
   page en marge vide. Au-delà de 1 400 px la coquille devient fluide : le
   `clamp` part exactement de la valeur fixe (76 vw vaut 1 064 px à 1 400 px de
   fenêtre, donc c'est le plancher qui l'emporte) et le raccord ne se voit pas,
   puis elle suit la fenêtre jusqu'à 1 440 px, atteints vers 1 895 px. On
   s'arrête là : les mesures en `ch` (lede 60, prose 66, `.measure` 72) tiennent
   déjà les paragraphes à une longueur lisible — la largeur gagnée profite aux
   cartes, aux tableaux et aux blocs de code, pas au texte courant.

   Ce bloc est en fin de fichier et pas à côté de `.shell` : `.grid--2` et
   `main.ref` sont déclarés plus bas, à spécificité égale, et un `@media`
   n'ajoute aucune spécificité — placé plus haut, il serait écrasé. */
@media (min-width: 1400px) {
  :root { --shell: clamp(1140px, 76vw, 1440px); }
  main.ref { max-width: clamp(1180px, 80vw, 1480px); }
}

/* Les planchers de grille montent APRÈS la coquille, et pas avec elle : c'est
   le point délicat, `auto-fit` recompte ses colonnes dès que la place le
   permet, dans les deux sens. Entre 1 400 et 1 600 px de fenêtre le `clamp`
   est encore sur son plancher — la coquille n'a pas bougé, et des planchers
   déjà relevés là feraient RÉTRÉCIR `.grid--3` de quatre colonnes à trois.

   1 640 px est le seuil mesuré : la coquille y vaut 1 246 px, soit 1 206 px
   utiles, juste avant le point où les anciens planchers laisseraient entrer la
   colonne de trop (290 px en tolère quatre dès 1 213 px utiles, 230 px en
   tolère cinq dès 1 220). Au-delà, la grille de six cartes de
   /meteo/ se réempilerait en 5+1 et celle de neuf en 5+4. On veut des cartes
   plus larges, pas de nouvelles orphelines : 350 et 280 px sont les plus
   petites valeurs qui tiennent le compte de colonnes jusqu'à 1 440 px. */
@media (min-width: 1640px) {
  .grid--2 { grid-template-columns: repeat(auto-fit, minmax(350px, 1fr)); }
  .grid--3 { grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); }
}
