metalfrom.eu/apps/web/site/styles.css
Nicolas FRYDER fcb20e2e11 perf(api): compression des réponses, et troncature de la carte enfin signalée
Le site public charge l'intégralité du corpus une seconde après l'ouverture de
la page (loadAllHeatPoints), pour la heatmap et la recherche. Rien ne
compressait dans la chaîne — ni Fastify, ni Traefik. Ce n'était donc pas un
risque théorique mais la facture de chaque visiteur, à chaque visite.

Mesuré sur 100 000 groupes avec des données réalistes, en-tête Accept-Encoding
d'un vrai navigateur : 21,5 Mo deviennent 1,9 Mo.

gzip est préféré à brotli, contre l'intuition : br sort 2,3 Mo là où gzip fait
1,9 Mo. La qualité brotli par défaut est réglée pour la vitesse, et sur ce JSON
très répétitif elle perd sur les deux tableaux à la fois — taille ET CPU. Seuil
à 1 Ko, en dessous duquel compresser coûte plus que ça ne rapporte.

/api/clusters plafonnait par ailleurs sa réponse à 2000 groupes ou 1000
clusters sans le dire, ni côté API ni côté client : dans une zone dense, des
groupes disparaissaient de la carte sans aucun signal. La réponse porte
désormais `truncated` et `limit`, et l'interface affiche un avertissement
invitant à zoomer. Clé de traduction ajoutée dans les 21 langues, la
convention du fichier étant une couverture complète.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-22 14:35:12 +02:00

1411 lines
27 KiB
CSS

:root {
--bg: #05060a;
--text: #e9eef5;
--muted: #a2b0c2;
--border: rgba(255,255,255,0.08);
--blood: #c61a1a;
--bone: #e7e2da;
--glow: rgba(198,26,26,0.22);
--sidebar-width: 420px;
--topbar-height: 64px;
--footer-height: 32px;
}
* {
box-sizing: border-box;
}
html, body {
height: 100%;
margin: 0;
background: var(--bg);
color: var(--text);
}
body {
font-family: Inter, system-ui, -apple-system, Segoe UI, Roboto, Arial, sans-serif;
overflow: hidden;
display: grid;
grid-template-rows: var(--topbar-height) 1fr var(--footer-height);
height: 100vh;
height: 100dvh; /* Use dynamic viewport height for mobile */
position: fixed;
width: 100%;
top: 0;
left: 0;
}
body::before {
content: "";
position: fixed;
inset: 0;
background:
radial-gradient(1200px 800px at 18% 12%, rgba(198,26,26,0.12), transparent 56%),
radial-gradient(900px 700px at 90% 20%, rgba(231,226,218,0.05), transparent 60%),
radial-gradient(1400px 900px at 50% 110%, rgba(0,0,0,0.8), transparent 60%),
repeating-linear-gradient(135deg, rgba(255,255,255,0.018) 0 2px, transparent 2px 6px);
pointer-events: none;
mix-blend-mode: screen;
opacity: 0.55;
}
#app {
min-height: 0;
position: relative;
width: 100%;
height: 100%;
}
/* ===== TOPBAR ===== */
#topbar {
position: relative;
display: flex;
align-items: center;
justify-content: space-between;
gap: 16px;
padding: 0 18px;
height: var(--topbar-height);
background: linear-gradient(90deg, rgba(6,8,14,0.96), rgba(12,14,22,0.88));
border-bottom: 1px solid var(--border);
box-shadow: 0 12px 50px rgba(0,0,0,0.35);
z-index: 1002;
}
.brand {
font-family: "UnifrakturCook", serif;
font-size: 26px;
letter-spacing: 0.6px;
text-shadow: 0 0 24px rgba(198,26,26,0.16);
user-select: none;
line-height: 1;
}
.topbar-right {
display: flex;
align-items: center;
gap: 8px;
}
.lang-dropdown { position: relative; }
.lang-trigger {
background: rgba(255,255,255,0.06);
border: 1px solid rgba(255,255,255,0.12);
border-radius: 8px;
color: rgba(231,226,218,0.85);
font-size: 12px;
font-family: inherit;
padding: 5px 10px;
cursor: pointer;
height: 36px;
display: flex;
align-items: center;
gap: 6px;
transition: border-color 120ms ease;
}
.lang-trigger:hover { border-color: rgba(198,26,26,0.40); }
.lang-trigger:focus { outline: none; border-color: rgba(198,26,26,0.60); }
.lang-arrow { color: rgba(231,226,218,0.35); font-size: 10px; }
.lang-options {
position: absolute;
top: calc(100% + 4px);
right: 0;
background: rgba(10,12,20,0.98);
border: 1px solid rgba(255,255,255,0.12);
border-radius: 10px;
min-width: 150px;
z-index: 999;
padding: 4px;
box-shadow: 0 8px 32px rgba(0,0,0,0.5);
backdrop-filter: blur(8px);
}
.lang-options.hidden { display: none; }
.lang-opt {
display: flex;
align-items: center;
gap: 8px;
width: 100%;
padding: 7px 10px;
background: none;
border: none;
color: rgba(231,226,218,0.85);
font-size: 13px;
font-family: inherit;
cursor: pointer;
border-radius: 7px;
text-align: left;
transition: background 80ms;
}
.lang-opt:hover { background: rgba(255,255,255,0.08); }
.lang-opt.current { color: rgba(231,226,218,1); background: rgba(198,26,26,0.18); }
.social-link {
display: inline-flex;
align-items: center;
justify-content: center;
gap: 6px;
min-width: 36px;
height: 36px;
padding: 0 10px;
border-radius: 10px;
border: 1px solid rgba(255,255,255,0.10);
background: rgba(4,6,10,0.60);
color: rgba(231,226,218,0.85);
transition: transform 120ms ease, border-color 120ms ease, background 120ms ease, color 120ms ease;
text-decoration: none;
white-space: nowrap;
}
.social-link:hover {
transform: translateY(-1px);
border-color: rgba(198,26,26,0.40);
background: rgba(198,26,26,0.10);
color: var(--bone);
}
.social-link svg {
width: 18px;
height: 18px;
flex-shrink: 0;
}
.ma-text {
font-size: 12px;
font-weight: 700;
letter-spacing: 0.2px;
}
.external-icon {
width: 14px !important;
height: 14px !important;
opacity: 0.7;
}
.ma-link:hover {
border-color: rgba(198,26,26,0.60);
background: rgba(198,26,26,0.18);
}
.ma-link .external-icon {
opacity: 0.85;
}
.sidebar-toggle {
display: inline-flex;
align-items: center;
gap: 10px;
border: 1px solid rgba(255,255,255,0.10);
background: rgba(4,6,10,0.62);
color: rgba(231,226,218,0.92);
padding: 8px 12px;
border-radius: 12px;
font-size: 12px;
font-weight: 800;
cursor: pointer;
user-select: none;
transition: transform 120ms ease, border-color 120ms ease, background 120ms ease;
}
.sidebar-toggle .icon {
font-size: 16px;
}
.sidebar-toggle:hover {
transform: translateY(-1px);
border-color: rgba(198,26,26,0.40);
background: rgba(198,26,26,0.10);
}
/* ===== SIDEBAR ===== */
#sidebar {
position: fixed;
left: 0;
top: var(--topbar-height);
bottom: var(--footer-height);
width: var(--sidebar-width);
height: auto;
min-height: 0;
background: linear-gradient(180deg, rgba(8,10,16,0.94), rgba(7,9,21,0.96));
border-right: 1px solid var(--border);
box-shadow: 12px 0 60px rgba(0,0,0,0.35);
overflow: auto;
padding: 24px 20px 24px 20px;
backdrop-filter: blur(12px);
z-index: 1000;
transform: translateX(0);
transition: transform 220ms ease, opacity 180ms ease;
}
.sidebar-inner {
min-height: 0;
}
#app.sidebar-collapsed #sidebar {
transform: translateX(-100%);
opacity: 0;
pointer-events: none;
}
/* Sidebar overlay removed - sidebar now only closes via toggle button */
/* ===== MAP ===== */
#mapWrap {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
width: 100%;
height: 100%;
touch-action: pan-x pan-y;
overflow: hidden;
}
#map {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
width: 100% !important;
height: 100% !important;
touch-action: pan-x pan-y;
}
#map,
.leaflet-container {
background: #05060a;
height: 100% !important;
width: 100% !important;
}
/* Force Leaflet to respect container height */
.leaflet-container {
position: absolute !important;
top: 0;
left: 0;
right: 0;
bottom: 0;
}
/* ===== SEARCH ===== */
.topbar {
display: flex;
align-items: center;
gap: 12px;
margin-bottom: 20px;
}
.search {
flex: 1;
position: relative;
}
.search-suggestions {
position: absolute;
top: 100%;
left: 0;
right: 0;
margin-top: 4px;
background: rgba(4,6,10,0.95);
border: 1px solid rgba(255,255,255,0.10);
border-radius: 12px;
max-height: 300px;
overflow-y: auto;
z-index: 1000;
display: none;
box-shadow: 0 10px 40px rgba(0,0,0,0.40);
backdrop-filter: blur(10px);
}
.search-suggestions.visible {
display: block;
}
.suggestion-item {
padding: 10px 14px;
cursor: pointer;
border-bottom: 1px solid rgba(255,255,255,0.05);
transition: background 120ms ease;
}
.suggestion-item:last-child {
border-bottom: none;
}
.suggestion-item:hover {
background: rgba(198,26,26,0.10);
}
.suggestion-name {
font-weight: 700;
font-size: 13px;
color: var(--text);
margin-bottom: 4px;
}
.suggestion-meta {
font-size: 11px;
color: rgba(162,176,194,0.85);
}
input {
width: 100%;
padding: 13px 14px 13px 42px;
border-radius: 16px;
border: 1px solid rgba(255,255,255,0.10);
background: rgba(4,6,10,0.72);
color: var(--text);
outline: none;
font-size: 14px;
box-shadow: 0 0 0 1px rgba(0,0,0,0.35) inset, 0 10px 30px rgba(0,0,0,0.18);
transition: border-color 120ms ease, box-shadow 120ms ease, transform 120ms ease;
}
input:focus {
border-color: rgba(198,26,26,0.55);
box-shadow: 0 0 0 1px rgba(0,0,0,0.35) inset, 0 0 0 3px rgba(198,26,26,0.10), 0 10px 30px rgba(0,0,0,0.22);
transform: translateY(-1px);
}
input::placeholder {
color: rgba(162,176,194,0.68);
}
.search::before {
content: "⌕";
position: absolute;
left: 14px;
top: 50%;
transform: translateY(-50%);
color: rgba(231,226,218,0.75);
font-size: 16px;
opacity: 0.9;
pointer-events: none;
}
/* ===== STATS CHIPS ===== */
.stats {
display: flex;
gap: 6px;
flex-wrap: wrap;
margin: 0 0 16px 0;
}
.chip {
display: inline-flex;
align-items: center;
gap: 6px;
padding: 6px 10px;
border-radius: 999px;
border: 1px solid rgba(255,255,255,0.10);
background: rgba(4,6,10,0.55);
box-shadow: 0 10px 30px rgba(0,0,0,0.14);
font-size: 11px;
color: rgba(231,226,218,0.85);
user-select: none;
}
.chip b {
color: var(--bone);
font-weight: 900;
letter-spacing: 0.2px;
}
.dot {
width: 6px;
height: 6px;
border-radius: 50%;
background: var(--blood);
box-shadow: 0 0 16px var(--glow);
}
/* ===== CONTROLS ===== */
.controls {
background: rgba(4,6,10,0.35);
border-radius: 18px;
padding: 12px;
margin-bottom: 16px;
}
.controls-head {
display: flex;
align-items: center;
justify-content: space-between;
gap: 10px;
margin-bottom: 0;
}
.controls-actions {
display: flex;
align-items: center;
gap: 6px;
flex-wrap: wrap;
}
.controls-title {
font-weight: 900;
font-size: 13px;
letter-spacing: 0.3px;
color: rgba(231,226,218,0.92);
user-select: none;
text-transform: uppercase;
}
.row {
display: flex;
gap: 10px;
flex-wrap: wrap;
}
/* ===== BUTTONS ===== */
.btn {
display: inline-flex;
align-items: center;
gap: 8px;
border: 1px solid rgba(255,255,255,0.10);
background: rgba(4,6,10,0.62);
color: rgba(231,226,218,0.92);
padding: 10px 14px;
border-radius: 12px;
font-size: 13px;
font-weight: 700;
cursor: pointer;
user-select: none;
transition: transform 120ms ease, border-color 120ms ease, background 120ms ease;
white-space: nowrap;
}
.btn-compact {
padding: 8px 10px;
font-size: 12px;
border-radius: 10px;
}
.btn:hover {
transform: translateY(-1px);
border-color: rgba(198,26,26,0.40);
background: rgba(198,26,26,0.10);
}
.btn:active {
transform: translateY(0px);
}
.btn-mini {
display: inline-flex;
align-items: center;
gap: 6px;
border: 1px solid rgba(255,255,255,0.10);
background: rgba(4,6,10,0.62);
color: rgba(231,226,218,0.92);
padding: 6px 10px;
border-radius: 10px;
font-size: 11px;
font-weight: 700;
cursor: pointer;
user-select: none;
transition: transform 120ms ease, border-color 120ms ease, background 120ms ease;
white-space: nowrap;
}
.btn-mini:hover {
transform: translateY(-1px);
border-color: rgba(198,26,26,0.40);
background: rgba(198,26,26,0.10);
}
.btn .badge {
display: inline-flex;
align-items: center;
justify-content: center;
min-width: 20px;
height: 20px;
padding: 0 7px;
border-radius: 999px;
background: rgba(198,26,26,0.22);
border: 1px solid rgba(198,26,26,0.35);
color: var(--bone);
font-weight: 900;
font-size: 11px;
}
/* ===== SWITCH ===== */
.switch {
display: inline-flex;
align-items: center;
gap: 10px;
padding: 6px 10px;
border-radius: 999px;
border: 1px solid rgba(255,255,255,0.10);
background: rgba(4,6,10,0.62);
cursor: pointer;
user-select: none;
font-size: 12px;
font-weight: 800;
color: rgba(231,226,218,0.92);
transition: transform 120ms ease, border-color 120ms ease, background 120ms ease;
}
.switch:hover {
transform: translateY(-1px);
border-color: rgba(198,26,26,0.40);
background: rgba(198,26,26,0.10);
}
.switch input {
display: none;
}
.switch .slider {
position: relative;
width: 34px;
height: 18px;
background: rgba(255,255,255,0.10);
border-radius: 999px;
border: 1px solid rgba(255,255,255,0.12);
box-shadow: inset 0 0 0 1px rgba(0,0,0,0.30);
transition: background 120ms ease, border-color 120ms ease;
}
.switch .slider::after {
content: "";
position: absolute;
top: 2px;
left: 2px;
width: 12px;
height: 12px;
border-radius: 50%;
background: rgba(231,226,218,0.85);
box-shadow: 0 2px 8px rgba(0,0,0,0.35);
transition: transform 120ms ease, background 120ms ease;
}
.switch input:checked + .slider {
background: rgba(198,26,26,0.35);
border-color: rgba(198,26,26,0.50);
}
.switch input:checked + .slider::after {
transform: translateX(16px);
background: rgba(231,226,218,0.95);
}
.switch-label {
white-space: nowrap;
}
/* ===== PANEL (LIST) ===== */
.panel {
background: rgba(4,6,10,0.40);
border-radius: 18px;
overflow: hidden;
box-shadow: 0 18px 55px rgba(0,0,0,0.30);
}
.panel-header {
display: flex;
align-items: center;
justify-content: space-between;
gap: 12px;
padding: 14px 16px;
border-bottom: 1px solid rgba(255,255,255,0.08);
background: linear-gradient(90deg, rgba(198,26,26,0.08), transparent 55%);
}
.panel-header .h {
font-weight: 900;
font-size: 14px;
letter-spacing: 0.3px;
color: rgba(231,226,218,0.92);
user-select: none;
text-transform: uppercase;
}
.panel-header .sub {
font-size: 12px;
color: rgba(162,176,194,0.78);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
max-width: 260px;
}
.panel-body {
padding: 8px 10px;
max-height: calc(100vh - 480px);
overflow: auto;
}
/* ===== BAND ITEMS ===== */
.band {
padding: 12px 14px;
border-bottom: 1px solid rgba(255,255,255,0.04);
border-radius: 12px;
cursor: pointer;
transition: background 120ms ease, box-shadow 120ms ease;
}
.band:last-child {
border-bottom: none;
}
.band:hover {
background: rgba(198,26,26,0.06);
box-shadow: 0 0 0 1px rgba(198,26,26,0.10) inset;
}
.band.active {
background: rgba(198,26,26,0.14);
box-shadow: 0 0 0 1px rgba(198,26,26,0.20) inset, 0 0 22px rgba(198,26,26,0.18);
}
.name {
display: flex;
align-items: center;
gap: 12px;
font-weight: 900;
font-size: 14px;
letter-spacing: 0.15px;
}
.sigil {
width: 8px;
height: 8px;
background: var(--blood);
box-shadow: 0 0 18px var(--glow);
transform: rotate(45deg);
flex: 0 0 auto;
}
a {
color: var(--text);
text-decoration: none;
}
a:hover {
color: var(--bone);
text-decoration: underline;
}
.meta {
margin-top: 8px;
font-size: 12px;
color: rgba(162,176,194,0.88);
line-height: 1.5;
}
.meta b {
color: rgba(231,226,218,0.92);
font-weight: 700;
}
/* ===== FILTERS ===== */
.grid2 {
display: grid;
grid-template-columns: 1fr;
gap: 12px;
}
.filter-box {
background: rgba(4,6,10,0.35);
border-radius: 16px;
padding: 14px;
}
.filter-box + .filter-box {
margin-top: 12px;
}
.filter-title {
font-weight: 900;
font-size: 12px;
letter-spacing: 0.3px;
color: rgba(231,226,218,0.92);
margin-bottom: 12px;
text-transform: uppercase;
}
/* ===== SELECT ===== */
.select {
width: 100%;
padding: 11px 12px;
border-radius: 12px;
border: 1px solid rgba(255,255,255,0.10);
background: rgba(4,6,10,0.72);
color: var(--text);
font-size: 13px;
outline: none;
cursor: pointer;
}
.select:hover {
border-color: rgba(198,26,26,0.30);
}
/* ===== TOGGLES (STATUS) ===== */
.chips {
display: flex;
flex-wrap: wrap;
gap: 8px;
}
.toggle {
display: inline-flex;
align-items: center;
gap: 8px;
padding: 9px 12px;
border-radius: 999px;
border: 1px solid rgba(255,255,255,0.10);
background: rgba(4,6,10,0.55);
cursor: pointer;
user-select: none;
transition: transform 120ms ease, border-color 120ms ease, background 120ms ease;
font-size: 12px;
color: rgba(231,226,218,0.92);
font-weight: 700;
}
.toggle:hover {
transform: translateY(-1px);
border-color: rgba(198,26,26,0.35);
background: rgba(198,26,26,0.08);
}
.toggle .box {
width: 14px;
height: 14px;
border-radius: 4px;
border: 1px solid rgba(231,226,218,0.35);
background: rgba(0,0,0,0.25);
position: relative;
box-shadow: 0 0 0 1px rgba(0,0,0,0.20) inset;
flex: 0 0 auto;
}
.toggle.on .box {
border-color: rgba(198,26,26,0.55);
background: rgba(198,26,26,0.18);
box-shadow: 0 0 0 1px rgba(0,0,0,0.20) inset, 0 0 18px rgba(198,26,26,0.14);
}
.toggle.on .box::after {
content: "";
position: absolute;
inset: 3px;
background: rgba(231,226,218,0.80);
border-radius: 2px;
opacity: 0.85;
}
.count-badge {
color: rgba(162,176,194,0.90);
font-weight: 800;
font-size: 11px;
}
/* ===== MACRO GENRES ===== */
.macro-grid {
display: flex;
flex-wrap: wrap;
gap: 8px;
}
.macro-btn {
display: inline-flex;
align-items: center;
gap: 8px;
padding: 8px 10px;
border-radius: 999px;
border: 1px solid rgba(255,255,255,0.10);
background: rgba(4,6,10,0.55);
color: rgba(231,226,218,0.92);
font-size: 12px;
font-weight: 800;
cursor: pointer;
transition: transform 120ms ease, border-color 120ms ease, background 120ms ease;
user-select: none;
}
.macro-btn:hover {
transform: translateY(-1px);
border-color: rgba(198,26,26,0.35);
background: rgba(198,26,26,0.08);
}
.macro-btn.on {
border-color: rgba(198,26,26,0.50);
background: rgba(198,26,26,0.18);
box-shadow: 0 0 0 1px rgba(0,0,0,0.20) inset, 0 0 18px rgba(198,26,26,0.14);
}
/* ===== MULTISELECT ===== */
.multiselect {
border: 1px solid rgba(255,255,255,0.08);
background: rgba(4,6,10,0.50);
border-radius: 14px;
overflow: hidden;
}
.multiselect.is-collapsed {
display: none;
}
.dropdown-trigger {
width: 100%;
display: inline-flex;
align-items: center;
justify-content: space-between;
gap: 8px;
padding: 10px 12px;
border-radius: 12px;
border: 1px solid rgba(255,255,255,0.10);
background: rgba(4,6,10,0.60);
color: rgba(231,226,218,0.90);
font-size: 12px;
font-weight: 800;
cursor: pointer;
transition: transform 120ms ease, border-color 120ms ease, background 120ms ease;
margin-bottom: 10px;
}
.dropdown-trigger:hover {
transform: translateY(-1px);
border-color: rgba(198,26,26,0.35);
background: rgba(198,26,26,0.10);
}
.dropdown-trigger .summary {
color: rgba(162,176,194,0.90);
font-weight: 700;
}
.dropdown-trigger .caret {
color: rgba(231,226,218,0.70);
font-size: 12px;
}
.ms-head {
display: flex;
gap: 8px;
align-items: center;
padding: 10px;
border-bottom: 1px solid rgba(255,255,255,0.06);
}
.ms-search {
flex: 1;
padding: 9px 12px;
border-radius: 10px;
border: 1px solid rgba(255,255,255,0.10);
background: rgba(0,0,0,0.30);
color: var(--text);
font-size: 12px;
outline: none;
}
.ms-search::placeholder {
color: rgba(162,176,194,0.60);
}
.ms-actions {
display: flex;
gap: 6px;
}
.ms-list {
max-height: 200px;
overflow: auto;
padding: 10px;
display: flex;
flex-direction: column;
gap: 6px;
}
.ms-empty {
padding: 10px 12px;
border-radius: 10px;
border: 1px dashed rgba(255,255,255,0.10);
color: rgba(162,176,194,0.80);
font-size: 12px;
text-align: center;
}
.ms-item {
display: flex;
justify-content: space-between;
align-items: center;
gap: 12px;
padding: 10px 12px;
border-radius: 10px;
border: 1px solid rgba(255,255,255,0.06);
background: rgba(0,0,0,0.15);
cursor: pointer;
user-select: none;
font-size: 13px;
transition: border-color 120ms ease, background 120ms ease;
}
.ms-item:hover {
border-color: rgba(198,26,26,0.30);
background: rgba(198,26,26,0.08);
}
.ms-item.on {
border-color: rgba(198,26,26,0.40);
background: rgba(198,26,26,0.14);
}
/* ===== TIMELINE ===== */
.timeline {
padding: 8px 0 0 0;
}
.timeline-meta {
margin-top: 14px;
display: flex;
gap: 10px;
flex-wrap: wrap;
}
.timeline-empty {
padding: 10px 12px;
border-radius: 12px;
border: 1px dashed rgba(255,255,255,0.10);
color: rgba(162,176,194,0.85);
font-size: 12px;
text-align: center;
}
.noUi-target {
border: 1px solid rgba(255,255,255,0.10);
background: rgba(0,0,0,0.25);
box-shadow: none;
}
.noUi-connect {
background: rgba(198,26,26,0.35);
}
.noUi-handle {
border-radius: 12px;
border: 1px solid rgba(255,255,255,0.12);
background: rgba(4,6,10,0.90);
box-shadow: 0 0 18px rgba(198,26,26,0.14);
}
/* ===== LEAFLET CUSTOMIZATION ===== */
.leaflet-popup-content-wrapper,
.leaflet-popup-tip {
background: rgba(4,6,10,0.92);
color: var(--text);
border: 1px solid rgba(255,255,255,0.10);
box-shadow: 0 20px 60px rgba(0,0,0,0.55);
backdrop-filter: blur(10px);
}
.leaflet-popup-content a {
color: #e9eef5;
text-decoration: none;
transition: color 0.2s ease;
}
.leaflet-popup-content a:hover {
color: #c61a1a;
text-decoration: underline;
}
/* Zoom controls - move to right side and style to match UI */
.leaflet-control-zoom {
border: none !important;
box-shadow: none !important;
margin: 12px !important;
}
.leaflet-right .leaflet-control-zoom {
margin-right: 12px !important;
}
.leaflet-control-zoom a {
width: 36px !important;
height: 36px !important;
line-height: 36px !important;
font-size: 18px !important;
font-weight: 700 !important;
color: rgba(231,226,218,0.92) !important;
background: rgba(4,6,10,0.85) !important;
border: 1px solid rgba(255,255,255,0.12) !important;
border-radius: 10px !important;
transition: transform 120ms ease, border-color 120ms ease, background 120ms ease !important;
backdrop-filter: blur(8px);
}
.leaflet-control-zoom a,
.leaflet-control-zoom a:link,
.leaflet-control-zoom a:visited,
.leaflet-control-zoom a:hover,
.leaflet-control-zoom a:active,
.leaflet-control-zoom a:focus {
text-decoration: none !important;
}
.leaflet-control-zoom a:hover {
transform: translateY(-1px) !important;
border-color: rgba(198,26,26,0.45) !important;
background: rgba(198,26,26,0.15) !important;
color: var(--bone) !important;
}
.leaflet-control-zoom a:active {
transform: translateY(0) !important;
}
.leaflet-control-zoom-in {
border-radius: 10px 10px 0 0 !important;
margin-bottom: 0 !important;
border-bottom: none !important;
}
.leaflet-control-zoom-out {
border-radius: 0 0 10px 10px !important;
margin-top: -1px !important;
}
.leaflet-control-zoom a.leaflet-disabled {
color: rgba(162,176,194,0.40) !important;
background: rgba(4,6,10,0.60) !important;
cursor: not-allowed !important;
}
.leaflet-control-attribution {
background: rgba(4,6,10,0.70) !important;
color: rgba(162,176,194,0.85) !important;
border: 1px solid rgba(255,255,255,0.08);
}
.leaflet-control-attribution a {
color: rgba(162,176,194,0.85) !important;
}
.marker-cluster-small,
.marker-cluster-medium,
.marker-cluster-large {
background-color: rgba(198,26,26,0.16) !important;
}
.marker-cluster-small div,
.marker-cluster-medium div,
.marker-cluster-large div {
background-color: rgba(198,26,26,0.30) !important;
color: var(--text) !important;
border: 1px solid rgba(198,26,26,0.42);
box-shadow: 0 0 0 1px rgba(0,0,0,0.25) inset, 0 0 18px rgba(198,26,26,0.16);
font-weight: 900;
}
/* ===== LEGAL BAR ===== */
#legalBar {
display: flex;
align-items: center;
justify-content: center;
height: var(--footer-height);
background: rgba(4,6,10,0.85);
border-top: 1px solid var(--border);
font-size: 11px;
color: rgba(162,176,194,0.85);
}
.legal-inner {
display: inline-flex;
align-items: center;
gap: 10px;
}
.legal-link {
border: none;
background: transparent;
color: rgba(231,226,218,0.85);
cursor: pointer;
font-size: 11px;
font-weight: 700;
padding: 4px 6px;
border-radius: 8px;
transition: color 120ms ease, background 120ms ease;
}
.legal-link:hover {
color: var(--bone);
background: rgba(198,26,26,0.10);
}
.legal-dot {
color: rgba(162,176,194,0.70);
}
/* --- GoatCounter footer stats (add-on) --- */
.legal-inner {
flex-wrap: wrap; /* add-on: évite que ça déborde sur mobile */
}
.legal-stats {
display: inline-flex;
align-items: center;
gap: 8px;
padding: 2px 8px;
border-radius: 999px;
border: 1px solid rgba(255,255,255,0.10);
background: rgba(4,6,10,0.55);
}
.legal-stat {
display: inline-flex;
align-items: baseline;
gap: 6px;
font-size: 11px;
color: rgba(231,226,218,0.85);
}
.legal-stat b {
color: var(--bone);
font-weight: 900;
}
/* ===== MODAL ===== */
.modal-backdrop {
position: fixed;
inset: 0;
background: rgba(0,0,0,0.60);
backdrop-filter: blur(6px);
display: none;
align-items: center;
justify-content: center;
padding: 16px;
z-index: 9999;
}
.modal-backdrop.on {
display: flex;
}
.modal {
width: min(960px, 96vw);
max-height: min(88vh, 900px);
overflow: hidden;
border-radius: 18px;
border: 1px solid rgba(255,255,255,0.10);
background: rgba(4,6,10,0.92);
box-shadow: 0 30px 90px rgba(0,0,0,0.70);
backdrop-filter: blur(12px);
}
.modal-head {
display: flex;
align-items: center;
justify-content: space-between;
gap: 12px;
padding: 14px 16px;
border-bottom: 1px solid rgba(255,255,255,0.08);
background: linear-gradient(90deg, rgba(198,26,26,0.08), transparent 55%);
}
.modal-head .h {
font-weight: 900;
font-size: 14px;
color: rgba(231,226,218,0.92);
letter-spacing: 0.3px;
text-transform: uppercase;
}
.modal-head .x {
width: 36px;
height: 36px;
display: grid;
place-items: center;
border-radius: 12px;
border: 1px solid rgba(255,255,255,0.10);
background: rgba(4,6,10,0.55);
cursor: pointer;
user-select: none;
font-weight: 900;
font-size: 16px;
color: rgba(231,226,218,0.90);
transition: transform 120ms ease, border-color 120ms ease, background 120ms ease;
}
.modal-head .x:hover {
transform: scale(1.05);
border-color: rgba(198,26,26,0.40);
background: rgba(198,26,26,0.10);
}
.modal-body {
padding: 12px 14px;
overflow: auto;
max-height: calc(88vh - 66px);
}
/* ===== SCROLLBAR STYLING ===== */
::-webkit-scrollbar {
width: 8px;
height: 8px;
}
::-webkit-scrollbar-track {
background: rgba(0,0,0,0.20);
}
::-webkit-scrollbar-thumb {
background: rgba(198,26,26,0.30);
border-radius: 4px;
}
::-webkit-scrollbar-thumb:hover {
background: rgba(198,26,26,0.45);
}
/* ===== RESPONSIVE ===== */
@media (max-width: 1200px) {
:root {
--sidebar-width: 380px;
--topbar-height: 60px;
}
.brand {
font-size: 24px;
}
}
@media (max-width: 992px) {
:root {
--sidebar-width: 320px;
--topbar-height: 58px;
}
.brand {
font-size: 18px;
}
.topbar-right {
gap: 4px;
}
.social-link {
min-width: 32px;
height: 32px;
padding: 0 8px;
}
.social-link svg {
width: 16px;
height: 16px;
}
.ma-text {
font-size: 11px;
}
.external-icon {
width: 12px !important;
height: 12px !important;
}
#sidebar {
padding: 18px 16px;
}
/* Darker overlay on mobile for better contrast */
#app::before {
background: rgba(0,0,0,0.5);
}
.stats {
gap: 6px;
}
.chip {
padding: 5px 8px;
font-size: 10px;
}
.controls {
padding: 10px;
}
.btn {
padding: 7px 10px;
font-size: 11px;
}
.btn-compact {
padding: 6px 8px;
font-size: 11px;
}
}
@media (max-width: 640px) {
:root {
--sidebar-width: 280px;
--topbar-height: 52px;
}
.brand {
font-size: 16px;
}
.sidebar-toggle .label {
display: none;
}
.topbar-right {
gap: 3px;
}
.social-link {
min-width: 28px;
height: 28px;
padding: 0 6px;
}
.social-link svg {
width: 14px;
height: 14px;
}
.ma-text {
font-size: 10px;
}
.external-icon {
width: 10px !important;
height: 10px !important;
}
.switch {
padding: 4px 6px;
}
#sidebar {
width: 280px;
}
#app.sidebar-collapsed #sidebar {
width: 280px;
}
/* Ensure map still takes full space on very small screens */
#mapWrap {
min-height: 300px;
}
}
/* Signale que la carte ne montre qu'une partie des résultats de la zone.
Sans ça, la troncature du serveur était totalement invisible. */
.trunc-note {
margin-left: 6px;
color: #e0a144;
cursor: help;
font-weight: 700;
}
.trunc-note[hidden] { display: none; }