feat(r4): maquettes HD mobile technicien — 7 écrans offline-first à valider

Design d'abord : aucune ligne de code Expo avant validation. Ma journée
(en ligne / hors-ligne côte à côte), fiche OT, clôture terrain (bilan
codé R2, garde visible, variante « en file »), scan QR des étiquettes
A6 (R1, hors-ligne inclus), fiche ascenseur, checklist du mois (coches
individuelles en file), synchro & conflits (verrou optimiste, l'humain
tranche). Tokens répliqués, bi-thème, données du parc seedé.

5 décisions soumises avec les écrans : offline-first en file, verrou
optimiste, périmètre fermé technicien, scan résolu en local, photos
compressées en file — ni audio ni géolocalisation en R4 (loi 09-08).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
pr-daaif
2026-07-17 02:37:18 +01:00
parent 3d787a2d39
commit 2736a2f3a1
3 changed files with 658 additions and 1 deletions

View File

@@ -0,0 +1,641 @@
<!doctype html>
<html lang="fr">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>SIOP V2 — Maquettes HD · R4 Mobile technicien</title>
</head>
<body>
<!--
SIOP V2 — Maquettes HD de la release R4 « Mobile technicien » (design-first).
À VALIDER PAR LE RÉFÉRENT AVANT TOUT CODE EXPO (principe n°1).
Cible : l'app du TECHNICIEN (Ahmed) — offline-first, Expo Go.
La gestion reste web ; le demandeur reste sur le portail QR public (R2).
Tokens répliqués de ../tokens.css ; gabarit téléphone repris de maquette-r3
(écran portail) et étendu : tabbar, file de synchro, conflits.
Recette type (plan de releases) : mode avion en sous-sol → cocher la grille
→ retour réseau → synchro sans perdre une saisie (verrou optimiste).
-->
<style>
/* ═══ Tokens (répliques de ../tokens.css) ═══ */
:root{
--primaire:#1f4fb8;--primaire-actif:#1a439c;--primaire-doux:#eaf0fb;
--safran:#dd8a0b;--safran-doux:#fdf3e3;
--fond:#f5f7fa;--surface:#ffffff;--surface-2:#eef2f7;
--bordure:#dce3ec;--bordure-forte:#b9c4d4;
--encre:#1b2534;--encre-2:#55647a;--encre-3:#8494ab;
--st-ouvert:#3d6fe0;--st-ouvert-fond:#e9effc;--st-encours:#6d5bd8;--st-encours-fond:#efecfa;
--st-attente:#b96f07;--st-attente-fond:#fbf1df;--st-termine:#178a50;--st-termine-fond:#e6f5ec;
--st-annule:#68788f;--st-annule-fond:#edf0f4;
--prio-bloque:#d92626;--prio-bloque-fond:#fdeaea;--prio-haute:#d92626;
--prio-moyenne:#b96f07;--prio-basse:#178a50;--prio-aucune:#8494ab;
--succes:#178a50;--alerte:#b96f07;--danger:#d92626;--info:#3d6fe0;
--graf-1:#3b69d6;--graf-2:#dd8a0b;--graf-3:#1f9e8e;--graf-4:#8a63d2;--graf-grille:#e6ebf2;
--nav-fond:#16233b;--nav-encre:#c6d2e4;--nav-encre-vif:#ffffff;--nav-bordure:#24344f;
--police-ui:"Manrope","Avenir Next","Segoe UI Variable",system-ui,sans-serif;
--rayon:10px;--rayon-controle:8px;--ombre-menu:0 8px 24px rgb(16 30 54/.14);
--transition:140ms ease-out;
}
@media (prefers-color-scheme:dark){:root{
--primaire:#6e92e8;--primaire-actif:#8facf0;--primaire-doux:#1d2c4c;
--safran:#e89a1f;--safran-doux:#33270f;
--fond:#0f1622;--surface:#182234;--surface-2:#1e2a40;
--bordure:#2b3850;--bordure-forte:#3d4d6b;
--encre:#e8edf5;--encre-2:#a7b4c8;--encre-3:#6d7d96;
--st-ouvert:#7da2ee;--st-ouvert-fond:#1c2a47;--st-encours:#a394ec;--st-encours-fond:#262040;
--st-attente:#e0a33c;--st-attente-fond:#322510;--st-termine:#4bc084;--st-termine-fond:#12301f;
--st-annule:#93a3ba;--st-annule-fond:#222d3f;
--prio-bloque:#f26d6d;--prio-bloque-fond:#3a1414;--prio-haute:#f26d6d;
--prio-moyenne:#e0a33c;--prio-basse:#4bc084;--prio-aucune:#6d7d96;
--succes:#4bc084;--alerte:#e0a33c;--danger:#f26d6d;--info:#7da2ee;
--graf-1:#5580e4;--graf-2:#c7820a;--graf-3:#26a896;--graf-4:#9673de;--graf-grille:#24304a;
--nav-fond:#0c1524;--nav-encre:#a7b4c8;--nav-encre-vif:#f2f6fc;--nav-bordure:#1e2c44;
--ombre-menu:0 8px 24px rgb(0 0 0/.45);
}}
:root[data-theme="light"]{
--primaire:#1f4fb8;--primaire-actif:#1a439c;--primaire-doux:#eaf0fb;
--safran:#dd8a0b;--safran-doux:#fdf3e3;
--fond:#f5f7fa;--surface:#ffffff;--surface-2:#eef2f7;
--bordure:#dce3ec;--bordure-forte:#b9c4d4;
--encre:#1b2534;--encre-2:#55647a;--encre-3:#8494ab;
--st-ouvert:#3d6fe0;--st-ouvert-fond:#e9effc;--st-encours:#6d5bd8;--st-encours-fond:#efecfa;
--st-attente:#b96f07;--st-attente-fond:#fbf1df;--st-termine:#178a50;--st-termine-fond:#e6f5ec;
--st-annule:#68788f;--st-annule-fond:#edf0f4;
--prio-bloque:#d92626;--prio-bloque-fond:#fdeaea;--prio-haute:#d92626;
--prio-moyenne:#b96f07;--prio-basse:#178a50;--prio-aucune:#8494ab;
--succes:#178a50;--alerte:#b96f07;--danger:#d92626;--info:#3d6fe0;
--graf-1:#3b69d6;--graf-2:#dd8a0b;--graf-3:#1f9e8e;--graf-4:#8a63d2;--graf-grille:#e6ebf2;
--nav-fond:#16233b;--nav-encre:#c6d2e4;--nav-encre-vif:#ffffff;--nav-bordure:#24344f;
--ombre-menu:0 8px 24px rgb(16 30 54/.14);
}
:root[data-theme="dark"]{
--primaire:#6e92e8;--primaire-actif:#8facf0;--primaire-doux:#1d2c4c;
--safran:#e89a1f;--safran-doux:#33270f;
--fond:#0f1622;--surface:#182234;--surface-2:#1e2a40;
--bordure:#2b3850;--bordure-forte:#3d4d6b;
--encre:#e8edf5;--encre-2:#a7b4c8;--encre-3:#6d7d96;
--st-ouvert:#7da2ee;--st-ouvert-fond:#1c2a47;--st-encours:#a394ec;--st-encours-fond:#262040;
--st-attente:#e0a33c;--st-attente-fond:#322510;--st-termine:#4bc084;--st-termine-fond:#12301f;
--st-annule:#93a3ba;--st-annule-fond:#222d3f;
--prio-bloque:#f26d6d;--prio-bloque-fond:#3a1414;--prio-haute:#f26d6d;
--prio-moyenne:#e0a33c;--prio-basse:#4bc084;--prio-aucune:#6d7d96;
--succes:#4bc084;--alerte:#e0a33c;--danger:#f26d6d;--info:#7da2ee;
--graf-1:#5580e4;--graf-2:#c7820a;--graf-3:#26a896;--graf-4:#9673de;--graf-grille:#24304a;
--nav-fond:#0c1524;--nav-encre:#a7b4c8;--nav-encre-vif:#f2f6fc;--nav-bordure:#1e2c44;
--ombre-menu:0 8px 24px rgb(0 0 0/.45);
}
/* ═══ Base ═══ */
*{box-sizing:border-box;margin:0}
html,body{background:var(--fond)}
body{font-family:var(--police-ui);color:var(--encre);font-size:14px;line-height:1.5}
button{font:inherit;cursor:pointer;border:0;background:none;color:inherit}
button:focus-visible,a:focus-visible{outline:2px solid var(--primaire);outline-offset:2px;border-radius:4px}
.num{font-variant-numeric:tabular-nums}
/* ═══ Barre de revue (outil maquette, pas l'app) ═══ */
.revue{position:sticky;top:0;z-index:50;display:flex;align-items:center;gap:12px;flex-wrap:wrap;
padding:10px 16px;background:var(--nav-fond);color:var(--nav-encre);font-size:13px}
.revue b{color:var(--nav-encre-vif);letter-spacing:.02em}
.revue .onglets{display:flex;gap:4px;flex-wrap:wrap}
.revue .onglets button{padding:6px 10px;border-radius:6px;color:var(--nav-encre)}
.revue .onglets button:hover{background:rgb(255 255 255/.08);color:var(--nav-encre-vif)}
.revue .onglets button[aria-selected="true"]{background:rgb(255 255 255/.12);color:var(--nav-encre-vif);
box-shadow:inset 3px 0 0 var(--safran)}
.revue .droite{margin-left:auto;display:flex;align-items:center;gap:8px}
.revue .theme{padding:6px 10px;border:1px solid var(--nav-bordure);border-radius:6px}
.note-ecran{max-width:1120px;margin:14px auto 0;padding:0 20px;color:var(--encre-2);font-size:13px}
.note-ecran b{color:var(--encre)}
/* ═══ Écrans (mobile only — pas de coquille web en R4) ═══ */
.ecran{display:none;max-width:1120px;margin:18px auto 44px;padding:0 20px}
.ecran.actif{display:block}
.tels{display:flex;gap:28px;justify-content:center;flex-wrap:wrap}
.tel{width:310px;border:1px solid var(--bordure-forte);border-radius:28px;overflow:hidden;background:var(--fond);
box-shadow:var(--ombre-menu);display:flex;flex-direction:column}
.tel .encoche{height:26px;background:var(--nav-fond);display:flex;justify-content:center;align-items:center;flex:none}
.tel .encoche i{width:70px;height:7px;border-radius:999px;background:rgb(255 255 255/.18)}
.tel .legende{flex:none;text-align:center;font-size:11.5px;font-weight:700;letter-spacing:.05em;
text-transform:uppercase;color:var(--encre-3);padding:8px;background:var(--surface-2)}
.ecran-tel{padding:14px;display:flex;flex-direction:column;gap:10px;min-height:560px}
/* Entête app */
.entete-tel{display:flex;align-items:center;gap:8px}
.entete-tel .flamme{color:var(--safran);font-size:16px}
.entete-tel b{font-size:16px;letter-spacing:.03em}
.entete-tel small{color:var(--encre-3);font-size:10.5px;margin-top:3px}
.entete-tel .fin{margin-left:auto;display:flex;align-items:center;gap:6px}
.avatar-tel{width:26px;height:26px;border-radius:50%;background:var(--st-encours);color:#fff;
display:flex;align-items:center;justify-content:center;font-size:10.5px;font-weight:700}
.sync{font-size:10.5px;font-weight:700;color:var(--st-termine);background:var(--st-termine-fond);
padding:2px 8px;border-radius:999px;white-space:nowrap}
.sync.off{color:var(--st-attente);background:var(--st-attente-fond)}
.titre-tel{font-size:17px;font-weight:800;display:flex;align-items:center;gap:8px}
.titre-tel .filet{margin-left:auto;font-size:11px;color:var(--encre-3);font-weight:600}
/* Bandeaux */
.bandeau-off{display:flex;align-items:center;gap:8px;background:var(--st-attente-fond);color:var(--st-attente);
border:1px solid currentColor;border-radius:10px;padding:8px 10px;font-size:12px;font-weight:700}
.bandeau-urgence{display:flex;align-items:center;gap:8px;background:var(--prio-bloque-fond);color:var(--prio-bloque);
border-radius:10px;padding:8px 10px;font-size:12px;font-weight:800}
.point-pulse{width:8px;height:8px;border-radius:50%;background:currentColor;flex:none}
/* Cartes OT */
.carte-ot-tel{background:var(--surface);border:1px solid var(--bordure);border-radius:12px;padding:11px 12px;
border-left:4px solid transparent}
.carte-ot-tel.bloque{border-left-color:var(--prio-bloque)}
.carte-ot-tel.haute{border-left-color:var(--prio-haute)}
.carte-ot-tel.moyenne{border-left-color:var(--prio-moyenne)}
.carte-ot-tel.basse{border-left-color:var(--prio-basse)}
.carte-ot-tel .type-t{font-size:10.5px;letter-spacing:.06em;text-transform:uppercase;color:var(--encre-2);
font-weight:700;display:flex;justify-content:space-between;align-items:center;gap:6px}
.carte-ot-tel b{display:block;margin:3px 0 2px;font-size:14px}
.carte-ot-tel .ou{color:var(--encre-2);font-size:12px}
.st{font-size:10.5px;font-weight:700;padding:2px 8px;border-radius:999px;white-space:nowrap}
.st.ouvert{color:var(--st-ouvert);background:var(--st-ouvert-fond)}
.st.encours{color:var(--st-encours);background:var(--st-encours-fond)}
.st.attente{color:var(--st-attente);background:var(--st-attente-fond)}
.st.termine{color:var(--st-termine);background:var(--st-termine-fond)}
.pastille-file{font-size:10.5px;font-weight:700;color:var(--st-attente);background:var(--st-attente-fond);
padding:2px 8px;border-radius:999px}
/* Boutons */
.btn-tel{display:flex;justify-content:center;align-items:center;gap:8px;padding:12px;border-radius:10px;
font-weight:700;font-size:14.5px;background:var(--primaire);color:#fff;width:100%}
.btn-tel.vert{background:var(--succes)}
.btn-tel.gris{background:var(--bordure-forte);color:var(--surface)}
.btn-tel.contour{background:var(--surface);color:var(--primaire);border:1.5px solid var(--primaire)}
.paire-boutons{display:flex;gap:8px}
.paire-boutons .btn-tel{padding:10px;font-size:13px}
/* Fiche : cartes d'info */
.carte-tel{background:var(--surface);border:1px solid var(--bordure);border-radius:12px;padding:12px;
display:flex;flex-direction:column;gap:8px}
.carte-tel h4{font-size:10.5px;letter-spacing:.07em;text-transform:uppercase;color:var(--encre-2)}
.ligne-info{display:flex;justify-content:space-between;gap:10px;font-size:12.5px}
.ligne-info span:first-child{color:var(--encre-2)}
.ligne-info b{text-align:right}
.garde{font-size:11.5px;color:var(--alerte);font-weight:600}
/* Bilan codé (selects) */
.champ-tel{display:flex;flex-direction:column;gap:4px}
.champ-tel label{font-size:11px;font-weight:700;color:var(--encre-2)}
.champ-tel label em{color:var(--danger);font-style:normal}
.select-tel{border:1.5px solid var(--bordure-forte);border-radius:9px;background:var(--surface);
padding:9px 10px;font-size:13px;color:var(--encre);display:flex;justify-content:space-between;align-items:center}
.select-tel.vide{color:var(--encre-3)}
.grille-2-tel{display:grid;grid-template-columns:1fr 1fr;gap:8px}
/* Checklist */
.progress{height:8px;border-radius:999px;background:var(--surface-2);overflow:hidden}
.progress i{display:block;height:100%;border-radius:999px;background:var(--succes);width:58%}
.check-item{display:flex;align-items:center;gap:10px;background:var(--surface);border:1px solid var(--bordure);
border-radius:10px;padding:10px 12px;font-size:13px}
.check-item .case{width:20px;height:20px;border-radius:6px;border:2px solid var(--bordure-forte);flex:none}
.check-item.fait .case{background:var(--succes);border-color:var(--succes);position:relative}
.check-item.fait .case::after{content:'✓';color:#fff;font-size:13px;font-weight:800;position:absolute;inset:0;
display:flex;align-items:center;justify-content:center}
.check-item.fait{color:var(--encre-2)}
.check-item .file-chip{margin-left:auto}
/* Scan */
.viseur{flex:1;min-height:340px;border-radius:12px;background:
radial-gradient(circle at 50% 45%, #2c3a52 0%, #131c2c 70%);position:relative;display:flex;
align-items:center;justify-content:center}
.viseur .cadre-qr{width:170px;height:170px;border-radius:14px;border:2.5px solid var(--safran);
box-shadow:0 0 0 2000px rgb(9 14 22/.45)}
.viseur p{position:absolute;bottom:14px;color:#dfe7f2;font-size:12.5px}
/* Historique fiche ascenseur */
.hist-item{display:flex;gap:8px;align-items:baseline;font-size:12.5px;padding:7px 0;border-top:1px solid var(--bordure)}
.hist-item:first-of-type{border-top:0}
.hist-item .ref{color:var(--primaire);font-weight:700;flex:none}
.hist-item .quand{margin-left:auto;color:var(--encre-3);font-size:11px;white-space:nowrap}
/* File de synchro */
.file-item{display:flex;align-items:center;gap:10px;background:var(--surface);border:1px solid var(--bordure);
border-radius:10px;padding:10px 12px;font-size:12.5px}
.file-item .ico{width:28px;height:28px;border-radius:8px;background:var(--surface-2);display:flex;
align-items:center;justify-content:center;flex:none;font-size:14px}
.file-item .quoi b{display:block;font-size:12.5px}
.file-item .quoi span{color:var(--encre-2);font-size:11px}
.file-item .etat{margin-left:auto;font-size:10.5px;font-weight:700;padding:2px 8px;border-radius:999px;white-space:nowrap}
.etat.attente{color:var(--st-attente);background:var(--st-attente-fond)}
.etat.envoi{color:var(--info);background:var(--st-ouvert-fond)}
.etat.fait{color:var(--st-termine);background:var(--st-termine-fond)}
.etat.conflit{color:var(--danger);background:var(--prio-bloque-fond)}
.carte-conflit{background:var(--prio-bloque-fond);border:1.5px solid var(--danger);border-radius:12px;
padding:12px;display:flex;flex-direction:column;gap:8px}
.carte-conflit h4{color:var(--danger);font-size:12.5px;display:flex;gap:6px;align-items:center}
.carte-conflit p{font-size:12px;color:var(--encre)}
.carte-conflit small{font-size:11px;color:var(--encre-2)}
/* Tabbar */
.tabbar{margin-top:auto;display:flex;border-top:1px solid var(--bordure);background:var(--surface);
border-radius:0 0 0 0;padding:6px 4px 8px}
.tabbar a{flex:1;display:flex;flex-direction:column;align-items:center;gap:2px;font-size:9.5px;
font-weight:700;color:var(--encre-3);text-decoration:none;position:relative}
.tabbar a.actif{color:var(--primaire)}
.tabbar a .pic{font-size:17px;line-height:1.2}
.tabbar .badge-tab{position:absolute;top:-3px;right:calc(50% - 16px);background:var(--st-attente);
color:#fff;font-size:9px;font-weight:800;padding:0 5px;border-radius:999px}
.tabbar .badge-tab.rouge{background:var(--prio-bloque)}
/* Photos jointes */
.photos-tel{display:flex;gap:8px}
.photo-tel{width:56px;height:56px;border-radius:9px;background:var(--surface-2);border:1px solid var(--bordure);
display:flex;align-items:center;justify-content:center;font-size:19px;position:relative}
.photo-tel .file-chip{position:absolute;bottom:-6px;right:-6px}
.file-chip{font-size:9px;font-weight:800;color:var(--st-attente);background:var(--st-attente-fond);
border:1px solid currentColor;padding:0 5px;border-radius:999px}
</style>
<header class="revue">
<b>SIOP · Maquettes R4 — Mobile technicien</b>
<nav class="onglets" role="tablist" aria-label="Écrans">
<button role="tab" aria-selected="true" data-cible="jour">1 · Ma journée</button>
<button role="tab" aria-selected="false" data-cible="fiche-ot">2 · Fiche OT</button>
<button role="tab" aria-selected="false" data-cible="cloture">3 · Clôture terrain</button>
<button role="tab" aria-selected="false" data-cible="scan">4 · Scan QR</button>
<button role="tab" aria-selected="false" data-cible="ascenseur">5 · Fiche ascenseur</button>
<button role="tab" aria-selected="false" data-cible="checklist">6 · Checklist du mois</button>
<button role="tab" aria-selected="false" data-cible="synchro">7 · Synchro & conflits</button>
</nav>
<div class="droite"><button class="theme" id="btn-theme">Thème : auto</button></div>
</header>
<!-- ═══ 1 · MA JOURNÉE ═══ -->
<p class="note-ecran" data-note="jour"><b>Intention :</b> l'app s'ouvre sur les OT d'Ahmed, triés
<b>priorité puis échéance</b> — urgence « personne bloquée » toujours en tête. Le même écran vit
<b>en ligne et hors-ligne</b> : hors-ligne, rien ne disparaît, un bandeau l'assume et la tabbar
compte les saisies en file. La pastille de synchro est permanente (vert = à jour, ambre = en attente).</p>
<section class="ecran actif" id="jour">
<div class="tels">
<div class="tel">
<div class="encoche"><i></i></div>
<div class="legende">En ligne — à jour</div>
<div class="ecran-tel">
<div class="entete-tel">
<span class="flamme"></span><b>SIOP</b>
<small>Technicien</small>
<span class="fin"><span class="sync">Synchro à jour</span><span class="avatar-tel">AB</span></span>
</div>
<div class="titre-tel">Ma journée <span class="filet">jeudi 17 juil.</span></div>
<div class="bandeau-urgence"><span class="point-pulse"></span>1 personne bloquée — B2 · Tour Atlas</div>
<div class="carte-ot-tel bloque">
<div class="type-t">OT-2026-0342 · Dépannage <span class="st ouvert">Ouvert</span></div>
<b>Personne bloquée en cabine</b>
<div class="ou">Asc. B2 — Tour Atlas · Aïn Diab</div>
</div>
<div class="carte-ot-tel haute">
<div class="type-t">OT-2026-0341 · Dépannage <span class="st encours">En cours</span></div>
<b>Bruit anormal en gaine</b>
<div class="ou">Asc. A1 — Résidence Al Manar · échéance 18 juil.</div>
</div>
<div class="carte-ot-tel moyenne">
<div class="type-t">OT-2026-0336 · Préventif <span class="st ouvert">Ouvert</span></div>
<b>Contrôle mensuel — juillet</b>
<div class="ou">Asc. A2 — Résidence Al Manar · grille 0/12</div>
</div>
<div class="carte-ot-tel basse">
<div class="type-t">OT-2026-0329 · Travaux <span class="st attente">En attente</span></div>
<b>Remplacement coulisseaux</b>
<div class="ou">Asc. C1 — Anfa Place · pièce commandée (BC-2026-0024)</div>
</div>
<nav class="tabbar">
<a class="actif" href="#"><span class="pic"></span>Ma journée</a>
<a href="#"><span class="pic"></span>Scanner</a>
<a href="#"><span class="pic"></span>Préventif</a>
<a href="#"><span class="pic"></span>Synchro</a>
</nav>
</div>
</div>
<div class="tel">
<div class="encoche"><i></i></div>
<div class="legende">Hors-ligne — sous-sol</div>
<div class="ecran-tel">
<div class="entete-tel">
<span class="flamme"></span><b>SIOP</b>
<small>Technicien</small>
<span class="fin"><span class="sync off">Hors-ligne</span><span class="avatar-tel">AB</span></span>
</div>
<div class="titre-tel">Ma journée <span class="filet">jeudi 17 juil.</span></div>
<div class="bandeau-off">⚠ Hors-ligne — vos saisies partent en file et se synchroniseront au retour du réseau.</div>
<div class="carte-ot-tel haute">
<div class="type-t">OT-2026-0341 · Dépannage <span class="st encours">En cours</span></div>
<b>Bruit anormal en gaine</b>
<div class="ou">Asc. A1 — Résidence Al Manar · échéance 18 juil.</div>
</div>
<div class="carte-ot-tel moyenne">
<div class="type-t">OT-2026-0336 · Préventif <span class="st ouvert">Ouvert</span> <span class="pastille-file">2 en file</span></div>
<b>Contrôle mensuel — juillet</b>
<div class="ou">Asc. A2 — Résidence Al Manar · grille 7/12</div>
</div>
<div class="carte-ot-tel basse">
<div class="type-t">OT-2026-0329 · Travaux <span class="st attente">En attente</span></div>
<b>Remplacement coulisseaux</b>
<div class="ou">Asc. C1 — Anfa Place · pièce commandée (BC-2026-0024)</div>
</div>
<nav class="tabbar">
<a class="actif" href="#"><span class="pic"></span>Ma journée</a>
<a href="#"><span class="pic"></span>Scanner</a>
<a href="#"><span class="pic"></span>Préventif</a>
<a href="#"><span class="pic"></span>Synchro<span class="badge-tab">3</span></a>
</nav>
</div>
</div>
</div>
</section>
<!-- ═══ 2 · FICHE OT ═══ -->
<p class="note-ecran" data-note="fiche-ot" hidden><b>Intention :</b> la même machine à états que le web
(R2) — un seul <b>bouton principal</b> selon l'état, jamais de liste de transitions. Consommer une pièce
et saisir du temps reprennent les règles R3 (prix et taux <b>figés</b> annoncés avant le geste). Les photos
partent en file comme le reste. Aucune saisie n'exige le réseau.</p>
<section class="ecran" id="fiche-ot">
<div class="tels">
<div class="tel">
<div class="encoche"><i></i></div>
<div class="legende">OT en cours — actions terrain</div>
<div class="ecran-tel">
<div class="entete-tel">
<span class="flamme"></span><b> OT-2026-0341</b>
<span class="fin"><span class="sync">Synchro à jour</span></span>
</div>
<div class="titre-tel">Bruit anormal en gaine <span class="st encours">En cours</span></div>
<div class="carte-tel">
<h4>Intervention</h4>
<div class="ligne-info"><span>Équipement</span><b>Asc. A1 — Résidence Al Manar</b></div>
<div class="ligne-info"><span>Priorité</span><b style="color:var(--prio-haute)">Haute</b></div>
<div class="ligne-info"><span>Échéance</span><b>18 juillet</b></div>
<div class="ligne-info"><span>Demande liée</span><b>DEM-2026-0107 · Karim D.</b></div>
</div>
<div class="carte-tel">
<h4>Pièces & main-d'œuvre — 505 MAD</h4>
<div class="ligne-info"><span>Coulisseau 16 mm × 2</span><b class="num">240</b></div>
<div class="ligne-info"><span>Graisse guide × 1</span><b class="num">85</b></div>
<div class="ligne-info"><span>Ahmed · 1 h 30 × 120/h</span><b class="num">180</b></div>
<div class="paire-boutons">
<button class="btn-tel contour">+ Pièce</button>
<button class="btn-tel contour">+ Temps</button>
</div>
</div>
<div class="carte-tel">
<h4>Photos</h4>
<div class="photos-tel">
<span class="photo-tel">🖼</span>
<span class="photo-tel">🖼<span class="file-chip">en file</span></span>
<span class="photo-tel" style="color:var(--primaire);font-size:23px">+</span>
</div>
</div>
<button class="btn-tel vert">Clôturer l'intervention</button>
<div class="garde">Bilan incomplet : « État des portes », « Action réalisée », « Élément concerné » — la clôture ouvrira le bilan.</div>
</div>
</div>
</div>
</section>
<!-- ═══ 3 · CLÔTURE TERRAIN ═══ -->
<p class="note-ecran" data-note="cloture" hidden><b>Intention :</b> le bilan codé R2, plein écran et au
pouce : 3 champs requis (<em>*</em>), la garde reste <b>visible et bloquante</b> tant qu'ils manquent —
identique au web, mêmes référentiels administrables. Hors-ligne, « Clôturer » met la clôture <b>en
file</b> : l'OT passe localement à « Terminé (en file) » et se confirme à la synchro.</p>
<section class="ecran" id="cloture">
<div class="tels">
<div class="tel">
<div class="encoche"><i></i></div>
<div class="legende">Bilan incomplet — garde visible</div>
<div class="ecran-tel">
<div class="entete-tel"><span class="flamme"></span><b> Clôturer OT-2026-0341</b></div>
<div class="carte-tel">
<h4>Bilan d'intervention — requis pour clôturer</h4>
<div class="grille-2-tel">
<div class="champ-tel"><label>État des portes <em>*</em></label><span class="select-tel">Fonctionnelles ▾</span></div>
<div class="champ-tel"><label>Position cabine</label><span class="select-tel vide">Sélectionner ▾</span></div>
<div class="champ-tel"><label>Anomalie constatée</label><span class="select-tel">Frottement guides ▾</span></div>
<div class="champ-tel"><label>Cause extérieure</label><span class="select-tel vide">Sélectionner ▾</span></div>
<div class="champ-tel"><label>Action réalisée <em>*</em></label><span class="select-tel">Remplacement pièce ▾</span></div>
<div class="champ-tel"><label>Élément concerné <em>*</em></label><span class="select-tel vide">Sélectionner ▾</span></div>
</div>
<div class="garde">⚠ « Élément concerné » manque — la clôture restera bloquée (même garde que le web).</div>
</div>
<div class="carte-tel">
<h4>Checklist liée — 12/12 ✓</h4>
<div class="ligne-info"><span>Grille de juillet cochée sur place</span><b style="color:var(--succes)">complète</b></div>
</div>
<button class="btn-tel gris">Clôturer (bilan incomplet)</button>
</div>
</div>
<div class="tel">
<div class="encoche"><i></i></div>
<div class="legende">Complet, hors-ligne — clôture en file</div>
<div class="ecran-tel">
<div class="entete-tel"><span class="flamme"></span><b> Clôturer OT-2026-0341</b>
<span class="fin"><span class="sync off">Hors-ligne</span></span></div>
<div class="carte-tel">
<h4>Bilan d'intervention — complet</h4>
<div class="grille-2-tel">
<div class="champ-tel"><label>État des portes <em>*</em></label><span class="select-tel">Fonctionnelles ▾</span></div>
<div class="champ-tel"><label>Position cabine</label><span class="select-tel">À niveau ▾</span></div>
<div class="champ-tel"><label>Anomalie constatée</label><span class="select-tel">Frottement guides ▾</span></div>
<div class="champ-tel"><label>Cause extérieure</label><span class="select-tel">Aucune ▾</span></div>
<div class="champ-tel"><label>Action réalisée <em>*</em></label><span class="select-tel">Remplacement pièce ▾</span></div>
<div class="champ-tel"><label>Élément concerné <em>*</em></label><span class="select-tel">Guides ▾</span></div>
</div>
</div>
<button class="btn-tel vert">Clôturer — partira à la synchro</button>
<div class="bandeau-off">La clôture est enregistrée sur le téléphone. Elle sera rejouée telle quelle au retour du réseau.</div>
</div>
</div>
</div>
</section>
<!-- ═══ 4 · SCAN QR ═══ -->
<p class="note-ecran" data-note="scan" hidden><b>Intention :</b> le scanner lit le <b>QR des étiquettes
A6</b> posées en R1 (la référence de l'appareil) et ouvre la fiche — y compris <b>hors-ligne</b>, sur le
parc déjà synchronisé. En dessous de l'épaule : saisie manuelle de la référence. Aucune géolocalisation
en R4 (backlog v2, loi 09-08 : minimisation).</p>
<section class="ecran" id="scan">
<div class="tels">
<div class="tel">
<div class="encoche"><i></i></div>
<div class="legende">Scanner — QR de l'étiquette A6</div>
<div class="ecran-tel">
<div class="entete-tel"><span class="flamme"></span><b>Scanner</b>
<span class="fin"><span class="sync off">Hors-ligne</span></span></div>
<div class="viseur">
<span class="cadre-qr"></span>
<p>Visez le QR de l'étiquette de cabine</p>
</div>
<button class="btn-tel contour">Saisir la référence (A1, B2…)</button>
<nav class="tabbar">
<a href="#"><span class="pic"></span>Ma journée</a>
<a class="actif" href="#"><span class="pic"></span>Scanner</a>
<a href="#"><span class="pic"></span>Préventif</a>
<a href="#"><span class="pic"></span>Synchro<span class="badge-tab">3</span></a>
</nav>
</div>
</div>
</div>
</section>
<!-- ═══ 5 · FICHE ASCENSEUR ═══ -->
<p class="note-ecran" data-note="ascenseur" hidden><b>Intention :</b> après le scan, tout ce qu'Ahmed
doit savoir <b>devant la machine</b> : identité, statut, organes, historique des interventions (bilans
codés lisibles). Consultation seule : la création d'OT reste au dispatcher (web) et le signalement au
portail QR public (R2) — le mobile n'ajoute pas de 3ᵉ canal.</p>
<section class="ecran" id="ascenseur">
<div class="tels">
<div class="tel">
<div class="encoche"><i></i></div>
<div class="legende">Résultat du scan — Asc. A1</div>
<div class="ecran-tel">
<div class="entete-tel"><span class="flamme"></span><b> Asc. A1</b>
<span class="fin"><span class="st termine">En service</span></span></div>
<div class="titre-tel">Otis Gen2 — Résidence Al Manar</div>
<div class="carte-tel">
<h4>Identité</h4>
<div class="ligne-info"><span>Emplacement</span><b>Hall principal</b></div>
<div class="ligne-info"><span>Mise en service</span><b>mars 2019</b></div>
<div class="ligne-info"><span>Sous contrat</span><b style="color:var(--succes)">Oui — préventif mensuel</b></div>
<div class="ligne-info"><span>Gardien</span><b>M. Alami · 06 12 34 56 78</b></div>
</div>
<div class="carte-tel">
<h4>Interventions récentes</h4>
<div class="hist-item"><span class="ref">OT-0341</span> Bruit anormal — guides <span class="quand">en cours</span></div>
<div class="hist-item"><span class="ref">OT-0329</span> Portes — contact remplacé <span class="quand">2 juil.</span></div>
<div class="hist-item"><span class="ref">OT-0318</span> Préventif juin — 12/12 ✓ <span class="quand">18 juin</span></div>
<div class="hist-item"><span class="ref">OT-0303</span> Armoire cde — fusible <span class="quand">30 mai</span></div>
</div>
<div class="carte-tel">
<h4>Organes suivis</h4>
<div class="ligne-info"><span>Treuil ZAA20</span><b></b></div>
<div class="ligne-info"><span>Portes cabine S3300</span><b>2 pannes / 12 mois</b></div>
<div class="ligne-info"><span>Armoire de commande</span><b>1 panne / 12 mois</b></div>
</div>
<button class="btn-tel">Voir mes OT sur cet appareil (2)</button>
</div>
</div>
</div>
</section>
<!-- ═══ 6 · CHECKLIST DU MOIS ═══ -->
<p class="note-ecran" data-note="checklist" hidden><b>Intention :</b> la grille préventive R2, cochable
<b>au pouce et hors-ligne</b> — chaque coche part en file individuellement (pas de « tout ou rien » :
7 coches faites = 7 coches sauvées, même si le téléphone s'éteint). La progression et le statut du mois
sont ceux du serveur à la dernière synchro, assumés comme tels.</p>
<section class="ecran" id="checklist">
<div class="tels">
<div class="tel">
<div class="encoche"><i></i></div>
<div class="legende">Grille de juillet — hors-ligne, 7/12</div>
<div class="ecran-tel">
<div class="entete-tel"><span class="flamme"></span><b> Préventif — juillet</b>
<span class="fin"><span class="sync off">Hors-ligne</span></span></div>
<div class="titre-tel">Asc. A2 — grille mensuelle <span class="filet num">7/12</span></div>
<div class="progress"><i></i></div>
<div class="check-item fait"><span class="case"></span>Verrouillage portes palières</div>
<div class="check-item fait"><span class="case"></span>Contacts de porte cabine</div>
<div class="check-item fait"><span class="case"></span>Niveau d'huile du treuil</div>
<div class="check-item fait"><span class="case"></span>Jeu des coulisseaux <span class="file-chip">en file</span></div>
<div class="check-item fait"><span class="case"></span>Éclairage cabine & secours <span class="file-chip">en file</span></div>
<div class="check-item"><span class="case"></span>Parachute — essai statique</div>
<div class="check-item"><span class="case"></span>Fins de course haut/bas</div>
<div class="check-item"><span class="case"></span>Téléalarme — essai d'appel</div>
<div class="bandeau-off">2 coches en file — la grille se recale à la synchro.</div>
</div>
</div>
</div>
</section>
<!-- ═══ 7 · SYNCHRO & CONFLITS ═══ -->
<p class="note-ecran" data-note="synchro" hidden><b>Intention :</b> la file est <b>visible et honnête</b> :
chaque saisie hors-ligne y est listée, rejouée dans l'ordre au retour du réseau. Conflit (verrou
optimiste : l'OT a changé côté serveur depuis la lecture) → la file <b>s'arrête sur l'élément</b>, montre
qui a modifié quoi et quand, et l'humain tranche — rien n'est écrasé ni perdu en silence. C'est l'écran
de la recette type « mode avion en sous-sol ».</p>
<section class="ecran" id="synchro">
<div class="tels">
<div class="tel">
<div class="encoche"><i></i></div>
<div class="legende">Retour réseau — file en cours</div>
<div class="ecran-tel">
<div class="entete-tel"><span class="flamme"></span><b>Synchro</b>
<span class="fin"><span class="sync">Envoi… 2/4</span></span></div>
<div class="titre-tel">File d'attente <span class="filet">rejouée dans l'ordre</span></div>
<div class="file-item"><span class="ico"></span>
<span class="quoi"><b>Coche « Jeu des coulisseaux »</b><span>OT-2026-0336 · 14 h 21</span></span>
<span class="etat fait">envoyée</span></div>
<div class="file-item"><span class="ico"></span>
<span class="quoi"><b>Coche « Éclairage cabine »</b><span>OT-2026-0336 · 14 h 24</span></span>
<span class="etat fait">envoyée</span></div>
<div class="file-item"><span class="ico">🖼</span>
<span class="quoi"><b>Photo — guides (1,8 Mo)</b><span>OT-2026-0341 · 14 h 32</span></span>
<span class="etat envoi">envoi…</span></div>
<div class="file-item"><span class="ico">🏁</span>
<span class="quoi"><b>Clôture + bilan codé</b><span>OT-2026-0341 · 14 h 40</span></span>
<span class="etat attente">en attente</span></div>
<nav class="tabbar">
<a href="#"><span class="pic"></span>Ma journée</a>
<a href="#"><span class="pic"></span>Scanner</a>
<a href="#"><span class="pic"></span>Préventif</a>
<a class="actif" href="#"><span class="pic"></span>Synchro<span class="badge-tab">2</span></a>
</nav>
</div>
</div>
<div class="tel">
<div class="encoche"><i></i></div>
<div class="legende">Conflit — l'humain tranche</div>
<div class="ecran-tel">
<div class="entete-tel"><span class="flamme"></span><b>Synchro</b>
<span class="fin"><span class="sync off">1 conflit</span></span></div>
<div class="titre-tel">File d'attente <span class="filet">arrêtée sur le conflit</span></div>
<div class="carte-conflit">
<h4>⚠ Conflit sur OT-2026-0341</h4>
<p><b>Salma Idrissi a modifié cet OT à 14 h 38</b> (réassigné + commentaire) pendant que vous étiez hors-ligne. Votre clôture de 14 h 40 n'a <b>pas</b> été appliquée.</p>
<small>Votre saisie est conservée telle quelle dans la file — rien n'est perdu.</small>
<button class="btn-tel" style="padding:10px;font-size:13px">Revoir l'OT à jour puis rejouer</button>
<button class="btn-tel contour" style="padding:10px;font-size:13px">Abandonner ma clôture</button>
</div>
<div class="file-item"><span class="ico">🏁</span>
<span class="quoi"><b>Clôture + bilan codé</b><span>OT-2026-0341 · 14 h 40</span></span>
<span class="etat conflit">conflit</span></div>
<div class="file-item"><span class="ico">🖼</span>
<span class="quoi"><b>Photo — guides (1,8 Mo)</b><span>OT-2026-0341 · 14 h 32</span></span>
<span class="etat fait">envoyée</span></div>
<nav class="tabbar">
<a href="#"><span class="pic"></span>Ma journée</a>
<a href="#"><span class="pic"></span>Scanner</a>
<a href="#"><span class="pic"></span>Préventif</a>
<a class="actif" href="#"><span class="pic"></span>Synchro<span class="badge-tab rouge">1</span></a>
</nav>
</div>
</div>
</div>
</section>
<script>
(function(){
var onglets=document.querySelectorAll('.revue .onglets button');
var ecrans=document.querySelectorAll('.ecran');
var notes=document.querySelectorAll('.note-ecran');
onglets.forEach(function(b){b.addEventListener('click',function(){
onglets.forEach(function(x){x.setAttribute('aria-selected','false')});
b.setAttribute('aria-selected','true');
var cible=b.dataset.cible;
ecrans.forEach(function(e){e.classList.toggle('actif',e.id===cible)});
notes.forEach(function(n){n.hidden=(n.dataset.note!==cible)});
window.scrollTo({top:0});
})});
var ordre=['auto','light','dark'];var i=0;
var bt=document.getElementById('btn-theme');
bt.addEventListener('click',function(){
i=(i+1)%3;var m=ordre[i];
if(m==='auto'){document.documentElement.removeAttribute('data-theme')}
else{document.documentElement.setAttribute('data-theme',m)}
bt.textContent='Thème : '+(m==='auto'?'auto':(m==='light'?'clair':'sombre'));
});
})();
</script>
</body>
</html>

View File

@@ -4,6 +4,21 @@ Trace chronologique des sessions (la plus récente en premier). Le **playbook**
---
## 2026-07-17 — Pr. Daaif (+ Claude) — R4 ouverte : maquettes mobile (design d'abord)
**Actions**
- **`maquette-r4.html`** (docs/02-design/maquettes) : 7 écrans de l'app technicien — Ma journée (en ligne ET hors-ligne côte à côte), Fiche OT, Clôture terrain (bilan codé R2, garde visible ; variante « en file » hors-ligne), Scan QR (étiquettes A6 de R1, hors-ligne inclus), Fiche ascenseur (consultation devant la machine), Checklist du mois (coches individuelles en file), **Synchro & conflits** (file visible, conflit de verrou optimiste où l'humain tranche). Tokens répliqués, bi-thème, gabarit téléphone repris de la maquette R3, données du parc seedé. Vérifiée en navigateur (7 onglets + bascule sombre, zéro erreur console).
- Artefact de validation publié pour le référent (7 écrans + preuve bi-thème + **5 décisions à acter** : D1 offline-first lecture locale/écriture en file, D2 verrou optimiste tranché par l'humain, D3 périmètre fermé « app du technicien » sans création d'OT mobile, D4 scan local des étiquettes R1, D5 photos compressées en file — pas d'audio ni de géolocalisation en R4, loi 09-08).
**Décisions**
- Aucune actée — les 5 décisions ci-dessus **attendent la validation du référent avec les écrans**. Aucune ligne de code Expo avant (principe n°1).
**Prochaine étape** : validation référent (maquettes + décisions) → R4.1 socle mobile (Expo, coquille + connexion démo + lecture hors-ligne) ; en parallèle, redéploiement Dokploy de `release/r3` toujours à faire.
---
## 2026-07-17 — Pr. Daaif (+ Claude) — R3 CLOSE : tag `release/r3`
**Actions**