From 109ab3951cba7771ce8b00781e74d8d71c73fcc9 Mon Sep 17 00:00:00 2001 From: Daniel Date: Sun, 13 Sep 2026 02:54:56 +0200 Subject: [PATCH] fix: the Save for a card stays in view while you are inside that card MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit You could change an image model, scroll past it, and never learn there was a button. The Availability card runs to about 1,300 pixels: the image models sit above the slide reviewer, which sits above the Save, so the fields and the thing that saves them were never on screen together. The save row is now sticky. It pins to the bottom of the window while you are anywhere inside its card and settles back into place at the end. That class is already on four cards, so Clinical Assistant, Search Sources, SMTP and OIDC get it too. Two things were stopping sticky from working, and both were invisible: .card sets overflow:hidden to clip its rounded header, and overflow hidden on an ancestor silently disables position:sticky in every descendant. clip does the same clipping without making the card a scroll container. Then #admin-tab sets overflow:auto as part of the tab shell — which makes it the nearest scrolling ancestor for everything inside it while it never actually scrolls, because the document does. bottom:0 resolved against a box 7,700px tall, which is to say it did not stick at all. Admin now opts out of that overflow the way #assistant-tab already does; nothing in there needs the clipping, since every wide thing already scrolls in a container of its own. Checked in a browser rather than reasoned about: with the image fields on screen the bar's bottom edge is at 820px in an 820px viewport. Audited the other cards while here. Registration, Users and Discover & test have no Save because they have nothing to save — they are actions and search boxes. Roster's is called "Set default". Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01Dv6sqaY6Vq3ChZHMem3cnU --- public/css/styles.css | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/public/css/styles.css b/public/css/styles.css index 3580a73d..eb4229bd 100644 --- a/public/css/styles.css +++ b/public/css/styles.css @@ -108,6 +108,14 @@ body{font-family:'Inter',system-ui,sans-serif;background:var(--g50);color:var(-- /* The assistant brings its own full-bleed layout, so it takes the shell's place rather than nesting a second card inside it. */ .main-content > #assistant-tab.active{padding:0;border:none;box-shadow:none;background:transparent;overflow:visible;} +/* Admin gives up the shell's overflow for the same reason the assistant does, + but for a different effect: overflow:auto here makes this the nearest + scrolling ancestor for everything inside, while it never actually scrolls — + the document does. A sticky element then resolves bottom:0 against a box + 7,000px tall, which is to say it does not stick at all. The admin save bars + depend on it, and nothing in admin needs the clipping: every wide thing in + there already scrolls in a container of its own. */ +.main-content > #admin-tab.active{overflow:visible;} @media(max-width:768px){ .main-content{padding:8px;} .main-content > .tab-content.active{padding:12px;border-radius:12px;} @@ -1286,7 +1294,27 @@ textarea.full-input{resize:vertical;} .admin-note { font-size:12px; color:var(--g500); margin:0; line-height:1.5; } .admin-badge { font-size:11px; padding:2px 8px; border-radius:10px; background:var(--g100); color:var(--g600); white-space:nowrap; } .admin-search-row { display:flex; gap:8px; flex-wrap:wrap; align-items:center; } -.admin-save-row { border-top:1px solid var(--g100); padding-top:12px; display:flex; align-items:center; gap:8px; flex-wrap:wrap; } +/* The Save for a card, kept in view while you are inside that card. + These cards are long — the image models sit above a slide reviewer, which + sits above the Save — so it was possible to change a setting, scroll on, and + never learn there was a button. It sticks to the bottom of the window until + the card ends, then sits where it always did. + The negative margins let the bar span the card's padding rather than floating + in a gutter; the background is opaque because content scrolls under it. */ +.admin-save-row { + border-top:1px solid var(--g100); display:flex; align-items:center; gap:8px; flex-wrap:wrap; + position:sticky; bottom:0; z-index:2; + background:var(--white,#fff); + margin:0 -16px -14px; padding:12px 16px 14px; +} +/* .card sets overflow:hidden to clip its rounded header, and overflow:hidden on + an ancestor silently disables position:sticky in every descendant. clip does + the same clipping without making the card a scroll container. Scoped to admin + cards rather than every card in the app. */ +details.card { overflow:clip; } +@media (prefers-reduced-motion: no-preference) { .admin-save-row { transition:box-shadow .15s ease; } } +/* A hint of lift only while it is actually stuck, so a card at rest looks flat. */ +.admin-save-row:not(:last-child) { box-shadow:0 -1px 0 var(--g100); } .admin-kind-switch { display:flex; flex-wrap:wrap; gap:6px; } .admin-discover-kind { display:inline-flex; align-items:center; gap:6px; padding:5px 12px; border:1px solid var(--g300); border-radius:999px; background:white; color:var(--g700); font-size:12px; font-weight:600; cursor:pointer; } .admin-discover-kind:hover { background:var(--g100); }