diff --git a/TODO.md b/TODO.md index 1afd4ab..e09dd2a 100644 --- a/TODO.md +++ b/TODO.md @@ -1,9 +1,11 @@ # TODO -> Last updated: 2026-06-21 -> Context: Migrate all -based icons to inline SVG via PHP helper so CSS color cascade works +> Last updated: 2026-06-22 +> Context: Add mobile-responsive accordion + chip bar to repertoire filter index (column headings restored) ## Pending +- [ ] #rep-student-touch Replace hover student popover with tap-to-open drawer for mobile `(repertoire.php, repertoire.css)` +- [ ] #rep-polish Polish: scroll-position memory on HTMX swap, animation tuning `(repertoire.css)` - [ ] #icon-color-verify Verify icon colors render correctly across all pages (header, admin tables, forms, dialogs, cleanup modal) ## Completed diff --git a/app/public/assets/css/repertoire.css b/app/public/assets/css/repertoire.css index a760c8f..f412d24 100644 --- a/app/public/assets/css/repertoire.css +++ b/app/public/assets/css/repertoire.css @@ -16,7 +16,7 @@ display: grid; grid-template-columns: minmax(3rem, 0.45fr) - minmax(12rem, 1fr) + minmax(16rem, 1.2fr) minmax(9rem, 1fr) minmax(7rem, 1fr) minmax(8rem, 1fr) @@ -29,45 +29,92 @@ height: 100%; } -@media (max-width: 1024px) { - .repertoire-index { - grid-template-columns: 1fr 1fr 1fr; - padding: 0; - grid-template-rows: auto auto 1fr; - min-height: auto; +/* ---- Active filter chip bar ---- */ +.rep-chip-bar { + display: none; +} + +@media (max-width: 1025px) { + .rep-chip-bar { + display: flex; + flex-wrap: wrap; + align-items: center; + gap: var(--space-2xs); + padding: var(--space-2xs) var(--space-s); + border-bottom: 1px solid var(--border-secondary); + margin: 0; + position: sticky; + top: 0; + z-index: 10; + background: var(--bg-primary); } } -@media (max-width: 600px) { - .repertoire-index { - grid-template-columns: 1fr; - padding: 0; - grid-template-rows: none; - min-height: auto; - } +.rep-chip-bar__label { + font-family: var(--font-display); + font-size: var(--step--2); + letter-spacing: 0.08em; + text-transform: uppercase; + color: var(--text-secondary); + margin-right: var(--space-3xs); + white-space: nowrap; +} - /* On single column, each section is a self-contained block again */ - .repertoire-col { - display: flex; - flex-direction: column; - overflow: hidden; - min-height: 12rem; - border-bottom: 1px solid var(--border-primary); - } +.rep-chip { + display: inline-flex; + align-items: center; + gap: var(--space-3xs); + padding: var(--space-3xs) var(--space-2xs); + background: var(--accent-muted); + border: 1px solid var(--accent-primary); + border-radius: 99px; + font-family: var(--font-body); + font-size: var(--step--2); + color: var(--accent-primary); + cursor: pointer; + white-space: nowrap; + transition: background 0.15s, color 0.15s; +} - .repertoire-col:last-child { - border-bottom: none; - } +.rep-chip:hover { + background: var(--accent-primary); + color: var(--accent-foreground); +} - .repertoire-col > h2 { - grid-row: unset; - align-self: unset; - } +.rep-chip__dim { + font-weight: 500; + text-transform: uppercase; + letter-spacing: 0.05em; + font-size: 0.75em; + color: var(--accent-secondary); +} - .repertoire-col > ul { - grid-row: unset; - flex: 1; - } +.rep-chip:hover .rep-chip__dim { + color: inherit; + opacity: 0.8; +} + +.rep-chip__remove { + font-size: 1.1em; + line-height: 1; + font-weight: 600; +} + +/* ---- Accordion: visible only on mobile (≤ 640px) ---- */ + +/* Desktop: heading-text visible, toggle hidden */ +.rep-accordion__heading-text { + /* visible — inherits the h2 styling above */ +} + +.rep-accordion__toggle, +.rep-accordion__chevron, +.rep-accordion__badge { + display: none; +} + +.rep-accordion__panel { + display: contents; } /* Each section becomes transparent to the grid so h2+ul sit in the 2-row layout */ @@ -79,33 +126,215 @@ grid-row: 1; font-family: var(--font-display); font-size: var(--step--1); - letter-spacing: 0.12em; + letter-spacing: 0.08em; text-transform: uppercase; color: var(--text-primary); font-weight: 398; - line-height: 23px; + line-height: 1.3; margin: 0; padding: var(--space-xs) 0 var(--space-3xs) 0; border-bottom: 1px solid var(--text-primary); align-self: end; - hyphens: manual; + hyphens: auto; word-break: normal; - overflow-wrap: normal; + overflow-wrap: break-word; } .repertoire-col > ul { grid-row: 2; overflow-y: auto; overflow-x: hidden; - padding: var(--space-2xs) 0 var(--space-l) 0; + padding-top: var(--space-2xs); + padding-bottom: var(--space-l); + padding-left: 0; + padding-right: 0; } /* Strip list chrome inside repertoire columns */ .repertoire-col ul { list-style: none; margin: 0; + padding: 0; } +/* ---- Responsive (≤ 1025px): accordion mode, chip bar, students as results ---- */ +@media (max-width: 1025px) { + .repertoire-index { + display: flex; + flex-direction: column; + min-height: 0; + height: 100%; + overflow-y: hidden; + gap: 0; + margin: 0; + } + + /* Each column becomes a block-level accordion section */ + .repertoire-col { + display: block; + border-bottom: 1px solid var(--text-primary); + } + + .repertoire-col[data-col="students"] { + border-bottom: none; + } + + /* Flex order: years/ap/or/fi first, then keywords, students last */ + .repertoire-col[data-col="years"] { order: 0; } + .repertoire-col[data-col="ap"] { order: 1; } + .repertoire-col[data-col="or"] { order: 2; } + .repertoire-col[data-col="fi"] { order: 3; } + .repertoire-col[data-col="kw"] { order: 4; } + .repertoire-col[data-col="students"] { order: 5; } + + /* Students column: not an accordion — open results list below filters */ + .repertoire-col[data-col="students"] { + border-bottom: none; + border-top: none; + margin-top: 0; + padding-top: 0; + flex: 1; + min-height: 0; + display: flex; + flex-direction: column; + } + + .repertoire-col[data-col="students"] .rep-accordion__toggle { + display: none; + } + + .repertoire-col[data-col="students"] .rep-accordion__heading-text { + display: none; + } + + .repertoire-col[data-col="students"] .rep-accordion__panel { + display: block; + max-height: none; + overflow-y: auto; + flex: 1; + } + + /* Hide the plain h2 — the toggle button replaces it */ + .repertoire-col > h2 { + display: block; + grid-row: unset; + align-self: unset; + border-bottom: none; + padding: 0; + margin: 0; + font-size: inherit; + line-height: inherit; + } + + /* Hide heading text on mobile (toggle button replaces it) */ + .rep-accordion__heading-text { + display: none; + } + + /* Accordion toggle: full-width touch target */ + .rep-accordion__toggle { + display: flex; + align-items: center; + justify-content: space-between; + width: 100%; + min-height: 48px; + padding: var(--space-xs) var(--space-s); + background: none; + border: none; + font-family: var(--font-display); + font-size: var(--step--2); + letter-spacing: 0.08em; + text-transform: uppercase; + color: var(--text-primary); + font-weight: 398; + text-align: left; + cursor: pointer; + } + + .rep-accordion__toggle:active { + background: var(--bg-secondary); + } + + /* Badge: active filter count */ + .rep-accordion__badge { + display: inline-flex; + align-items: center; + justify-content: center; + min-width: 1.4em; + height: 1.4em; + padding: 0 0.35em; + margin-left: var(--space-2xs); + background: var(--accent-primary); + color: var(--accent-foreground); + border-radius: 99px; + font-family: var(--font-body); + font-size: var(--step--2); + font-weight: 500; + letter-spacing: 0; + text-transform: none; + } + + /* Chevron: CSS triangle */ + .rep-accordion__chevron { + display: inline-block; + width: 10px; + height: 10px; + flex-shrink: 0; + margin-left: var(--space-2xs); + border-right: 2px solid var(--text-secondary); + border-bottom: 2px solid var(--text-secondary); + transform: rotate(45deg); + transition: transform 0.2s; + } + + .rep-accordion__toggle[aria-expanded="true"] .rep-accordion__chevron { + transform: rotate(-135deg); + } + + /* Panel: collapsed by default */ + .rep-accordion__panel { + display: block; + max-height: 0; + overflow: hidden; + transition: max-height 0.3s ease; + } + + .rep-accordion__panel.is-open { + max-height: 60vh; + overflow-y: auto; + } + + /* Reposition the