judu/ex-egopublic Fork
⑂ d60d720
Commits
⬇ Clone ▾
git clone https://git.rickub.com/judu/ex-ego.git
git clone ssh://git@rickub.com/judu/ex-ego.git

Host key fingerprint (ed25519): SHA256:iycHnxEyq0Q7uyVpB7JlznP0G7JrTPXLYRcAU5CSLhc — verify it before your first connect.

Download ZIP

fix(a11y): lot P1 de l'audit WCAG — labels durée/date, contrastes AA (accent-deep pour les fonds, accent-700 pour le texte, textes atténués à 70 %), pill d'équipe teintée à 25 % (encre garantie ≥ 4.5:1 sur les 15 teintes)Unverified

Claude-Session: https://claude.ai/code/session_01FPKHKGfqvnvXKY9tNhYmkh
Julien Durillon committed 2026-08-08T18:47:00+02:00 Browse files
d60d720 parent: 1401cf3
modified assets/style.css +38 -31
@@ -6,6 +6,10 @@
66 --color-surface: #ebddc5;
77 --color-text: #201e1d;
88 --color-accent: #c67139;
9+ /* Variante a11y : ≥ 4.5:1 avec la crème — fonds porteurs de texte crème
10+ (boutons primaires, timer, badge). L'accent d'origine reste pour le
11+ décoratif (focus, pastilles, sélection). */
12+ --color-accent-deep: #9c4f1d;
913 --color-accent-2: #7a8a5e;
1014 --color-divider: color-mix(in srgb, #201e1d 16%, transparent);
1115
@@ -69,7 +73,8 @@ h1, h2, h3, h4 {
6973 line-height: 1.12; letter-spacing: -0.015em; margin: 0 0 var(--space-2);
7074 }
7175 p { margin: 0 0 var(--space-3); }
72-a { color: var(--color-accent); text-underline-offset: 3px; }
76+/* accent-700 pour le texte : l'accent d'origine plafonne à 3:1 sur crème. */
77+a { color: var(--color-accent-700); text-underline-offset: 3px; }
7378 :focus { outline: none; }
7479 :focus-visible { outline: 2px solid var(--color-accent); outline-offset: 2px; }
7580 ::selection { background: color-mix(in srgb, var(--color-accent) 30%, transparent); }
@@ -78,7 +83,7 @@ input[type=number]::-webkit-outer-spin-button,
7883 input[type=number]::-webkit-inner-spin-button { -webkit-appearance: none; appearance: none; margin: 0; }
7984 input[type=number] { -moz-appearance: textfield; appearance: textfield; }
8085
81-.text-muted { color: color-mix(in srgb, var(--color-text) 55%, transparent); }
86+.text-muted { color: color-mix(in srgb, var(--color-text) 70%, transparent); }
8287
8388 /* — boutons — */
8489 .btn {
@@ -92,13 +97,13 @@ input[type=number] { -moz-appearance: textfield; appearance: textfield; }
9297 }
9398 .btn svg { display: block; }
9499 .btn:disabled, .btn[aria-disabled="true"] { opacity: 0.45; cursor: not-allowed; pointer-events: none; }
95-.btn-primary { background: var(--color-accent); color: var(--color-bg); }
96-.btn-primary:hover { background: var(--color-accent-600); }
97-.btn-primary:active { background: var(--color-accent-700); }
100+.btn-primary { background: var(--color-accent-deep); color: var(--color-bg); }
101+.btn-primary:hover { background: var(--color-accent-700); }
102+.btn-primary:active { background: var(--color-accent-900); }
98103 .btn-secondary { border-color: var(--color-divider); }
99104 .btn-secondary:hover { background: color-mix(in srgb, var(--color-text) 7%, transparent); }
100105 .btn-secondary:active { background: color-mix(in srgb, var(--color-text) 14%, transparent); }
101-.btn-ghost { color: var(--color-accent); padding-inline: var(--space-1); }
106+.btn-ghost { color: var(--color-accent-700); padding-inline: var(--space-1); }
102107 .btn-ghost:hover { background: color-mix(in srgb, var(--color-accent) 10%, transparent); }
103108 .btn-icon { width: 36px; height: 36px; padding: 0; }
104109 .btn-icon-sm { width: 32px; height: 32px; padding: 0; }
@@ -124,7 +129,7 @@ input[type=number] { -moz-appearance: textfield; appearance: textfield; }
124129 padding: var(--space-3); border-radius: calc(var(--radius-lg) * 1.15);
125130 background: var(--color-surface);
126131 }
127-.card-kicker { font-size: 10px; letter-spacing: 0.1em; text-transform: uppercase; color: var(--color-accent); }
132+.card-kicker { font-size: 10px; letter-spacing: 0.1em; text-transform: uppercase; color: var(--color-accent-700); }
128133 .card-body { margin: 0; font-size: 13px; opacity: 0.8; }
129134
130135 /* — tags — */
@@ -148,19 +153,21 @@ input[type=number] { -moz-appearance: textfield; appearance: textfield; }
148153
149154 .app-header { padding: var(--space-6) var(--space-4) var(--space-3); }
150155 .app-topline { display: flex; align-items: center; gap: var(--space-2); margin-bottom: 4px; }
151-/* Fond = couleur de l'équipe (hash de l'id) et texte au meilleur contraste,
152- tous deux posés en style inline par le serveur. */
156+/* Couleur d'équipe (hash de l'id, --team-color inline) : fond teinté à 25 %
157+ pour garantir ≥ 4.5:1 avec l'encre quelle que soit la teinte, pastille en
158+ couleur pleine pour l'identification. */
153159 .team-pill {
154160 display: inline-flex; align-items: center; gap: 8px; font-size: 14px;
155- padding: 9px 15px; border-radius: 999px;
156- background: var(--color-accent-2-200); color: var(--color-accent-2-900);
161+ padding: 9px 15px 9px 12px; border-radius: 999px;
162+ background: color-mix(in srgb, var(--team-color, var(--color-accent-2)) 25%, var(--color-bg));
163+ color: var(--color-text);
157164 }
158-/* Pastille couleur d'équipe (sheet « Changer d'équipe »). */
165+/* Pastille couleur d'équipe (pill d'en-tête + sheet « Changer d'équipe »). */
159166 .team-dot { width: 12px; height: 12px; border-radius: 999px; flex: none; }
160167 /* Pill-sélecteur (plusieurs équipes) : ouvre la sheet #equipes. */
161168 a.team-pill { text-decoration: none; cursor: pointer; }
162-a.team-pill:hover { filter: brightness(1.06); }
163-.app-topline .who { margin-left: auto; font-size: 12px; opacity: .6; }
169+a.team-pill:hover { filter: brightness(.96); }
170+.app-topline .who { margin-left: auto; font-size: 12px; opacity: .7; }
164171 .app-header h1 { margin: 0; font-size: 29px; letter-spacing: -0.02em; }
165172
166173 /* Dégagement bas = tab bar + bandeau timer + marge, safe area comprise.
@@ -187,7 +194,7 @@ a.team-pill:hover { filter: brightness(1.06); }
187194 font: inherit; font-size: 15px; font-weight: 700;
188195 }
189196 .timer-banner .t-note { font-size: 13px; font-weight: 400; opacity: .85; }
190-.timer-running { background: var(--color-accent); color: var(--color-bg); }
197+.timer-running { background: var(--color-accent-deep); color: var(--color-bg); }
191198 .timer-waiting { background: var(--color-accent-200); color: var(--color-accent-900); }
192199 .timer-start {
193200 background: var(--color-surface); color: var(--color-accent-700);
@@ -210,7 +217,7 @@ a.team-pill:hover { filter: brightness(1.06); }
210217 font-size: 44px; line-height: 1.1; color: var(--color-accent-900);
211218 }
212219 .chrono-start { margin: var(--space-2) 0 0; font-size: 14px; color: var(--color-accent-900); opacity: .7; }
213-.chrono-hint { margin: var(--space-4) 0 var(--space-6); font-size: 14px; opacity: .6; text-align: center; text-wrap: pretty; }
220+.chrono-hint { margin: var(--space-4) 0 var(--space-6); font-size: 14px; opacity: .7; text-align: center; text-wrap: pretty; }
214221
215222 /* Bandeau « X min mesurées » (étape 1). */
216223 .measure-card {
@@ -243,7 +250,7 @@ a.team-pill:hover { filter: brightness(1.06); }
243250 .tab {
244251 flex: 1; display: flex; flex-direction: column; align-items: center; gap: 3px;
245252 padding: 8px 2px; border-radius: 999px; text-decoration: none;
246- color: color-mix(in srgb, var(--color-text) 50%, transparent);
253+ color: color-mix(in srgb, var(--color-text) 70%, transparent);
247254 font-size: 11px;
248255 }
249256 .tab[aria-current="page"] { color: var(--color-accent-700); font-weight: 700; }
@@ -251,7 +258,7 @@ a.team-pill:hover { filter: brightness(1.06); }
251258 .tab-badge {
252259 position: absolute; top: -4px; right: -6px;
253260 min-width: 16px; height: 16px; padding: 0 4px; border-radius: 999px;
254- background: var(--color-accent); color: var(--color-bg);
261+ background: var(--color-accent-deep); color: var(--color-bg);
255262 font-size: 10px; font-weight: 700;
256263 display: flex; align-items: center; justify-content: center;
257264 box-shadow: 0 0 0 2px var(--color-surface);
@@ -304,11 +311,11 @@ a.team-pill:hover { filter: brightness(1.06); }
304311 display: flex; align-items: center; justify-content: center; margin-bottom: var(--space-6);
305312 }
306313 .login h1 { font-size: 44px; margin: 0 0 var(--space-2); letter-spacing: -0.02em; }
307-.login .tagline { font-size: 15px; opacity: .65; margin: 0 0 var(--space-8); max-width: 15em; }
314+.login .tagline { font-size: 15px; opacity: .7; margin: 0 0 var(--space-8); max-width: 15em; }
308315 .form-error { font-size: 13px; color: var(--color-accent-700); margin: 0 0 var(--space-3); }
309316
310317 /* — ajout étape 1 : liste de tâches — */
311-.step-hint { font-size: 13px; opacity: .6; margin: 0 0 var(--space-4); }
318+.step-hint { font-size: 13px; opacity: .7; margin: 0 0 var(--space-4); }
312319 .task-pick { display: grid; gap: var(--space-2); }
313320 .task-pick a {
314321 display: flex; align-items: center; gap: var(--space-3);
@@ -318,7 +325,7 @@ a.team-pill:hover { filter: brightness(1.06); }
318325 }
319326 .task-pick a:hover { border-color: var(--color-accent); }
320327 .task-pick .tname { flex: 1; }
321-.task-pick .tweek { font-size: 12px; opacity: .5; }
328+.task-pick .tweek { font-size: 12px; opacity: .7; }
322329 .dot { border-radius: 999px; flex: none; display: inline-block; }
323330 .dot-14 { width: 14px; height: 14px; }
324331 .dot-12 { width: 12px; height: 12px; }
@@ -327,7 +334,7 @@ a.team-pill:hover { filter: brightness(1.06); }
327334 /* — ajout étape 2 — */
328335 .picked { display: flex; align-items: center; gap: var(--space-2); margin-bottom: var(--space-6); }
329336 .picked .pname { font-size: 20px; font-family: var(--font-heading); }
330-.mini-label { font-size: 12px; opacity: .7; margin: 0 0 var(--space-2); }
337+.mini-label { display: block; font-size: 12px; opacity: .7; margin: 0 0 var(--space-2); }
331338 .duration-row { display: flex; align-items: center; gap: var(--space-3); margin-bottom: var(--space-3); }
332339 .stepper {
333340 display: flex; align-items: center; gap: var(--space-1);
@@ -348,17 +355,17 @@ a.team-pill:hover { filter: brightness(1.06); }
348355 background: transparent; border-color: transparent;
349356 }
350357 .duration-row .unit { font-size: 15px; opacity: .7; }
351-.duration-row .pretty { font-size: 13px; opacity: .5; }
358+.duration-row .pretty { font-size: 13px; opacity: .7; }
352359 .presets { display: flex; gap: var(--space-2); flex-wrap: wrap; margin-bottom: var(--space-6); }
353360 .preset {
354361 padding: 9px 16px; border-radius: 999px; font-size: 14px;
355362 font-family: var(--font-heading); text-decoration: none;
356363 border: 1px solid var(--color-divider); color: var(--color-text);
357364 }
358-.preset[aria-current="true"] { background: var(--color-accent); color: var(--color-bg); border-color: transparent; }
365+.preset[aria-current="true"] { background: var(--color-accent-deep); color: var(--color-bg); border-color: transparent; }
359366 .date-row { display: flex; gap: var(--space-2); align-items: center; margin-bottom: var(--space-3); }
360367 .date-row .input { flex: 1; min-height: 44px; text-align: center; }
361-.date-label { font-size: 13px; opacity: .6; margin: 0 0 var(--space-6); }
368+.date-label { font-size: 13px; opacity: .7; margin: 0 0 var(--space-6); }
362369
363370 /* — stats — */
364371 .legend { display: flex; flex-wrap: wrap; gap: var(--space-2) var(--space-3); margin-bottom: var(--space-6); padding: 0; list-style: none; }
@@ -368,11 +375,11 @@ a.team-pill:hover { filter: brightness(1.06); }
368375 .chart-head { display: flex; align-items: center; gap: var(--space-2); margin-bottom: var(--space-1); }
369376 .chart-head h2 { margin: 0; font-size: 21px; }
370377 .chart-nav { margin-left: auto; display: flex; gap: 6px; }
371-.chart-range { font-size: 12px; opacity: .55; margin: 0 0 var(--space-4); }
372-.chart-empty { font-size: 14px; opacity: .55; margin: 0; padding: var(--space-6) 0; }
378+.chart-range { font-size: 12px; opacity: .7; margin: 0 0 var(--space-4); }
379+.chart-empty { font-size: 14px; opacity: .7; margin: 0; padding: var(--space-6) 0; }
373380 .cols { display: flex; align-items: flex-end; gap: var(--space-4); height: 190px; padding-top: var(--space-2); }
374381 .col { flex: 1; display: flex; flex-direction: column; align-items: center; gap: 6px; height: 100%; justify-content: flex-end; }
375-.col .total { font-size: 12px; opacity: .6; }
382+.col .total { font-size: 12px; opacity: .7; }
376383 .col .user { font-size: 13px; font-weight: 600; }
377384 .col-bar {
378385 width: 100%; max-width: 64px; display: flex; flex-direction: column;
@@ -397,9 +404,9 @@ a.team-pill:hover { filter: brightness(1.06); }
397404 .sheet-head .pname { font-family: var(--font-heading); font-size: 20px; }
398405 .sheet-head .close { margin-left: auto; }
399406 .sheet-figures { display: flex; gap: var(--space-6); }
400-.sheet-figures .k { font-size: 11px; opacity: .55; text-transform: uppercase; letter-spacing: .08em; }
407+.sheet-figures .k { font-size: 11px; opacity: .7; text-transform: uppercase; letter-spacing: .08em; }
401408 .sheet-figures .v { font-size: 30px; font-family: var(--font-heading); }
402-.sheet-note { font-size: 13px; opacity: .6; margin: var(--space-4) 0 0; }
409+.sheet-note { font-size: 13px; opacity: .7; margin: var(--space-4) 0 0; }
403410
404411 /* — mes temps — */
405412 .times { list-style: none; margin: 0; padding: 0; }
@@ -409,7 +416,7 @@ a.team-pill:hover { filter: brightness(1.06); }
409416 }
410417 .times .tinfo { flex: 1; min-width: 0; }
411418 .times .ttask { font-size: 15px; }
412-.times .tdate { font-size: 12px; opacity: .55; }
419+.times .tdate { font-size: 12px; opacity: .7; }
413420 .times .tdur { font-size: 16px; font-family: var(--font-heading); }
414421
415422 /* — tâches — */
@@ -6,6 +6,10 @@
6 --color-surface: #ebddc5;6 --color-surface: #ebddc5;
7 --color-text: #201e1d;7 --color-text: #201e1d;
8 --color-accent: #c67139;8 --color-accent: #c67139;
9+ /* Variante a11y : ≥ 4.5:1 avec la crème — fonds porteurs de texte crème
10+ (boutons primaires, timer, badge). L'accent d'origine reste pour le
11+ décoratif (focus, pastilles, sélection). */
12+ --color-accent-deep: #9c4f1d;
9 --color-accent-2: #7a8a5e;13 --color-accent-2: #7a8a5e;
10 --color-divider: color-mix(in srgb, #201e1d 16%, transparent);14 --color-divider: color-mix(in srgb, #201e1d 16%, transparent);
11 15
@@ -69,7 +73,8 @@ h1, h2, h3, h4 {
69 line-height: 1.12; letter-spacing: -0.015em; margin: 0 0 var(--space-2);73 line-height: 1.12; letter-spacing: -0.015em; margin: 0 0 var(--space-2);
70 }74 }
71 p { margin: 0 0 var(--space-3); }75 p { margin: 0 0 var(--space-3); }
72-a { color: var(--color-accent); text-underline-offset: 3px; }76+/* accent-700 pour le texte : l'accent d'origine plafonne à 3:1 sur crème. */
77+a { color: var(--color-accent-700); text-underline-offset: 3px; }
73 :focus { outline: none; }78 :focus { outline: none; }
74 :focus-visible { outline: 2px solid var(--color-accent); outline-offset: 2px; }79 :focus-visible { outline: 2px solid var(--color-accent); outline-offset: 2px; }
75 ::selection { background: color-mix(in srgb, var(--color-accent) 30%, transparent); }80 ::selection { background: color-mix(in srgb, var(--color-accent) 30%, transparent); }
@@ -78,7 +83,7 @@ input[type=number]::-webkit-outer-spin-button,
78 input[type=number]::-webkit-inner-spin-button { -webkit-appearance: none; appearance: none; margin: 0; }83 input[type=number]::-webkit-inner-spin-button { -webkit-appearance: none; appearance: none; margin: 0; }
79 input[type=number] { -moz-appearance: textfield; appearance: textfield; }84 input[type=number] { -moz-appearance: textfield; appearance: textfield; }
80 85
81-.text-muted { color: color-mix(in srgb, var(--color-text) 55%, transparent); }86+.text-muted { color: color-mix(in srgb, var(--color-text) 70%, transparent); }
82 87
83 /* — boutons — */88 /* — boutons — */
84 .btn {89 .btn {
@@ -92,13 +97,13 @@ input[type=number] { -moz-appearance: textfield; appearance: textfield; }
92 }97 }
93 .btn svg { display: block; }98 .btn svg { display: block; }
94 .btn:disabled, .btn[aria-disabled="true"] { opacity: 0.45; cursor: not-allowed; pointer-events: none; }99 .btn:disabled, .btn[aria-disabled="true"] { opacity: 0.45; cursor: not-allowed; pointer-events: none; }
95-.btn-primary { background: var(--color-accent); color: var(--color-bg); }100+.btn-primary { background: var(--color-accent-deep); color: var(--color-bg); }
96-.btn-primary:hover { background: var(--color-accent-600); }101+.btn-primary:hover { background: var(--color-accent-700); }
97-.btn-primary:active { background: var(--color-accent-700); }102+.btn-primary:active { background: var(--color-accent-900); }
98 .btn-secondary { border-color: var(--color-divider); }103 .btn-secondary { border-color: var(--color-divider); }
99 .btn-secondary:hover { background: color-mix(in srgb, var(--color-text) 7%, transparent); }104 .btn-secondary:hover { background: color-mix(in srgb, var(--color-text) 7%, transparent); }
100 .btn-secondary:active { background: color-mix(in srgb, var(--color-text) 14%, transparent); }105 .btn-secondary:active { background: color-mix(in srgb, var(--color-text) 14%, transparent); }
101-.btn-ghost { color: var(--color-accent); padding-inline: var(--space-1); }106+.btn-ghost { color: var(--color-accent-700); padding-inline: var(--space-1); }
102 .btn-ghost:hover { background: color-mix(in srgb, var(--color-accent) 10%, transparent); }107 .btn-ghost:hover { background: color-mix(in srgb, var(--color-accent) 10%, transparent); }
103 .btn-icon { width: 36px; height: 36px; padding: 0; }108 .btn-icon { width: 36px; height: 36px; padding: 0; }
104 .btn-icon-sm { width: 32px; height: 32px; padding: 0; }109 .btn-icon-sm { width: 32px; height: 32px; padding: 0; }
@@ -124,7 +129,7 @@ input[type=number] { -moz-appearance: textfield; appearance: textfield; }
124 padding: var(--space-3); border-radius: calc(var(--radius-lg) * 1.15);129 padding: var(--space-3); border-radius: calc(var(--radius-lg) * 1.15);
125 background: var(--color-surface);130 background: var(--color-surface);
126 }131 }
127-.card-kicker { font-size: 10px; letter-spacing: 0.1em; text-transform: uppercase; color: var(--color-accent); }132+.card-kicker { font-size: 10px; letter-spacing: 0.1em; text-transform: uppercase; color: var(--color-accent-700); }
128 .card-body { margin: 0; font-size: 13px; opacity: 0.8; }133 .card-body { margin: 0; font-size: 13px; opacity: 0.8; }
129 134
130 /* — tags — */135 /* — tags — */
@@ -148,19 +153,21 @@ input[type=number] { -moz-appearance: textfield; appearance: textfield; }
148 153
149 .app-header { padding: var(--space-6) var(--space-4) var(--space-3); }154 .app-header { padding: var(--space-6) var(--space-4) var(--space-3); }
150 .app-topline { display: flex; align-items: center; gap: var(--space-2); margin-bottom: 4px; }155 .app-topline { display: flex; align-items: center; gap: var(--space-2); margin-bottom: 4px; }
151-/* Fond = couleur de l'équipe (hash de l'id) et texte au meilleur contraste,156+/* Couleur d'équipe (hash de l'id, --team-color inline) : fond teinté à 25 %
152- tous deux posés en style inline par le serveur. */157+ pour garantir ≥ 4.5:1 avec l'encre quelle que soit la teinte, pastille en
158+ couleur pleine pour l'identification. */
153 .team-pill {159 .team-pill {
154 display: inline-flex; align-items: center; gap: 8px; font-size: 14px;160 display: inline-flex; align-items: center; gap: 8px; font-size: 14px;
155- padding: 9px 15px; border-radius: 999px;161+ padding: 9px 15px 9px 12px; border-radius: 999px;
156- background: var(--color-accent-2-200); color: var(--color-accent-2-900);162+ background: color-mix(in srgb, var(--team-color, var(--color-accent-2)) 25%, var(--color-bg));
163+ color: var(--color-text);
157 }164 }
158-/* Pastille couleur d'équipe (sheet « Changer d'équipe »). */165+/* Pastille couleur d'équipe (pill d'en-tête + sheet « Changer d'équipe »). */
159 .team-dot { width: 12px; height: 12px; border-radius: 999px; flex: none; }166 .team-dot { width: 12px; height: 12px; border-radius: 999px; flex: none; }
160 /* Pill-sélecteur (plusieurs équipes) : ouvre la sheet #equipes. */167 /* Pill-sélecteur (plusieurs équipes) : ouvre la sheet #equipes. */
161 a.team-pill { text-decoration: none; cursor: pointer; }168 a.team-pill { text-decoration: none; cursor: pointer; }
162-a.team-pill:hover { filter: brightness(1.06); }169+a.team-pill:hover { filter: brightness(.96); }
163-.app-topline .who { margin-left: auto; font-size: 12px; opacity: .6; }170+.app-topline .who { margin-left: auto; font-size: 12px; opacity: .7; }
164 .app-header h1 { margin: 0; font-size: 29px; letter-spacing: -0.02em; }171 .app-header h1 { margin: 0; font-size: 29px; letter-spacing: -0.02em; }
165 172
166 /* Dégagement bas = tab bar + bandeau timer + marge, safe area comprise.173 /* Dégagement bas = tab bar + bandeau timer + marge, safe area comprise.
@@ -187,7 +194,7 @@ a.team-pill:hover { filter: brightness(1.06); }
187 font: inherit; font-size: 15px; font-weight: 700;194 font: inherit; font-size: 15px; font-weight: 700;
188 }195 }
189 .timer-banner .t-note { font-size: 13px; font-weight: 400; opacity: .85; }196 .timer-banner .t-note { font-size: 13px; font-weight: 400; opacity: .85; }
190-.timer-running { background: var(--color-accent); color: var(--color-bg); }197+.timer-running { background: var(--color-accent-deep); color: var(--color-bg); }
191 .timer-waiting { background: var(--color-accent-200); color: var(--color-accent-900); }198 .timer-waiting { background: var(--color-accent-200); color: var(--color-accent-900); }
192 .timer-start {199 .timer-start {
193 background: var(--color-surface); color: var(--color-accent-700);200 background: var(--color-surface); color: var(--color-accent-700);
@@ -210,7 +217,7 @@ a.team-pill:hover { filter: brightness(1.06); }
210 font-size: 44px; line-height: 1.1; color: var(--color-accent-900);217 font-size: 44px; line-height: 1.1; color: var(--color-accent-900);
211 }218 }
212 .chrono-start { margin: var(--space-2) 0 0; font-size: 14px; color: var(--color-accent-900); opacity: .7; }219 .chrono-start { margin: var(--space-2) 0 0; font-size: 14px; color: var(--color-accent-900); opacity: .7; }
213-.chrono-hint { margin: var(--space-4) 0 var(--space-6); font-size: 14px; opacity: .6; text-align: center; text-wrap: pretty; }220+.chrono-hint { margin: var(--space-4) 0 var(--space-6); font-size: 14px; opacity: .7; text-align: center; text-wrap: pretty; }
214 221
215 /* Bandeau « X min mesurées » (étape 1). */222 /* Bandeau « X min mesurées » (étape 1). */
216 .measure-card {223 .measure-card {
@@ -243,7 +250,7 @@ a.team-pill:hover { filter: brightness(1.06); }
243 .tab {250 .tab {
244 flex: 1; display: flex; flex-direction: column; align-items: center; gap: 3px;251 flex: 1; display: flex; flex-direction: column; align-items: center; gap: 3px;
245 padding: 8px 2px; border-radius: 999px; text-decoration: none;252 padding: 8px 2px; border-radius: 999px; text-decoration: none;
246- color: color-mix(in srgb, var(--color-text) 50%, transparent);253+ color: color-mix(in srgb, var(--color-text) 70%, transparent);
247 font-size: 11px;254 font-size: 11px;
248 }255 }
249 .tab[aria-current="page"] { color: var(--color-accent-700); font-weight: 700; }256 .tab[aria-current="page"] { color: var(--color-accent-700); font-weight: 700; }
@@ -251,7 +258,7 @@ a.team-pill:hover { filter: brightness(1.06); }
251 .tab-badge {258 .tab-badge {
252 position: absolute; top: -4px; right: -6px;259 position: absolute; top: -4px; right: -6px;
253 min-width: 16px; height: 16px; padding: 0 4px; border-radius: 999px;260 min-width: 16px; height: 16px; padding: 0 4px; border-radius: 999px;
254- background: var(--color-accent); color: var(--color-bg);261+ background: var(--color-accent-deep); color: var(--color-bg);
255 font-size: 10px; font-weight: 700;262 font-size: 10px; font-weight: 700;
256 display: flex; align-items: center; justify-content: center;263 display: flex; align-items: center; justify-content: center;
257 box-shadow: 0 0 0 2px var(--color-surface);264 box-shadow: 0 0 0 2px var(--color-surface);
@@ -304,11 +311,11 @@ a.team-pill:hover { filter: brightness(1.06); }
304 display: flex; align-items: center; justify-content: center; margin-bottom: var(--space-6);311 display: flex; align-items: center; justify-content: center; margin-bottom: var(--space-6);
305 }312 }
306 .login h1 { font-size: 44px; margin: 0 0 var(--space-2); letter-spacing: -0.02em; }313 .login h1 { font-size: 44px; margin: 0 0 var(--space-2); letter-spacing: -0.02em; }
307-.login .tagline { font-size: 15px; opacity: .65; margin: 0 0 var(--space-8); max-width: 15em; }314+.login .tagline { font-size: 15px; opacity: .7; margin: 0 0 var(--space-8); max-width: 15em; }
308 .form-error { font-size: 13px; color: var(--color-accent-700); margin: 0 0 var(--space-3); }315 .form-error { font-size: 13px; color: var(--color-accent-700); margin: 0 0 var(--space-3); }
309 316
310 /* — ajout étape 1 : liste de tâches — */317 /* — ajout étape 1 : liste de tâches — */
311-.step-hint { font-size: 13px; opacity: .6; margin: 0 0 var(--space-4); }318+.step-hint { font-size: 13px; opacity: .7; margin: 0 0 var(--space-4); }
312 .task-pick { display: grid; gap: var(--space-2); }319 .task-pick { display: grid; gap: var(--space-2); }
313 .task-pick a {320 .task-pick a {
314 display: flex; align-items: center; gap: var(--space-3);321 display: flex; align-items: center; gap: var(--space-3);
@@ -318,7 +325,7 @@ a.team-pill:hover { filter: brightness(1.06); }
318 }325 }
319 .task-pick a:hover { border-color: var(--color-accent); }326 .task-pick a:hover { border-color: var(--color-accent); }
320 .task-pick .tname { flex: 1; }327 .task-pick .tname { flex: 1; }
321-.task-pick .tweek { font-size: 12px; opacity: .5; }328+.task-pick .tweek { font-size: 12px; opacity: .7; }
322 .dot { border-radius: 999px; flex: none; display: inline-block; }329 .dot { border-radius: 999px; flex: none; display: inline-block; }
323 .dot-14 { width: 14px; height: 14px; }330 .dot-14 { width: 14px; height: 14px; }
324 .dot-12 { width: 12px; height: 12px; }331 .dot-12 { width: 12px; height: 12px; }
@@ -327,7 +334,7 @@ a.team-pill:hover { filter: brightness(1.06); }
327 /* — ajout étape 2 — */334 /* — ajout étape 2 — */
328 .picked { display: flex; align-items: center; gap: var(--space-2); margin-bottom: var(--space-6); }335 .picked { display: flex; align-items: center; gap: var(--space-2); margin-bottom: var(--space-6); }
329 .picked .pname { font-size: 20px; font-family: var(--font-heading); }336 .picked .pname { font-size: 20px; font-family: var(--font-heading); }
330-.mini-label { font-size: 12px; opacity: .7; margin: 0 0 var(--space-2); }337+.mini-label { display: block; font-size: 12px; opacity: .7; margin: 0 0 var(--space-2); }
331 .duration-row { display: flex; align-items: center; gap: var(--space-3); margin-bottom: var(--space-3); }338 .duration-row { display: flex; align-items: center; gap: var(--space-3); margin-bottom: var(--space-3); }
332 .stepper {339 .stepper {
333 display: flex; align-items: center; gap: var(--space-1);340 display: flex; align-items: center; gap: var(--space-1);
@@ -348,17 +355,17 @@ a.team-pill:hover { filter: brightness(1.06); }
348 background: transparent; border-color: transparent;355 background: transparent; border-color: transparent;
349 }356 }
350 .duration-row .unit { font-size: 15px; opacity: .7; }357 .duration-row .unit { font-size: 15px; opacity: .7; }
351-.duration-row .pretty { font-size: 13px; opacity: .5; }358+.duration-row .pretty { font-size: 13px; opacity: .7; }
352 .presets { display: flex; gap: var(--space-2); flex-wrap: wrap; margin-bottom: var(--space-6); }359 .presets { display: flex; gap: var(--space-2); flex-wrap: wrap; margin-bottom: var(--space-6); }
353 .preset {360 .preset {
354 padding: 9px 16px; border-radius: 999px; font-size: 14px;361 padding: 9px 16px; border-radius: 999px; font-size: 14px;
355 font-family: var(--font-heading); text-decoration: none;362 font-family: var(--font-heading); text-decoration: none;
356 border: 1px solid var(--color-divider); color: var(--color-text);363 border: 1px solid var(--color-divider); color: var(--color-text);
357 }364 }
358-.preset[aria-current="true"] { background: var(--color-accent); color: var(--color-bg); border-color: transparent; }365+.preset[aria-current="true"] { background: var(--color-accent-deep); color: var(--color-bg); border-color: transparent; }
359 .date-row { display: flex; gap: var(--space-2); align-items: center; margin-bottom: var(--space-3); }366 .date-row { display: flex; gap: var(--space-2); align-items: center; margin-bottom: var(--space-3); }
360 .date-row .input { flex: 1; min-height: 44px; text-align: center; }367 .date-row .input { flex: 1; min-height: 44px; text-align: center; }
361-.date-label { font-size: 13px; opacity: .6; margin: 0 0 var(--space-6); }368+.date-label { font-size: 13px; opacity: .7; margin: 0 0 var(--space-6); }
362 369
363 /* — stats — */370 /* — stats — */
364 .legend { display: flex; flex-wrap: wrap; gap: var(--space-2) var(--space-3); margin-bottom: var(--space-6); padding: 0; list-style: none; }371 .legend { display: flex; flex-wrap: wrap; gap: var(--space-2) var(--space-3); margin-bottom: var(--space-6); padding: 0; list-style: none; }
@@ -368,11 +375,11 @@ a.team-pill:hover { filter: brightness(1.06); }
368 .chart-head { display: flex; align-items: center; gap: var(--space-2); margin-bottom: var(--space-1); }375 .chart-head { display: flex; align-items: center; gap: var(--space-2); margin-bottom: var(--space-1); }
369 .chart-head h2 { margin: 0; font-size: 21px; }376 .chart-head h2 { margin: 0; font-size: 21px; }
370 .chart-nav { margin-left: auto; display: flex; gap: 6px; }377 .chart-nav { margin-left: auto; display: flex; gap: 6px; }
371-.chart-range { font-size: 12px; opacity: .55; margin: 0 0 var(--space-4); }378+.chart-range { font-size: 12px; opacity: .7; margin: 0 0 var(--space-4); }
372-.chart-empty { font-size: 14px; opacity: .55; margin: 0; padding: var(--space-6) 0; }379+.chart-empty { font-size: 14px; opacity: .7; margin: 0; padding: var(--space-6) 0; }
373 .cols { display: flex; align-items: flex-end; gap: var(--space-4); height: 190px; padding-top: var(--space-2); }380 .cols { display: flex; align-items: flex-end; gap: var(--space-4); height: 190px; padding-top: var(--space-2); }
374 .col { flex: 1; display: flex; flex-direction: column; align-items: center; gap: 6px; height: 100%; justify-content: flex-end; }381 .col { flex: 1; display: flex; flex-direction: column; align-items: center; gap: 6px; height: 100%; justify-content: flex-end; }
375-.col .total { font-size: 12px; opacity: .6; }382+.col .total { font-size: 12px; opacity: .7; }
376 .col .user { font-size: 13px; font-weight: 600; }383 .col .user { font-size: 13px; font-weight: 600; }
377 .col-bar {384 .col-bar {
378 width: 100%; max-width: 64px; display: flex; flex-direction: column;385 width: 100%; max-width: 64px; display: flex; flex-direction: column;
@@ -397,9 +404,9 @@ a.team-pill:hover { filter: brightness(1.06); }
397 .sheet-head .pname { font-family: var(--font-heading); font-size: 20px; }404 .sheet-head .pname { font-family: var(--font-heading); font-size: 20px; }
398 .sheet-head .close { margin-left: auto; }405 .sheet-head .close { margin-left: auto; }
399 .sheet-figures { display: flex; gap: var(--space-6); }406 .sheet-figures { display: flex; gap: var(--space-6); }
400-.sheet-figures .k { font-size: 11px; opacity: .55; text-transform: uppercase; letter-spacing: .08em; }407+.sheet-figures .k { font-size: 11px; opacity: .7; text-transform: uppercase; letter-spacing: .08em; }
401 .sheet-figures .v { font-size: 30px; font-family: var(--font-heading); }408 .sheet-figures .v { font-size: 30px; font-family: var(--font-heading); }
402-.sheet-note { font-size: 13px; opacity: .6; margin: var(--space-4) 0 0; }409+.sheet-note { font-size: 13px; opacity: .7; margin: var(--space-4) 0 0; }
403 410
404 /* — mes temps — */411 /* — mes temps — */
405 .times { list-style: none; margin: 0; padding: 0; }412 .times { list-style: none; margin: 0; padding: 0; }
@@ -409,7 +416,7 @@ a.team-pill:hover { filter: brightness(1.06); }
409 }416 }
410 .times .tinfo { flex: 1; min-width: 0; }417 .times .tinfo { flex: 1; min-width: 0; }
411 .times .ttask { font-size: 15px; }418 .times .ttask { font-size: 15px; }
412-.times .tdate { font-size: 12px; opacity: .55; }419+.times .tdate { font-size: 12px; opacity: .7; }
413 .times .tdur { font-size: 16px; font-family: var(--font-heading); }420 .times .tdur { font-size: 16px; font-family: var(--font-heading); }
414 421
415 /* — tâches — */422 /* — tâches — */
modified src/charts.rs +0 -40
@@ -30,35 +30,6 @@ pub fn team_color(team_id: Uuid) -> &'static str {
3030 PALETTE[(team_id.as_u128() % PALETTE.len() as u128) as usize]
3131 }
3232
33-/// Couleur de texte au meilleur contraste WCAG sur un fond donné : l'encre ou
34-/// la crème du design Organic (tokens --color-text / --color-bg).
35-pub fn contrast_text(bg_hex: &str) -> &'static str {
36- const DARK: &str = "#201e1d";
37- const LIGHT: &str = "#f5ead8";
38- let bg = luminance(bg_hex);
39- if ratio(bg, luminance(DARK)) >= ratio(bg, luminance(LIGHT)) {
40- DARK
41- } else {
42- LIGHT
43- }
44-}
45-
46-/// Luminance relative sRGB (WCAG 2) d'une couleur « #rrggbb ».
47-fn luminance(hex: &str) -> f64 {
48- let chan = |i: usize| {
49- let v = u8::from_str_radix(hex.get(i..i + 2).unwrap_or("00"), 16).unwrap_or(0) as f64
50- / 255.0;
51- if v <= 0.03928 { v / 12.92 } else { ((v + 0.055) / 1.055).powf(2.4) }
52- };
53- 0.2126 * chan(1) + 0.7152 * chan(3) + 0.0722 * chan(5)
54-}
55-
56-/// Ratio de contraste WCAG entre deux luminances.
57-fn ratio(a: f64, b: f64) -> f64 {
58- let (hi, lo) = if a > b { (a, b) } else { (b, a) };
59- (hi + 0.05) / (lo + 0.05)
60-}
61-
6233 /// « 45 min », « 2 h », « 12 h 30 »
6334 pub fn fmt_minutes(total: i64) -> String {
6435 let (h, m) = (total / 60, total % 60);
@@ -303,15 +274,4 @@ mod tests {
303274 assert!(PALETTE.contains(&team_color(id)));
304275 assert_eq!(team_color(Uuid::from_u128(8)), PALETTE[8]);
305276 }
306-
307- #[test]
308- fn contrast_text_picks_readable_ink() {
309- assert_eq!(contrast_text("#56633f"), "#f5ead8"); // olive sombre → crème
310- assert_eq!(contrast_text("#6d4a33"), "#f5ead8"); // cacao → crème
311- assert_eq!(contrast_text("#ccdbb2"), "#201e1d"); // vert pâle → encre
312- assert_eq!(contrast_text("#e3c088"), "#201e1d"); // sable → encre
313- for bg in PALETTE {
314- assert!(["#201e1d", "#f5ead8"].contains(&contrast_text(bg)));
315- }
316- }
317277 }
@@ -30,35 +30,6 @@ pub fn team_color(team_id: Uuid) -> &'static str {
30 PALETTE[(team_id.as_u128() % PALETTE.len() as u128) as usize]30 PALETTE[(team_id.as_u128() % PALETTE.len() as u128) as usize]
31 }31 }
32 32
33-/// Couleur de texte au meilleur contraste WCAG sur un fond donné : l'encre ou
34-/// la crème du design Organic (tokens --color-text / --color-bg).
35-pub fn contrast_text(bg_hex: &str) -> &'static str {
36- const DARK: &str = "#201e1d";
37- const LIGHT: &str = "#f5ead8";
38- let bg = luminance(bg_hex);
39- if ratio(bg, luminance(DARK)) >= ratio(bg, luminance(LIGHT)) {
40- DARK
41- } else {
42- LIGHT
43- }
44-}
45-
46-/// Luminance relative sRGB (WCAG 2) d'une couleur « #rrggbb ».
47-fn luminance(hex: &str) -> f64 {
48- let chan = |i: usize| {
49- let v = u8::from_str_radix(hex.get(i..i + 2).unwrap_or("00"), 16).unwrap_or(0) as f64
50- / 255.0;
51- if v <= 0.03928 { v / 12.92 } else { ((v + 0.055) / 1.055).powf(2.4) }
52- };
53- 0.2126 * chan(1) + 0.7152 * chan(3) + 0.0722 * chan(5)
54-}
55-
56-/// Ratio de contraste WCAG entre deux luminances.
57-fn ratio(a: f64, b: f64) -> f64 {
58- let (hi, lo) = if a > b { (a, b) } else { (b, a) };
59- (hi + 0.05) / (lo + 0.05)
60-}
61-
62 /// « 45 min », « 2 h », « 12 h 30 »33 /// « 45 min », « 2 h », « 12 h 30 »
63 pub fn fmt_minutes(total: i64) -> String {34 pub fn fmt_minutes(total: i64) -> String {
64 let (h, m) = (total / 60, total % 60);35 let (h, m) = (total / 60, total % 60);
@@ -303,15 +274,4 @@ mod tests {
303 assert!(PALETTE.contains(&team_color(id)));274 assert!(PALETTE.contains(&team_color(id)));
304 assert_eq!(team_color(Uuid::from_u128(8)), PALETTE[8]);275 assert_eq!(team_color(Uuid::from_u128(8)), PALETTE[8]);
305 }276 }
306-
307- #[test]
308- fn contrast_text_picks_readable_ink() {
309- assert_eq!(contrast_text("#56633f"), "#f5ead8"); // olive sombre → crème
310- assert_eq!(contrast_text("#6d4a33"), "#f5ead8"); // cacao → crème
311- assert_eq!(contrast_text("#ccdbb2"), "#201e1d"); // vert pâle → encre
312- assert_eq!(contrast_text("#e3c088"), "#201e1d"); // sable → encre
313- for bg in PALETTE {
314- assert!(["#201e1d", "#f5ead8"].contains(&contrast_text(bg)));
315- }
316- }
317 }277 }
modified src/render.rs +1 -3
@@ -47,10 +47,8 @@ pub struct Shell {
4747 pub username: String,
4848 /// Nom de l'équipe active (pill de l'en-tête).
4949 pub team_name: String,
50- /// Couleur de l'équipe active (fond de la pill d'en-tête).
50+ /// Couleur de l'équipe active (teinte de la pill d'en-tête).
5151 pub team_color: &'static str,
52- /// Encre ou crème selon le meilleur contraste sur team_color.
53- pub team_text: &'static str,
5452 /// "add" | "stats" | "times" | "settings"
5553 pub tab: &'static str,
5654 pub toast: Option<String>,
@@ -47,10 +47,8 @@ pub struct Shell {
47 pub username: String,47 pub username: String,
48 /// Nom de l'équipe active (pill de l'en-tête).48 /// Nom de l'équipe active (pill de l'en-tête).
49 pub team_name: String,49 pub team_name: String,
50- /// Couleur de l'équipe active (fond de la pill d'en-tête).50+ /// Couleur de l'équipe active (teinte de la pill d'en-tête).
51 pub team_color: &'static str,51 pub team_color: &'static str,
52- /// Encre ou crème selon le meilleur contraste sur team_color.
53- pub team_text: &'static str,
54 /// "add" | "stats" | "times" | "settings"52 /// "add" | "stats" | "times" | "settings"
55 pub tab: &'static str,53 pub tab: &'static str,
56 pub toast: Option<String>,54 pub toast: Option<String>,
modified src/routes/mod.rs +1 -2
@@ -14,7 +14,7 @@ use axum::response::{Redirect, Response};
1414 use axum::routing::{get, post};
1515
1616 use crate::auth::extractor::AuthUser;
17-use crate::charts::{contrast_text, fmt_minutes, team_color};
17+use crate::charts::{fmt_minutes, team_color};
1818 use crate::db::{invitations, teams as teams_db, timers, users};
1919 use crate::error::AppError;
2020 use crate::render::{Shell, TeamChoiceView, TimerView};
@@ -156,7 +156,6 @@ pub async fn shell(
156156 username,
157157 team_name: ctx.team_name.clone(),
158158 team_color: team_color(ctx.team_id),
159- team_text: contrast_text(team_color(ctx.team_id)),
160159 tab,
161160 toast,
162161 invite_count,
@@ -14,7 +14,7 @@ use axum::response::{Redirect, Response};
14 use axum::routing::{get, post};14 use axum::routing::{get, post};
15 15
16 use crate::auth::extractor::AuthUser;16 use crate::auth::extractor::AuthUser;
17-use crate::charts::{contrast_text, fmt_minutes, team_color};17+use crate::charts::{fmt_minutes, team_color};
18 use crate::db::{invitations, teams as teams_db, timers, users};18 use crate::db::{invitations, teams as teams_db, timers, users};
19 use crate::error::AppError;19 use crate::error::AppError;
20 use crate::render::{Shell, TeamChoiceView, TimerView};20 use crate::render::{Shell, TeamChoiceView, TimerView};
@@ -156,7 +156,6 @@ pub async fn shell(
156 username,156 username,
157 team_name: ctx.team_name.clone(),157 team_name: ctx.team_name.clone(),
158 team_color: team_color(ctx.team_id),158 team_color: team_color(ctx.team_id),
159- team_text: contrast_text(team_color(ctx.team_id)),
160 tab,159 tab,
161 toast,160 toast,
162 invite_count,161 invite_count,
modified templates/add_step2.html +3 -3
@@ -10,7 +10,7 @@
1010 <input type="hidden" name="csrf" value="{{ csrf }}">
1111 <input type="hidden" name="tache" value="{{ tache }}">
1212
13- <p class="mini-label">Durée</p>
13+ <label class="mini-label" for="minutes">Durée</label>
1414 <div class="duration-row">
1515 <div class="stepper">
1616 <a class="stepper-btn" href="{{ minus_href }}" data-step="-5" aria-label="Cinq minutes de moins">
@@ -75,12 +75,12 @@
7575 {% endfor %}
7676 </div>
7777
78- <p class="mini-label">Date</p>
78+ <label class="mini-label" for="date">Date</label>
7979 <div class="date-row">
8080 <a class="btn btn-secondary btn-icon" href="{{ day_prev }}" aria-label="Jour précédent">
8181 <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.75" stroke-linecap="round" stroke-linejoin="round"><path d="M15 18l-6-6 6-6"></path></svg>
8282 </a>
83- <input class="input" name="date" type="date" value="{{ date }}" required>
83+ <input class="input" id="date" name="date" type="date" value="{{ date }}" required>
8484 {% if let Some(next) = day_next %}
8585 <a class="btn btn-secondary btn-icon" href="{{ next }}" aria-label="Jour suivant">
8686 <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.75" stroke-linecap="round" stroke-linejoin="round"><path d="M9 18l6-6-6-6"></path></svg>
@@ -10,7 +10,7 @@
10 <input type="hidden" name="csrf" value="{{ csrf }}">10 <input type="hidden" name="csrf" value="{{ csrf }}">
11 <input type="hidden" name="tache" value="{{ tache }}">11 <input type="hidden" name="tache" value="{{ tache }}">
12 12
13- <p class="mini-label">Durée</p>13+ <label class="mini-label" for="minutes">Durée</label>
14 <div class="duration-row">14 <div class="duration-row">
15 <div class="stepper">15 <div class="stepper">
16 <a class="stepper-btn" href="{{ minus_href }}" data-step="-5" aria-label="Cinq minutes de moins">16 <a class="stepper-btn" href="{{ minus_href }}" data-step="-5" aria-label="Cinq minutes de moins">
@@ -75,12 +75,12 @@
75 {% endfor %}75 {% endfor %}
76 </div>76 </div>
77 77
78- <p class="mini-label">Date</p>78+ <label class="mini-label" for="date">Date</label>
79 <div class="date-row">79 <div class="date-row">
80 <a class="btn btn-secondary btn-icon" href="{{ day_prev }}" aria-label="Jour précédent">80 <a class="btn btn-secondary btn-icon" href="{{ day_prev }}" aria-label="Jour précédent">
81 <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.75" stroke-linecap="round" stroke-linejoin="round"><path d="M15 18l-6-6 6-6"></path></svg>81 <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.75" stroke-linecap="round" stroke-linejoin="round"><path d="M15 18l-6-6 6-6"></path></svg>
82 </a>82 </a>
83- <input class="input" name="date" type="date" value="{{ date }}" required>83+ <input class="input" id="date" name="date" type="date" value="{{ date }}" required>
84 {% if let Some(next) = day_next %}84 {% if let Some(next) = day_next %}
85 <a class="btn btn-secondary btn-icon" href="{{ next }}" aria-label="Jour suivant">85 <a class="btn btn-secondary btn-icon" href="{{ next }}" aria-label="Jour suivant">
86 <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.75" stroke-linecap="round" stroke-linejoin="round"><path d="M9 18l6-6-6-6"></path></svg>86 <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.75" stroke-linecap="round" stroke-linejoin="round"><path d="M9 18l6-6-6-6"></path></svg>
modified templates/app.html +5 -3
@@ -4,12 +4,14 @@
44 <header class="app-header">
55 <div class="app-topline">
66 {% if !shell.teams.is_empty() %}
7- <a class="team-pill" href="#equipes" aria-label="Changer d'équipe" style="background:{{ shell.team_color }};color:{{ shell.team_text }}">
7+ <a class="team-pill" href="#equipes" aria-label="Changer d'équipe" style="--team-color:{{ shell.team_color }}">
8+ <span class="team-dot" style="background:{{ shell.team_color }}"></span>
89 {{ shell.team_name }}
910 <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"><path d="M6 9l6 6 6-6"></path></svg>
1011 </a>
1112 {% else %}
12- <span class="team-pill" style="background:{{ shell.team_color }};color:{{ shell.team_text }}">
13+ <span class="team-pill" style="--team-color:{{ shell.team_color }}">
14+ <span class="team-dot" style="background:{{ shell.team_color }}"></span>
1315 {{ shell.team_name }}
1416 </span>
1517 {% endif %}
@@ -75,7 +77,7 @@
7577 <span class="team-dot" style="background:{{ t.color }}"></span>
7678 <span style="flex:1;text-align:left">
7779 <span style="display:block;font-size:16px">{{ t.name }}</span>
78- <span style="display:block;font-size:12px;opacity:.6">{{ t.meta }}</span>
80+ <span style="display:block;font-size:12px;opacity:.7">{{ t.meta }}</span>
7981 </span>
8082 {% if t.current %}<svg width="17" height="17" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.75" stroke-linecap="round" stroke-linejoin="round"><path d="M20 6L9 17l-5-5"></path></svg>{% endif %}
8183 </button>
@@ -4,12 +4,14 @@
4 <header class="app-header">4 <header class="app-header">
5 <div class="app-topline">5 <div class="app-topline">
6 {% if !shell.teams.is_empty() %}6 {% if !shell.teams.is_empty() %}
7- <a class="team-pill" href="#equipes" aria-label="Changer d'équipe" style="background:{{ shell.team_color }};color:{{ shell.team_text }}">7+ <a class="team-pill" href="#equipes" aria-label="Changer d'équipe" style="--team-color:{{ shell.team_color }}">
8+ <span class="team-dot" style="background:{{ shell.team_color }}"></span>
8 {{ shell.team_name }}9 {{ shell.team_name }}
9 <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"><path d="M6 9l6 6 6-6"></path></svg>10 <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"><path d="M6 9l6 6 6-6"></path></svg>
10 </a>11 </a>
11 {% else %}12 {% else %}
12- <span class="team-pill" style="background:{{ shell.team_color }};color:{{ shell.team_text }}">13+ <span class="team-pill" style="--team-color:{{ shell.team_color }}">
14+ <span class="team-dot" style="background:{{ shell.team_color }}"></span>
13 {{ shell.team_name }}15 {{ shell.team_name }}
14 </span>16 </span>
15 {% endif %}17 {% endif %}
@@ -75,7 +77,7 @@
75 <span class="team-dot" style="background:{{ t.color }}"></span>77 <span class="team-dot" style="background:{{ t.color }}"></span>
76 <span style="flex:1;text-align:left">78 <span style="flex:1;text-align:left">
77 <span style="display:block;font-size:16px">{{ t.name }}</span>79 <span style="display:block;font-size:16px">{{ t.name }}</span>
78- <span style="display:block;font-size:12px;opacity:.6">{{ t.meta }}</span>80+ <span style="display:block;font-size:12px;opacity:.7">{{ t.meta }}</span>
79 </span>81 </span>
80 {% if t.current %}<svg width="17" height="17" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.75" stroke-linecap="round" stroke-linejoin="round"><path d="M20 6L9 17l-5-5"></path></svg>{% endif %}82 {% if t.current %}<svg width="17" height="17" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.75" stroke-linecap="round" stroke-linejoin="round"><path d="M20 6L9 17l-5-5"></path></svg>{% endif %}
81 </button>83 </button>
modified templates/settings.html +5 -5
@@ -37,7 +37,7 @@
3737 </div>
3838 </div>
3939 </form>
40-<p style="font-size:12px;opacity:.55;margin:0 0 var(--space-6)">Le nouveau nom est visible par tous les membres.</p>
40+<p style="font-size:12px;opacity:.7;margin:0 0 var(--space-6)">Le nouveau nom est visible par tous les membres.</p>
4141
4242 <h4 style="margin:0 0 var(--space-2)">Membres de {{ shell.team_name }}</h4>
4343 <div style="display:flex;flex-wrap:wrap;gap:var(--space-2);margin-bottom:var(--space-4)">
@@ -55,7 +55,7 @@
5555 </div>
5656 </form>
5757 {% if let Some(e) = invite_error %}<p class="form-error" style="margin:0 0 var(--space-2)">{{ e }}</p>{% endif %}
58-<p style="font-size:12px;opacity:.55;margin:0">L'utilisateur doit déjà avoir un compte. Il reçoit une invitation à accepter de son côté.</p>
58+<p style="font-size:12px;opacity:.7;margin:0">L'utilisateur doit déjà avoir un compte. Il reçoit une invitation à accepter de son côté.</p>
5959
6060 {% if !sent.is_empty() %}
6161 <h4 style="margin:var(--space-6) 0 var(--space-2)">Invitations en attente</h4>
@@ -63,7 +63,7 @@
6363 <div class="sent-row">
6464 <div style="flex:1;min-width:0">
6565 <div style="font-size:15px">{{ si.name }}</div>
66- <div style="font-size:12px;opacity:.55">{{ si.meta }}</div>
66+ <div style="font-size:12px;opacity:.7">{{ si.meta }}</div>
6767 </div>
6868 <form method="post" action="{{ si.cancel_action }}" style="margin:0">
6969 <input type="hidden" name="csrf" value="{{ csrf }}">
@@ -81,7 +81,7 @@
8181 <button type="submit" class="btn btn-primary" style="min-height:44px">Créer</button>
8282 </div>
8383 </form>
84-<p style="font-size:12px;opacity:.55;margin:var(--space-2) 0 0">Tu bascules dessus aussitôt — invite ensuite qui tu veux.</p>
84+<p style="font-size:12px;opacity:.7;margin:var(--space-2) 0 0">Tu bascules dessus aussitôt — invite ensuite qui tu veux.</p>
8585
8686 {% if can_leave %}
8787 <form method="post" action="/equipes/quitter">
@@ -89,7 +89,7 @@
8989 <button type="submit" class="btn btn-block"
9090 style="min-height:46px;margin-top:var(--space-6);color:var(--color-accent-700);border:1px solid var(--color-accent-300)">Quitter « {{ shell.team_name }} »</button>
9191 </form>
92-<p style="font-size:11px;opacity:.45;margin-top:var(--space-2);text-align:center">Tes temps déjà saisis restent dans les stats de l'équipe.</p>
92+<p style="font-size:11px;opacity:.7;margin-top:var(--space-2);text-align:center">Tes temps déjà saisis restent dans les stats de l'équipe.</p>
9393 {% endif %}
9494
9595 <h4 style="margin:var(--space-8) 0 var(--space-3)">Session</h4>
@@ -37,7 +37,7 @@
37 </div>37 </div>
38 </div>38 </div>
39 </form>39 </form>
40-<p style="font-size:12px;opacity:.55;margin:0 0 var(--space-6)">Le nouveau nom est visible par tous les membres.</p>40+<p style="font-size:12px;opacity:.7;margin:0 0 var(--space-6)">Le nouveau nom est visible par tous les membres.</p>
41 41
42 <h4 style="margin:0 0 var(--space-2)">Membres de {{ shell.team_name }}</h4>42 <h4 style="margin:0 0 var(--space-2)">Membres de {{ shell.team_name }}</h4>
43 <div style="display:flex;flex-wrap:wrap;gap:var(--space-2);margin-bottom:var(--space-4)">43 <div style="display:flex;flex-wrap:wrap;gap:var(--space-2);margin-bottom:var(--space-4)">
@@ -55,7 +55,7 @@
55 </div>55 </div>
56 </form>56 </form>
57 {% if let Some(e) = invite_error %}<p class="form-error" style="margin:0 0 var(--space-2)">{{ e }}</p>{% endif %}57 {% if let Some(e) = invite_error %}<p class="form-error" style="margin:0 0 var(--space-2)">{{ e }}</p>{% endif %}
58-<p style="font-size:12px;opacity:.55;margin:0">L'utilisateur doit déjà avoir un compte. Il reçoit une invitation à accepter de son côté.</p>58+<p style="font-size:12px;opacity:.7;margin:0">L'utilisateur doit déjà avoir un compte. Il reçoit une invitation à accepter de son côté.</p>
59 59
60 {% if !sent.is_empty() %}60 {% if !sent.is_empty() %}
61 <h4 style="margin:var(--space-6) 0 var(--space-2)">Invitations en attente</h4>61 <h4 style="margin:var(--space-6) 0 var(--space-2)">Invitations en attente</h4>
@@ -63,7 +63,7 @@
63 <div class="sent-row">63 <div class="sent-row">
64 <div style="flex:1;min-width:0">64 <div style="flex:1;min-width:0">
65 <div style="font-size:15px">{{ si.name }}</div>65 <div style="font-size:15px">{{ si.name }}</div>
66- <div style="font-size:12px;opacity:.55">{{ si.meta }}</div>66+ <div style="font-size:12px;opacity:.7">{{ si.meta }}</div>
67 </div>67 </div>
68 <form method="post" action="{{ si.cancel_action }}" style="margin:0">68 <form method="post" action="{{ si.cancel_action }}" style="margin:0">
69 <input type="hidden" name="csrf" value="{{ csrf }}">69 <input type="hidden" name="csrf" value="{{ csrf }}">
@@ -81,7 +81,7 @@
81 <button type="submit" class="btn btn-primary" style="min-height:44px">Créer</button>81 <button type="submit" class="btn btn-primary" style="min-height:44px">Créer</button>
82 </div>82 </div>
83 </form>83 </form>
84-<p style="font-size:12px;opacity:.55;margin:var(--space-2) 0 0">Tu bascules dessus aussitôt — invite ensuite qui tu veux.</p>84+<p style="font-size:12px;opacity:.7;margin:var(--space-2) 0 0">Tu bascules dessus aussitôt — invite ensuite qui tu veux.</p>
85 85
86 {% if can_leave %}86 {% if can_leave %}
87 <form method="post" action="/equipes/quitter">87 <form method="post" action="/equipes/quitter">
@@ -89,7 +89,7 @@
89 <button type="submit" class="btn btn-block"89 <button type="submit" class="btn btn-block"
90 style="min-height:46px;margin-top:var(--space-6);color:var(--color-accent-700);border:1px solid var(--color-accent-300)">Quitter « {{ shell.team_name }} »</button>90 style="min-height:46px;margin-top:var(--space-6);color:var(--color-accent-700);border:1px solid var(--color-accent-300)">Quitter « {{ shell.team_name }} »</button>
91 </form>91 </form>
92-<p style="font-size:11px;opacity:.45;margin-top:var(--space-2);text-align:center">Tes temps déjà saisis restent dans les stats de l'équipe.</p>92+<p style="font-size:11px;opacity:.7;margin-top:var(--space-2);text-align:center">Tes temps déjà saisis restent dans les stats de l'équipe.</p>
93 {% endif %}93 {% endif %}
94 94
95 <h4 style="margin:var(--space-8) 0 var(--space-3)">Session</h4>95 <h4 style="margin:var(--space-8) 0 var(--space-3)">Session</h4>