v0.3 Phase 4h: counterlines test on LumotiaNotice
Test commit for Jake's round-6 spec. Subtle 1-px inset shadow in a
softened complementary hue, applied to LumotiaNotice only. Other
test surfaces (Button.destructive, status pills, record ring, active
nav) reserved for after evaluation.
Tokens (quietware scope only, v0.2 surface unchanged):
--counterline-width: 1px
Raw complementary hues per Jake's table:
--role-info-counterline var(--color-accent) /* copper for blue */
--role-danger-counterline #6EA8FF /* soft blue for red */
--role-success-counterline #B891FF /* soft violet for green */
--role-caution-counterline #3A6BFF /* soft blue for yellow */
Tinted per-mode via color-mix:
Dark mode: 32% opacity (slightly stronger against dark surface)
Light mode: 22% opacity (whisper-quiet against cream)
HC mode: all transparent, --counterline-width: 0
Per-usage notice tokens emitted:
--notice-{role}-counterline
LumotiaNotice applies via Tailwind arbitrary value:
shadow-[inset_0_0_0_var(--counterline-width,0)_var(--notice-{tone}-counterline,transparent)]
HC contract zeroes both the width and the colour token so the 2-px
HC border carries the tactile detail instead.
Honest evaluation of the visible result.
At 1px and 22%/32% opacity the counterline is implemented
correctly but reads as whisper-quiet to the point of being almost
invisible at standard viewing zoom. Doesn't look noisy (the risk
Jake flagged), but also doesn't add perceptible tactility.
Pending Jake's call:
(a) raise opacity to ~45% dark / ~35% light for visibility,
(b) keep at current opacity for the quietness,
(c) revert and proceed Phase 5c.
Phase 5c proceeds either way; this commit does NOT block the
layout migration.
Verified.
- npm run check: 0 errors, 0 warnings across 5707 files.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -351,7 +351,32 @@ LumotiaNotice now reads these via Tailwind arbitrary-value classes (`bg-[var(--n
|
|||||||
|
|
||||||
Per Jake's round-5 spec: yellow stays yellow (visible signal), ochre only appears as small-text ink, and brown/khaki never represents the caution role's primary identity again.
|
Per Jake's round-5 spec: yellow stays yellow (visible signal), ochre only appears as small-text ink, and brown/khaki never represents the caution role's primary identity again.
|
||||||
|
|
||||||
### Phase 5b — Browser-preview reclassification. Landed 2026-05-15.
|
### Phase 4h — Counterlines test (TBD: keep or remove). Landed 2026-05-15.
|
||||||
|
|
||||||
|
Test commit per Jake's round-6 spec. Subtle 1-px inner-shadow detail in a softened complementary hue, applied to LumotiaNotice only. Other test surfaces (Button.destructive, status pills, record ring, active nav) reserved for after evaluation.
|
||||||
|
|
||||||
|
Tokens added under quietware scope:
|
||||||
|
|
||||||
|
```css
|
||||||
|
--counterline-width: 1px;
|
||||||
|
|
||||||
|
--role-info-counterline: var(--color-accent); /* copper for blue */
|
||||||
|
--role-danger-counterline: #6EA8FF; /* soft blue for red */
|
||||||
|
--role-success-counterline: #B891FF; /* soft violet for green */
|
||||||
|
--role-caution-counterline: #3A6BFF; /* soft blue for yellow */
|
||||||
|
|
||||||
|
--notice-{role}-counterline: color-mix(in srgb, <role-counterline> {32% dark / 22% light}, transparent)
|
||||||
|
```
|
||||||
|
|
||||||
|
HC contract: `--counterline-width: 0`, all counterline tokens forced to `transparent`. The 2-px HC border IS the tactile detail in that mode.
|
||||||
|
|
||||||
|
LumotiaNotice applies the counterline via Tailwind arbitrary value:
|
||||||
|
|
||||||
|
```svelte
|
||||||
|
shadow-[inset_0_0_0_var(--counterline-width,0)_var(--notice-{tone}-counterline,transparent)]
|
||||||
|
```
|
||||||
|
|
||||||
|
**Honest evaluation.** At 1px / 22% light / 32% dark opacity the effect is whisper-quiet to the point of being almost invisible at standard viewing. Doesn't look noisy (which was the risk Jake flagged), but also doesn't add perceptible tactility. Pending Jake's call: keep with raised opacity (perhaps 45% dark / 35% light), keep at current opacity for the quietness, or revert. Phase 5c proceeds either way.
|
||||||
|
|
||||||
Targeted scope per Jake's round-4 feedback: the browser-preview state used to render as a red error block in `DictationPage.svelte`. That is an environment limitation, not a failed action. Reclassified as a slim info notice with friendlier copy:
|
Targeted scope per Jake's round-4 feedback: the browser-preview state used to render as a red error block in `DictationPage.svelte`. That is an environment limitation, not a failed action. Reclassified as a slim info notice with friendlier copy:
|
||||||
|
|
||||||
|
|||||||
@@ -217,6 +217,31 @@
|
|||||||
|
|
||||||
--quietware-texture-opacity: var(--grain-opacity);
|
--quietware-texture-opacity: var(--grain-opacity);
|
||||||
--quietware-texture-color: rgba(243, 239, 231, 1);
|
--quietware-texture-color: rgba(243, 239, 231, 1);
|
||||||
|
|
||||||
|
/* ----------------------------------------------------------
|
||||||
|
Phase 4h — counterlines (test).
|
||||||
|
Tactile-only 1-px inner-shadow detail using a softened
|
||||||
|
complementary hue. NOT a second semantic signal — meaning is
|
||||||
|
still carried by signal + icon + label. HC contract zeroes
|
||||||
|
the width.
|
||||||
|
---------------------------------------------------------- */
|
||||||
|
--counterline-width: 1px;
|
||||||
|
|
||||||
|
/* Raw complementary hues per Jake's spec. */
|
||||||
|
--role-info-counterline: var(--color-accent);
|
||||||
|
--role-danger-counterline: #6EA8FF;
|
||||||
|
--role-success-counterline: #B891FF;
|
||||||
|
--role-caution-counterline: #3A6BFF;
|
||||||
|
|
||||||
|
/* Tinted per theme. Dark mode uses 32% opacity (~slightly stronger
|
||||||
|
so it reads against the dark surface). Per-usage aliases so
|
||||||
|
components subscribe semantically. */
|
||||||
|
--notice-info-counterline: color-mix(in srgb, var(--role-info-counterline) 32%, transparent);
|
||||||
|
--notice-danger-counterline: color-mix(in srgb, var(--role-danger-counterline) 32%, transparent);
|
||||||
|
--notice-success-counterline: color-mix(in srgb, var(--role-success-counterline) 32%, transparent);
|
||||||
|
--notice-caution-counterline: color-mix(in srgb, var(--role-caution-counterline) 32%, transparent);
|
||||||
|
|
||||||
|
--button-danger-counterline: var(--notice-danger-counterline);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ============================================================
|
/* ============================================================
|
||||||
@@ -299,6 +324,15 @@
|
|||||||
--grain-opacity: 0.07;
|
--grain-opacity: 0.07;
|
||||||
--quietware-texture-opacity: var(--grain-opacity);
|
--quietware-texture-opacity: var(--grain-opacity);
|
||||||
--quietware-texture-color: rgba(29, 27, 24, 1);
|
--quietware-texture-color: rgba(29, 27, 24, 1);
|
||||||
|
|
||||||
|
/* Phase 4h light-mode counterlines. Lower opacity (22%) so the
|
||||||
|
detail stays whisper-quiet against the cream surface. */
|
||||||
|
--notice-info-counterline: color-mix(in srgb, var(--role-info-counterline) 22%, transparent);
|
||||||
|
--notice-danger-counterline: color-mix(in srgb, var(--role-danger-counterline) 22%, transparent);
|
||||||
|
--notice-success-counterline: color-mix(in srgb, var(--role-success-counterline) 22%, transparent);
|
||||||
|
--notice-caution-counterline: color-mix(in srgb, var(--role-caution-counterline) 22%, transparent);
|
||||||
|
|
||||||
|
--button-danger-counterline: var(--notice-danger-counterline);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ============================================================
|
/* ============================================================
|
||||||
@@ -383,6 +417,15 @@
|
|||||||
--panel-radius: 8px;
|
--panel-radius: 8px;
|
||||||
--quietware-texture-opacity: 0;
|
--quietware-texture-opacity: 0;
|
||||||
--quietware-texture-color: rgba(0, 0, 0, 0);
|
--quietware-texture-color: rgba(0, 0, 0, 0);
|
||||||
|
|
||||||
|
/* HC contract: counterlines disabled (the 2-px HC border IS the
|
||||||
|
tactile detail in this mode). */
|
||||||
|
--counterline-width: 0;
|
||||||
|
--notice-info-counterline: transparent;
|
||||||
|
--notice-danger-counterline: transparent;
|
||||||
|
--notice-success-counterline: transparent;
|
||||||
|
--notice-caution-counterline: transparent;
|
||||||
|
--button-danger-counterline: transparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Dark-base high-contrast — black background, white borders. Used
|
/* Dark-base high-contrast — black background, white borders. Used
|
||||||
|
|||||||
@@ -56,15 +56,23 @@
|
|||||||
// --notice-{tone}-border outer border colour
|
// --notice-{tone}-border outer border colour
|
||||||
// --notice-{tone}-bg hand-tuned pale tint surface
|
// --notice-{tone}-bg hand-tuned pale tint surface
|
||||||
//
|
//
|
||||||
|
// v0.3 Phase 4h — counterlines. A subtle 1-px inset shadow in a
|
||||||
|
// softened complementary hue. Tactile-only detail; not a second
|
||||||
|
// semantic signal. HC contract zeroes --counterline-width.
|
||||||
|
//
|
||||||
|
// --notice-{tone}-counterline softened-complement tint
|
||||||
|
// --counterline-width 1px in quietware, 0 in HC
|
||||||
|
//
|
||||||
// v0.2 fallback values are defined at :root in the same tokens file
|
// v0.2 fallback values are defined at :root in the same tokens file
|
||||||
// via color-mix from the v0.2 --color-{role} tokens, so the Notice
|
// via color-mix from the v0.2 --color-{role} tokens, so the Notice
|
||||||
// renders sensibly with or without quietware active.
|
// renders sensibly with or without quietware active.
|
||||||
const palette: Record<Tone, { bar: string; bg: string; border: string; iconColor: string; icon: typeof Info }> = {
|
const palette: Record<Tone, { bar: string; bg: string; border: string; iconColor: string; shadow: string; icon: typeof Info }> = {
|
||||||
info: {
|
info: {
|
||||||
bar: "border-l-[var(--notice-info-bar)]",
|
bar: "border-l-[var(--notice-info-bar)]",
|
||||||
bg: "bg-[var(--notice-info-bg)]",
|
bg: "bg-[var(--notice-info-bg)]",
|
||||||
border: "border-[var(--notice-info-border)]",
|
border: "border-[var(--notice-info-border)]",
|
||||||
iconColor: "text-[var(--notice-info-icon)]",
|
iconColor: "text-[var(--notice-info-icon)]",
|
||||||
|
shadow: "shadow-[inset_0_0_0_var(--counterline-width,0)_var(--notice-info-counterline,transparent)]",
|
||||||
icon: Info,
|
icon: Info,
|
||||||
},
|
},
|
||||||
caution: {
|
caution: {
|
||||||
@@ -72,6 +80,7 @@
|
|||||||
bg: "bg-[var(--notice-caution-bg)]",
|
bg: "bg-[var(--notice-caution-bg)]",
|
||||||
border: "border-[var(--notice-caution-border)]",
|
border: "border-[var(--notice-caution-border)]",
|
||||||
iconColor: "text-[var(--notice-caution-icon)]",
|
iconColor: "text-[var(--notice-caution-icon)]",
|
||||||
|
shadow: "shadow-[inset_0_0_0_var(--counterline-width,0)_var(--notice-caution-counterline,transparent)]",
|
||||||
icon: AlertTriangle,
|
icon: AlertTriangle,
|
||||||
},
|
},
|
||||||
danger: {
|
danger: {
|
||||||
@@ -79,6 +88,7 @@
|
|||||||
bg: "bg-[var(--notice-danger-bg)]",
|
bg: "bg-[var(--notice-danger-bg)]",
|
||||||
border: "border-[var(--notice-danger-border)]",
|
border: "border-[var(--notice-danger-border)]",
|
||||||
iconColor: "text-[var(--notice-danger-icon)]",
|
iconColor: "text-[var(--notice-danger-icon)]",
|
||||||
|
shadow: "shadow-[inset_0_0_0_var(--counterline-width,0)_var(--notice-danger-counterline,transparent)]",
|
||||||
icon: AlertOctagon,
|
icon: AlertOctagon,
|
||||||
},
|
},
|
||||||
success: {
|
success: {
|
||||||
@@ -86,6 +96,7 @@
|
|||||||
bg: "bg-[var(--notice-success-bg)]",
|
bg: "bg-[var(--notice-success-bg)]",
|
||||||
border: "border-[var(--notice-success-border)]",
|
border: "border-[var(--notice-success-border)]",
|
||||||
iconColor: "text-[var(--notice-success-icon)]",
|
iconColor: "text-[var(--notice-success-icon)]",
|
||||||
|
shadow: "shadow-[inset_0_0_0_var(--counterline-width,0)_var(--notice-success-counterline,transparent)]",
|
||||||
icon: CheckCircle,
|
icon: CheckCircle,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@@ -101,7 +112,7 @@
|
|||||||
role={ariaRole}
|
role={ariaRole}
|
||||||
class="rounded-r-lg rounded-l-sm border border-l-4 text-[13px] flex gap-2.5
|
class="rounded-r-lg rounded-l-sm border border-l-4 text-[13px] flex gap-2.5
|
||||||
{slim ? 'px-3 py-2 items-center' : 'px-4 py-3 items-start'}
|
{slim ? 'px-3 py-2 items-center' : 'px-4 py-3 items-start'}
|
||||||
{tonePal.bar} {tonePal.border} {tonePal.bg} {classes}"
|
{tonePal.bar} {tonePal.border} {tonePal.bg} {tonePal.shadow} {classes}"
|
||||||
>
|
>
|
||||||
<ToneIcon size={slim ? 14 : 16} class="shrink-0 {slim ? '' : 'mt-0.5'} {tonePal.iconColor}" aria-hidden="true" />
|
<ToneIcon size={slim ? 14 : 16} class="shrink-0 {slim ? '' : 'mt-0.5'} {tonePal.iconColor}" aria-hidden="true" />
|
||||||
<div class="flex-1 min-w-0 leading-relaxed text-text">
|
<div class="flex-1 min-w-0 leading-relaxed text-text">
|
||||||
|
|||||||
Reference in New Issue
Block a user