mirror of
https://github.com/Ark0N/Codeman.git
synced 2026-10-20 09:09:35 +02:00
fix(ui): keep the security notice card reachable and readable everywhere
- The card is capped to the room below the toast stack's top and scrolls inside itself. The stack is fixed and cannot scroll, so on a phone in landscape the update toast's buttons sat below the screen with only the × left, which records the notice unread. The accent bar becomes a background layer, which stays put while the content scrolls. - Small amber text and the primary button use --notice-ink, darkened a step on the four light skins, where --yellow measured 3.9 to 4.4:1 for the 10.6px eyebrow (now 5.1 or better, the button label 5.7 or better). - The update toast that carries a notice frames itself in the accent colour and leaves the amber to the warning section inside it. - The × uses --text-dim (2.4:1 on og before, 5.5 now). - Phones: every button fills its row (a wrapped Dismiss no longer sits stray at the left) and is 44px tall, and the × gets a 44px box. - The title balances its lines, and the card matches the plain toast's 420px so a toast stacked under it lines up. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
5e405bbbb9
commit
ee6b115023
1 file changed
+49
-25
+49
-25
@@ -9726,20 +9726,30 @@ kbd {
|
|||||||
/* Security notice card (security-notices.json; showSecurityNotice / showUpdateNotice in
|
/* Security notice card (security-notices.json; showSecurityNotice / showUpdateNotice in
|
||||||
panels-ui.js). Its own card in the toast stack, never the plain pill, and in the SAME
|
panels-ui.js). Its own card in the toast stack, never the plain pill, and in the SAME
|
||||||
container, so it shares the toasts' position and z-index. Theme tokens only, so every skin
|
container, so it shares the toasts' position and z-index. Theme tokens only, so every skin
|
||||||
reads: the light skins' --yellow is already a dark amber that holds on white, and the
|
reads. Small amber text and the primary button use --notice-ink: --yellow on the dark
|
||||||
primary button's ink is --bg-card (dark ink on the dark skins' light amber, white ink on
|
skins, and on the light skins --yellow darkened a step, because their --yellow alone is
|
||||||
the light skins' dark amber). The entrance animates opacity and transform only, and
|
under 4.5:1 for 11-12px text on white (3.9 to 4.4 measured). The primary button's label is
|
||||||
nothing moves under prefers-reduced-motion. */
|
--bg-card (dark on the dark skins' light amber, white on the light skins' dark amber). The
|
||||||
|
entrance animates opacity and transform only, and nothing moves under
|
||||||
|
prefers-reduced-motion.
|
||||||
|
|
||||||
|
The card is capped to the room below the stack's top and scrolls inside itself: the
|
||||||
|
container is fixed and does not scroll, so on a short screen (a phone in landscape) the
|
||||||
|
buttons at the bottom were otherwise off-screen and unreachable. The accent bar down the
|
||||||
|
left edge (amber running into red) is therefore a background layer, not a positioned
|
||||||
|
child: a background stays put while the content scrolls. */
|
||||||
.security-notice {
|
.security-notice {
|
||||||
position: relative;
|
--notice-ink: var(--yellow);
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: auto minmax(0, 1fr) auto;
|
grid-template-columns: auto minmax(0, 1fr) auto;
|
||||||
column-gap: 0.75rem;
|
column-gap: 0.75rem;
|
||||||
align-items: start;
|
align-items: start;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
width: min(27rem, calc(100vw - 1rem));
|
width: min(420px, calc(100vw - 1rem));
|
||||||
|
max-height: calc(var(--app-height, 100dvh) - var(--header-height) - 1rem);
|
||||||
padding: 0.85rem 0.55rem 0.9rem 1.05rem;
|
padding: 0.85rem 0.55rem 0.9rem 1.05rem;
|
||||||
background:
|
background:
|
||||||
|
linear-gradient(180deg, var(--yellow), var(--red)) left top / 4px 100% no-repeat,
|
||||||
linear-gradient(180deg, color-mix(in srgb, var(--yellow) 9%, transparent), transparent 6rem),
|
linear-gradient(180deg, color-mix(in srgb, var(--yellow) 9%, transparent), transparent 6rem),
|
||||||
var(--bg-card);
|
var(--bg-card);
|
||||||
border: 1px solid color-mix(in srgb, var(--yellow) 32%, var(--border));
|
border: 1px solid color-mix(in srgb, var(--yellow) 32%, var(--border));
|
||||||
@@ -9748,7 +9758,9 @@ kbd {
|
|||||||
color: var(--text);
|
color: var(--text);
|
||||||
font-size: 0.8rem;
|
font-size: 0.8rem;
|
||||||
line-height: 1.45;
|
line-height: 1.45;
|
||||||
overflow: hidden;
|
overflow-x: hidden;
|
||||||
|
overflow-y: auto;
|
||||||
|
overscroll-behavior: contain;
|
||||||
pointer-events: auto;
|
pointer-events: auto;
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
transform: translateY(-6px) scale(0.985);
|
transform: translateY(-6px) scale(0.985);
|
||||||
@@ -9760,15 +9772,17 @@ kbd {
|
|||||||
transform: none;
|
transform: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The accent bar: amber running into red down the left edge. */
|
html:is([data-skin="paper-gray"], [data-skin="solarized-light"], [data-skin="catppuccin-latte"], [data-skin="rose-pine-dawn"]) .security-notice {
|
||||||
.security-notice::before {
|
--notice-ink: color-mix(in srgb, var(--yellow) 85%, black);
|
||||||
content: '';
|
}
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
/* The update toast carrying a notice is still an update: its frame takes the accent colour,
|
||||||
bottom: 0;
|
and the amber is left to the warning section inside it. */
|
||||||
left: 0;
|
.security-notice.update-notice {
|
||||||
width: 4px;
|
background:
|
||||||
background: linear-gradient(180deg, var(--yellow), var(--red));
|
linear-gradient(var(--accent), var(--accent)) left top / 4px 100% no-repeat,
|
||||||
|
var(--bg-card);
|
||||||
|
border-color: color-mix(in srgb, var(--accent) 30%, var(--border));
|
||||||
}
|
}
|
||||||
|
|
||||||
.security-notice-icon {
|
.security-notice-icon {
|
||||||
@@ -9778,7 +9792,7 @@ kbd {
|
|||||||
width: 2rem;
|
width: 2rem;
|
||||||
height: 2rem;
|
height: 2rem;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
color: var(--yellow);
|
color: var(--notice-ink);
|
||||||
background: color-mix(in srgb, var(--yellow) 15%, transparent);
|
background: color-mix(in srgb, var(--yellow) 15%, transparent);
|
||||||
box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--yellow) 30%, transparent);
|
box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--yellow) 30%, transparent);
|
||||||
}
|
}
|
||||||
@@ -9804,7 +9818,7 @@ kbd {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.security-notice-eyebrow {
|
.security-notice-eyebrow {
|
||||||
color: var(--yellow);
|
color: var(--notice-ink);
|
||||||
font-size: 0.66rem;
|
font-size: 0.66rem;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
letter-spacing: 0.09em;
|
letter-spacing: 0.09em;
|
||||||
@@ -9818,6 +9832,7 @@ kbd {
|
|||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
line-height: 1.3;
|
line-height: 1.3;
|
||||||
overflow-wrap: anywhere;
|
overflow-wrap: anywhere;
|
||||||
|
text-wrap: balance;
|
||||||
}
|
}
|
||||||
|
|
||||||
.security-notice-body,
|
.security-notice-body,
|
||||||
@@ -9850,7 +9865,7 @@ kbd {
|
|||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 0.4rem;
|
gap: 0.4rem;
|
||||||
color: var(--yellow);
|
color: var(--notice-ink);
|
||||||
}
|
}
|
||||||
|
|
||||||
.security-notice-section-head svg {
|
.security-notice-section-head svg {
|
||||||
@@ -9891,12 +9906,12 @@ kbd {
|
|||||||
padding: 0.45rem 0.85rem;
|
padding: 0.45rem 0.85rem;
|
||||||
border: 1px solid transparent;
|
border: 1px solid transparent;
|
||||||
border-radius: var(--btn-radius);
|
border-radius: var(--btn-radius);
|
||||||
background: var(--yellow);
|
background: var(--notice-ink);
|
||||||
color: var(--bg-card);
|
color: var(--bg-card);
|
||||||
}
|
}
|
||||||
|
|
||||||
.security-notice-primary:hover {
|
.security-notice-primary:hover {
|
||||||
background: color-mix(in srgb, var(--yellow) 86%, var(--text));
|
background: color-mix(in srgb, var(--notice-ink) 86%, var(--text));
|
||||||
}
|
}
|
||||||
|
|
||||||
.security-notice-secondary {
|
.security-notice-secondary {
|
||||||
@@ -9936,7 +9951,7 @@ kbd {
|
|||||||
border: none;
|
border: none;
|
||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
background: none;
|
background: none;
|
||||||
color: var(--text-muted);
|
color: var(--text-dim);
|
||||||
font-size: 1.15rem;
|
font-size: 1.15rem;
|
||||||
line-height: 1;
|
line-height: 1;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
@@ -9952,15 +9967,24 @@ kbd {
|
|||||||
outline-offset: 2px;
|
outline-offset: 2px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Phones: the full width minus the stack's 0.5rem gutters, and the notice's own button
|
/* Phones: the full width minus the stack's 0.5rem gutters. Every button grows to fill its
|
||||||
takes the room left beside Dismiss (wrapping under it when the label is long). */
|
row (so one that wraps fills its own instead of sitting stray at the left) and is at least
|
||||||
|
--touch-target-min tall; the × gets a touch-sized box too, its negative margin keeping the
|
||||||
|
glyph where it sits on a desktop. */
|
||||||
@media (max-width: 599px) {
|
@media (max-width: 599px) {
|
||||||
.security-notice {
|
.security-notice {
|
||||||
width: calc(100vw - 1rem);
|
width: calc(100vw - 1rem);
|
||||||
}
|
}
|
||||||
|
|
||||||
.security-notice-primary {
|
.security-notice-actions > button {
|
||||||
flex: 1 1 auto;
|
flex: 1 1 auto;
|
||||||
|
min-height: var(--touch-target-min);
|
||||||
|
}
|
||||||
|
|
||||||
|
.security-notice-close {
|
||||||
|
width: var(--touch-target-min);
|
||||||
|
height: var(--touch-target-min);
|
||||||
|
margin: -0.75rem -0.5rem 0 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user