/* ══════════════════════════════════════════════════════════════════════════ POLICES AUTO-HÉBERGÉES — IBM Plex (2026-10-13) Material injectait `theme.font: {text, code}`, ce qui ajoutait au un preconnect vers fonts.gstatic.com et une feuille depuis fonts.googleapis.com. Chaque visite transmettait donc l'IP du visiteur à Google AVANT tout consentement — et le site vitrine avait fait exactement l'inverse en T10, délibérément, pour cette raison (jurisprudence LG München 2022, doctrine CNIL) et pour ne pas contredire « vos données ne sortent pas de chez vous ». La doc affichait donc le contraire de l'engagement du produit. `theme.font: false` dans mkdocs.yml supprime les deux balises ; les 16 woff2 viennent du dépôt du site (mêmes fichiers, mêmes unicode-range, déjà éprouvés en production depuis juin). ⚠️ LES ITALIQUES SONT SYNTHÉTISÉES. Google servait 4 fontes italiques (Sans 300i/400i/700i, Mono 400i) que nous n'avons pas : le navigateur incline donc la romaine. C'est visible sur `_Einstellungen:_` et les intertitres en italique des blocs générés. Pour y remédier, récupérer les woff2 italiques depuis le dépôt officiel IBM/plex (OFL) et ajouter les @font-face correspondants — méthode déjà documentée au T10 du site. ══════════════════════════════════════════════════════════════════════════ */ :root { --md-text-font: "IBM Plex Sans"; --md-code-font: "IBM Plex Mono"; } @font-face{font-family:'IBM Plex Sans';font-style:normal;font-weight:300;font-display:swap;src:url('../assets/fonts/ibm-plex-sans-latin-ext-300.woff2') format('woff2');unicode-range:U+0100-02AF,U+0304,U+0308,U+0329,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20CF,U+2113,U+2C60-2C7F,U+A720-A7FF} @font-face{font-family:'IBM Plex Sans';font-style:normal;font-weight:400;font-display:swap;src:url('../assets/fonts/ibm-plex-sans-latin-ext-400.woff2') format('woff2');unicode-range:U+0100-02AF,U+0304,U+0308,U+0329,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20CF,U+2113,U+2C60-2C7F,U+A720-A7FF} @font-face{font-family:'IBM Plex Sans';font-style:normal;font-weight:500;font-display:swap;src:url('../assets/fonts/ibm-plex-sans-latin-ext-500.woff2') format('woff2');unicode-range:U+0100-02AF,U+0304,U+0308,U+0329,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20CF,U+2113,U+2C60-2C7F,U+A720-A7FF} @font-face{font-family:'IBM Plex Sans';font-style:normal;font-weight:600;font-display:swap;src:url('../assets/fonts/ibm-plex-sans-latin-ext-600.woff2') format('woff2');unicode-range:U+0100-02AF,U+0304,U+0308,U+0329,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20CF,U+2113,U+2C60-2C7F,U+A720-A7FF} @font-face{font-family:'IBM Plex Sans';font-style:normal;font-weight:700;font-display:swap;src:url('../assets/fonts/ibm-plex-sans-latin-ext-700.woff2') format('woff2');unicode-range:U+0100-02AF,U+0304,U+0308,U+0329,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20CF,U+2113,U+2C60-2C7F,U+A720-A7FF} @font-face{font-family:'IBM Plex Sans';font-style:normal;font-weight:300;font-display:swap;src:url('../assets/fonts/ibm-plex-sans-latin-300.woff2') format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+2074,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD} @font-face{font-family:'IBM Plex Sans';font-style:normal;font-weight:400;font-display:swap;src:url('../assets/fonts/ibm-plex-sans-latin-400.woff2') format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+2074,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD} @font-face{font-family:'IBM Plex Sans';font-style:normal;font-weight:500;font-display:swap;src:url('../assets/fonts/ibm-plex-sans-latin-500.woff2') format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+2074,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD} @font-face{font-family:'IBM Plex Sans';font-style:normal;font-weight:600;font-display:swap;src:url('../assets/fonts/ibm-plex-sans-latin-600.woff2') format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+2074,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD} @font-face{font-family:'IBM Plex Sans';font-style:normal;font-weight:700;font-display:swap;src:url('../assets/fonts/ibm-plex-sans-latin-700.woff2') format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+2074,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD} @font-face{font-family:'IBM Plex Mono';font-style:normal;font-weight:400;font-display:swap;src:url('../assets/fonts/ibm-plex-mono-latin-ext-400.woff2') format('woff2');unicode-range:U+0100-02AF,U+0304,U+0308,U+0329,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20CF,U+2113,U+2C60-2C7F,U+A720-A7FF} @font-face{font-family:'IBM Plex Mono';font-style:normal;font-weight:500;font-display:swap;src:url('../assets/fonts/ibm-plex-mono-latin-ext-500.woff2') format('woff2');unicode-range:U+0100-02AF,U+0304,U+0308,U+0329,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20CF,U+2113,U+2C60-2C7F,U+A720-A7FF} @font-face{font-family:'IBM Plex Mono';font-style:normal;font-weight:600;font-display:swap;src:url('../assets/fonts/ibm-plex-mono-latin-ext-600.woff2') format('woff2');unicode-range:U+0100-02AF,U+0304,U+0308,U+0329,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20CF,U+2113,U+2C60-2C7F,U+A720-A7FF} @font-face{font-family:'IBM Plex Mono';font-style:normal;font-weight:400;font-display:swap;src:url('../assets/fonts/ibm-plex-mono-latin-400.woff2') format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+2074,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD} @font-face{font-family:'IBM Plex Mono';font-style:normal;font-weight:500;font-display:swap;src:url('../assets/fonts/ibm-plex-mono-latin-500.woff2') format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+2074,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD} @font-face{font-family:'IBM Plex Mono';font-style:normal;font-weight:600;font-display:swap;src:url('../assets/fonts/ibm-plex-mono-latin-600.woff2') format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+2074,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD} /* ETM PowerSync — surcharge couleurs de marque sur Material (scheme slate) */ [data-md-color-scheme="slate"] { --md-primary-fg-color: #31a3dd; /* cyan ETM */ --md-primary-fg-color--light: #5cb8e6; --md-primary-fg-color--dark: #2589bd; --md-accent-fg-color: #fec113; /* ambre ETM */ --md-default-bg-color: #0a1f2b; --md-default-bg-color--light: #0d2b3b; --md-code-bg-color: #06151d; --md-footer-bg-color: #0d2b3b; } [data-md-color-scheme="slate"] .md-typeset a { color: var(--md-primary-fg-color); } /* badges — 3 familles : canal APT · stabilité plugin · maturité fonctionnalité */ .badge{font-family:"IBM Plex Mono",monospace;font-size:.7rem;letter-spacing:.06em; text-transform:uppercase;padding:2px 8px;border-radius:20px;font-weight:600;white-space:nowrap; display:inline-block;vertical-align:middle;line-height:1.4} /* canal APT */ .badge.stable {color:#3fd18a;background:rgba(63,209,138,.12);border:1px solid rgba(63,209,138,.3)} .badge.testing {color:#fec113;background:rgba(254,193,19,.1);border:1px solid rgba(254,193,19,.3)} .badge.nightly {color:#8fa9b5;background:rgba(143,169,181,.1);border:1px solid rgba(143,169,181,.3)} /* stabilité plugin (meta.json) */ .badge.consumer {color:#31a3dd;background:rgba(49,163,221,.1);border:1px solid rgba(49,163,221,.3)} .badge.community {color:#a78bfa;background:rgba(167,139,250,.1);border:1px solid rgba(167,139,250,.3)} .badge.experimental {color:#fb923c;background:rgba(251,146,60,.1);border:1px solid rgba(251,146,60,.3)} /* origine plugin (PORTING_STATUS.repo ou champ origin:) */ .badge.origin-nymea {color:#94a3b8;background:rgba(148,163,184,.1);border:1px solid rgba(148,163,184,.3)} .badge.origin-etm {color:#4ade80;background:rgba(74,222,128,.1);border:1px solid rgba(74,222,128,.3)} .badge.origin-tiers {color:#fb923c;background:rgba(251,146,60,.1);border:1px solid rgba(251,146,60,.3)} /* maturité fonctionnalités (à la main) */ .badge.ok {color:#3fd18a;background:rgba(63,209,138,.12);border:1px solid rgba(63,209,138,.3)} .badge.part {color:#fec113;background:rgba(254,193,19,.1);border:1px solid rgba(254,193,19,.3)} .badge.road {color:#8fa9b5;background:rgba(143,169,181,.1);border:1px solid rgba(143,169,181,.3)} /* permission scope badges (API JsonRPC) */ .badge.perm-none {color:#3fd18a;background:rgba(63,209,138,.12);border:1px solid rgba(63,209,138,.3)} .badge.perm-control {color:#fec113;background:rgba(254,193,19,.1);border:1px solid rgba(254,193,19,.3)} .badge.perm-configure {color:#fb923c;background:rgba(251,146,60,.1);border:1px solid rgba(251,146,60,.3)} .badge.perm-admin {color:#ef4444;background:rgba(239,68,68,.1);border:1px solid rgba(239,68,68,.3)} .badge.perm-unknown {color:#94a3b8;background:rgba(148,163,184,.1);border:1px solid rgba(148,163,184,.3)} /* ══════════════════════════════════════════════════════════════════════════ SÉLECTEUR DE LANGUE — drapeaux (2026-10-13) Material rend son sélecteur en liste déroulante, chaque entrée portant un `hreflang` : on l'habille en CSS, sans toucher au gabarit du thème. Drapeaux en SVG inline (data-URI) et NON en emoji : 🇫🇷 ne s'affiche pas sous Windows, où Chrome rend « FR » dans un carré faute de police de drapeaux. Le NOM de la langue reste affiché à côté — un drapeau désigne un pays, pas une langue, et l'anglais ici sert les deux marchés plus la communauté. ══════════════════════════════════════════════════════════════════════════ */ .md-select__link[hreflang]{display:flex;align-items:center;gap:.6rem} .md-select__link[hreflang]::before{content:"";width:1.25em;height:.9em;flex:none; background-size:cover;background-position:center;border-radius:1px; box-shadow:0 0 0 1px rgba(255,255,255,.22)} .md-select__link[hreflang="fr"]::before{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 3 2'%3E%3Crect width='3' height='2' fill='%23ED2939'/%3E%3Crect width='2' height='2' fill='%23FFFFFF'/%3E%3Crect width='1' height='2' fill='%23002395'/%3E%3C/svg%3E")} .md-select__link[hreflang="de"]::before{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 5 3'%3E%3Crect width='5' height='3' fill='%23FFCE00'/%3E%3Crect width='5' height='2' fill='%23DD0000'/%3E%3Crect width='5' height='1' fill='%23000000'/%3E%3C/svg%3E")} .md-select__link[hreflang="en"]::before{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 60 30'%3E%3Crect width='60' height='30' fill='%23012169'/%3E%3Cpath d='M0,0 60,30M60,0 0,30' stroke='%23FFFFFF' stroke-width='6'/%3E%3Cpath d='M0,0 60,30M60,0 0,30' stroke='%23C8102E' stroke-width='4'/%3E%3Cpath d='M30,0v30M0,15h60' stroke='%23FFFFFF' stroke-width='10'/%3E%3Cpath d='M30,0v30M0,15h60' stroke='%23C8102E' stroke-width='6'/%3E%3C/svg%3E")} /* ────────────────────────────────────────────────────────────────────────── LE BOUTON DU SÉLECTEUR — drapeau de la langue courante (2026-10-15) Material affiche son icône `translate` : un idéogramme 文 collé à un A. Elle dit « traduire », pas « vous êtes en français », et à la taille du bandeau on ne la lit pas — on y voit un symbole asiatique. Remplacée par le drapeau de la langue courante plus son code, exactement comme sur etm-powersync.fr. Le drapeau se choisit sur `html[lang]`, que mkdocs-static-i18n pose déjà par locale (`fr` à la racine, `de` sous /de/, `en` sous /en/) : aucun gabarit du thème n'est surchargé, rien à maintenir à chaque mise à jour de Material. Le `aria-label` du bouton (« Sélectionner la langue ») est inchangé et porte seul le sens pour les lecteurs d'écran : il l'emporte sur le contenu, donc le « FR » décoratif du ::after n'est pas annoncé deux fois. ────────────────────────────────────────────────────────────────────────── */ .md-header__option{margin-right:.2rem} .md-header__option .md-select>.md-header__button{ display:flex;align-items:center;gap:.34rem; width:auto;padding:.28rem .42rem;margin:.1rem; border-radius:.15rem;opacity:1; transition:background-color .2s; } .md-header__option .md-select>.md-header__button:hover{background:rgba(255,255,255,.1)} /* l'icône `translate` du thème : on la masque, on ne la supprime pas */ .md-header__option .md-select>.md-header__button>svg{display:none} .md-header__option .md-select>.md-header__button::before{ content:"";flex:none;width:1.3rem;height:.92rem;border-radius:2px; background-size:cover;background-position:center; /* liseré : sans lui, la bande blanche du drapeau français se perd dans le bandeau clair, et le noir du drapeau allemand dans le bandeau sombre */ box-shadow:0 0 0 1px rgba(255,255,255,.45); } .md-header__option .md-select>.md-header__button::after{ font-family:var(--md-code-font-family,monospace); font-size:.62rem;font-weight:700;letter-spacing:.08em;line-height:1; } html[lang="fr"] .md-header__option .md-select>.md-header__button::before{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 3 2'%3E%3Crect width='3' height='2' fill='%23ED2939'/%3E%3Crect width='2' height='2' fill='%23FFFFFF'/%3E%3Crect width='1' height='2' fill='%23002395'/%3E%3C/svg%3E")} html[lang="de"] .md-header__option .md-select>.md-header__button::before{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 5 3'%3E%3Crect width='5' height='3' fill='%23FFCE00'/%3E%3Crect width='5' height='2' fill='%23DD0000'/%3E%3Crect width='5' height='1' fill='%23000000'/%3E%3C/svg%3E")} html[lang="en"] .md-header__option .md-select>.md-header__button::before{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 60 30'%3E%3Crect width='60' height='30' fill='%23012169'/%3E%3Cpath d='M0,0 60,30M60,0 0,30' stroke='%23FFFFFF' stroke-width='6'/%3E%3Cpath d='M0,0 60,30M60,0 0,30' stroke='%23C8102E' stroke-width='4'/%3E%3Cpath d='M30,0v30M0,15h60' stroke='%23FFFFFF' stroke-width='10'/%3E%3Cpath d='M30,0v30M0,15h60' stroke='%23C8102E' stroke-width='6'/%3E%3C/svg%3E")} html[lang="fr"] .md-header__option .md-select>.md-header__button::after{content:"FR"} html[lang="de"] .md-header__option .md-select>.md-header__button::after{content:"DE"} html[lang="en"] .md-header__option .md-select>.md-header__button::after{content:"EN"} /* dans la liste déroulante, la langue courante se distingue des deux autres : sinon les trois lignes sont identiques et on ne sait pas d'où l'on part */ html[lang="fr"] .md-select__link[hreflang="fr"], html[lang="de"] .md-select__link[hreflang="de"], html[lang="en"] .md-select__link[hreflang="en"]{font-weight:700;color:var(--md-accent-fg-color)} /* les deux langues non courantes : drapeau légèrement en retrait, il reprend ses couleurs au survol — même convention que sur le site */ .md-select__link[hreflang]::before{opacity:.65;transition:opacity .2s} .md-select__link[hreflang]:hover::before, html[lang="fr"] .md-select__link[hreflang="fr"]::before, html[lang="de"] .md-select__link[hreflang="de"]::before, html[lang="en"] .md-select__link[hreflang="en"]::before{opacity:1}