diff --git a/containers/libreportal/frontend/css/tasks.css b/containers/libreportal/frontend/css/tasks.css index 1b650de..c8dd65b 100644 --- a/containers/libreportal/frontend/css/tasks.css +++ b/containers/libreportal/frontend/css/tasks.css @@ -383,25 +383,16 @@ } /* Multi-select checkbox sat to the right of the row's Delete button. - Sized + framed to match the surrounding .task-btn buttons so the row - reads as a single action group. Hides the native input and renders - a custom box; `cursor: pointer` on the wrapping label keeps the - whole 24×24 hit target clickable. */ + Mirrors the .setup-app checkbox from the setup wizard: accent fill + + white SVG check + pop-in, no separate frame. The label wrapper is just + a hit-target — visible chrome is all on .task-select-box. Sized down + to 18px so it sits inline with the 22px-tall .task-btn buttons. */ .task-select { display: inline-flex; align-items: center; justify-content: center; - width: 22px; - height: 22px; - border-radius: 6px; - border: 1px solid rgba(var(--text-rgb), 0.12); - background: rgba(var(--text-rgb), 0.04); cursor: pointer; - transition: background 0.18s ease, border-color 0.18s ease; -} -.task-select:hover { - background: var(--surface-hover); - border-color: var(--status-success); + padding: 2px; } .task-select input[type="checkbox"] { position: absolute; @@ -410,43 +401,54 @@ width: 0; height: 0; } .task-select-box { - width: 12px; - height: 12px; - border-radius: 3px; - border: 1.5px solid rgba(var(--text-rgb), 0.45); - background: transparent; + width: 18px; + height: 18px; + flex-shrink: 0; + border-radius: 5px; + background: rgba(var(--text-rgb), 0.04); + border: 1.5px solid rgba(var(--text-rgb), 0.18); + box-shadow: inset 0 0 0 1px rgba(var(--text-rgb), 0.02); position: relative; - transition: background 0.12s ease, border-color 0.12s ease; + transition: background 0.18s ease, border-color 0.18s ease, box-shadow 0.18s ease; +} +.task-select:hover .task-select-box { + border-color: rgba(var(--accent-rgb), 0.55); + box-shadow: 0 0 0 3px rgba(var(--accent-rgb), 0.08); +} +.task-select input[type="checkbox"]:focus-visible + .task-select-box { + outline: none; + border-color: rgba(var(--accent-rgb), 0.85); + box-shadow: 0 0 0 3px rgba(var(--accent-rgb), 0.20); } .task-select input[type="checkbox"]:checked + .task-select-box { - background: var(--status-success); - border-color: var(--status-success); + background: linear-gradient(135deg, var(--accent), var(--accent)); + border-color: rgba(var(--accent-rgb), 0.9); + box-shadow: 0 0 0 1px rgba(var(--accent-rgb), 0.35); } .task-select input[type="checkbox"]:checked + .task-select-box::after { content: ""; position: absolute; - top: 1px; - left: 4px; - width: 3px; - height: 7px; - border: solid var(--text-on-accent, #fff); - border-width: 0 2px 2px 0; - transform: rotate(45deg); + inset: 0; + background-image: url("data:image/svg+xml;utf8,"); + background-repeat: no-repeat; + background-position: center; + background-size: 12px 12px; + animation: taskCheckPop 0.22s cubic-bezier(0.34, 1.56, 0.64, 1); } -.task-select input[type="checkbox"]:focus-visible + .task-select-box { - outline: 2px solid var(--accent); - outline-offset: 2px; +@keyframes taskCheckPop { + 0% { transform: scale(0.4); opacity: 0; } + 100% { transform: scale(1); opacity: 1; } } -/* Master "Select all" toggle in the status/action bar (left of Clear All). - Uses the same custom-box visual as the row checkbox so the two reinforce - each other; the label sits inline with the button text style. */ +/* Master "Select all" toggle in the action bar (right of Clear All). + Reuses .task-select-box so the two checkboxes are visually identical. + The wrapping label adds the inline "Select all" text + a hover lift. */ .task-select-all { display: inline-flex; align-items: center; - gap: 6px; + gap: 8px; cursor: pointer; - padding: 4px 8px; + padding: 4px 10px; border-radius: 6px; font-size: 11px; color: var(--text-secondary); @@ -463,22 +465,40 @@ pointer-events: none; width: 0; height: 0; } -/* The indeterminate state (some-but-not-all visible rows ticked) shows - a horizontal dash instead of a check. */ +.task-select-all:hover .task-select-box { + border-color: rgba(var(--accent-rgb), 0.55); + box-shadow: 0 0 0 3px rgba(var(--accent-rgb), 0.08); +} +.task-select-all input[type="checkbox"]:checked + .task-select-box { + background: linear-gradient(135deg, var(--accent), var(--accent)); + border-color: rgba(var(--accent-rgb), 0.9); + box-shadow: 0 0 0 1px rgba(var(--accent-rgb), 0.35); +} +.task-select-all input[type="checkbox"]:checked + .task-select-box::after { + content: ""; + position: absolute; + inset: 0; + background-image: url("data:image/svg+xml;utf8,"); + background-repeat: no-repeat; + background-position: center; + background-size: 12px 12px; + animation: taskCheckPop 0.22s cubic-bezier(0.34, 1.56, 0.64, 1); +} +/* Indeterminate state — some-but-not-all visible rows ticked. Swap the + check SVG for a horizontal dash, still white on accent. */ .task-select-all input[type="checkbox"]:indeterminate + .task-select-box { - background: var(--status-success); - border-color: var(--status-success); + background: linear-gradient(135deg, var(--accent), var(--accent)); + border-color: rgba(var(--accent-rgb), 0.9); + box-shadow: 0 0 0 1px rgba(var(--accent-rgb), 0.35); } .task-select-all input[type="checkbox"]:indeterminate + .task-select-box::after { content: ""; position: absolute; - top: 4px; - left: 1px; - width: 8px; - height: 2px; - background: var(--text-on-accent, #fff); - border: none; - transform: none; + inset: 0; + background-image: url("data:image/svg+xml;utf8,"); + background-repeat: no-repeat; + background-position: center; + background-size: 12px 12px; } .task-select-all-label { font-weight: 500;