Files
lidar_rendu/lidar_pipeline/web/map.css

268 lines
18 KiB
CSS
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/* Carte LiDAR — tuiles XYZ, habillage minimal type carte grand public. */
/* Réglages communs : toute règle y puise (couleurs, texte, arrondis,
espacements, ombres, superpositions). Deux palettes : claire par défaut,
sombre si le système le demande (sauf clair forcé) ou si elle est forcée. */
:root {
color-scheme: light;
--bg: #eef0f3;
--surface: rgba(251, 251, 250, 0.96);
--surface-2: #eef0f3; /* champs, segments, boutons neutres */
--border: #d6d9de;
--text: #1d232b;
--muted: #5b6573;
--accent: #1f6fb2;
--on-accent: #ffffff;
--track: #cfd4da;
--print: #d99a00;
--gen-running: #d9730d;
--gen-pending: #0b8fc0;
--gen-failed: #c8452c;
--gen-sel: var(--accent);
--fs-xs: 11px; --fs-sm: 12px; --fs-md: 13px; --fs-lg: 16px;
--r-sm: 6px; --r-md: 10px; --r-full: 999px;
--sp-1: 4px; --sp-2: 8px; --sp-3: 12px; --sp-4: 16px;
--shadow-sm: 0 2px 8px rgba(0, 0, 0, 0.18);
--shadow-lg: 0 6px 24px rgba(0, 0, 0, 0.28);
--z-map-ui: 800; --z-panel: 900; --z-popup: 950;
--z-loading: 960; --z-toast: 1000; --z-modal: 1100;
}
@media (prefers-color-scheme: dark) {
:root:not([data-theme="light"]) {
color-scheme: dark;
--bg: #0b0e13; --surface: rgba(16, 20, 27, 0.95); --surface-2: rgba(255, 255, 255, 0.06);
--border: rgba(255, 255, 255, 0.12); --text: #d9dee6; --muted: #8b94a3;
--accent: #5aa9e6; --on-accent: #0b0e13; --track: rgba(255, 255, 255, 0.18);
--print: #ffd166; --gen-running: #f4a261; --gen-pending: #4cc9f0; --gen-failed: #e76f51;
--shadow-sm: 0 4px 16px rgba(0, 0, 0, 0.4); --shadow-lg: 0 6px 24px rgba(0, 0, 0, 0.45);
}
}
:root[data-theme="dark"] {
color-scheme: dark;
--bg: #0b0e13; --surface: rgba(16, 20, 27, 0.95); --surface-2: rgba(255, 255, 255, 0.06);
--border: rgba(255, 255, 255, 0.12); --text: #d9dee6; --muted: #8b94a3;
--accent: #5aa9e6; --on-accent: #0b0e13; --track: rgba(255, 255, 255, 0.18);
--print: #ffd166; --gen-running: #f4a261; --gen-pending: #4cc9f0; --gen-failed: #e76f51;
--shadow-sm: 0 4px 16px rgba(0, 0, 0, 0.4); --shadow-lg: 0 6px 24px rgba(0, 0, 0, 0.45);
}
* { box-sizing: border-box; margin: 0; padding: 0; }
[hidden] { display: none !important; }
html, body { height: 100%; overflow: hidden; background: var(--bg); color: var(--text);
font: var(--fs-md)/1.45 -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; }
#map { position: absolute; inset: 0; background: var(--bg); }
.leaflet-container { background: var(--bg); font: inherit; }
/* Fond OSM assombri pour laisser ressortir les rendus LiDAR. Filtre posé sur
le conteneur de la couche, pas sur chaque tuile : même rendu (opérations
par pixel), mais une seule passe de filtre au lieu d'une par tuile —
−30 % de CPU (moteur de rendu + GPU) en déplacement, mesuré sous Chrome. */
.leaflet-tile-pane .leaflet-layer.base-dark { filter: brightness(0.38) contrast(1.1) saturate(0.7); }
.card { position: fixed; z-index: var(--z-panel); background: var(--surface); color: var(--text);
border: 1px solid var(--border); border-radius: var(--r-md);
box-shadow: var(--shadow-lg);
backdrop-filter: blur(8px); -webkit-backdrop-filter: blur(8px); }
/* Fiche de dalle : à droite du panneau (ordinateur), en haut (téléphone). */
#tilecard { left: max(var(--sp-3), var(--panel-w)); top: 12px; width: 340px; max-width: calc(100vw - 24px);
max-height: calc(100vh - 24px); overflow-y: auto; }
.info-sec { margin-top: 10px; }
.info-sec h4 { margin: 0 0 4px; font-size: var(--fs-xs); font-weight: 700; letter-spacing: 0.06em;
text-transform: uppercase; color: var(--muted); }
.info-kv { display: grid; grid-template-columns: max-content 1fr; gap: 2px 10px; font-size: var(--fs-sm); }
.info-kv dt { color: var(--muted); }
.info-kv dd { margin: 0; overflow-wrap: anywhere; }
.info-dl { display: inline-block; margin-top: 6px; padding: 6px 10px; border-radius: var(--r-sm);
background: color-mix(in srgb, var(--accent) 18%, transparent); color: var(--text); text-decoration: none; font-weight: 600; }
.info-dl:hover { background: color-mix(in srgb, var(--accent) 30%, transparent); }
.rose-cap { font-size: var(--fs-xs); color: var(--text); line-height: 1.3; }
.rose-cap span { color: var(--muted); font-size: var(--fs-xs); }
.card-head { display: flex; align-items: center; gap: 8px; padding: 8px 10px; border-bottom: 1px solid var(--border); }
.card-title { font-size: var(--fs-sm); font-weight: 700; letter-spacing: 0.04em; text-transform: uppercase; color: var(--muted); }
.card-body { padding: 6px 8px 8px; max-height: min(60vh, 520px); overflow-y: auto; }
.card-foot { display: flex; gap: 8px; padding: 8px 4px 2px; margin-top: 6px; border-top: 1px solid var(--border); }
/* --- composants communs --------------------------------------------------- */
.btn, button { display: inline-flex; align-items: center; justify-content: center; gap: var(--sp-1);
min-height: 32px; padding: 0 var(--sp-3); border-radius: var(--r-sm); border: 1px solid var(--border);
background: var(--surface-2); color: var(--text); font: inherit; font-size: var(--fs-sm); cursor: pointer; }
.btn:hover, button:hover { border-color: var(--accent); }
.btn:disabled, button:disabled { opacity: 0.5; cursor: default; }
.btn-primary { background: var(--accent); border-color: var(--accent); color: var(--on-accent); font-weight: 600; }
.btn-primary:hover { filter: brightness(1.08); }
.btn.accent, .btn.busy { border-color: var(--accent); color: var(--accent); }
.btn-ghost { background: transparent; }
.btn-icon { min-height: 0; padding: var(--sp-1) var(--sp-2); border: none; background: none;
color: var(--muted); font-size: var(--fs-lg); }
.btn-icon:hover { color: var(--text); }
.row { display: flex; gap: var(--sp-2); align-items: center; }
.row > .btn, .row > .field { flex: 1; min-width: 0; }
.field { height: 32px; min-width: 0; width: 100%; padding: 0 var(--sp-2); border-radius: var(--r-sm);
border: 1px solid var(--border); background: var(--surface-2); color: var(--text);
font: inherit; font-size: var(--fs-sm); }
select.field[multiple] { height: auto; padding: var(--sp-1); }
.field option { background-color: var(--surface); color: var(--text); }
.seg { display: grid; grid-auto-flow: column; grid-auto-columns: 1fr; border: 1px solid var(--border);
border-radius: var(--r-sm); overflow: hidden; }
.seg button { min-height: 32px; border: none; border-radius: 0; background: var(--surface-2); color: var(--muted); }
.seg button + button { border-left: 1px solid var(--border); }
.seg button[aria-pressed="true"] { background: var(--accent); color: var(--on-accent); font-weight: 600; }
.seg button:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
.hint { font-size: var(--fs-sm); color: var(--muted); margin: var(--sp-1) 0; }
input[type="range"] { -webkit-appearance: none; appearance: none; width: 100%; height: 20px;
background: transparent; cursor: pointer; }
input[type="range"]::-webkit-slider-runnable-track { height: 4px; border-radius: 2px; background: var(--track); }
input[type="range"]::-webkit-slider-thumb { -webkit-appearance: none; width: 14px; height: 14px;
margin-top: -5px; border-radius: 50%; background: var(--accent); border: 2px solid var(--surface); }
input[type="range"]::-moz-range-track { height: 4px; border-radius: 2px; background: var(--track); }
input[type="range"]::-moz-range-thumb { width: 10px; height: 10px; border-radius: 50%;
background: var(--accent); border: 2px solid var(--surface); }
@media (max-width: 720px) {
.btn, button, .field, .seg button { min-height: 40px; }
.field { height: 40px; }
}
/* Ligne du fond de carte : œil, nom, opacité. */
.base-row { display: grid; grid-template-columns: 32px minmax(0, 1fr) auto; align-items: center;
gap: var(--sp-2); padding: var(--sp-1) 0; }
.base-row .base-ctl { grid-column: 2 / -1; display: grid; grid-template-columns: minmax(0, 1fr) 40px;
gap: var(--sp-2); align-items: center; }
/* Affichage : une couche principale, la précision seule ou superposée. */
.view-row { display: grid; grid-template-columns: auto minmax(0, 1fr); align-items: center;
gap: 8px; padding: 8px 4px 4px; border-top: 1px solid var(--border); margin-top: 4px; }
.view-label { font-size: var(--fs-xs); font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase; color: var(--muted); }
.view-row .layer-name { color: var(--text); }
.prec-ctl { display: grid; grid-template-columns: auto minmax(0, 1fr) 34px; gap: 8px;
align-items: center; padding: 6px 4px 0; font-size: var(--fs-xs); color: var(--muted); }
.prec-legend { padding: 8px 4px 2px; }
.prec-bar { display: grid; grid-template-columns: repeat(16, 1fr); height: 10px;
border: 1px solid var(--border); border-radius: 3px; overflow: hidden; }
.prec-ticks { display: flex; justify-content: space-between; font-size: var(--fs-xs); color: var(--muted);
font-variant-numeric: tabular-nums; margin-top: 2px; }
.prec-cap { font-size: var(--fs-xs); color: var(--muted); margin-top: 2px; }
.eye { width: 24px; height: 24px; padding: 0; border: none; background: none; color: var(--muted);
display: flex; align-items: center; justify-content: center; }
.eye.on { color: var(--accent); }
.eye svg { width: 16px; height: 16px; }
.layer-name { font-size: var(--fs-sm); color: var(--muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.base-row .layer-name { color: var(--text); cursor: pointer; }
.base-row:not(.on) .layer-name { color: var(--muted); }
.pct { font-size: var(--fs-xs); color: var(--muted); text-align: right; font-variant-numeric: tabular-nums; }
#tools { position: fixed; right: var(--sp-3); bottom: calc(var(--sheet-h) + var(--sp-3));
z-index: var(--z-map-ui); display: flex; flex-direction: column; gap: var(--sp-2); }
@media (max-width: 720px) {
#tools { top: var(--sp-3); bottom: auto; }
}
/* L'attribution Leaflet reste en bas à droite : les outils passent au-dessus. */
@media (min-width: 721px) { #tools { bottom: 44px; } }
#tools button { width: 38px; height: 38px; padding: 0; font-size: var(--fs-lg); background: var(--surface);
border: 1px solid var(--border); box-shadow: var(--shadow-sm); }
/* Indicateur de chargement : tuiles restantes pour finir la vue courante
(fond + LiDAR), barre de progression du lot en cours. */
.tileload { position: fixed; left: calc(var(--panel-w) + (100vw - var(--panel-w)) / 2); top: auto;
bottom: calc(var(--sheet-h) + var(--sp-3)); transform: translateX(-50%); z-index: var(--z-loading);
display: flex; align-items: center; gap: 8px; padding: 5px 12px; border-radius: var(--r-full);
background: var(--surface); border: 1px solid var(--border); font-size: var(--fs-sm);
box-shadow: var(--shadow-sm); pointer-events: none;
transition: opacity 0.3s ease; white-space: nowrap; }
.tileload.done { opacity: 0; }
.tl-spin { width: 12px; height: 12px; border-radius: var(--r-full); flex: none;
border: 2px solid color-mix(in srgb, var(--accent) 25%, transparent); border-top-color: var(--accent);
animation: tlspin 0.8s linear infinite; }
.tileload.done .tl-spin { animation: none; border-color: var(--accent); }
@keyframes tlspin { to { transform: rotate(360deg); } }
.tl-bar { width: 60px; height: 4px; border-radius: var(--r-sm); background: var(--track);
overflow: hidden; flex: none; }
.tl-bar span { display: block; height: 100%; width: 0; background: var(--accent);
transition: width 0.2s ease; }
.toast { position: fixed; left: calc(var(--panel-w) + (100vw - var(--panel-w)) / 2);
bottom: calc(var(--sheet-h) + 56px); transform: translateX(-50%); z-index: var(--z-toast);
background: var(--surface); border: 1px solid var(--border); border-radius: var(--r-sm);
padding: 7px 12px; font-size: var(--fs-sm); color: var(--text); max-width: 80vw; text-align: center; }
.meta { font-size: var(--fs-xs); color: var(--muted); margin: 2px 0; }
.meta b { color: var(--text); font-weight: 600; }
.mono { font-family: ui-monospace, "SF Mono", Menlo, monospace; font-size: var(--fs-xs);
background: var(--surface-2); border: 1px solid var(--border); border-radius: var(--r-sm);
padding: 6px 8px; word-break: break-all; margin: 4px 0 8px; }
.use-note { font-size: var(--fs-xs); color: var(--muted); line-height: 1.5; }
.leaflet-control-attribution { background: var(--surface) !important; color: var(--muted) !important; }
.leaflet-control-attribution a { color: var(--accent) !important; }
/* --- génération de tuiles ------------------------------------------------ */
.print-msg { font-size: var(--fs-sm); margin-left: 8px; }
.print-handle { display: flex; align-items: center; justify-content: center; cursor: move;
font-size: var(--fs-lg); color: #1b1b1b; background: var(--print); border: 2px solid #1b1b1b;
border-radius: var(--r-full); box-shadow: 0 1px 6px rgba(0,0,0,0.5); }
body.drawing { cursor: crosshair !important; }
body.drawing .leaflet-container { cursor: crosshair !important; }
.gen-row { display: grid; grid-template-columns: 92px minmax(0, 1fr); gap: 6px;
align-items: center; margin: 4px 0; font-size: var(--fs-xs); color: var(--muted); }
.chk { display: flex; gap: 7px; align-items: center; font-size: var(--fs-xs);
color: var(--muted); margin: 4px 0; cursor: pointer; }
.chk input { accent-color: var(--accent); }
.gen-log { font: var(--fs-xs)/1.5 ui-monospace, "SF Mono", Menlo, monospace; color: var(--muted);
background: rgba(0,0,0,0.35); border: 1px solid var(--border); border-radius: var(--r-sm);
padding: 6px 8px; max-height: 130px; overflow-y: auto; white-space: pre-wrap;
word-break: break-all; margin: 6px 0; }
#tools button.accent { color: var(--accent); border-color: var(--accent); }
#tools button.busy { color: var(--accent); border-color: var(--accent); }
/* Cadres des dalles du run : orange pulsant = rendu en cours, bleu = en
attente, rouge = échec. Les dalles faites n'ont pas de cadre. */
@keyframes genpulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.35; } }
.gen-frame-running { stroke: var(--gen-running); fill: color-mix(in srgb, var(--gen-running) 13%, transparent); animation: genpulse 1.4s ease-in-out infinite; }
.gen-frame-pending { stroke: var(--gen-pending); fill: color-mix(in srgb, var(--gen-pending) 8%, transparent); stroke-dasharray: 6 4; }
.gen-frame-failed { stroke: var(--gen-failed); fill: color-mix(in srgb, var(--gen-failed) 20%, transparent); }
.gen-sel { stroke: var(--accent); fill: color-mix(in srgb, var(--accent) 12%, transparent); cursor: pointer; }
/* --- panneau unique à onglets ------------------------------------------------
Ordinateur : colonne à gauche, repliable en bande d'icônes.
Téléphone : volet en bas à trois hauteurs (fermé / mi-hauteur / plein). */
#panel { position: fixed; z-index: var(--z-panel); display: flex; flex-direction: column;
background: var(--surface); color: var(--text); border: 1px solid var(--border);
box-shadow: var(--shadow-lg); backdrop-filter: blur(8px); -webkit-backdrop-filter: blur(8px);
left: var(--sp-3); top: var(--sp-3); bottom: var(--sp-3); width: 340px; border-radius: var(--r-md); }
.panel-head { display: flex; align-items: center; gap: var(--sp-1); padding: var(--sp-2);
border-bottom: 1px solid var(--border); }
.panel-tabs { display: flex; gap: var(--sp-1); flex: 1; min-width: 0; }
.panel-tabs button { flex: 1; min-width: 0; flex-direction: column; gap: 0; min-height: 44px;
padding: var(--sp-1); border: none; background: transparent; color: var(--muted); }
.panel-tabs button[aria-selected="true"] { background: var(--surface-2); color: var(--accent); }
.tab-ico { font-size: var(--fs-lg); line-height: 1.1; }
.tab-lbl { font-size: var(--fs-xs); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 100%; }
.panel-body { flex: 1; overflow-y: auto; padding: var(--sp-3); overscroll-behavior: contain; }
.panel-body section > * + * { margin-top: var(--sp-2); }
.panel-stat { font-size: var(--fs-sm); color: var(--muted); }
.sec-title { font-size: var(--fs-xs); font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase;
color: var(--muted); margin-top: var(--sp-4); }
.legend { display: flex; align-items: center; gap: var(--sp-3); }
.legend canvas { width: 96px; height: 96px; flex: none; }
.sheet-grip { display: none; }
#panel.collapsed { width: 60px; }
#panel.collapsed .panel-body, #panel.collapsed .tab-lbl { display: none; }
#panel.collapsed .panel-head { flex-direction: column; border-bottom: none; }
#panel.collapsed .panel-tabs { flex-direction: column; align-self: stretch; }
#panel.collapsed #panelCollapse { transform: rotate(180deg); }
/* La carte, l'échelle et les messages se décalent de la largeur du panneau. */
body { --panel-w: 364px; --sheet-h: 0px; }
body.panel-collapsed { --panel-w: 84px; }
.leaflet-bottom.leaflet-left { left: var(--panel-w); }
@media (max-width: 720px) {
body, body.panel-collapsed { --panel-w: 0px; }
#panel, #panel.collapsed { left: 0; right: 0; top: auto; bottom: 0; width: auto;
border-radius: var(--r-md) var(--r-md) 0 0; border-bottom: none; transition: height 0.2s ease; }
#panel[data-sheet="closed"] { height: 72px; }
#panel[data-sheet="half"] { height: 45vh; }
#panel[data-sheet="full"] { height: calc(100vh - var(--sp-4)); }
#panel[data-sheet="closed"] .panel-body { display: none; }
#panelCollapse { display: none; }
.sheet-grip { display: flex; justify-content: center; padding: var(--sp-2) 0 0; cursor: grab; touch-action: none; }
.sheet-grip span { width: 36px; height: 4px; border-radius: var(--r-full); background: var(--muted); }
.panel-head { padding: var(--sp-1) var(--sp-2); }
.leaflet-bottom { bottom: var(--sheet-h); }
/* Attribution sur toute la largeur : l'échelle passe au-dessus d'elle,
l'indicateur de chargement en haut de l'écran (à gauche des outils). */
.leaflet-bottom.leaflet-left .leaflet-control-scale { margin-bottom: 28px; }
.tileload { top: var(--sp-3); bottom: auto; }
}