diff --git a/README.md b/README.md index 316acd9..5837f09 100644 --- a/README.md +++ b/README.md @@ -25,11 +25,11 @@ session comes back when you reopen the app. | | | |---|---| | **Agent indicator on every tab** | A tab lights the moment Claude Code or Codex starts working and shows when the answer has landed, a question is waiting, or a turn failed. Pick Minimal, Ring or Full; a finished tab wears the app icon's rainbow, flowing. | -| **Two tab styles** | Classic flat tabs, or Powerline: chevron segments whose arrow edge is the agent's mark. | +| **Two tab styles** | Classic flat tabs, or Powerline: chevron segments whose arrow edge is the agent's mark. `Ctrl+Tab` goes along the strip or back to the tab you used last. | | **Sessions that come back** | Close the app and reopen it: every tab returns in its folder, and agent conversations resume on their own. | | **Local dictation** | Hold `Right Alt` and speak. [whisper.cpp](https://github.com/ggml-org/whisper.cpp) runs on your PC, offline, and never presses Enter. | | **Command help** | Press `F1`, describe a task in plain words and copy the command. Works offline. | -| **Themes that dress the window** | About forty themes, a theme editor, fifteen fonts and acrylic. The whole window follows the theme. | +| **Themes that dress the window** | About forty themes, a theme editor, fifteen fonts and a see-through window. The whole window follows the theme. | | **Made for AI CLIs** | Images paste into Claude Code, dropped files type their path, and `Shift+Enter` is a newline. | | **Asks before it interrupts** | Closing a tab with a running agent asks first. A plain shell just closes. | | **Open terminal here** | Right-click any folder in Explorer to open it in a new tab. | @@ -52,7 +52,7 @@ Works with PowerShell 7, Windows PowerShell, Command Prompt and any installed WS | Key | Action | |---|---| | `Ctrl+T` / `Ctrl+W` | New tab / close tab | -| `Ctrl+Tab` / `Ctrl+Shift+Tab` | Next / previous tab | +| `Ctrl+Tab` / `Ctrl+Shift+Tab` | Next / previous tab, in strip order or most recently used (Settings > Appearance > Tab switching) | | `Ctrl+1` to `Ctrl+9` | Jump to a tab | | `Ctrl+F` | Find in the scrollback (`Ctrl+Shift+F` too; in vim or less, `Ctrl+F` stays page down) | | `Ctrl+,` | Settings | diff --git a/core/README.md b/core/README.md index ecc5931..1fef098 100644 --- a/core/README.md +++ b/core/README.md @@ -137,6 +137,17 @@ there is no Opacity row and no `termOpacity`/`setTermOpacity`: where `acrylic.kind` is 'window' the theme Background's alpha is the window's see-through (`termGroundAlpha`, `withGroundAlpha`, `legacyTermOpacity` for a host's one-time migration); `TERMINAL_OPTIONS` is the same list in every host. +Since 0.31.0 (#156) the switch alone makes such a window see-through: an +opaque ground in force under it paints Prism's default levels +(`seeThroughAlpha`, 0xb9 dark / 0xd1 light, `lib/seeThrough.ts`) through +`paintsAlpha`, the one rule `termGroundAlpha` and Save changes' dirty check +share. The switch is read as stored (`termAcrylic`): the rule that held High +Contrast solid went with the theme (owner, 2026-10-11). The +row is named by `acrylicLabel()` ("See-through window" there, the list's label +in Prism) and drawn right under the wall, before `afterTheme`. +Since 0.31.0 (#157) the wall orders the presets after its leading cards with +`orderTermThemes` (`lib/themeOrder.ts`): neutral grounds first, then coloured, +each black to white by OKLab L; neutral is chroma below `NEUTRAL_CHROMA`. Spec: `docs/superpowers/specs/2026-10-03-colour-picker-alpha-design.md`. diff --git a/core/package.json b/core/package.json index 70269f6..4b0c7b4 100644 --- a/core/package.json +++ b/core/package.json @@ -1,6 +1,6 @@ { "name": "prism-term-core", - "version": "0.30.0", + "version": "0.31.0", "description": "What Prism Terminal and Prism share: the terminal (pty, shells, agent detection and indicator, themes, links, the panel, dictation) and the update chip with its window. TypeScript source, compiled by the host.", "license": "MIT", "private": true, diff --git a/core/renderer/components/ThemeSwitchAsk.tsx b/core/renderer/components/ThemeSwitchAsk.tsx index ed04b35..91db59c 100644 --- a/core/renderer/components/ThemeSwitchAsk.tsx +++ b/core/renderer/components/ThemeSwitchAsk.tsx @@ -1,5 +1,6 @@ import { useEffect, useRef, type JSX } from 'react' import { ROW_BUTTON } from '../settings/fields' +import { acrylicWord } from '../settings/sections/opts' /** * UNSAVED CHANGES ASK BEFORE A THEME SWITCH (owner, 2026-09-23: "if you have @@ -64,7 +65,7 @@ export default function ThemeSwitchAsk({ Save your changes first?

- Switching theme puts the agent colours and acrylic back to the new theme's own. + Switching theme puts the agent colours and {acrylicWord()} back to the new theme's own. Your changes are not saved yet.

diff --git a/core/renderer/host.test.ts b/core/renderer/host.test.ts index acfd279..f60a097 100644 --- a/core/renderer/host.test.ts +++ b/core/renderer/host.test.ts @@ -1,6 +1,6 @@ import { afterEach, beforeEach, describe, expect, it } from 'vitest' import { configureTermCore, resetTermCore, termHost, type TermApi, type TermHostConfig } from './host' -import { agentColorChoice, agentIndicator, saveCustomTermTheme, setTermThemeId, termAcrylic, termExtraDefaults, termGroundAlpha, termThemeId, withGroundAlpha } from './lib/termLook' +import { agentColorChoice, agentIndicator, paintsAlpha, saveCustomTermTheme, setTermAcrylic, setTermThemeId, termAcrylic, termExtraDefaults, termGroundAlpha, termThemeId, withGroundAlpha } from './lib/termLook' import { CH } from '../shared/channels' // The seam is what lets ONE terminal serve two apps. These tests are the two @@ -117,3 +117,62 @@ describe('the ground alpha a saved setup carries', () => { expect(withGroundAlpha(palette)).toEqual(palette) }) }) + +// #156: the switch alone makes the window see-through where the terminal owns +// the window acrylic, as Prism's "See-through window" does. An opaque ground +// in force paints Prism's default, measured light or dark; a ground that +// carries its own alpha keeps it. +describe('the see-through window (#156)', () => { + afterEach(() => resetTermCore()) + beforeEach(() => localStorage.clear()) + + it('switch on over a preset: the default, by the ground light or dark', () => { + configureTermCore(PRISM_TERMINAL) + setTermThemeId('dracula') + expect(termGroundAlpha()).toBe(1) + setTermAcrylic(true) + expect(termGroundAlpha()).toBe(0xb9 / 255) + setTermThemeId('paper') + setTermAcrylic(true) + expect(termGroundAlpha()).toBe(0xd1 / 255) + }) + it('an opaque picked Background is measured, not the theme under it', () => { + let picked: string | null = '#ffffff' + configureTermCore({ ...PRISM_TERMINAL, terminalGround: () => picked }) + setTermThemeId('dracula') + setTermAcrylic(true) + expect(termGroundAlpha()).toBe(0xd1 / 255) + // A picked alpha wins over the default: the Alpha slider still tunes it. + picked = '#ffffff99' + expect(termGroundAlpha()).toBe(0x99 / 255) + }) + it('an opaque Custom paints the default; one with an alpha keeps it', () => { + configureTermCore(PRISM_TERMINAL) + saveCustomTermTheme({ bg: '#111111', fg: '#eeeeee', cursor: '#ff0000', ansi: {} }) + setTermThemeId('custom') + setTermAcrylic(true) + expect(termGroundAlpha()).toBe(0xb9 / 255) + saveCustomTermTheme({ bg: '#11111180', fg: '#eeeeee', cursor: '#ff0000', ansi: {} }) + expect(termGroundAlpha()).toBe(0x80 / 255) + }) + it('Save as Custom carries the default, so a saved setup stays see-through', () => { + configureTermCore(PRISM_TERMINAL) + setTermThemeId('dracula') + setTermAcrylic(true) + expect(withGroundAlpha({ bg: '#1e1f29' }).bg).toBe('#1e1f29b9') + }) + it('in Prism, where the style owns the glass, nothing changes', () => { + configureTermCore(PRISM) + setTermThemeId('dracula') + setTermAcrylic(true) + expect(termGroundAlpha()).toBe(1) + }) + it('paintsAlpha: the one rule the window and the dirty check share', () => { + expect(paintsAlpha(1, '#000000', false)).toBe(1) + expect(paintsAlpha(1, '#000000', true)).toBe(0xb9 / 255) + expect(paintsAlpha(1, '#ffffff', true)).toBe(0xd1 / 255) + expect(paintsAlpha(0x80 / 255, '#ffffff', true)).toBe(0x80 / 255) + // The 30% floor, on or off. + expect(paintsAlpha(0x05 / 255, '#000000', true)).toBe(0x4d / 255) + }) +}) diff --git a/core/renderer/lib/__snapshots__/themeOrder.test.ts.snap b/core/renderer/lib/__snapshots__/themeOrder.test.ts.snap new file mode 100644 index 0000000..6868b8a --- /dev/null +++ b/core/renderer/lib/__snapshots__/themeOrder.test.ts.snap @@ -0,0 +1,45 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`orderTermThemes (#157) > holds the whole order 1`] = ` +[ + "pitch", + "volt", + "prism", + "campbell", + "pt-default", + "graphite", + "monokai", + "gruvbox-dark", + "mist", + "catppuccin-latte", + "paper", + "phosphor", + "amber", + "garnet", + "plum", + "moss", + "rosewood", + "tokyonight", + "horizon", + "dracula", + "catppuccin-mocha", + "kanagawa", + "ocean", + "umber", + "solarized-dark", + "synthwave", + "marine", + "cobalt", + "nord", + "retro", + "cinder", + "fawn", + "sage", + "lavender", + "peach", + "mint", + "blossom", + "sky", + "butter", +] +`; diff --git a/core/renderer/lib/seeThrough.test.ts b/core/renderer/lib/seeThrough.test.ts new file mode 100644 index 0000000..f6d365f --- /dev/null +++ b/core/renderer/lib/seeThrough.test.ts @@ -0,0 +1,28 @@ +import { describe, expect, it } from 'vitest' +import { SEE_THROUGH_ALPHA, SEE_THROUGH_MAX, seeThroughAlpha } from './seeThrough' + +describe('the default see-through (#156)', () => { + it("is Prism's two levels as they paint: 0xb9 on dark, 0xd1 on light", () => { + expect(Math.round(SEE_THROUGH_ALPHA.dark * 255)).toBe(0xb9) + expect(Math.round(SEE_THROUGH_ALPHA.light * 255)).toBe(0xd1) + expect(seeThroughAlpha('#0b0b0f')).toBe(SEE_THROUGH_ALPHA.dark) + expect(seeThroughAlpha('#ffffff')).toBe(SEE_THROUGH_ALPHA.light) + }) + it('light is measured: relative luminance above 0.4', () => { + // #aaaaaa is 0.402, #a9a9a9 is 0.397: either side of the edge. + expect(seeThroughAlpha('#aaaaaa')).toBe(SEE_THROUGH_ALPHA.light) + expect(seeThroughAlpha('#a9a9a9')).toBe(SEE_THROUGH_ALPHA.dark) + }) + it('a see-through colour reads by its own opaque colour, not its composite', () => { + expect(seeThroughAlpha('#ffffff20')).toBe(SEE_THROUGH_ALPHA.light) + expect(seeThroughAlpha('#00000020')).toBe(SEE_THROUGH_ALPHA.dark) + }) + it('an unparseable ground reads as dark', () => { + expect(seeThroughAlpha('soup')).toBe(SEE_THROUGH_ALPHA.dark) + }) + it("the cap sits below opaque and above both defaults, so Alpha and the switch agree", () => { + expect(Math.round(SEE_THROUGH_MAX * 255)).toBe(0xf2) + expect(SEE_THROUGH_MAX).toBeGreaterThan(SEE_THROUGH_ALPHA.light) + expect(SEE_THROUGH_MAX).toBeLessThan(1) + }) +}) diff --git a/core/renderer/lib/seeThrough.ts b/core/renderer/lib/seeThrough.ts new file mode 100644 index 0000000..aa36e3f --- /dev/null +++ b/core/renderer/lib/seeThrough.ts @@ -0,0 +1,34 @@ +import { opaque } from './colour' +import { luminance } from './termAnsi' + +/** + * THE SEE-THROUGH WINDOW'S DEFAULT (#156; owner, 2026-10-10: "add support for + * the see through window setting ... its in prism in style settings i want it + * here too"). Where the terminal owns the window acrylic (Prism Terminal), the + * switch alone makes the window see-through, as Prism's does: an OPAQUE ground + * under it paints at Prism's own levels, as they paint. + * + * Prism's `SEE_THROUGH_LEVEL` is 70 on a dark style and 49 on a light one + * (the levels Glacier and Orchid paint). A level paints + * `glass = 0.85 - level / 100 * 0.55`, alpha `1 - (1 - glass * 0.75) ^ 3`: + * level 70 is 0.724, the byte 0xb9; level 49 is 0.820, the byte 0xd1. Stored + * as those bytes so the window and the Alpha field name the same value. + */ +export const SEE_THROUGH_ALPHA = { dark: 0xb9 / 255, light: 0xd1 / 255 } as const + +/** + * The highest Alpha a ground may carry while the switch is on: 95%, the byte + * 0xf2. Opaque is the switch's OFF (Prism's rule: the switch and the alpha + * always agree), and an Alpha of 100 under the switch would read back as the + * default and make the slider jump. + */ +export const SEE_THROUGH_MAX = 0xf2 / 255 + +/** + * The default see-through for a ground: light or dark MEASURED from its own + * opaque colour (relative luminance above 0.4, the test chromeTheme uses for + * `data-mode`), never read off a theme's name. Unparseable reads as dark. + */ +export function seeThroughAlpha(ground: string): number { + return luminance(opaque(ground)) > 0.4 ? SEE_THROUGH_ALPHA.light : SEE_THROUGH_ALPHA.dark +} diff --git a/core/renderer/lib/termLook.ts b/core/renderer/lib/termLook.ts index 487f345..5278677 100644 --- a/core/renderer/lib/termLook.ts +++ b/core/renderer/lib/termLook.ts @@ -9,7 +9,12 @@ import { type AgentIndicator } from '../host' import { liveThemeId } from './termThemeRetired' -import { alphaOf, parseColour, toStored, withAlpha } from './colour' +import { alphaOf, opaque, parseColour, toStored, withAlpha } from './colour' +import { seeThroughAlpha } from './seeThrough' +// A CYCLE, and a safe one: termTheme imports this module too, and neither reads +// the other at module load (only inside functions, at call time), so either may +// be evaluated first. +import { resolveTermTheme } from './termTheme' export type { AgentIndicator } @@ -419,13 +424,44 @@ function stored(c: unknown): string | null { * they write, but a stored or hand-edited `#12121205` must not paint an all * but invisible window. The floor is the byte 30% gives (0x4d), so every * value a picker or the migration writes reads unchanged. + * + * And there, with the see-through switch on, an OPAQUE ground paints + * the default see-through (#156, `paintsAlpha`): a preset is no longer 1. */ export function termGroundAlpha(): number { const a = rawGroundAlpha() - return hostOwnsWindowAcrylic() ? Math.max(GROUND_ALPHA_MIN, a) : a + if (!hostOwnsWindowAcrylic()) return a + // The ground is only looked up when the default can apply: resolving a + // theme on every read of an alpha that needs none would be waste. + const on = termAcrylic() + return paintsAlpha(a, on && isOpaque(a) ? groundInForce() : '#000000', on) } /** The lowest window see-through: Opacity 30's byte, round(0.3 * 255). */ export const GROUND_ALPHA_MIN = 0x4d / 255 + +/** + * THE ONE RULE for what a ground paints where the terminal owns the window + * acrylic (#156), shared by the window (`termGroundAlpha`) and Save changes' + * dirty check (`useTermSetup`), so the two can never disagree about a saved + * setup. With the switch on, an OPAQUE ground paints the default see-through + * (Prism's levels, by the ground light or dark): on means see-through by + * itself, as Prism's switch does, where before #156 a preset stayed solid and + * the switch looked broken. A ground that carries an alpha keeps it, floored + * at 30% as the Opacity slider was. + */ +export function paintsAlpha(raw: number, ground: string, acrylicOn: boolean): number { + if (acrylicOn && isOpaque(raw)) return seeThroughAlpha(ground) + return Math.max(GROUND_ALPHA_MIN, raw) +} +/** Opaque BY THE BYTE: an alpha that stores as ff is opaque. */ +const isOpaque = (a: number): boolean => Math.round(a * 255) >= 255 + +/** The ground in force, opaque, in the order the window paints it: the + * host's picked one, else the theme's own (a Custom's `bg` included). */ +function groundInForce(): string { + return opaque(hostGround() ?? resolveTermTheme(termThemeId()).background) +} + function rawGroundAlpha(): number { const picked = hostGround() if (picked) return alphaOf(picked) @@ -442,10 +478,23 @@ function rawGroundAlpha(): number { * the colour editor opens on, so a see-through window stays see-through * through a save (the Opacity slider was carried in the setup the same way). * Where the host's style owns the glass (Prism), the palette as it is. + * + * It is the alpha the WINDOW paints (`termGroundAlpha`), the default measured + * from the picked Background where one is in force: what the user saw is what + * is saved, and what Save changes' dirty check reads back. Measuring from the + * palette's own ground instead (review of #156) saved a dark Custom under an + * opaque white pick at b9 while the window and the check stayed at d1, so + * Save changes stayed lit after every save. + * + * Without a pick the ground is the PALETTE's own, not the active theme's: + * every preset card has an edit button, and a light preset edited under a + * dark active theme opened, and saved, at the dark level (review of the fix + * above). For the active theme the two are the same ground. */ export function withGroundAlpha(palette: T): T { if (!hostOwnsWindowAcrylic()) return palette - return { ...palette, bg: withAlpha(palette.bg, termGroundAlpha()) } + const ground = opaque(hostGround() ?? palette.bg) + return { ...palette, bg: withAlpha(palette.bg, paintsAlpha(rawGroundAlpha(), ground, termAcrylic())) } } export function saveCustomTermTheme(theme: CustomTermTheme): void { diff --git a/core/renderer/lib/themeOrder.test.ts b/core/renderer/lib/themeOrder.test.ts new file mode 100644 index 0000000..c5cb0b8 --- /dev/null +++ b/core/renderer/lib/themeOrder.test.ts @@ -0,0 +1,59 @@ +import { describe, expect, it } from 'vitest' +import { TERM_PRESETS } from './termTheme' +import { NEUTRAL_CHROMA, oklch, orderTermThemes } from './themeOrder' + +const NEUTRALS = [ + 'pitch', 'volt', 'prism', 'campbell', 'pt-default', + 'graphite', 'monokai', 'gruvbox-dark', 'mist', 'catppuccin-latte', 'paper' +] + +describe('oklch', () => { + it('measures black, white and a grey as achromatic, black to white', () => { + expect(oklch('#000000').L).toBeCloseTo(0, 3) + expect(oklch('#ffffff').L).toBeCloseTo(1, 3) + expect(oklch('#808080').C).toBeLessThan(1e-4) + expect(oklch('#ff0000').C).toBeGreaterThan(0.2) + }) +}) + +describe('orderTermThemes (#157)', () => { + const ordered = orderTermThemes(TERM_PRESETS) + const neutral = (bg: string): boolean => oklch(bg).C < NEUTRAL_CHROMA + + it('is a permutation of the input and leaves the input alone', () => { + expect(ordered).toHaveLength(TERM_PRESETS.length) + expect(new Set(ordered)).toEqual(new Set(TERM_PRESETS)) + expect(orderTermThemes(TERM_PRESETS).map((p) => p.id)).toEqual(ordered.map((p) => p.id)) + }) + + it('puts every neutral theme before every coloured one', () => { + const firstColoured = ordered.findIndex((p) => !neutral(p.bg)) + expect(ordered.slice(firstColoured).every((p) => !neutral(p.bg))).toBe(true) + }) + + it('runs black to white inside each group', () => { + for (const group of [ordered.filter((p) => neutral(p.bg)), ordered.filter((p) => !neutral(p.bg))]) { + for (let i = 1; i < group.length; i++) expect(oklch(group[i].bg).L).toBeGreaterThanOrEqual(oklch(group[i - 1].bg).L) + } + }) + + it('measures the eleven neutral grounds', () => { + expect(ordered.filter((p) => neutral(p.bg)).map((p) => p.id).sort()).toEqual([...NEUTRALS].sort()) + }) + + it('has no preset ground on the fence, so a new theme cannot land there unnoticed', () => { + for (const p of TERM_PRESETS) expect(Math.abs(oklch(p.bg).C - NEUTRAL_CHROMA), p.id).toBeGreaterThan(0.001) + }) + + // No two presets share a ground since High Contrast left (owner, 2026-10-11), + // so the tie is a made-up pair: a new preset on an existing ground keeps its place. + it('keeps the list order on a tie', () => { + const a = { id: 'a', bg: '#101010' } + const b = { id: 'b', bg: '#101010' } + expect(orderTermThemes([b, a]).map((p) => p.id)).toEqual(['b', 'a']) + }) + + it('holds the whole order', () => { + expect(ordered.map((p) => p.id)).toMatchSnapshot() + }) +}) diff --git a/core/renderer/lib/themeOrder.ts b/core/renderer/lib/themeOrder.ts new file mode 100644 index 0000000..55f6ae4 --- /dev/null +++ b/core/renderer/lib/themeOrder.ts @@ -0,0 +1,57 @@ +/** + * The order of the terminal theme wall (#157). The owner, 2026-10-10: "ordered + * from black to white ... dark colours should be before all coloured, maybe + * actually coloured themes last, first black to white then coloured". So: + * the neutral themes first, black to white, then the coloured ones, black to + * white. Computed off each ground, never typed, so a new theme files itself. + */ +import { normalizeColor } from './termAnsi' + +/** sRGB channel (0..1) to linear light. */ +function linear(c: number): number { + return c <= 0.04045 ? c / 12.92 : ((c + 0.055) / 1.055) ** 2.4 +} + +/** + * OKLab lightness L (0 black .. 1 white, perceptual: "the black or white + * scale") and chroma C (how coloured) of a colour; Bjorn Ottosson's matrices. + * Perceptual on purpose: WCAG luminance puts a saturated blue far darker than + * it looks, which would file it among the blacks. + */ +export function oklch(colour: string): { L: number; C: number } { + const hex = normalizeColor(colour, '#000000') + const r = linear(parseInt(hex.slice(1, 3), 16) / 255) + const g = linear(parseInt(hex.slice(3, 5), 16) / 255) + const b = linear(parseInt(hex.slice(5, 7), 16) / 255) + const l = Math.cbrt(0.4122214708 * r + 0.5363325363 * g + 0.0514459929 * b) + const m = Math.cbrt(0.2119034982 * r + 0.6806995451 * g + 0.1073969566 * b) + const s = Math.cbrt(0.0883024619 * r + 0.2817188376 * g + 0.6299787005 * b) + const L = 0.2104542553 * l + 0.793617785 * m - 0.0040720468 * s + const A = 1.9779984951 * l - 2.428592205 * m + 0.4505937099 * s + const B = 0.0259040371 * l + 0.7827717662 * m - 0.808675766 * s + return { L, C: Math.hypot(A, B) } +} + +/** + * Below this OKLab chroma a ground reads as neutral. MEASURED (2026-10-10, the + * forty preset grounds sorted by C; High Contrast, one of the greys, left on + * 2026-10-11): 0 (six pure greys), 0.0027 Mist, 0.0055 + * Volt, 0.0058 Catppuccin Latte, 0.0082 Paper, 0.0085 Prism, 0.0109 Monokai, + * then 0.0147 Sage, 0.0149 Cinder and Blossom, 0.0157 Horizon and up to 0.1316 + * Retro. 0.0109 to 0.0147 is the widest gap below 0.02, and this sits in it; + * a unit test keeps every preset at least 0.001 away from it. + */ +export const NEUTRAL_CHROMA = 0.0125 + +/** + * Neutral grounds first, then coloured, each group black to white by OKLab L. + * A copy; ties keep the input order (Array.prototype.sort is stable). + */ +export function orderTermThemes(list: readonly T[]): T[] { + const keyed = list.map((item) => { + const { L, C } = oklch(item.bg) + return { item, L, coloured: C >= NEUTRAL_CHROMA ? 1 : 0 } + }) + keyed.sort((a, b) => a.coloured - b.coloured || a.L - b.L) + return keyed.map((k) => k.item) +} diff --git a/core/renderer/settings/TerminalAppearance.tsx b/core/renderer/settings/TerminalAppearance.tsx index 82f5953..fd676bb 100644 --- a/core/renderer/settings/TerminalAppearance.tsx +++ b/core/renderer/settings/TerminalAppearance.tsx @@ -22,6 +22,7 @@ import { ColourField } from './ColourPicker' import { AgentIndicatorSetting, AttentionSettings } from './TerminalBehaviour' import { ThemeWall } from './theme/ThemeWall' import { useNoAcrylic, useTermSetup } from './theme/useTermSetup' +import { acrylicLabel, saveSetupTitle } from './sections/opts' // THE TERMINAL'S LOOK, as one settings section for both hosts (#15): the theme // wall and its editor, font, size, acrylic, and the two agent indicator @@ -76,6 +77,9 @@ export function TerminalAppearanceSettings({ // The theme Background's alpha is the window's see-through here (#114). const windowAcrylic = hostOwnsWindowAcrylic() const noAcrylic = useNoAcrylic() + // Where the terminal owns the window acrylic, the see-through window (#156); + // in Prism the name this row always had. + const acrylicName = windowAcrylic ? acrylicLabel() : 'Acrylic background' return (
{/* WHAT NO THEME OWNS COMES FIRST (owner, 2026-09-28: font and font size @@ -122,7 +126,7 @@ export function TerminalAppearanceSettings({ } /> @@ -133,7 +137,7 @@ export function TerminalAppearanceSettings({ why instead of offering a switch that would do nothing. */} diff --git a/core/renderer/settings/coreIndex.ts b/core/renderer/settings/coreIndex.ts index 2bdbb2d..5027e41 100644 --- a/core/renderer/settings/coreIndex.ts +++ b/core/renderer/settings/coreIndex.ts @@ -5,7 +5,7 @@ import { MARK_OPTIONS } from './markOptions' import { terminalOptionIds } from './options' import type { SettingsIndexEntry } from './layout/search' import { SETTINGS_SECTIONS, type SettingsSectionId } from './sectionIds' -import { acrylicSub, opt, themeSub } from './sections/opts' +import { acrylicLabel, acrylicSub, opt, themeSub } from './sections/opts' /** * THE CORE'S ROWS FOR FIND A SETTING (2026-10-05): one entry per terminal, @@ -48,7 +48,8 @@ export function coreSettingsIndex({ page: pageOf(section), section: SETTINGS_SECTIONS[section] || '', sectionId: section, - label: o.label, + // The see-through row is named per host (#156), as the page names it. + label: id === 'term-acrylic' ? acrylicLabel() : o.label, sub, icon: o.icon, keywords: o.keywords diff --git a/core/renderer/settings/options.ts b/core/renderer/settings/options.ts index 72eee45..19419a3 100644 --- a/core/renderer/settings/options.ts +++ b/core/renderer/settings/options.ts @@ -51,7 +51,7 @@ export const TERMINAL_OPTIONS: readonly TerminalOption[] = [ { id: 'agent-hooks', label: 'Exact status from Claude Code', type: 'switch', key: 'prism.term.agentHooks', section: 'claude', icon: 'hook', sub: 'Applies to terminals opened after a change.', keywords: 'hooks plugin status anthropic' }, // The theme wall, and under it only what a theme sets (2026-09-28). { id: 'term-theme', label: 'Terminal theme', type: 'theme', key: 'prism.term.theme', section: 'theme', icon: 'brush', sub: 'Colours of the terminal and the window.', keywords: 'colors palette scheme dark light preset custom' }, - { id: 'term-acrylic', label: 'Acrylic terminal background', type: 'switch', key: 'prism.term.acrylic', section: 'theme', icon: 'glass', sub: 'The desktop shows through the window.', keywords: 'transparent glass blur mica see through' }, + { id: 'term-acrylic', label: 'Acrylic terminal background', type: 'switch', key: 'prism.term.acrylic', section: 'theme', icon: 'glass', sub: 'The desktop shows through the window.', keywords: 'acrylic transparent glass blur mica see through' }, // No Opacity row (#114): the theme Background's alpha is the window's // see-through where the terminal owns the window acrylic. { id: 'agent-color', label: 'Agent working colour', type: 'colour', key: 'prism.term.agentColor', section: 'colours', icon: 'working', sub: 'Follows the accent.', keywords: 'color indicator busy' }, diff --git a/core/renderer/settings/sections/MarkColoursSection.tsx b/core/renderer/settings/sections/MarkColoursSection.tsx index 8d762e8..f55e9c5 100644 --- a/core/renderer/settings/sections/MarkColoursSection.tsx +++ b/core/renderer/settings/sections/MarkColoursSection.tsx @@ -13,8 +13,7 @@ import { RESET_LINK, SaveButton } from '../fields' import { SettingRow } from '../layout/SettingRow' import { SettingsSection } from '../layout/SettingsSection' import { useTermSetup } from '../theme/useTermSetup' -import { opt, sectionTitle } from './opts' -import { SAVE_SETUP_TITLE } from './TerminalThemeSection' +import { opt, saveSetupTitle, sectionTitle } from './opts' const OWN = 'Your own colour.' @@ -37,7 +36,7 @@ export function MarkColoursSection(): JSX.Element { } + action={} > {agentCol && ( diff --git a/core/renderer/settings/sections/TerminalThemeSection.tsx b/core/renderer/settings/sections/TerminalThemeSection.tsx index e8d453e..4078894 100644 --- a/core/renderer/settings/sections/TerminalThemeSection.tsx +++ b/core/renderer/settings/sections/TerminalThemeSection.tsx @@ -6,22 +6,21 @@ import { SettingRow } from '../layout/SettingRow' import { SettingsSection } from '../layout/SettingsSection' import { ThemeWall } from '../theme/ThemeWall' import { useNoAcrylic, useTermSetup } from '../theme/useTermSetup' -import { acrylicSub, opt, sectionTitle, themeSub } from './opts' - -/** What the Save changes button says it does, in both places it is drawn. */ -export const SAVE_SETUP_TITLE = 'Saves the theme, agent colours and acrylic as Custom' +import { acrylicLabel, acrylicSub, opt, saveSetupTitle, sectionTitle, themeSub } from './opts' /** * THE THEME, as one section (2026-10-05): the theme row with Save changes, the - * wall of cards, the host's own rows that a theme sets (Prism Terminal: - * Background and Accent), and acrylic. Under the wall only what a theme DOES - * set (2026-09-28); the font and the indicator live in their own sections. + * wall of cards, acrylic, and the host's own rows that a theme sets (Prism + * Terminal: Background and Accent). Under the wall only what a theme DOES set + * (2026-09-28); the font and the indicator live in their own sections. + * Acrylic comes FIRST under the wall (#156), as Prism's "See-through window" + * does: see-through first, then the theme's colours. */ export function TerminalThemeSection({ afterTheme, onThemePicked }: { - /** The host's own rows that a theme sets, right under the wall. */ + /** The host's own rows that a theme sets, under the wall and acrylic. */ afterTheme?: ReactNode /** A card was picked (Custom included), after the pick landed. */ onThemePicked?: () => void @@ -31,27 +30,28 @@ export function TerminalThemeSection({ const noAcrylic = useNoAcrylic() const theme = opt('term-theme') const acrylic = opt('term-acrylic') + const label = acrylicLabel() return ( - + - {afterTheme} {/* The material does not exist before Windows 11, so there the row says why instead of offering a switch that would do nothing. */} - + + {afterTheme} ) } diff --git a/core/renderer/settings/sections/opts.test.ts b/core/renderer/settings/sections/opts.test.ts new file mode 100644 index 0000000..5940eb4 --- /dev/null +++ b/core/renderer/settings/sections/opts.test.ts @@ -0,0 +1,57 @@ +import { afterEach, beforeEach, describe, expect, it } from 'vitest' +import { configureTermCore, resetTermCore, type TermHostConfig } from '../../host' +import { coreSettingsIndex } from '../coreIndex' +import { acrylicLabel, acrylicSub, opt, saveSetupTitle } from './opts' + +// #156: where the terminal owns the window acrylic (Prism Terminal), the +// acrylic row IS the see-through window and is worded as Prism words its own; +// in Prism it stays the terminal's row under the app's see-through. + +const base = { + api: {} as TermHostConfig['api'], + themedAgentColors: () => ({ working: '#5b5bd6', finished: '#22c55e' }), + ownsKey: () => false +} +const WINDOW: TermHostConfig = { + ...base, + defaults: { theme: 'prism', acrylic: false, indicator: 'minimal', agentColor: '', agentDoneColor: '' }, + followsHostStyle: false, + paintsGround: true, + acrylic: { kind: 'window', supported: async () => true } +} +const STYLE: TermHostConfig = { + ...base, + defaults: { theme: 'style', acrylic: true, indicator: 'full', agentColor: '#f97316', agentDoneColor: '#22c55e' }, + followsHostStyle: true, + paintsGround: false, + acrylic: { kind: 'style' } +} + +describe('the acrylic row, per host (#156)', () => { + beforeEach(() => localStorage.clear()) + afterEach(() => resetTermCore()) + + it("Prism Terminal: Prism's own name and words", () => { + configureTermCore(WINDOW) + expect(acrylicLabel()).toBe('See-through window') + expect(acrylicSub()).toBe('The desktop shows behind every surface.') + }) + it('Prism: the terminal row keeps its name and words', () => { + configureTermCore(STYLE) + expect(acrylicLabel()).toBe(opt('term-acrylic').label) + expect(acrylicSub()).toBe('The desktop shows through the terminal.') + }) + it('Find a setting words the row as the page does', () => { + configureTermCore(WINDOW) + const row = coreSettingsIndex({ pageOf: () => 'appearance', nvidia: false }).find((e) => e.id === 'term-acrylic') + expect(row).toMatchObject({ label: 'See-through window', sub: 'The desktop shows behind every surface.' }) + // "see through" still finds it by its keywords in Prism's wording too. + expect(row?.keywords).toContain('see through') + }) + it('Save changes names the setting as the page does, per host', () => { + configureTermCore(WINDOW) + expect(saveSetupTitle()).toBe('Saves the theme, agent colours and see-through window as Custom') + configureTermCore(STYLE) + expect(saveSetupTitle()).toBe('Saves the theme, agent colours and acrylic as Custom') + }) +}) \ No newline at end of file diff --git a/core/renderer/settings/sections/opts.ts b/core/renderer/settings/sections/opts.ts index 98840fa..4b35cdd 100644 --- a/core/renderer/settings/sections/opts.ts +++ b/core/renderer/settings/sections/opts.ts @@ -32,7 +32,26 @@ export const sectionTitle = (id: SettingsSectionId): string => SETTINGS_SECTIONS export const themeSub = (): string => followsHostStyle() ? 'Colours of the terminal text and ground.' : opt('term-theme').sub +/** + * THE SEE-THROUGH WINDOW (#156; owner, 2026-10-10: "its in prism in style + * settings i want it here too"). Where the terminal owns the window acrylic + * (Prism Terminal) this row IS the see-through window, so it wears the name + * and words of Prism's own row. In Prism it stays the terminal's acrylic, a + * row under the app's "See-through window": two rows of one name would be + * wrong there. `options.ts` keeps Prism's label, which Prism's gate reads. + */ +export const acrylicLabel = (): string => + hostOwnsWindowAcrylic() ? 'See-through window' : opt('term-acrylic').label + +/** The setting as the rest of the page names it in a sentence (review of + * #156): Save changes' tooltip and the theme switch question said "acrylic" + * in Prism Terminal, where no row on the page is called that any more. */ +export const acrylicWord = (): string => (hostOwnsWindowAcrylic() ? 'see-through window' : 'acrylic') + +/** What Save changes says it does, in every place it is drawn. */ +export const saveSetupTitle = (): string => `Saves the theme, agent colours and ${acrylicWord()} as Custom` + /** The acrylic row's subtext, by what acrylic means in this host: the * window's own material, or the app style's let through the terminal. */ export const acrylicSub = (): string => - hostOwnsWindowAcrylic() ? opt('term-acrylic').sub : 'The desktop shows through the terminal.' + !hostOwnsWindowAcrylic() ? 'The desktop shows through the terminal.' : 'The desktop shows behind every surface.' diff --git a/core/renderer/settings/theme/ThemeWall.tsx b/core/renderer/settings/theme/ThemeWall.tsx index 3a0507e..28f7408 100644 --- a/core/renderer/settings/theme/ThemeWall.tsx +++ b/core/renderer/settings/theme/ThemeWall.tsx @@ -3,7 +3,6 @@ import { followsHostStyle, hostDefaults, hostOwnsWindowAcrylic } from '../../hos import { applyCustomExtras, customTermTheme, - saveCustomTermTheme, setTermThemeId, termThemeId, useCustomTermTheme, @@ -13,12 +12,13 @@ import { type CustomTermTheme } from '../../lib/termLook' import { resolveCustomTheme, resolveTermTheme, watchTermTheme, TERM_PRESETS } from '../../lib/termTheme' -import { luminance, normalizeColor } from '../../lib/termAnsi' +import { orderTermThemes } from '../../lib/themeOrder' import type { AlphaRange } from '../../lib/colour' +import { SEE_THROUGH_MAX } from '../../lib/seeThrough' import { ColourField } from '../ColourPicker' import ThemeSwitchAsk from '../../components/ThemeSwitchAsk' import { ANSI_KEYS, cardAnsi, paletteOf, pickPreset, presetLook } from './palette' -import { useNoAcrylic, useTermSetup } from './useTermSetup' +import { saveAsCustom, useNoAcrylic, useTermSetup } from './useTermSetup' // THE THEME WALL, once for both layouts of the theme section (2026-10-05): // the cards, Show all, the switch question and the colour editor. Extracted @@ -277,7 +277,7 @@ const TWO_ROWS = 268 /** * The wall itself: Custom, the host's default, Follow style where the host - * has styles, then every preset by brightness; the pencil on the chosen card; + * has styles, then every preset neutral-first, black to white (#157); the pencil on the chosen card; * Show all; the question when a pick would drop unsaved changes; the editor. * `onThemePicked`: a pick landed (Custom included), for a host whose own rows * follow the theme (Prism Terminal forgets its picked background and accent). @@ -286,7 +286,7 @@ export function ThemeWall({ onThemePicked, className = '' }: { onThemePicked?: ( const themeId = useTermThemeId() const acrylicOn = useTermAcrylic() const custom = useCustomTermTheme() - const { dirty, save, extras } = useTermSetup() + const { dirty, save } = useTermSetup() const noAcrylic = useNoAcrylic() const windowAcrylic = hostOwnsWindowAcrylic() // The Custom card draws what the terminal draws (#113 review), not the raw @@ -296,25 +296,19 @@ export function ThemeWall({ onThemePicked, className = '' }: { onThemePicked?: ( // style repaints :root. Only a host WITH styles has one (Prism). const [styleTheme, setStyleTheme] = useState(() => resolveTermTheme(followsHostStyle() ? 'style' : termThemeId())) useEffect(() => (followsHostStyle() ? watchTermTheme(setStyleTheme) : undefined), []) - // Presets ordered by brightness, the themes nearest your own look leading: - // on a light theme the wall runs light to dark, on a dark one dark to light. - // The direction is MEASURED off the theme worn when the page opened, and - // read once: the chrome follows the theme now, so re-sorting on every pick - // would shuffle the wall under the pointer that just clicked a card. - const [lightFirst] = useState( - () => luminance(normalizeColor(resolveTermTheme(termThemeId()).background, '#000000')) > 0.4 - ) // CUSTOM LEADS THE WALL, then THE HOST'S OWN DEFAULT (owner, 2026-09-22: "it // should be first in the list"; then 2026-09-23: "custom should come before // default"). Prism Terminal's default is a preset (PT Default); Prism's is // 'style', which is no preset, so there Custom leads Follow style. const defaultPreset = TERM_PRESETS.find((p) => p.id === hostDefaults().theme) - const sortedPresets = useMemo(() => { - const lum = (bg: string): number => luminance(normalizeColor(bg, '#000000')) - return TERM_PRESETS.filter((p) => p !== defaultPreset).sort((a, b) => - lightFirst ? lum(b.bg) - lum(a.bg) : lum(a.bg) - lum(b.bg) - ) - }, [lightFirst, defaultPreset]) + // Then every other preset in ONE fixed order (#157, owner 2026-10-10): the + // neutral grounds black to white, then the coloured ones black to white, + // measured in lib/themeOrder. Fixed, so a pick never reshuffles the wall + // (the old light-first flip read the worn theme once for that reason). + const sortedPresets = useMemo( + () => orderTermThemes(TERM_PRESETS.filter((p) => p !== defaultPreset)), + [defaultPreset] + ) // The editor popup, seeded from the SELECTED theme. Presets never change - // editing always lands in the Custom slot. const [editing, setEditing] = useState(null) @@ -445,15 +439,25 @@ export function ThemeWall({ onThemePicked, className = '' }: { onThemePicked?: ( {editing && ( { // The Custom slot is the WHOLE setup (code review 2026-09-24, // #8): saved as a bare palette, the agent colours and // acrylic it held were gone for good. And it is a theme pick like // a card's (#29), so the host forgets its own window colours and // the edited background is the one that shows. - saveCustomTermTheme({ ...t, ...extras }) - setTermThemeId('custom') + saveAsCustom(t) setEditing(null) onThemePicked?.() }} diff --git a/core/renderer/settings/theme/useTermSetup.test.ts b/core/renderer/settings/theme/useTermSetup.test.ts new file mode 100644 index 0000000..96bcf08 --- /dev/null +++ b/core/renderer/settings/theme/useTermSetup.test.ts @@ -0,0 +1,72 @@ +import { afterEach, beforeEach, describe, expect, it } from 'vitest' +import { configureTermCore, resetTermCore, type TermHostConfig } from '../../host' +import { + customTermTheme, + saveCustomTermTheme, + setTermAcrylic, + setTermThemeId, + withGroundAlpha +} from '../../lib/termLook' +import { paletteOf } from './palette' +import { saveTermSetup, termSetupState } from './useTermSetup' + +// Review of #156: Save changes judges, and saves, what the window paints, so a +// picked opaque Background does not light it by its lightness. + +let picked: string | null = null +const PRISM_TERMINAL: TermHostConfig = { + api: {} as TermHostConfig['api'], + defaults: { theme: 'prism', acrylic: false, indicator: 'minimal', agentColor: '', agentDoneColor: '' }, + followsHostStyle: false, + paintsGround: true, + themedAgentColors: () => ({ working: '#5b5bd6', finished: '#22c55e' }), + acrylic: { kind: 'window', supported: async () => true }, + ownsKey: () => false, + terminalGround: () => picked +} + +describe('the setup Save changes judges (#156 review)', () => { + beforeEach(() => { + localStorage.clear() + picked = null + configureTermCore(PRISM_TERMINAL) + }) + afterEach(() => resetTermCore()) + + it('an opaque picked Background does not light Save changes, light or dark', () => { + saveCustomTermTheme({ bg: '#111111', fg: '#eeeeee', cursor: '#ff0000', ansi: {}, acrylic: true }) + setTermThemeId('custom') + setTermAcrylic(true) + expect(termSetupState().dirty).toBe(false) + picked = '#ffffff' + expect(termSetupState().dirty).toBe(false) + picked = '#000000' + expect(termSetupState().dirty).toBe(false) + // A see-through pick still does. + picked = '#ffffff99' + expect(termSetupState().dirty).toBe(true) + }) + + it('a save under an opaque light pick is clean afterwards', () => { + saveCustomTermTheme({ bg: '#111111', fg: '#eeeeee', cursor: '#ff0000', ansi: {}, acrylic: true }) + setTermThemeId('custom') + setTermAcrylic(true) + picked = '#ffffff' + saveTermSetup() + // The level the window painted (white's d1), not the Custom's own b9: + // saving b9 left Save changes lit after every save. + expect(customTermTheme()?.bg).toBe('#111111d1') + expect(termSetupState().dirty).toBe(false) + }) + + it('editing a light preset that is not the active theme opens at its own level', () => { + // Every preset card has an edit button: with no pick, the window's ground + // is the ACTIVE (dark) theme's, which says nothing about this palette. + setTermThemeId('prism') + setTermAcrylic(true) + expect(withGroundAlpha(paletteOf('catppuccin-latte')).bg.slice(-2)).toBe('d1') + // Under an opaque pick the pick is what paints, for any palette. + picked = '#111111' + expect(withGroundAlpha(paletteOf('catppuccin-latte')).bg.slice(-2)).toBe('b9') + }) +}) diff --git a/core/renderer/settings/theme/useTermSetup.ts b/core/renderer/settings/theme/useTermSetup.ts index 79b6816..613c704 100644 --- a/core/renderer/settings/theme/useTermSetup.ts +++ b/core/renderer/settings/theme/useTermSetup.ts @@ -1,9 +1,16 @@ import { useEffect, useState } from 'react' -import { hostOwnsWindowAcrylic, termHost } from '../../host' +import { hostGround, hostOwnsWindowAcrylic, termHost } from '../../host' import { + agentColorChoice, + agentDoneColorChoice, + agentQuestionColorChoice, + customTermTheme, saveCustomTermTheme, setTermThemeId, + paintsAlpha, + termAcrylic, termExtraDefaults, + termGroundAlpha, termThemeId, useAgentColorChoice, useAgentDoneColorChoice, @@ -14,7 +21,8 @@ import { useTermThemeId, withGroundAlpha } from '../../lib/termLook' -import { alphaOf } from '../../lib/colour' +import { alphaOf, opaque } from '../../lib/colour' +import { resolveTermTheme } from '../../lib/termTheme' import { paletteOf } from './palette' /** @@ -39,20 +47,31 @@ export interface TermSetup { } export function useTermSetup(): TermSetup { - const themeId = useTermThemeId() - const acrylicOn = useTermAcrylic() + // Subscribed for the re-render only; the state is read in one place below. + useTermThemeId() + useTermAcrylic() + useTermGroundAlpha() + useAgentColorChoice() + useAgentDoneColorChoice() + useAgentQuestionColorChoice() + useCustomTermTheme() + const { dirty, extras } = termSetupState() + return { dirty, save: saveTermSetup, extras } +} + +/** Dirty and the extras, from the stores as they are (tested). */ +export function termSetupState(): Pick { + const themeId = termThemeId() + const acrylicOn = termAcrylic() // The window's see-through (#114): the alpha of the ground in force, the // picked Background's first. A byte, so the comparison below is exact. - const groundByte = Math.round(useTermGroundAlpha() * 255) + const groundByte = Math.round(termGroundAlpha() * 255) + const custom = customTermTheme() // The CHOICES ('' = follow the theme) are what is saved and compared. - const agentCol = useAgentColorChoice() - const doneCol = useAgentDoneColorChoice() - const questionCol = useAgentQuestionColorChoice() - const custom = useCustomTermTheme() const extras = { - indicatorColor: agentCol, - doneColor: doneCol, - questionColor: questionCol, + indicatorColor: agentColorChoice(), + doneColor: agentDoneColorChoice(), + questionColor: agentQuestionColorChoice(), acrylic: acrylicOn } // Dirty = the SETTINGS deviate from the selected theme's stock: any theme @@ -65,22 +84,43 @@ export function useTermSetup(): TermSetup { indicatorColor: src?.indicatorColor ?? termExtraDefaults().indicatorColor, doneColor: src?.doneColor ?? termExtraDefaults().doneColor, questionColor: src?.questionColor ?? termExtraDefaults().questionColor, - acrylic: src?.acrylic ?? termExtraDefaults().acrylic + acrylic: (src?.acrylic ?? termExtraDefaults().acrylic) } // THE UNSAVED-CHANGES QUESTION SURVIVES THE SLIDER (#114, #60). Opacity was // one of the extras, so a changed one lit Save changes and a theme pick // asked before forgetting it. Its place is taken by the ground's alpha in - // force against the theme's own (a preset is opaque, a Custom has its bg's): - // a see-through picked Background lights Save changes in the same way. - // Only where that alpha is the window's (Prism has no such alpha). - const ownByte = src ? Math.round(alphaOf(src.bg) * 255) : 255 - const dirty = - JSON.stringify(extras) !== JSON.stringify(baseline) || (hostOwnsWindowAcrylic() && groundByte !== ownByte) - const save = (): void => { - saveCustomTermTheme({ ...withGroundAlpha(paletteOf(termThemeId())), ...extras }) - setTermThemeId('custom') + // force against what the theme's own setup paints: a see-through picked + // Background lights Save changes in the same way. Only where that alpha is + // the window's (Prism has no such alpha, and is not asked to resolve one). + // The theme's own is computed by the rule the window paints by (#156, + // `paintsAlpha`): an older Custom saved with acrylic on and an opaque `bg` + // paints the default see-through, so it is not dirty on pick. A preset's own + // setup has the host's default acrylic (off in Prism Terminal). + // Its default level is measured from the ground the WINDOW measures from, + // the picked Background first (review of #156): an opaque pick changes no + // setting, so it must not light Save changes by being lighter or darker + // than the theme's own ground. + const ownByte = (): number => { + const picked = hostGround() + const ground = picked ? opaque(picked) : (src?.bg ?? resolveTermTheme(themeId).background) + return Math.round(paintsAlpha(src ? alphaOf(src.bg) : 1, ground, baseline.acrylic) * 255) } - return { dirty, save, extras } + const dirty = + JSON.stringify(extras) !== JSON.stringify(baseline) || (hostOwnsWindowAcrylic() && groundByte !== ownByte()) + return { dirty, extras } +} + +/** Save the whole setup in force as Custom, and select it. */ +export function saveTermSetup(): void { + saveAsCustom(withGroundAlpha(paletteOf(termThemeId()))) +} + +/** Save a palette with the setup in force as Custom, and select it: Save + * changes, and the colour editor's save. */ +export function saveAsCustom(palette: ReturnType): void { + const { extras } = termSetupState() + saveCustomTermTheme({ ...palette, ...extras }) + setTermThemeId('custom') } /** diff --git a/docs/regression-rules.md b/docs/regression-rules.md index d32b036..ea2bfb4 100644 --- a/docs/regression-rules.md +++ b/docs/regression-rules.md @@ -176,6 +176,19 @@ one-liner in `CLAUDE.md` only if it is among the most important. **Ctrl+W closes a tab, in BOTH apps** (owner, 2026-09-19, reversing the first build's Ctrl+Shift+W, which still works). Known cost, accepted: the shell loses delete-word on that chord; Ctrl+Backspace does the same job. +- **MOST RECENT COMMITS ON CTRL RELEASE** (#158; owner, 2026-10-10: "add a + new tab switching mode called most recent. so you can either switch chronologically or by most + recently used"). Settings > Appearance > Window > Tab switching, `prism.window.tabSwitch`: + `order` (In order, the DEFAULT, `stepTab` exactly as before) or `recent`. In Most recent, + Ctrl+Tab walks a SNAPSHOT of the used list taken at the hold's first press (`lib/tabMru.ts`): + one press flips to the tab used before, more presses while Ctrl is held go further back, + Shift goes the other way. The list is reordered ONLY when the hold ends: Control's keyup + (window, capture), the window's blur, or any other Ctrl chord. Reordering on each press makes + the second Tab flip straight back (a ping-pong) and the oldest tabs unreachable. Any other + activation (a click, Ctrl+1..9, a new tab, a close handing over) is a use at once, and one during + a hold (a click with Ctrl still down, a tab opened or closed) ends the hold (`walkHolds`); closed + tabs leave the list. Not persisted. Listens to Control's keyup only, never `onData` (rule 10). Held by + `tabMru.test.ts`, `tabSwitchPrefs.test.ts` and the `tabSwitch` e2e. - **The window's edge is a faint hairline that follows the theme** (owner, same day; `windowEdge.ts` + Prism's `dwmHelper.ts`). DWM's border is always one physical pixel, so it cannot be thinner; what reads as thickness is contrast, so it is drawn a small step off the theme's own diff --git a/docs/superpowers/plans/2026-10-10-look-and-mru.md b/docs/superpowers/plans/2026-10-10-look-and-mru.md new file mode 100644 index 0000000..2b13769 --- /dev/null +++ b/docs/superpowers/plans/2026-10-10-look-and-mru.md @@ -0,0 +1,134 @@ +# Plan: see-through window, theme order, Most recent tab switching (#156, #157, #158) + +Spec: `docs/superpowers/specs/2026-10-10-look-and-mru-design.md`. Worktree +`.claude/worktrees/look-mru`, branch `feat/look-mru` (stacked on #155). TDD: each pure function's +test first. One commit per task group. No em-dashes. No push, no PR, no merge from this plan's +build agents; e2e only in the Gate task, one run at a time. + +**Amended 2026-10-11:** the owner removed the High Contrast theme ("remove the theme called high +contrast"), so everything below about it (`termAcrylicInForce`, `seeThroughBlocked`, "High +contrast stays solid.", the high-contrast neutral and tie) went with it; the switch is read as +stored (`termAcrylic`). See the spec's decision 6. + +## Task 0: versions + +- `core/package.json` 0.30.0 to 0.31.0; `package.json` 0.36.0 to 0.37.0 (and `package-lock.json`'s + root version fields). + +## Task 1: theme order (#157), core + +1. `core/renderer/lib/themeOrder.test.ts` (red): permutation; neutrals before coloured; L + non-decreasing per group; neutral set = {pitch, high-contrast, volt, prism, campbell, pt-default, + graphite, monokai, gruvbox-dark, mist, catppuccin-latte, paper}; no ground within 0.001 of + `NEUTRAL_CHROMA`; stable ties (pitch before high-contrast); `toMatchSnapshot()` of the id order. +2. `core/renderer/lib/themeOrder.ts`: `oklch(hex)`, `NEUTRAL_CHROMA = 0.0125`, + `orderTermThemes(list: readonly T[]): T[]`. Comment the measurement. +3. `core/renderer/settings/theme/ThemeWall.tsx`: drop `lightFirst` and the luminance sort; + `sortedPresets = orderTermThemes(TERM_PRESETS.filter((p) => p !== defaultPreset))`. Leading + cards unchanged (Custom, host default, Follow style). Update the component's doc comment. + +## Task 2: see-through default, core + +1. `core/renderer/lib/seeThrough.test.ts` (red), then `core/renderer/lib/seeThrough.ts`: + `SEE_THROUGH_ALPHA` (0xb9/255 dark, 0xd1/255 light; comment the Prism levels 70/49 and the + paintedAlpha formula), `SEE_THROUGH_MAX = 0xf2 / 255`, `seeThroughAlpha(ground)` (luminance of + the opaque colour > 0.4 is light; `luminance`/`normalizeColor` from `termAnsi.ts`, `opaque` + from `colour.ts`). +2. `core/renderer/lib/termLook.ts`: + - `termAcrylicInForce()`: `termAcrylic()` and not (`hostOwnsWindowAcrylic()` and + `liveThemeId(termThemeId()) === 'high-contrast'`); `useTermAcrylicInForce()`. + - `termGroundAlpha()`: window host, `termAcrylicInForce()`, raw alpha 1 (>= 255/255 by byte): + `seeThroughAlpha(groundInForce())`; else as today. `groundInForce()` = `hostGround()` ?? + custom `bg` ?? `resolveTermTheme(termThemeId()).background` (call-time import of + `./termTheme`; comment why the cycle is safe). + - Export a pure `paintsAlpha(rawAlpha, ground, acrylicOn)` used by both `termGroundAlpha` and + `useTermSetup`'s baseline, so the dirty check and the window share one rule. +3. Tests in `core/renderer/host.test.ts` (or a new `termLook.seeThrough.test.ts`): the cases in the + spec's Tests list, with a window host and with a style host. +4. `core/renderer/settings/theme/useTermSetup.ts`: `ownByte` through `paintsAlpha` with the saved + setup's own `acrylic` and ground. +5. `core/renderer/settings/theme/ThemeWall.tsx:448`: editor `bgAlpha` = + `{ alphaMin: 0.3, alphaMax: SEE_THROUGH_MAX, alphaDisabled: !acrylicInForce || noAcrylic }`. + +## Task 3: the row, core + +1. `core/renderer/settings/sections/opts.ts`: `acrylicLabel()` ("See-through window" where the + terminal owns the window acrylic, else `opt('term-acrylic').label`); `acrylicSub()` gives + "The desktop shows behind every surface." there, and "High contrast stays solid." when High + Contrast blocks it. Test both host kinds (new `opts.test.ts` or the existing options test). +2. `TerminalThemeSection.tsx`: the switch row BEFORE `{afterTheme}`; label `acrylicLabel()`; + `off`/`disabled` also when High Contrast blocks it; Switch `on={acrylicInForce && !noAcrylic}`. + Keep `id="term-acrylic"`. +3. `TerminalAppearance.tsx` (legacy) label through `acrylicLabel()`; `coreIndex.ts` label through + `acrylicLabel()`. +4. `options.ts` entry unchanged (Prism's gate reads it as text). Keywords may gain nothing: "see + through" is already there. + +## Task 4: PT's window, src + +1. `src/renderer/src/App.tsx` `paintChrome`: `const acrylic = termAcrylicInForce()` (material and + alpha both). +2. `src/renderer/src/components/settings/AppearancePage.tsx`: `themeColours()` shows + `termGroundAlpha()` while the switch is in force and nothing is picked; Background `range` + `{ alphaMin: 0.3, alphaMax: SEE_THROUGH_MAX, alphaDisabled: !acrylic }`; `acrylic` from + `useTermAcrylicInForce()`. +3. `settingsIndex.ts` `ROW_ORDER`: `'term-theme', 'term-acrylic', 'window-background', + 'window-accent'`. +4. `src/renderer/src/lib/chromeTheme.test.ts`: each preset at `seeThroughAlpha(its bg)`, text fills + flattened and 4.5:1. +5. Run `npm test`, `npm run typecheck`, `npm run lint`; update snapshots only where the change is + the intended one (say which in the commit). + +## Task 5: Most recent (#158), src + +1. `src/renderer/src/lib/tabSwitchPrefs.ts` (+ test): key `prism.window.tabSwitch`, + `'order' | 'recent'`, default `'order'`, `useTabSwitch`, `onTabSwitchChange`. +2. `src/renderer/src/lib/tabMru.test.ts` (red), then `tabMru.ts`: `touchMru(mru, id)`, + `syncMru(mru, tabIds, activeId)` (drop closed, add unknown ids after the known ones in strip + order, active to the front when the list was empty), `startWalk(mru)`, `stepWalk(walk, dir)`, + `walkTarget(walk)`. Cases from the spec. +3. `App.tsx`: + - refs `mru` (seeded from the boot state: active, then strip order) and `walk`. + - effect on `[state.tabs, activeId]`: `mru = syncMru(...)`; when no walk, `touchMru(activeId)`. + - Ctrl+Tab branch: In order unchanged. Most recent: `hit()`; start a walk if none (from the + synced list), step by `shiftKey ? -1 : 1`, `setState(pickTab(s, walkTarget))`; a list under 2 + does nothing. + - Any other Ctrl chord handled in `onKey` first commits a running walk. + - `keyup` (capture) on window: `e.key === 'Control'` commits; `blur` on window commits. Commit = + `walk = null; mru = touchMru(mru, activeId)`. Remove both listeners in the cleanup. +4. `appOptions.ts`: `{ id: 'tab-switch', label: 'Tab switching', sub: 'Which tab comes next when you switch.', + section: 'window', page: 'appearance', icon: 'key', keywords: 'ctrl tab mru recent order cycle + switch next previous last used', store: ['prism.window.tabSwitch'] }`, after `tab-style`. +5. `AppearancePage.tsx` Window section: a `SettingRow id="tab-switch"` with + `Segmented` options `[{ id: 'order', name: 'In order' }, { id: 'recent', name: 'Most recent' }]` + after Tab style; live sub per value (spec). +6. `settingsIndex.ts` `ROW_ORDER`: `'tab-width', 'tab-style', 'tab-switch', 'title-bar', ...`. +7. Unit: `appOptions.test.ts`, `settingsCopy.test.ts` (eight plain words), the ROW_ORDER test. + +## Task 6: e2e scenarios (written, NOT run here) + +In `tools/e2e/run.mjs`: +- `PREF_PAGE` (line ~170): `'tab-switch': 'appearance'`. +- New `seeThrough` and `tabSwitch` scenarios (spec). End idle; close through `closeApp`. +- `themeCards`: wall DOM order equals `[pt-default, ...orderTermThemes(rest)]`. The order is + computed in the scenario from the same bg values read off the cards, or hardcoded from the + unit snapshot (prefer reading `data-term-card` ids and comparing to a list exported for the test). +- `settingsLook` `want` (line ~3572): `['tab-width', 'tab-style', 'tab-switch', 'title-bar', + 'window-edges', 'term-theme', 'term-acrylic', 'window-background', 'window-accent']`. +- Check `options`, `opacityAlpha`, `accent`, `pickedGround` for assumptions the default see-through + breaks (an acrylic-on window asserted opaque); fix the assertion to the new rule, never the rule. + +## Task 7: docs + +- `README.md` features and keys rows; `docs/two-apps.md` (theme order, see-through default, + Appearance order); `core/README.md` (acrylic contract, `orderTermThemes`); + `docs/regression-rules.md` new entry "Most recent commits on Ctrl release" with its tests. + +## Task 8: Gate (one agent, alone) + +1. `npm test`, `npm run typecheck`, `npm run lint` green. +2. `npm run e2e -- ` one at a time for: seeThrough, tabSwitch, themeCards, themeSwitch, + settingsLook, settingsSearch, settingsKeys, options, opacityAlpha, accent, pickedGround, + colourPicker, theme, reviewKeys, tabWidth, tabStyle. Then the full `npm run e2e` once. +3. LOOK at `.e2e-shots/settings-appearance-*.png`, `see-through.png`, `theme-wall.png`. +4. Commit fixes with the PR-ready message trailer. diff --git a/docs/superpowers/specs/2026-10-10-look-and-mru-design.md b/docs/superpowers/specs/2026-10-10-look-and-mru-design.md new file mode 100644 index 0000000..addd194 --- /dev/null +++ b/docs/superpowers/specs/2026-10-10-look-and-mru-design.md @@ -0,0 +1,272 @@ +# See-through window, theme order and Most recent tab switching (#156, #157, #158) + +Date: 2026-10-10. Branch `feat/look-mru`, stacked on `feat/154-full-style` (PR #155). +Versions: app `package.json` 0.36.0 to **0.37.0**; `core/package.json` 0.30.0 to **0.31.0** (core +changes, so this ships to Prism too). + +## The owner's words (2026-10-10, verbatim) + +> also add support for the see through winmdow setting in prism terminal if its not here already, +> its in prism in style settings i wnat it here too.also sort all the terminal themes so therye +> ordered form black to white with colroed ones in between depending on where they fall on teh black +> or white scale not sure whta thats called but the tint of their colro determins weather their +> darker or brighter then teh next. but dark colros shoudl be before all colred, amybe acutally +> colroed themes last first black to white then colroed. also add a new tab switching mode called +> most recent. so you can either switch chronologically or by most recently used. createa plan for +> all this then build, ill be gone so youll have to do all these thigns and ill test once im back. + +The owner is away; every decision below is made by the implementer and flagged for the owner's +review in the PR. The owner is visually impaired and works zoomed in: contrast and clarity matter. + +--- + +## 1. See-through window (#156) + +### What Prism has + +Prism, Settings > Appearance, section "This theme" +(`Prism/src/renderer/src/components/settings/AppearancePage.tsx:99-141`, `appOptions.ts:74`): + +- Row `see-through`, label **"See-through window"**, sub **"The desktop shows behind every + surface."**, icon `glass`, a Switch. It sits right under the theme wall, before the theme's colours. +- The switch is the SAME value as Primary's alpha: on means the painted alpha is below 1 + (`paintedAlpha(shown) < 1`). Turning it on over a SOLID theme writes a see-through level of + `SEE_THROUGH_LEVEL = { dark: 70, light: 49 }` (the levels Glacier and Orchid paint); turning it + off over a glassy theme writes 0. Either is an edit of the theme, so it lights Save changes. +- Hidden on the high contrast themes: "their contrast is measured on a solid ground, and glass + would put an unmeasurable desktop under the text." +- What a level paints (`theme.ts:1271-1286`): `glass = 0.85 - level/100 * 0.55`, painted alpha + `1 - (1 - glass * 0.75)^3`. Level 70 (dark) paints **0.724 = byte 0xb9**; level 49 (light) + paints **0.820 = byte 0xd1**. + +### What Prism Terminal has today + +PT already has the switch, under another name and with a gap that makes it look broken: + +- Row `term-acrylic`, label "Acrylic terminal background", sub "The desktop shows through the + window.", `core/renderer/settings/options.ts:54`; drawn by + `core/renderer/settings/sections/TerminalThemeSection.tsx:45-54` in Settings > Appearance > + Theme, AFTER the wall and after PT's own Background colour and Accent colour rows + (`src/renderer/src/components/settings/AppearancePage.tsx:197-208`, `ROW_ORDER` in + `settingsIndex.ts:41`). Store `prism.term.acrylic`, default off (`src/renderer/src/termHost.ts:27`). +- It switches the window's acrylic material (`App.tsx:100-123`, `paintChrome`), and the window + paints at `termGroundAlpha()` (`core/renderer/lib/termLook.ts:423-437`): the picked Background's + alpha, else a Custom's `bg` alpha, else **1 for every preset**. +- **THE GAP**: on any preset with no picked Background, switching it on changes the material but + the ground is painted opaque, so the desktop does NOT show. It shows only after the user also + lowers the Alpha slider of the Background colour picker (the #114 design: "the Background's alpha + is the window's see-through"). That is why it reads as missing. Prism's switch, by contrast, + makes the window see-through by itself. +- Windows 10: the row says "Needs Windows 11." and is off (`useNoAcrylic`). + +### Decisions + +1. **No second switch.** The existing `term-acrylic` row IS the see-through window. Same id, same + store key, same `TERMINAL_OPTIONS` entry (so neither app's parity test and no saved setting + changes). +2. **Name and words like Prism's, in PT only.** In a host whose terminal owns the window acrylic + (`hostOwnsWindowAcrylic()`, i.e. PT) the row reads **"See-through window"** / + **"The desktop shows behind every surface."** In Prism the terminal row keeps "Acrylic terminal + background" and its own sub: there it is a TERMINAL setting under Prism's own app-level + "See-through window", and two rows with one name would be wrong. Done the way the sub already + differs per host (`sections/opts.ts:37` `acrylicSub`): a new `acrylicLabel()` beside it, used by + `TerminalThemeSection`, the legacy `TerminalAppearance.tsx` and `coreIndex.ts` (Find a setting). + `options.ts` keeps Prism's label (Prism's gate reads that file as text). No new `TermHostConfig` + field: it derives from `acrylic.kind`, which is declared. +3. **On means see-through, by itself (Prism's behaviour).** Where the terminal owns the window + acrylic and the switch is on, an OPAQUE ground in force (alpha 1: every preset, a picked + Background with no alpha, an opaque Custom) paints at the **default see-through**: + `0xb9/255` on a dark ground, `0xd1/255` on a light one, Prism's own two levels as they paint. + Light or dark is MEASURED from the ground in force (relative luminance > 0.4, the same test + `chromeTheme.ts:105` uses for `data-mode`), never read off a name. A ground that already carries + an alpha (30% to 95%) keeps it: the Background picker's Alpha slider still tunes how much. + - New pure `core/renderer/lib/seeThrough.ts`: `SEE_THROUGH_ALPHA = { dark: 0xb9 / 255, light: + 0xd1 / 255 }`, `SEE_THROUGH_MAX = 0xf2 / 255`, `seeThroughAlpha(groundHex): number`. + - `termGroundAlpha()` (`termLook.ts:423`): where `hostOwnsWindowAcrylic()` and `termAcrylic()` + and the raw alpha is 1, return `seeThroughAlpha(opaque ground in force)`; otherwise as today + (floored at 30%). The opaque ground in force is `hostGround()`, else the Custom's `bg`, else + the preset's background, read through `resolveTermTheme` (a call-time import; `termTheme.ts` + already imports `termLook` the same way, and neither reads the other at module load). + - So Prism, where `acrylic.kind` is 'style', is untouched. +4. **Opaque is the switch's off.** While the switch is on, the Background colour picker (PT's + `window-background` row) and the theme editor's Background (`ThemeWall.tsx:448`) cap Alpha at + `SEE_THROUGH_MAX` (95%), `alphaMin` stays 0.3: an Alpha of 100 would read back as the default + and the slider would jump. Same rule as Prism: the switch and the alpha always agree. + PT's Background row shows the alpha IN FORCE while nothing is picked (`themeColours()` in + `AppearancePage.tsx:65-76` uses `termGroundAlpha()` under the switch instead of 1). +5. **The row moves up, right under the wall**, before Background colour and Accent colour, as in + Prism (see-through first, then the theme's colours). `TerminalThemeSection` renders the switch + before `afterTheme`. Prism passes no `afterTheme`, so its Terminal page does not change. PT's + `ROW_ORDER` becomes `... 'term-theme', 'term-acrylic', 'window-background', 'window-accent' ...`. +6. **REMOVED (owner, 2026-10-11: "remove the theme called high contrast").** This was "High + Contrast stays solid": in a window-acrylic host the row was drawn off and disabled under + `high-contrast` and the window painted solid whatever was stored (`termAcrylicInForce`, + `seeThroughBlocked`). The theme is gone (its id maps to Pitch), so the rule, its "in force vs + stored" distinction and its tests went with it: the switch is read as stored (`termAcrylic`) + by the window, the Background row, the editor and Save changes. +7. **Save changes** keeps working: the switch is a theme extra already (`termExtraDefaults().acrylic`), + and Save as Custom stores `withGroundAlpha(...)`, which now carries the default alpha, so a saved + Custom stays see-through. `useTermSetup`'s dirty check compares the ground alpha in force with + the alpha the saved setup paints, computed by the SAME rule (an older Custom saved with + `acrylic: true` and an opaque `bg` paints the default, so it is not dirty on pick). The default + level is measured from the ground the window measures from, the picked Background first, so an + opaque pick does not light Save changes by its lightness; `withGroundAlpha` measures from the + palette's own ground, so a save keeps the Custom's own level. +8. **Contrast.** Chrome text fills are already flattened under a see-through ground + (`chromeTheme.ts`, #114). Unit-test every preset at the two default alphas (text 4.5:1 on the + composite, as the existing `under a see-through ground` test does at its alpha). + +**Known, accepted change on update**: anyone who had the switch ON with an opaque ground (it looked +solid) now sees a see-through window. That is the bug being fixed; the owner's Stable copy is one +such profile if he ever turned it on. Said in the PR. + +--- + +## 2. Theme order (#157) + +### Today + +`core/renderer/settings/theme/ThemeWall.tsx:299-317`: Custom first, then the host's default preset +(PT Default in PT; none in Prism, whose default is 'style'), then "Follow style" (Prism only), then +every other preset sorted by the WCAG luminance of its background, DARK TO LIGHT or LIGHT TO DARK +depending on whether the theme worn when the page opened is light (`lightFirst`). No neutral vs +coloured grouping. The wall shows two rows until "Show all". + +### Decision + +**Neutral themes first, black to white; then coloured themes, black to white.** Computed, not typed: + +- New pure `core/renderer/lib/themeOrder.ts`: `oklch(hex) -> { L, C }` (OKLab, Björn Ottosson's + matrices) and `orderTermThemes(presets)`. Lightness is OKLab **L** (perceptual lightness, "the + black or white scale"); a theme is **neutral** when the OKLab chroma **C** of its ground is below + `NEUTRAL_CHROMA = 0.0125`. Each group sorts by L ascending; ties keep `TERM_PRESETS` order (stable + sort); no two presets share a ground since High Contrast was removed (2026-10-11). +- **The threshold is measured** (2026-10-10, the forty grounds): sorted by C, the grounds run 0 + (six pure greys), 0.0027 Mist, 0.0055 Volt, 0.0058 Catppuccin Latte, 0.0082 Paper, 0.0085 Prism, + 0.0109 Monokai, then **0.0147** Sage, 0.0149 Cinder and Blossom, 0.0157 Horizon and up to 0.1316 + Retro. 0.0109 to 0.0147 is the widest gap below 0.02, and 0.0125 sits in it. A unit test holds + that no preset ground is within 0.001 of the threshold, so a new theme cannot land on the fence + unnoticed. +- Neutral (12; 11 since High Contrast was removed, 2026-10-11): Pitch, High Contrast, Volt, Prism, Campbell, PT Default, Graphite, Monokai, Gruvbox + Dark, Mist, Catppuccin Latte, Paper. Coloured (28): the rest, from Phosphor (L 0.147) to Butter + (0.967). Cinder (`#383c44`, a blue slate, C 0.0149) lands with the coloured: it is measurably as + tinted as Blossom, and the rule is measured, not named. +- The fixed direction replaces `lightFirst` (the owner asked for one order). The leading cards stay + as the owner set them (2026-09-22/23): **Custom, then the host's default (PT Default), then Follow + style (Prism)**, then the computed order. In Prism, PT Default is not the default, so it takes its + place among the neutrals. +- **Prism** gets the same order on its Terminal page's wall: the rule is about the terminal themes, + which are the same forty in both apps, so it is right there too. Said in the PR. +- `docs/two-apps.md` (FORTY THEMES paragraph) gets the order rule. + +--- + +## 3. Tab switching: Most recent (#158) + +### Today + +`src/renderer/src/App.tsx:538-540`: Ctrl+Tab / Ctrl+Shift+Tab call `stepTab(s, +-1)` +(`src/renderer/src/lib/tabs.ts:45-51`), strip order, wrapping; the Settings tab is a tab like any +other. `termHost.ts:70` claims Ctrl+Tab from xterm. There is no other next/previous chord +(no Ctrl+PageUp/PageDown). App shell only: nothing in `core/`, Prism unaffected. + +### Decision + +- Setting **"Tab switching"** (`tab-switch`), a Segmented control, **"In order"** (default) / + **"Most recent"**, in Settings > Appearance > Window, right after Tab style (the strip's other + rows). Sub at rest "Which tab comes next when you switch."; live sub "The next tab along the + strip." / "Back to the tab you used last." (as built: settings text names no keys). Icon `key`. Store `prism.window.tabSwitch` + (`'order' | 'recent'`, anything else reads 'order'), in a new `src/renderer/src/lib/tabSwitchPrefs.ts` + shaped like `tabWidthPrefs.ts`. Never touched: In order, so nobody's keys change on update. +- In **Most recent**, Ctrl+Tab and Ctrl+Shift+Tab walk the most-recently-used list, as browsers and + VS Code do: + - The first Ctrl+Tab of a hold goes to the tab used before this one; each further Tab while Ctrl + is held goes one further back; Ctrl+Shift+Tab goes the other way (from the far end on a fresh + hold). Wraps. + - The list is SNAPSHOT at the first press and only reordered when **Ctrl is released** (keyup of + Control, or the window losing focus): then the tab landed on moves to the front. So a single + Ctrl+Tab flips between the last two tabs, and repeated presses walk instead of ping-ponging. + - Any other activation (a click, Ctrl+1..9, Ctrl+T, Ctrl+, , a close handing over) moves the tab + in front to the head of the list at once. Any other Ctrl chord pressed during a walk ends the + walk first (commit), then acts. A click on another tab, or a tab opened or closed, while Ctrl is + still held ends the walk too (`walkHolds`): that activation is a use at once. + - Closed tabs leave the list; new tabs enter it (at the front, as they are activated). At launch + the list is the active tab, then the rest in strip order (not persisted: history across launches + is not a thing the owner asked for). The Settings tab takes part, as in In order. + - Under a close question or the update window the chords still do nothing (rule from #10). +- Pure `src/renderer/src/lib/tabMru.ts`: `touchMru`, `syncMru(mru, tabIds, activeId)`, + `startWalk`, `stepWalk`, `walkTarget`, `walkHolds`. App holds the list and the walk in refs and listens to + keyup (capture) and window blur. In order keeps `stepTab` exactly. +- Regression rule 10 is untouched: this listens to the Control keyup only, never to `onData`. + +--- + +## What changes where + +**core/ (ships to Prism; bump 0.31.0):** +- `lib/seeThrough.ts` (new), `lib/termLook.ts` (`termGroundAlpha` default; `termAcrylicInForce` until 2026-10-11), + `lib/themeOrder.ts` (new). +- `settings/sections/opts.ts` (`acrylicLabel`, `acrylicSub`; its High Contrast wording removed 2026-10-11), + `settings/sections/TerminalThemeSection.tsx` (label, row above `afterTheme`), + `settings/TerminalAppearance.tsx` (label; legacy, Prism-only in practice), `settings/coreIndex.ts` + (label), `settings/theme/ThemeWall.tsx` (order; editor alpha cap and in-force acrylic), + `settings/theme/useTermSetup.ts` (dirty check by the same rule). +- Prism-visible effect: only the terminal theme wall's order. Everything else is gated on + `acrylic.kind === 'window'`, or is a host's own rows. + +**src/ (PT only; app 0.37.0):** `App.tsx` (paintChrome reads `termAcrylic`; MRU), +`lib/tabMru.ts`, `lib/tabSwitchPrefs.ts` (new), `components/settings/AppearancePage.tsx` +(Background alpha in force and cap; Tab switching row), `appOptions.ts` (`tab-switch`), +`settingsIndex.ts` (`ROW_ORDER`). + +## Tests + +Unit (vitest): +- `core/renderer/lib/seeThrough.test.ts`: dark and light bytes, the 0.4 luminance edge, a + see-through hex reads its own opaque colour. +- `core/renderer/lib/termLook` / `host.test.ts`: window host + switch on + preset = default alpha + (dark preset 0xb9, light preset 0xd1); picked Background with alpha keeps it; switch off = 1; + style host (Prism) unchanged. (The High Contrast case went with the theme, 2026-10-11.) +- `core/renderer/lib/themeOrder.test.ts`: permutation of the input; every neutral before every + coloured; L non-decreasing in each group; the measured neutral list exactly; no ground within + 0.001 of the threshold; the full id order as a snapshot; stable on ties. +- `core/renderer/settings/sections/opts` test: label and sub per host kind. +- `src/renderer/src/lib/chromeTheme.test.ts`: every preset at its default see-through alpha, text + 4.5:1 on the composite. +- `src/renderer/src/lib/tabMru.test.ts`: touch, sync (closed leave, new enter), single flip, walk + three back, Shift walks the other way, wrap, a walk over a list of one does nothing. +- `src/renderer/src/lib/tabSwitchPrefs.test.ts`: default, validation, notify. +- `appOptions.test.ts` / `settingsCopy.test.ts` / settingsIndex order test: the new row. + +e2e (`tools/e2e/run.mjs`): +- New **`seeThrough`**: on a dark preset, the switch alone paints `--p-bg` at alpha `b9`; on Paper + at `d1`; the Background picker's Alpha reads 73 / 82 and is capped at 95; a picked alpha of 60 + wins; off is solid; the row's label is + "See-through window" and it sits right under the wall; screenshot `.e2e-shots/see-through.png`. +- New **`tabSwitch`**: default In order still steps the strip; set Most recent; visit A, B, C; + Ctrl+Tab lands on B, again on C (no ping-pong); hold Ctrl, Tab, Tab lands on A, release; then + Ctrl+Tab goes to C; Ctrl+Shift+Tab walks the other way; closing a tab removes it; a new tab enters. +- **`themeCards`**: the wall's DOM order equals `[pt-default, ...orderTermThemes(rest)]` (Custom + absent in a fresh profile); keeps the `theme-wall.png` screenshot. +- **`settingsLook`** (line ~3572 `want`): Appearance rows gain `tab-switch` and `term-acrylic` moves + up; the acrylic contrast check now runs over real glass. +- **`options`**: picks up the new app row from `APP_OPTIONS`; adjust if it hardcodes the theme + section's slot order. + +Gate scenarios: `seeThrough tabSwitch themeCards themeSwitch settingsLook settingsSearch +settingsKeys options opacityAlpha accent pickedGround colourPicker theme reviewKeys tabWidth +tabStyle`, then the full `npm run e2e` once, alone. LOOK at `.e2e-shots/settings-appearance-*.png`, +`see-through.png` and `theme-wall.png`. + +## Docs + +- `README.md`: features row "Themes that dress the window" says see-through window; the keys table + `Ctrl+Tab` row says "next / previous tab, in strip order or most recently used". +- `docs/two-apps.md`: the theme order rule (FORTY THEMES paragraph); the #114 paragraph gets "on + means see-through: an opaque ground under the switch paints Prism's levels"; the Appearance order + line (the see-through row now under the wall). +- `core/README.md`: the acrylic contract paragraph (default see-through, `seeThroughAlpha`, + `termAcrylicInForce`, `acrylicLabel`), and `orderTermThemes`. +- `docs/regression-rules.md`: new entry **"Most recent commits on Ctrl release"** (the walk is a + snapshot; the order updates only when Ctrl is released or the window loses focus; held by + `tabMru.test.ts` and the `tabSwitch` e2e). diff --git a/docs/two-apps.md b/docs/two-apps.md index bc09c5b..e9f4a32 100644 --- a/docs/two-apps.md +++ b/docs/two-apps.md @@ -224,8 +224,9 @@ so an update never silently changes what an existing user sees; the bridge to ma pink, green ... i want a noctua theme, don't call it that but use that nice brown beige colour scheme"; then 2026-09-24: "make more themes so we have 40 themes total like the trailer says. verify all themes look good, no invisible text, make some typical colour schemes like a green - window, blue, and more fun ones ... don't make them ugly"). THE COUNT IS FORTY, the trailer's - number, held by a test. Core `TERM_PRESETS`: the neutrals (PT Default, Prism, Pitch, Cinder, + window, blue, and more fun ones ... don't make them ugly"). THE COUNT WAS FORTY, the trailer's + number, held by a test; thirty-nine since High Contrast was removed (owner, 2026-10-11: "remove + the theme called high contrast"; its id maps to Pitch in `termThemeRetired.ts`). Core `TERM_PRESETS`: the neutrals (PT Default, Prism, Pitch, Cinder, Graphite, Volt, Paper, Mist); a dark and a light per colour (Umber and Fawn, the fan's brown and beige; Rosewood and Blossom; Moss and Sage); the classic looks (Phosphor, Amber, Marine, Retro, Campbell, High Contrast); more colours (Ocean, Garnet, Plum, Lavender, Sky, Peach, @@ -234,6 +235,14 @@ so an update never silently changes what an existing user sees; the bridge to ma Horizon). NO INVISIBLE TEXT is a test (`termTheme.legible.test.ts`): text 4.5:1, cursor and accent 3:1, all sixteen 3:1 against the theme's own ground. It caught Catppuccin Latte's own cursor at 2.3:1, which is its mauve here. Original themes give base colours only. + **THE WALL'S ORDER IS MEASURED** (#157; owner, 2026-10-10: "first black to white then + coloured"): after the leading cards (Custom, the host's default, Follow style in Prism), core + `orderTermThemes` (`lib/themeOrder.ts`) puts the neutral grounds first, then the coloured ones, + each black to white by OKLab L. Neutral is OKLab chroma below `NEUTRAL_CHROMA` 0.0125, measured + in the widest gap of the forty grounds (Monokai 0.0109, Sage 0.0147), so Cinder, a blue slate, + files with the coloured. One fixed order in both apps (it replaced the light-first flip); + `themeOrder.test.ts` snapshots it and keeps every ground 0.001 off the threshold, and the + `themeCards` e2e reads that snapshot against the wall. **VOLT TOOK INK'S PLACE** (#93; owner, 2026-09-28, with a screenshot: "make one of the black themes this colour scheme with black and that yellow greenish colour, kind of cyberpunk"): `#d8ff26` on `#050706`; Ink, the blue-black next to Prism and Tokyo Night, retired to `prism`. @@ -315,8 +324,8 @@ so an update never silently changes what an existing user sees; the bridge to ma transcend" the theme's save, "so changing a theme should not reset the font and font size or if you use a minimal or full agent indicator, or edges. those options should be above the themes"). Since #134 Appearance runs: the Window section (Tab width, Show title bar, Panel edges), then the - Theme section (the theme row with Save changes, the wall, what a theme SETS: Background, Accent, - Acrylic). The font and its size are Terminal's Text section; the indicator and the agent colours + Theme section (the theme row with Save changes, the wall, what a theme SETS: See-through window, + Background, Accent; the see-through row right under the wall since #156, as in Prism). The font and its size are Terminal's Text section; the indicator and the agent colours are on Agents, where Mark colours carries the SAME Save changes (both save the whole setup and light together, `theme/useTermSetup.ts`). A theme switch and Save as Custom leave the font and its size alone (`termExtraDefaults`, `resetTermExtras`, @@ -368,7 +377,20 @@ so an update never silently changes what an existing user sees; the bridge to ma paint and maps a saved Opacity N to byte round(N / 100 * 255), which is exactly what N painted (snapshot `chromeTheme.opacity.test.ts`): the saved `Custom.opacity` folds into `Custom.bg`, the live value onto the picked Background. The ground alpha takes Opacity's place in Save changes' - dirty check, so a theme pick still asks first (#60). The Accent's alpha is for FILLS; + dirty check, so a theme pick still asks first (#60). + **ON MEANS SEE-THROUGH, BY ITSELF** (#156; owner, 2026-10-10, of Prism's "See-through window": + "i want it here too"). Before it the switch changed the material and left every preset's ground + opaque, so it looked broken. Now where `acrylic.kind` is 'window' an OPAQUE ground under the + switch paints Prism's own levels as they paint (level 70 dark = byte 0xb9, level 49 light = + 0xd1, light measured as luminance > 0.4; `lib/seeThrough.ts`, and `paintsAlpha` in `termLook.ts`, + shared by the window and Save changes' dirty check). A ground with an alpha keeps it; under the + switch the Alpha stops at 95% (`SEE_THROUGH_MAX`: opaque is the switch's off). #156 first held + High Contrast solid under the switch; that rule was removed with the theme (owner, 2026-10-11), + so the stored switch is the one in force everywhere. + In this app the row reads "See-through window" / "The desktop shows behind every surface." + (`acrylicLabel`, `acrylicSub`); Prism keeps "Acrylic terminal background", a terminal row under + its own app-level See-through window, and nothing there changes. The `seeThrough` e2e holds it. + The Accent's alpha is for FILLS; `--p-accent-solid` is the line (rules, spinner, progress, rings, an unpicked working colour), `--p-on-accent` is chosen 4.5:1 on the composite (`selectionFor`), and under a see-through ground the text fills are flattened over `--p-bg-solid`. The `opacityAlpha` and `accent` e2e diff --git a/package-lock.json b/package-lock.json index 980737a..3c0521f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "prism-terminal", - "version": "0.36.0", + "version": "0.37.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "prism-terminal", - "version": "0.36.0", + "version": "0.37.0", "license": "MIT", "dependencies": { "@xterm/addon-fit": "^0.11.0", diff --git a/package.json b/package.json index 7b7f4e3..c47d0d9 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "prism-terminal", "productName": "Prism Terminal", - "version": "0.36.0", + "version": "0.37.0", "description": "A tabbed Windows terminal for AI CLIs.", "main": "./out/main/index.js", "author": "Max", diff --git a/src/renderer/src/App.tsx b/src/renderer/src/App.tsx index 0809ba5..fbee6b7 100644 --- a/src/renderer/src/App.tsx +++ b/src/renderer/src/App.tsx @@ -13,6 +13,8 @@ import TermFind from '@core/renderer/components/TermFind' import { TabStrip } from './components/TabStrip' import TitleBar, { TitleButtons } from './components/TitleBar' import { useTitleBarMode } from './lib/titleBarPrefs' +import { tabSwitch } from './lib/tabSwitchPrefs' +import { startWalk, stepWalk, syncMru, touchMru, walkHolds, walkTarget, type Mru, type Walk } from './lib/tabMru' import EmptyState from './components/EmptyState' import type { SettingsPage } from './components/settings/Settings' import { Dialog } from './components/Dialog' @@ -109,6 +111,7 @@ function paintChrome(): void { // Opacity slider): the picked Background's, else the theme's own (a Custom // may carry one), the same order the core reads. Passed as the byte's // fraction, unrounded, so the field and the window name the same alpha. + // An opaque ground under the switch paints the default see-through (#156). const tokens = chromeTokens( background ? { ...theme, background } : theme, acrylic ? termGroundAlpha() : 1, @@ -205,6 +208,49 @@ export default function App(): JSX.Element { // The latest of everything, for listeners registered once. const live = useRef({ state, workingIds, agentIds, blocked: false, front: '' }) + // MOST RECENT (#158): the tabs by last use, and the walk of a Ctrl hold. + // Refs, not state: nothing is drawn from them, and the key listener is + // registered once. Not persisted: at launch the list is the tab in front, + // then the strip. + const mru = useRef(syncMru([], boot.state.tabs.map((t) => t.id), boot.state.activeId)) + const walk = useRef(null) + /** The hold ended (Ctrl released, the window left, another chord): only + * now does the tab landed on move to the front, so repeated presses walk + * instead of flipping back and forth. */ + const commitWalk = useCallback((): void => { + if (!walk.current) return + walk.current = null + const id = live.current.state.activeId + if (id) mru.current = touchMru(mru.current, id) + }, []) + useEffect(() => { + mru.current = syncMru( + mru.current, + tabs.map((t) => t.id), + activeId + ) + // The hold ends on anything that is not its own step (walkHolds): a click + // on another tab while Ctrl is still down, or a tab opened or closed under + // it. Then the activation is a use at once, as it is outside a hold (a + // click, Ctrl+1..9, a new tab, a close handing over). + if (walk.current && !walkHolds(walk.current, tabs.map((t) => t.id), activeId)) walk.current = null + if (!walk.current && activeId) mru.current = touchMru(mru.current, activeId) + }, [tabs, activeId]) + useEffect(() => { + // Capture, on the window: the shell's xterm never gets to swallow it. + // Control's own keyup only; rule 10 is untouched, nothing here reads what + // reaches the pty. + const onUp = (e: KeyboardEvent): void => { + if (e.key === 'Control') commitWalk() + } + window.addEventListener('keyup', onUp, true) + window.addEventListener('blur', commitWalk) + return () => { + window.removeEventListener('keyup', onUp, true) + window.removeEventListener('blur', commitWalk) + } + }, [commitWalk]) + useEffect(() => { paintChrome() const offLook = onTermLookChange(paintChrome) @@ -526,6 +572,10 @@ export default function App(): JSX.Element { e.preventDefault() e.stopPropagation() } + // Any other Ctrl chord ends a Most recent walk first (#158), then acts: + // the tab the walk landed on counts as used. Control and Shift are the + // hold itself (Shift walks the other way), and Control repeats while held. + if (e.key !== 'Tab' && e.key !== 'Control' && e.key !== 'Shift') commitWalk() // ONE QUESTION AT A TIME, for the tab chords too (code review // 2026-09-24, #10): under a close question or the update window, Ctrl+Tab // or Ctrl+T moved the keyboard into a shell behind it, and the Enter @@ -537,7 +587,23 @@ export default function App(): JSX.Element { } if (e.key === 'Tab') { hit() - setState((s) => stepTab(s, e.shiftKey ? -1 : 1)) + const dir = e.shiftKey ? -1 : 1 + if (tabSwitch() === 'recent') { + // The walk is a snapshot taken at the hold's first press, of the + // list as it stands with the tab in front first (tabMru). + const { state: st } = live.current + if (!walk.current) { + const ids = st.tabs.map((t) => t.id) + const now = syncMru(mru.current, ids, st.activeId) + walk.current = startWalk(st.activeId ? touchMru(now, st.activeId) : now) + } + if (!walk.current) return + walk.current = stepWalk(walk.current, dir) + const id = walkTarget(walk.current) + setState((s) => pickTab(s, id)) + } else { + setState((s) => stepTab(s, dir)) + } } else if (!e.shiftKey && /^[1-9]$/.test(e.key)) { const t = live.current.state.tabs[Number(e.key) - 1] if (t) { @@ -569,7 +635,7 @@ export default function App(): JSX.Element { } window.addEventListener('keydown', onKey, true) return () => window.removeEventListener('keydown', onKey, true) - }, [newTab, requestClose, toggleHelp]) + }, [newTab, requestClose, toggleHelp, commitWalk]) const openRecent = useCallback( (path: string) => { @@ -694,9 +760,11 @@ export default function App(): JSX.Element { )} {/* The terminal paints its own ground (a second coat of a translucent --p-bg behind it reads darker than the rest of the window); the - pages that are not a terminal paint theirs here. */} + pages that are not a terminal paint theirs here, except Settings: + its frame paints its own, and a coat here too made the page 92% + solid under See-through (owner, 2026-10-11). */} {active?.kind === 'settings' && ( -
+
diff --git a/src/renderer/src/components/TabStrip.tsx b/src/renderer/src/components/TabStrip.tsx index 714cc96..686a092 100644 --- a/src/renderer/src/components/TabStrip.tsx +++ b/src/renderer/src/components/TabStrip.tsx @@ -386,7 +386,10 @@ export function TabStrip({ // answer for themselves made it flicker under the moving pointer. data-tab-strip data-tab-style={prompt ? 'prompt' : 'classic'} - className={`${dragInFlight ? 'no-drag' : 'drag'} p-styled-font relative flex ${inTitleRow ? 'min-w-0 flex-1' : 'h-8 shrink-0 border-b border-[var(--p-divider)]'} items-stretch gap-0 overflow-x-auto bg-[var(--p-tabs)] pr-1 text-[12px] transition-[background-color,border-color] duration-[550ms] [transition-timing-function:cubic-bezier(.16,1,.3,1)] ${ + // In the top row the ROW paints --p-tabs: a second coat here made the + // strip 92% solid under See-through while the buttons beside it were + // 73% (owner, 2026-10-11: "the tab bar" stays opaque). + className={`${dragInFlight ? 'no-drag' : 'drag'} p-styled-font relative flex ${inTitleRow ? 'min-w-0 flex-1' : 'h-8 shrink-0 border-b border-[var(--p-divider)] bg-[var(--p-tabs)]'} items-stretch gap-0 overflow-x-auto pr-1 text-[12px] transition-[background-color,border-color] duration-[550ms] [transition-timing-function:cubic-bezier(.16,1,.3,1)] ${ carry?.live ? 'cursor-grabbing [&_*]:cursor-grabbing' : '' }`} > diff --git a/src/renderer/src/components/settings/AppearancePage.tsx b/src/renderer/src/components/settings/AppearancePage.tsx index fcd15bd..fcad324 100644 --- a/src/renderer/src/components/settings/AppearancePage.tsx +++ b/src/renderer/src/components/settings/AppearancePage.tsx @@ -6,11 +6,21 @@ import { SettingRow } from '@core/renderer/settings/layout/SettingRow' import { SettingsSection } from '@core/renderer/settings/layout/SettingsSection' import { TerminalThemeSection } from '@core/renderer/settings/sections/TerminalThemeSection' import { alphaOf, withAlpha, type AlphaRange } from '@core/renderer/lib/colour' -import { customTermTheme, onTermLookChange, termThemeId, useTermAcrylic } from '@core/renderer/lib/termLook' +import { + customTermTheme, + onTermLookChange, + termAcrylic, + termGroundAlpha, + termThemeId, + useTermAcrylic, + useTermGroundAlpha +} from '@core/renderer/lib/termLook' +import { SEE_THROUGH_MAX } from '@core/renderer/lib/seeThrough' import { presetAccent, resolveTermTheme } from '@core/renderer/lib/termTheme' import { setWindowEdges, useWindowEdges } from '../../lib/edgesPrefs' import { setTabWidth, useTabWidth, type TabWidth } from '../../lib/tabWidthPrefs' import { setTabStyle, useTabStyle, type TabStyle } from '../../lib/tabStylePrefs' +import { setTabSwitch, useTabSwitch, type TabSwitch } from '../../lib/tabSwitchPrefs' import { setTitleBarMode, useTitleBarMode } from '../../lib/titleBarPrefs' import { setWindowAccent, useWindowAccent } from '../../lib/accentPrefs' import { onWindowBackgroundChange, setWindowBackground, useWindowBackground, windowBackground } from '../../lib/backgroundPrefs' @@ -57,6 +67,12 @@ const TAB_STYLE_OPTIONS: Array<{ id: TabStyle; name: string }> = [ { id: 'prompt', name: 'Powerline' } ] +// In order first: it is the default, Ctrl+Tab as it always was (#158). +const TAB_SWITCH_OPTIONS: Array<{ id: TabSwitch; name: string }> = [ + { id: 'order', name: 'In order' }, + { id: 'recent', name: 'Most recent' } +] + /** What the THEME in force would give the window, which is what a swatch * shows while nothing is chosen: computed the way the window computes it * (chromeTokens), not read back off the page, so it cannot lag a repaint. @@ -70,9 +86,12 @@ const themeColours = (): string => { const themeBg = chromeTokens(theme, 1, presetAccent(id)).vars['--p-bg-solid'] // The theme's ground AS THE WINDOW PAINTS IT (#114): its solid colour at the // theme's own alpha (a Custom may carry one), so the row shows the - // see-through that is in force while nothing is picked. + // see-through that is in force while nothing is picked. Under the switch + // that is what the window paints, an opaque theme's default included (#156), + // so the Alpha reads 73 on a dark preset rather than 100. const own = id === 'custom' ? customTermTheme() : null - return `${vars['--p-accent']}|${withAlpha(themeBg, own ? alphaOf(own.bg) : 1)}` + const alpha = termAcrylic() ? termGroundAlpha() : own ? alphaOf(own.bg) : 1 + return `${vars['--p-accent']}|${withAlpha(themeBg, alpha)}` } const onColoursChange = (cb: () => void): (() => void) => { const offs = [onTermLookChange(cb), onWindowBackgroundChange(cb)] @@ -92,6 +111,7 @@ function WindowColour({ id, sub, chosen, + shown = chosen, fromTheme, onPick, range @@ -99,6 +119,9 @@ function WindowColour({ id: 'window-background' | 'window-accent' sub: string chosen: string | null + /** What the field shows of the choice, where it paints otherwise than it + * is stored (an opaque Background under the see-through switch, #156). */ + shown?: string | null fromTheme: string onPick: (hex: string | null) => void /** The alpha this colour may carry (#114). */ @@ -114,7 +137,7 @@ function WindowColour({ )} {/* Escape in the picker puts back what was chosen when it opened, a row that followed the theme included (#112). */} - onPick(chosen)} {...range} /> + onPick(chosen)} {...range} /> ) } @@ -124,6 +147,7 @@ function WindowColours(): JSX.Element { const background = useWindowBackground() const [themeAccent, themeBg] = useSyncExternalStore(onColoursChange, themeColours).split('|') const acrylicOn = useTermAcrylic() + const groundAlpha = useTermGroundAlpha() // The material is Windows 11's (1809 has none): where main says it cannot // be had, the window never shows the desktop, so the alpha is as inert as // with the switch off, the rule the theme editor's Background follows. @@ -144,14 +168,18 @@ function WindowColours(): JSX.Element { {/* THE BACKGROUND'S ALPHA IS THE WINDOW'S SEE-THROUGH (#114; owner, 2026-10-03: alpha "should be built into the colour pickers ... it should not be a separate opacity setting"). At least 30%, and inert - while acrylic is off, when the desktop does not show through. */} + while acrylic is off, when the desktop does not show through. + OPAQUE IS THE SWITCH'S OFF (#156, Prism's rule): under it an opaque + pick paints the default see-through and the field shows that, and + the Alpha stops at 95%, so the field and the window always agree. */} {/* The accent's alpha is for its FILLS; its lines stay solid. */} + {/* Where Ctrl+Tab goes (#158): the strip, or the tab used last. The + sub says what the choice in force does, so the row answers it + without trying the keys; settings copy names no key (settingsCopy). */} + + + {/* A switch over the same store the segmented control wrote: on is `shown`, the default, the window as it always was (#91). */} diff --git a/src/renderer/src/components/settings/appOptions.test.ts b/src/renderer/src/components/settings/appOptions.test.ts index 84949c8..289f709 100644 --- a/src/renderer/src/components/settings/appOptions.test.ts +++ b/src/renderer/src/components/settings/appOptions.test.ts @@ -34,6 +34,7 @@ describe("this app's own settings rows", () => { [ "tab-width=prism.window.tabWidth", "tab-style=prism.window.tabStyle", + "tab-switch=prism.window.tabSwitch", "title-bar=prism.window.titleBar", "window-edges=prism.window.edges", "window-background=prism.window.background", @@ -87,4 +88,13 @@ describe('Find a setting', () => { const style = settingsIndex(true).find((e) => e.id === 'tab-style') expect(style?.keywords).toContain('chevron') }) + + it('finds Tab switching by what it does, right after Tab style, in the Window section (#158)', () => { + const index = settingsIndex(true) + const ids = index.map((e) => e.id) + expect(ids.indexOf('tab-switch')).toBe(ids.indexOf('tab-style') + 1) + const row = index.find((e) => e.id === 'tab-switch') + expect(`${row?.page}/${row?.section}`).toBe('appearance/Window') + for (const word of ['recent', 'ctrl', 'mru', 'order']) expect(row?.keywords).toContain(word) + }) }) diff --git a/src/renderer/src/components/settings/appOptions.ts b/src/renderer/src/components/settings/appOptions.ts index fbe48e3..b0c063e 100644 --- a/src/renderer/src/components/settings/appOptions.ts +++ b/src/renderer/src/components/settings/appOptions.ts @@ -28,6 +28,7 @@ export interface AppOption { export const APP_OPTIONS: readonly AppOption[] = [ { id: 'tab-width', label: 'Tab width', sub: 'Sized to the name, or all equal.', section: 'window', page: 'appearance', icon: 'tabs', keywords: 'size wide narrow equal fixed dynamic', store: ['prism.window.tabWidth'] }, { id: 'tab-style', label: 'Tab style', sub: 'Flat tabs, or arrows like a prompt.', section: 'window', page: 'appearance', icon: 'prompt', keywords: 'chevron arrow segment shape powerline classic', store: ['prism.window.tabStyle'] }, + { id: 'tab-switch', label: 'Tab switching', sub: 'Which tab comes next when you switch.', section: 'window', page: 'appearance', icon: 'key', keywords: 'ctrl tab mru recent order cycle switch next previous last used', store: ['prism.window.tabSwitch'] }, { id: 'title-bar', label: 'Show title bar', sub: 'When off, tabs share the top row.', section: 'window', page: 'appearance', icon: 'titlebar', keywords: 'caption top frame hide hidden', store: ['prism.window.titleBar'] }, { id: 'window-edges', label: 'Panel edges', sub: 'Lines between panels and around the window.', section: 'window', page: 'appearance', icon: 'edges', keywords: 'border lines hairline outline faint solid', store: ['prism.window.edges'] }, { id: 'window-background', label: 'Background colour', sub: 'Behind the text in window and terminal.', section: 'theme', page: 'appearance', icon: 'viewer', keywords: 'ground backdrop color transparent alpha opacity', store: ['prism.window.background'] }, diff --git a/src/renderer/src/components/settings/settingsIndex.ts b/src/renderer/src/components/settings/settingsIndex.ts index 21bb013..76748cd 100644 --- a/src/renderer/src/components/settings/settingsIndex.ts +++ b/src/renderer/src/components/settings/settingsIndex.ts @@ -38,7 +38,7 @@ const PAGE_OF: Record = { /** Every row in the order the pages draw them, which is the order Find a * setting lists matches in. A test holds this to the lists. */ export const ROW_ORDER = [ - 'tab-width', 'tab-style', 'title-bar', 'window-edges', 'term-theme', 'window-background', 'window-accent', 'term-acrylic', + 'tab-width', 'tab-style', 'tab-switch', 'title-bar', 'window-edges', 'term-theme', 'term-acrylic', 'window-background', 'window-accent', 'term-shell', 'newtab-mode', 'explorer-verb', 'term-font-family', 'term-font', 'help-enabled', 'agent-indicator', 'agent-done-on', 'agent-rainbow', 'agent-question-on', 'agent-failed-on', 'taskbar-badge', 'agent-hooks', 'agent-color', 'agent-done-color', 'agent-question-color', diff --git a/src/renderer/src/lib/__snapshots__/chromeTheme.opacity.test.ts.snap b/src/renderer/src/lib/__snapshots__/chromeTheme.opacity.test.ts.snap index 0afa6e0..66847c1 100644 --- a/src/renderer/src/lib/__snapshots__/chromeTheme.opacity.test.ts.snap +++ b/src/renderer/src/lib/__snapshots__/chromeTheme.opacity.test.ts.snap @@ -44,7 +44,7 @@ exports[`a saved opacity, as a ground alpha > dracula: every N from 30 to 100 pa "--p-on-accent": "#0b0b0f", "--p-preview": "#3a3b43", "--p-sel-bg": "#bd93f9", - "--p-side": "#1e1f294d", + "--p-side": "#1e1f2900", "--p-side-flat": "#272831", "--p-tab-active": "#1e1f2900", "--p-tabs": "#1e1f294d", @@ -70,7 +70,7 @@ exports[`a saved opacity, as a ground alpha > dracula: every N from 30 to 100 pa "--p-on-accent": "#0b0b0f", "--p-preview": "#3a3b43", "--p-sel-bg": "#bd93f9", - "--p-side": "#1e1f294f", + "--p-side": "#1e1f2900", "--p-side-flat": "#272831", "--p-tab-active": "#1e1f2900", "--p-tabs": "#1e1f294f", @@ -96,7 +96,7 @@ exports[`a saved opacity, as a ground alpha > dracula: every N from 30 to 100 pa "--p-on-accent": "#0b0b0f", "--p-preview": "#3a3b43", "--p-sel-bg": "#bd93f9", - "--p-side": "#1e1f2952", + "--p-side": "#1e1f2900", "--p-side-flat": "#272831", "--p-tab-active": "#1e1f2900", "--p-tabs": "#1e1f2952", @@ -122,7 +122,7 @@ exports[`a saved opacity, as a ground alpha > dracula: every N from 30 to 100 pa "--p-on-accent": "#0b0b0f", "--p-preview": "#3a3b43", "--p-sel-bg": "#bd93f9", - "--p-side": "#1e1f2954", + "--p-side": "#1e1f2900", "--p-side-flat": "#272831", "--p-tab-active": "#1e1f2900", "--p-tabs": "#1e1f2954", @@ -148,7 +148,7 @@ exports[`a saved opacity, as a ground alpha > dracula: every N from 30 to 100 pa "--p-on-accent": "#0b0b0f", "--p-preview": "#3a3b43", "--p-sel-bg": "#bd93f9", - "--p-side": "#1e1f2957", + "--p-side": "#1e1f2900", "--p-side-flat": "#272831", "--p-tab-active": "#1e1f2900", "--p-tabs": "#1e1f2957", @@ -174,7 +174,7 @@ exports[`a saved opacity, as a ground alpha > dracula: every N from 30 to 100 pa "--p-on-accent": "#0b0b0f", "--p-preview": "#3a3b43", "--p-sel-bg": "#bd93f9", - "--p-side": "#1e1f2959", + "--p-side": "#1e1f2900", "--p-side-flat": "#272831", "--p-tab-active": "#1e1f2900", "--p-tabs": "#1e1f2959", @@ -200,7 +200,7 @@ exports[`a saved opacity, as a ground alpha > dracula: every N from 30 to 100 pa "--p-on-accent": "#0b0b0f", "--p-preview": "#3a3b43", "--p-sel-bg": "#bd93f9", - "--p-side": "#1e1f295c", + "--p-side": "#1e1f2900", "--p-side-flat": "#272831", "--p-tab-active": "#1e1f2900", "--p-tabs": "#1e1f295c", @@ -226,7 +226,7 @@ exports[`a saved opacity, as a ground alpha > dracula: every N from 30 to 100 pa "--p-on-accent": "#0b0b0f", "--p-preview": "#3a3b43", "--p-sel-bg": "#bd93f9", - "--p-side": "#1e1f295e", + "--p-side": "#1e1f2900", "--p-side-flat": "#272831", "--p-tab-active": "#1e1f2900", "--p-tabs": "#1e1f295e", @@ -252,7 +252,7 @@ exports[`a saved opacity, as a ground alpha > dracula: every N from 30 to 100 pa "--p-on-accent": "#0b0b0f", "--p-preview": "#3a3b43", "--p-sel-bg": "#bd93f9", - "--p-side": "#1e1f2961", + "--p-side": "#1e1f2900", "--p-side-flat": "#272831", "--p-tab-active": "#1e1f2900", "--p-tabs": "#1e1f2961", @@ -278,7 +278,7 @@ exports[`a saved opacity, as a ground alpha > dracula: every N from 30 to 100 pa "--p-on-accent": "#0b0b0f", "--p-preview": "#3a3b43", "--p-sel-bg": "#bd93f9", - "--p-side": "#1e1f2963", + "--p-side": "#1e1f2900", "--p-side-flat": "#272831", "--p-tab-active": "#1e1f2900", "--p-tabs": "#1e1f2963", @@ -304,7 +304,7 @@ exports[`a saved opacity, as a ground alpha > dracula: every N from 30 to 100 pa "--p-on-accent": "#0b0b0f", "--p-preview": "#3a3b43", "--p-sel-bg": "#bd93f9", - "--p-side": "#1e1f2966", + "--p-side": "#1e1f2900", "--p-side-flat": "#272831", "--p-tab-active": "#1e1f2900", "--p-tabs": "#1e1f2966", @@ -330,7 +330,7 @@ exports[`a saved opacity, as a ground alpha > dracula: every N from 30 to 100 pa "--p-on-accent": "#0b0b0f", "--p-preview": "#3a3b43", "--p-sel-bg": "#bd93f9", - "--p-side": "#1e1f2969", + "--p-side": "#1e1f2900", "--p-side-flat": "#272831", "--p-tab-active": "#1e1f2900", "--p-tabs": "#1e1f2969", @@ -356,7 +356,7 @@ exports[`a saved opacity, as a ground alpha > dracula: every N from 30 to 100 pa "--p-on-accent": "#0b0b0f", "--p-preview": "#3a3b43", "--p-sel-bg": "#bd93f9", - "--p-side": "#1e1f296b", + "--p-side": "#1e1f2900", "--p-side-flat": "#272831", "--p-tab-active": "#1e1f2900", "--p-tabs": "#1e1f296b", @@ -382,7 +382,7 @@ exports[`a saved opacity, as a ground alpha > dracula: every N from 30 to 100 pa "--p-on-accent": "#0b0b0f", "--p-preview": "#3a3b43", "--p-sel-bg": "#bd93f9", - "--p-side": "#1e1f296e", + "--p-side": "#1e1f2900", "--p-side-flat": "#272831", "--p-tab-active": "#1e1f2900", "--p-tabs": "#1e1f296e", @@ -408,7 +408,7 @@ exports[`a saved opacity, as a ground alpha > dracula: every N from 30 to 100 pa "--p-on-accent": "#0b0b0f", "--p-preview": "#3a3b43", "--p-sel-bg": "#bd93f9", - "--p-side": "#1e1f2970", + "--p-side": "#1e1f2900", "--p-side-flat": "#272831", "--p-tab-active": "#1e1f2900", "--p-tabs": "#1e1f2970", @@ -434,7 +434,7 @@ exports[`a saved opacity, as a ground alpha > dracula: every N from 30 to 100 pa "--p-on-accent": "#0b0b0f", "--p-preview": "#3a3b43", "--p-sel-bg": "#bd93f9", - "--p-side": "#1e1f2973", + "--p-side": "#1e1f2900", "--p-side-flat": "#272831", "--p-tab-active": "#1e1f2900", "--p-tabs": "#1e1f2973", @@ -460,7 +460,7 @@ exports[`a saved opacity, as a ground alpha > dracula: every N from 30 to 100 pa "--p-on-accent": "#0b0b0f", "--p-preview": "#3a3b43", "--p-sel-bg": "#bd93f9", - "--p-side": "#1e1f2975", + "--p-side": "#1e1f2900", "--p-side-flat": "#272831", "--p-tab-active": "#1e1f2900", "--p-tabs": "#1e1f2975", @@ -486,7 +486,7 @@ exports[`a saved opacity, as a ground alpha > dracula: every N from 30 to 100 pa "--p-on-accent": "#0b0b0f", "--p-preview": "#3a3b43", "--p-sel-bg": "#bd93f9", - "--p-side": "#1e1f2978", + "--p-side": "#1e1f2900", "--p-side-flat": "#272831", "--p-tab-active": "#1e1f2900", "--p-tabs": "#1e1f2978", @@ -512,7 +512,7 @@ exports[`a saved opacity, as a ground alpha > dracula: every N from 30 to 100 pa "--p-on-accent": "#0b0b0f", "--p-preview": "#3a3b43", "--p-sel-bg": "#bd93f9", - "--p-side": "#1e1f297a", + "--p-side": "#1e1f2900", "--p-side-flat": "#272831", "--p-tab-active": "#1e1f2900", "--p-tabs": "#1e1f297a", @@ -538,7 +538,7 @@ exports[`a saved opacity, as a ground alpha > dracula: every N from 30 to 100 pa "--p-on-accent": "#0b0b0f", "--p-preview": "#3a3b43", "--p-sel-bg": "#bd93f9", - "--p-side": "#1e1f297d", + "--p-side": "#1e1f2900", "--p-side-flat": "#272831", "--p-tab-active": "#1e1f2900", "--p-tabs": "#1e1f297d", @@ -564,7 +564,7 @@ exports[`a saved opacity, as a ground alpha > dracula: every N from 30 to 100 pa "--p-on-accent": "#0b0b0f", "--p-preview": "#3a3b43", "--p-sel-bg": "#bd93f9", - "--p-side": "#1e1f2980", + "--p-side": "#1e1f2900", "--p-side-flat": "#272831", "--p-tab-active": "#1e1f2900", "--p-tabs": "#1e1f2980", @@ -590,7 +590,7 @@ exports[`a saved opacity, as a ground alpha > dracula: every N from 30 to 100 pa "--p-on-accent": "#0b0b0f", "--p-preview": "#3a3b43", "--p-sel-bg": "#bd93f9", - "--p-side": "#1e1f2982", + "--p-side": "#1e1f2900", "--p-side-flat": "#272831", "--p-tab-active": "#1e1f2900", "--p-tabs": "#1e1f2982", @@ -616,7 +616,7 @@ exports[`a saved opacity, as a ground alpha > dracula: every N from 30 to 100 pa "--p-on-accent": "#0b0b0f", "--p-preview": "#3a3b43", "--p-sel-bg": "#bd93f9", - "--p-side": "#1e1f2985", + "--p-side": "#1e1f2900", "--p-side-flat": "#272831", "--p-tab-active": "#1e1f2900", "--p-tabs": "#1e1f2985", @@ -642,7 +642,7 @@ exports[`a saved opacity, as a ground alpha > dracula: every N from 30 to 100 pa "--p-on-accent": "#0b0b0f", "--p-preview": "#3a3b43", "--p-sel-bg": "#bd93f9", - "--p-side": "#1e1f2987", + "--p-side": "#1e1f2900", "--p-side-flat": "#272831", "--p-tab-active": "#1e1f2900", "--p-tabs": "#1e1f2987", @@ -668,7 +668,7 @@ exports[`a saved opacity, as a ground alpha > dracula: every N from 30 to 100 pa "--p-on-accent": "#0b0b0f", "--p-preview": "#3a3b43", "--p-sel-bg": "#bd93f9", - "--p-side": "#1e1f298a", + "--p-side": "#1e1f2900", "--p-side-flat": "#272831", "--p-tab-active": "#1e1f2900", "--p-tabs": "#1e1f298a", @@ -694,7 +694,7 @@ exports[`a saved opacity, as a ground alpha > dracula: every N from 30 to 100 pa "--p-on-accent": "#0b0b0f", "--p-preview": "#3a3b43", "--p-sel-bg": "#bd93f9", - "--p-side": "#1e1f298c", + "--p-side": "#1e1f2900", "--p-side-flat": "#272831", "--p-tab-active": "#1e1f2900", "--p-tabs": "#1e1f298c", @@ -720,7 +720,7 @@ exports[`a saved opacity, as a ground alpha > dracula: every N from 30 to 100 pa "--p-on-accent": "#0b0b0f", "--p-preview": "#3a3b43", "--p-sel-bg": "#bd93f9", - "--p-side": "#1e1f298f", + "--p-side": "#1e1f2900", "--p-side-flat": "#272831", "--p-tab-active": "#1e1f2900", "--p-tabs": "#1e1f298f", @@ -746,7 +746,7 @@ exports[`a saved opacity, as a ground alpha > dracula: every N from 30 to 100 pa "--p-on-accent": "#0b0b0f", "--p-preview": "#3a3b43", "--p-sel-bg": "#bd93f9", - "--p-side": "#1e1f2991", + "--p-side": "#1e1f2900", "--p-side-flat": "#272831", "--p-tab-active": "#1e1f2900", "--p-tabs": "#1e1f2991", @@ -772,7 +772,7 @@ exports[`a saved opacity, as a ground alpha > dracula: every N from 30 to 100 pa "--p-on-accent": "#0b0b0f", "--p-preview": "#3a3b43", "--p-sel-bg": "#bd93f9", - "--p-side": "#1e1f2994", + "--p-side": "#1e1f2900", "--p-side-flat": "#272831", "--p-tab-active": "#1e1f2900", "--p-tabs": "#1e1f2994", @@ -798,7 +798,7 @@ exports[`a saved opacity, as a ground alpha > dracula: every N from 30 to 100 pa "--p-on-accent": "#0b0b0f", "--p-preview": "#3a3b43", "--p-sel-bg": "#bd93f9", - "--p-side": "#1e1f2996", + "--p-side": "#1e1f2900", "--p-side-flat": "#272831", "--p-tab-active": "#1e1f2900", "--p-tabs": "#1e1f2996", @@ -824,7 +824,7 @@ exports[`a saved opacity, as a ground alpha > dracula: every N from 30 to 100 pa "--p-on-accent": "#0b0b0f", "--p-preview": "#3a3b43", "--p-sel-bg": "#bd93f9", - "--p-side": "#1e1f2999", + "--p-side": "#1e1f2900", "--p-side-flat": "#272831", "--p-tab-active": "#1e1f2900", "--p-tabs": "#1e1f2999", @@ -850,7 +850,7 @@ exports[`a saved opacity, as a ground alpha > dracula: every N from 30 to 100 pa "--p-on-accent": "#0b0b0f", "--p-preview": "#3a3b43", "--p-sel-bg": "#bd93f9", - "--p-side": "#1e1f299c", + "--p-side": "#1e1f2900", "--p-side-flat": "#272831", "--p-tab-active": "#1e1f2900", "--p-tabs": "#1e1f299c", @@ -876,7 +876,7 @@ exports[`a saved opacity, as a ground alpha > dracula: every N from 30 to 100 pa "--p-on-accent": "#0b0b0f", "--p-preview": "#3a3b43", "--p-sel-bg": "#bd93f9", - "--p-side": "#1e1f299e", + "--p-side": "#1e1f2900", "--p-side-flat": "#272831", "--p-tab-active": "#1e1f2900", "--p-tabs": "#1e1f299e", @@ -902,7 +902,7 @@ exports[`a saved opacity, as a ground alpha > dracula: every N from 30 to 100 pa "--p-on-accent": "#0b0b0f", "--p-preview": "#3a3b43", "--p-sel-bg": "#bd93f9", - "--p-side": "#1e1f29a1", + "--p-side": "#1e1f2900", "--p-side-flat": "#272831", "--p-tab-active": "#1e1f2900", "--p-tabs": "#1e1f29a1", @@ -928,7 +928,7 @@ exports[`a saved opacity, as a ground alpha > dracula: every N from 30 to 100 pa "--p-on-accent": "#0b0b0f", "--p-preview": "#3a3b43", "--p-sel-bg": "#bd93f9", - "--p-side": "#1e1f29a3", + "--p-side": "#1e1f2900", "--p-side-flat": "#272831", "--p-tab-active": "#1e1f2900", "--p-tabs": "#1e1f29a3", @@ -954,7 +954,7 @@ exports[`a saved opacity, as a ground alpha > dracula: every N from 30 to 100 pa "--p-on-accent": "#0b0b0f", "--p-preview": "#3a3b43", "--p-sel-bg": "#bd93f9", - "--p-side": "#1e1f29a6", + "--p-side": "#1e1f2900", "--p-side-flat": "#272831", "--p-tab-active": "#1e1f2900", "--p-tabs": "#1e1f29a6", @@ -980,7 +980,7 @@ exports[`a saved opacity, as a ground alpha > dracula: every N from 30 to 100 pa "--p-on-accent": "#0b0b0f", "--p-preview": "#3a3b43", "--p-sel-bg": "#bd93f9", - "--p-side": "#1e1f29a8", + "--p-side": "#1e1f2900", "--p-side-flat": "#272831", "--p-tab-active": "#1e1f2900", "--p-tabs": "#1e1f29a8", @@ -1006,7 +1006,7 @@ exports[`a saved opacity, as a ground alpha > dracula: every N from 30 to 100 pa "--p-on-accent": "#0b0b0f", "--p-preview": "#3a3b43", "--p-sel-bg": "#bd93f9", - "--p-side": "#1e1f29ab", + "--p-side": "#1e1f2900", "--p-side-flat": "#272831", "--p-tab-active": "#1e1f2900", "--p-tabs": "#1e1f29ab", @@ -1032,7 +1032,7 @@ exports[`a saved opacity, as a ground alpha > dracula: every N from 30 to 100 pa "--p-on-accent": "#0b0b0f", "--p-preview": "#3a3b43", "--p-sel-bg": "#bd93f9", - "--p-side": "#1e1f29ad", + "--p-side": "#1e1f2900", "--p-side-flat": "#272831", "--p-tab-active": "#1e1f2900", "--p-tabs": "#1e1f29ad", @@ -1058,7 +1058,7 @@ exports[`a saved opacity, as a ground alpha > dracula: every N from 30 to 100 pa "--p-on-accent": "#0b0b0f", "--p-preview": "#3a3b43", "--p-sel-bg": "#bd93f9", - "--p-side": "#1e1f29b0", + "--p-side": "#1e1f2900", "--p-side-flat": "#272831", "--p-tab-active": "#1e1f2900", "--p-tabs": "#1e1f29b0", @@ -1084,7 +1084,7 @@ exports[`a saved opacity, as a ground alpha > dracula: every N from 30 to 100 pa "--p-on-accent": "#0b0b0f", "--p-preview": "#3a3b43", "--p-sel-bg": "#bd93f9", - "--p-side": "#1e1f29b3", + "--p-side": "#1e1f2900", "--p-side-flat": "#272831", "--p-tab-active": "#1e1f2900", "--p-tabs": "#1e1f29b3", @@ -1110,7 +1110,7 @@ exports[`a saved opacity, as a ground alpha > dracula: every N from 30 to 100 pa "--p-on-accent": "#0b0b0f", "--p-preview": "#3a3b43", "--p-sel-bg": "#bd93f9", - "--p-side": "#1e1f29b5", + "--p-side": "#1e1f2900", "--p-side-flat": "#272831", "--p-tab-active": "#1e1f2900", "--p-tabs": "#1e1f29b5", @@ -1136,7 +1136,7 @@ exports[`a saved opacity, as a ground alpha > dracula: every N from 30 to 100 pa "--p-on-accent": "#0b0b0f", "--p-preview": "#3a3b43", "--p-sel-bg": "#bd93f9", - "--p-side": "#1e1f29b8", + "--p-side": "#1e1f2900", "--p-side-flat": "#272831", "--p-tab-active": "#1e1f2900", "--p-tabs": "#1e1f29b8", @@ -1162,7 +1162,7 @@ exports[`a saved opacity, as a ground alpha > dracula: every N from 30 to 100 pa "--p-on-accent": "#0b0b0f", "--p-preview": "#3a3b43", "--p-sel-bg": "#bd93f9", - "--p-side": "#1e1f29ba", + "--p-side": "#1e1f2900", "--p-side-flat": "#272831", "--p-tab-active": "#1e1f2900", "--p-tabs": "#1e1f29ba", @@ -1188,7 +1188,7 @@ exports[`a saved opacity, as a ground alpha > dracula: every N from 30 to 100 pa "--p-on-accent": "#0b0b0f", "--p-preview": "#3a3b43", "--p-sel-bg": "#bd93f9", - "--p-side": "#1e1f29bd", + "--p-side": "#1e1f2900", "--p-side-flat": "#272831", "--p-tab-active": "#1e1f2900", "--p-tabs": "#1e1f29bd", @@ -1214,7 +1214,7 @@ exports[`a saved opacity, as a ground alpha > dracula: every N from 30 to 100 pa "--p-on-accent": "#0b0b0f", "--p-preview": "#3a3b43", "--p-sel-bg": "#bd93f9", - "--p-side": "#1e1f29bf", + "--p-side": "#1e1f2900", "--p-side-flat": "#272831", "--p-tab-active": "#1e1f2900", "--p-tabs": "#1e1f29bf", @@ -1240,7 +1240,7 @@ exports[`a saved opacity, as a ground alpha > dracula: every N from 30 to 100 pa "--p-on-accent": "#0b0b0f", "--p-preview": "#3a3b43", "--p-sel-bg": "#bd93f9", - "--p-side": "#1e1f29c2", + "--p-side": "#1e1f2900", "--p-side-flat": "#272831", "--p-tab-active": "#1e1f2900", "--p-tabs": "#1e1f29c2", @@ -1266,7 +1266,7 @@ exports[`a saved opacity, as a ground alpha > dracula: every N from 30 to 100 pa "--p-on-accent": "#0b0b0f", "--p-preview": "#3a3b43", "--p-sel-bg": "#bd93f9", - "--p-side": "#1e1f29c4", + "--p-side": "#1e1f2900", "--p-side-flat": "#272831", "--p-tab-active": "#1e1f2900", "--p-tabs": "#1e1f29c4", @@ -1292,7 +1292,7 @@ exports[`a saved opacity, as a ground alpha > dracula: every N from 30 to 100 pa "--p-on-accent": "#0b0b0f", "--p-preview": "#3a3b43", "--p-sel-bg": "#bd93f9", - "--p-side": "#1e1f29c7", + "--p-side": "#1e1f2900", "--p-side-flat": "#272831", "--p-tab-active": "#1e1f2900", "--p-tabs": "#1e1f29c7", @@ -1318,7 +1318,7 @@ exports[`a saved opacity, as a ground alpha > dracula: every N from 30 to 100 pa "--p-on-accent": "#0b0b0f", "--p-preview": "#3a3b43", "--p-sel-bg": "#bd93f9", - "--p-side": "#1e1f29c9", + "--p-side": "#1e1f2900", "--p-side-flat": "#272831", "--p-tab-active": "#1e1f2900", "--p-tabs": "#1e1f29c9", @@ -1344,7 +1344,7 @@ exports[`a saved opacity, as a ground alpha > dracula: every N from 30 to 100 pa "--p-on-accent": "#0b0b0f", "--p-preview": "#3a3b43", "--p-sel-bg": "#bd93f9", - "--p-side": "#1e1f29cc", + "--p-side": "#1e1f2900", "--p-side-flat": "#272831", "--p-tab-active": "#1e1f2900", "--p-tabs": "#1e1f29cc", @@ -1370,7 +1370,7 @@ exports[`a saved opacity, as a ground alpha > dracula: every N from 30 to 100 pa "--p-on-accent": "#0b0b0f", "--p-preview": "#3a3b43", "--p-sel-bg": "#bd93f9", - "--p-side": "#1e1f29cf", + "--p-side": "#1e1f2900", "--p-side-flat": "#272831", "--p-tab-active": "#1e1f2900", "--p-tabs": "#1e1f29cf", @@ -1396,7 +1396,7 @@ exports[`a saved opacity, as a ground alpha > dracula: every N from 30 to 100 pa "--p-on-accent": "#0b0b0f", "--p-preview": "#3a3b43", "--p-sel-bg": "#bd93f9", - "--p-side": "#1e1f29d1", + "--p-side": "#1e1f2900", "--p-side-flat": "#272831", "--p-tab-active": "#1e1f2900", "--p-tabs": "#1e1f29d1", @@ -1422,7 +1422,7 @@ exports[`a saved opacity, as a ground alpha > dracula: every N from 30 to 100 pa "--p-on-accent": "#0b0b0f", "--p-preview": "#3a3b43", "--p-sel-bg": "#bd93f9", - "--p-side": "#1e1f29d4", + "--p-side": "#1e1f2900", "--p-side-flat": "#272831", "--p-tab-active": "#1e1f2900", "--p-tabs": "#1e1f29d4", @@ -1448,7 +1448,7 @@ exports[`a saved opacity, as a ground alpha > dracula: every N from 30 to 100 pa "--p-on-accent": "#0b0b0f", "--p-preview": "#3a3b43", "--p-sel-bg": "#bd93f9", - "--p-side": "#1e1f29d6", + "--p-side": "#1e1f2900", "--p-side-flat": "#272831", "--p-tab-active": "#1e1f2900", "--p-tabs": "#1e1f29d6", @@ -1474,7 +1474,7 @@ exports[`a saved opacity, as a ground alpha > dracula: every N from 30 to 100 pa "--p-on-accent": "#0b0b0f", "--p-preview": "#3a3b43", "--p-sel-bg": "#bd93f9", - "--p-side": "#1e1f29d9", + "--p-side": "#1e1f2900", "--p-side-flat": "#272831", "--p-tab-active": "#1e1f2900", "--p-tabs": "#1e1f29d9", @@ -1500,7 +1500,7 @@ exports[`a saved opacity, as a ground alpha > dracula: every N from 30 to 100 pa "--p-on-accent": "#0b0b0f", "--p-preview": "#3a3b43", "--p-sel-bg": "#bd93f9", - "--p-side": "#1e1f29db", + "--p-side": "#1e1f2900", "--p-side-flat": "#272831", "--p-tab-active": "#1e1f2900", "--p-tabs": "#1e1f29db", @@ -1526,7 +1526,7 @@ exports[`a saved opacity, as a ground alpha > dracula: every N from 30 to 100 pa "--p-on-accent": "#0b0b0f", "--p-preview": "#3a3b43", "--p-sel-bg": "#bd93f9", - "--p-side": "#1e1f29de", + "--p-side": "#1e1f2900", "--p-side-flat": "#272831", "--p-tab-active": "#1e1f2900", "--p-tabs": "#1e1f29de", @@ -1552,7 +1552,7 @@ exports[`a saved opacity, as a ground alpha > dracula: every N from 30 to 100 pa "--p-on-accent": "#0b0b0f", "--p-preview": "#3a3b43", "--p-sel-bg": "#bd93f9", - "--p-side": "#1e1f29e0", + "--p-side": "#1e1f2900", "--p-side-flat": "#272831", "--p-tab-active": "#1e1f2900", "--p-tabs": "#1e1f29e0", @@ -1578,7 +1578,7 @@ exports[`a saved opacity, as a ground alpha > dracula: every N from 30 to 100 pa "--p-on-accent": "#0b0b0f", "--p-preview": "#3a3b43", "--p-sel-bg": "#bd93f9", - "--p-side": "#1e1f29e3", + "--p-side": "#1e1f2900", "--p-side-flat": "#272831", "--p-tab-active": "#1e1f2900", "--p-tabs": "#1e1f29e3", @@ -1604,7 +1604,7 @@ exports[`a saved opacity, as a ground alpha > dracula: every N from 30 to 100 pa "--p-on-accent": "#0b0b0f", "--p-preview": "#3a3b43", "--p-sel-bg": "#bd93f9", - "--p-side": "#1e1f29e6", + "--p-side": "#1e1f2900", "--p-side-flat": "#272831", "--p-tab-active": "#1e1f2900", "--p-tabs": "#1e1f29e6", @@ -1630,7 +1630,7 @@ exports[`a saved opacity, as a ground alpha > dracula: every N from 30 to 100 pa "--p-on-accent": "#0b0b0f", "--p-preview": "#3a3b43", "--p-sel-bg": "#bd93f9", - "--p-side": "#1e1f29e8", + "--p-side": "#1e1f2900", "--p-side-flat": "#272831", "--p-tab-active": "#1e1f2900", "--p-tabs": "#1e1f29e8", @@ -1656,7 +1656,7 @@ exports[`a saved opacity, as a ground alpha > dracula: every N from 30 to 100 pa "--p-on-accent": "#0b0b0f", "--p-preview": "#3a3b43", "--p-sel-bg": "#bd93f9", - "--p-side": "#1e1f29eb", + "--p-side": "#1e1f2900", "--p-side-flat": "#272831", "--p-tab-active": "#1e1f2900", "--p-tabs": "#1e1f29eb", @@ -1682,7 +1682,7 @@ exports[`a saved opacity, as a ground alpha > dracula: every N from 30 to 100 pa "--p-on-accent": "#0b0b0f", "--p-preview": "#3a3b43", "--p-sel-bg": "#bd93f9", - "--p-side": "#1e1f29ed", + "--p-side": "#1e1f2900", "--p-side-flat": "#272831", "--p-tab-active": "#1e1f2900", "--p-tabs": "#1e1f29ed", @@ -1708,7 +1708,7 @@ exports[`a saved opacity, as a ground alpha > dracula: every N from 30 to 100 pa "--p-on-accent": "#0b0b0f", "--p-preview": "#3a3b43", "--p-sel-bg": "#bd93f9", - "--p-side": "#1e1f29f0", + "--p-side": "#1e1f2900", "--p-side-flat": "#272831", "--p-tab-active": "#1e1f2900", "--p-tabs": "#1e1f29f0", @@ -1734,7 +1734,7 @@ exports[`a saved opacity, as a ground alpha > dracula: every N from 30 to 100 pa "--p-on-accent": "#0b0b0f", "--p-preview": "#3a3b43", "--p-sel-bg": "#bd93f9", - "--p-side": "#1e1f29f2", + "--p-side": "#1e1f2900", "--p-side-flat": "#272831", "--p-tab-active": "#1e1f2900", "--p-tabs": "#1e1f29f2", @@ -1760,7 +1760,7 @@ exports[`a saved opacity, as a ground alpha > dracula: every N from 30 to 100 pa "--p-on-accent": "#0b0b0f", "--p-preview": "#3a3b43", "--p-sel-bg": "#bd93f9", - "--p-side": "#1e1f29f5", + "--p-side": "#1e1f2900", "--p-side-flat": "#272831", "--p-tab-active": "#1e1f2900", "--p-tabs": "#1e1f29f5", @@ -1786,7 +1786,7 @@ exports[`a saved opacity, as a ground alpha > dracula: every N from 30 to 100 pa "--p-on-accent": "#0b0b0f", "--p-preview": "#3a3b43", "--p-sel-bg": "#bd93f9", - "--p-side": "#1e1f29f7", + "--p-side": "#1e1f2900", "--p-side-flat": "#272831", "--p-tab-active": "#1e1f2900", "--p-tabs": "#1e1f29f7", @@ -1812,7 +1812,7 @@ exports[`a saved opacity, as a ground alpha > dracula: every N from 30 to 100 pa "--p-on-accent": "#0b0b0f", "--p-preview": "#3a3b43", "--p-sel-bg": "#bd93f9", - "--p-side": "#1e1f29fa", + "--p-side": "#1e1f2900", "--p-side-flat": "#272831", "--p-tab-active": "#1e1f2900", "--p-tabs": "#1e1f29fa", @@ -1838,7 +1838,7 @@ exports[`a saved opacity, as a ground alpha > dracula: every N from 30 to 100 pa "--p-on-accent": "#0b0b0f", "--p-preview": "#3a3b43", "--p-sel-bg": "#bd93f9", - "--p-side": "#1e1f29fc", + "--p-side": "#1e1f2900", "--p-side-flat": "#272831", "--p-tab-active": "#1e1f2900", "--p-tabs": "#1e1f29fc", @@ -1895,7 +1895,7 @@ exports[`a saved opacity, as a ground alpha > github: every N from 30 to 100 pai "--p-on-accent": "#0b0b0f", "--p-preview": "#d5d3cd", "--p-sel-bg": "#3f8ccb", - "--p-side": "#f6f4ee4d", + "--p-side": "#f6f4ee00", "--p-side-flat": "#eeece6", "--p-tab-active": "#f6f4ee00", "--p-tabs": "#f6f4ee4d", @@ -1921,7 +1921,7 @@ exports[`a saved opacity, as a ground alpha > github: every N from 30 to 100 pai "--p-on-accent": "#0b0b0f", "--p-preview": "#d5d3cd", "--p-sel-bg": "#3f8ccb", - "--p-side": "#f6f4ee4f", + "--p-side": "#f6f4ee00", "--p-side-flat": "#eeece6", "--p-tab-active": "#f6f4ee00", "--p-tabs": "#f6f4ee4f", @@ -1947,7 +1947,7 @@ exports[`a saved opacity, as a ground alpha > github: every N from 30 to 100 pai "--p-on-accent": "#0b0b0f", "--p-preview": "#d5d3cd", "--p-sel-bg": "#3f8ccb", - "--p-side": "#f6f4ee52", + "--p-side": "#f6f4ee00", "--p-side-flat": "#eeece6", "--p-tab-active": "#f6f4ee00", "--p-tabs": "#f6f4ee52", @@ -1973,7 +1973,7 @@ exports[`a saved opacity, as a ground alpha > github: every N from 30 to 100 pai "--p-on-accent": "#0b0b0f", "--p-preview": "#d5d3cd", "--p-sel-bg": "#3f8ccb", - "--p-side": "#f6f4ee54", + "--p-side": "#f6f4ee00", "--p-side-flat": "#eeece6", "--p-tab-active": "#f6f4ee00", "--p-tabs": "#f6f4ee54", @@ -1999,7 +1999,7 @@ exports[`a saved opacity, as a ground alpha > github: every N from 30 to 100 pai "--p-on-accent": "#0b0b0f", "--p-preview": "#d5d3cd", "--p-sel-bg": "#3f8ccb", - "--p-side": "#f6f4ee57", + "--p-side": "#f6f4ee00", "--p-side-flat": "#eeece6", "--p-tab-active": "#f6f4ee00", "--p-tabs": "#f6f4ee57", @@ -2025,7 +2025,7 @@ exports[`a saved opacity, as a ground alpha > github: every N from 30 to 100 pai "--p-on-accent": "#0b0b0f", "--p-preview": "#d5d3cd", "--p-sel-bg": "#3f8ccb", - "--p-side": "#f6f4ee59", + "--p-side": "#f6f4ee00", "--p-side-flat": "#eeece6", "--p-tab-active": "#f6f4ee00", "--p-tabs": "#f6f4ee59", @@ -2051,7 +2051,7 @@ exports[`a saved opacity, as a ground alpha > github: every N from 30 to 100 pai "--p-on-accent": "#0b0b0f", "--p-preview": "#d5d3cd", "--p-sel-bg": "#3f8ccb", - "--p-side": "#f6f4ee5c", + "--p-side": "#f6f4ee00", "--p-side-flat": "#eeece6", "--p-tab-active": "#f6f4ee00", "--p-tabs": "#f6f4ee5c", @@ -2077,7 +2077,7 @@ exports[`a saved opacity, as a ground alpha > github: every N from 30 to 100 pai "--p-on-accent": "#0b0b0f", "--p-preview": "#d5d3cd", "--p-sel-bg": "#3f8ccb", - "--p-side": "#f6f4ee5e", + "--p-side": "#f6f4ee00", "--p-side-flat": "#eeece6", "--p-tab-active": "#f6f4ee00", "--p-tabs": "#f6f4ee5e", @@ -2103,7 +2103,7 @@ exports[`a saved opacity, as a ground alpha > github: every N from 30 to 100 pai "--p-on-accent": "#0b0b0f", "--p-preview": "#d5d3cd", "--p-sel-bg": "#3f8ccb", - "--p-side": "#f6f4ee61", + "--p-side": "#f6f4ee00", "--p-side-flat": "#eeece6", "--p-tab-active": "#f6f4ee00", "--p-tabs": "#f6f4ee61", @@ -2129,7 +2129,7 @@ exports[`a saved opacity, as a ground alpha > github: every N from 30 to 100 pai "--p-on-accent": "#0b0b0f", "--p-preview": "#d5d3cd", "--p-sel-bg": "#3f8ccb", - "--p-side": "#f6f4ee63", + "--p-side": "#f6f4ee00", "--p-side-flat": "#eeece6", "--p-tab-active": "#f6f4ee00", "--p-tabs": "#f6f4ee63", @@ -2155,7 +2155,7 @@ exports[`a saved opacity, as a ground alpha > github: every N from 30 to 100 pai "--p-on-accent": "#0b0b0f", "--p-preview": "#d5d3cd", "--p-sel-bg": "#3f8ccb", - "--p-side": "#f6f4ee66", + "--p-side": "#f6f4ee00", "--p-side-flat": "#eeece6", "--p-tab-active": "#f6f4ee00", "--p-tabs": "#f6f4ee66", @@ -2181,7 +2181,7 @@ exports[`a saved opacity, as a ground alpha > github: every N from 30 to 100 pai "--p-on-accent": "#0b0b0f", "--p-preview": "#d5d3cd", "--p-sel-bg": "#3f8ccb", - "--p-side": "#f6f4ee69", + "--p-side": "#f6f4ee00", "--p-side-flat": "#eeece6", "--p-tab-active": "#f6f4ee00", "--p-tabs": "#f6f4ee69", @@ -2207,7 +2207,7 @@ exports[`a saved opacity, as a ground alpha > github: every N from 30 to 100 pai "--p-on-accent": "#0b0b0f", "--p-preview": "#d5d3cd", "--p-sel-bg": "#3f8ccb", - "--p-side": "#f6f4ee6b", + "--p-side": "#f6f4ee00", "--p-side-flat": "#eeece6", "--p-tab-active": "#f6f4ee00", "--p-tabs": "#f6f4ee6b", @@ -2233,7 +2233,7 @@ exports[`a saved opacity, as a ground alpha > github: every N from 30 to 100 pai "--p-on-accent": "#0b0b0f", "--p-preview": "#d5d3cd", "--p-sel-bg": "#3f8ccb", - "--p-side": "#f6f4ee6e", + "--p-side": "#f6f4ee00", "--p-side-flat": "#eeece6", "--p-tab-active": "#f6f4ee00", "--p-tabs": "#f6f4ee6e", @@ -2259,7 +2259,7 @@ exports[`a saved opacity, as a ground alpha > github: every N from 30 to 100 pai "--p-on-accent": "#0b0b0f", "--p-preview": "#d5d3cd", "--p-sel-bg": "#3f8ccb", - "--p-side": "#f6f4ee70", + "--p-side": "#f6f4ee00", "--p-side-flat": "#eeece6", "--p-tab-active": "#f6f4ee00", "--p-tabs": "#f6f4ee70", @@ -2285,7 +2285,7 @@ exports[`a saved opacity, as a ground alpha > github: every N from 30 to 100 pai "--p-on-accent": "#0b0b0f", "--p-preview": "#d5d3cd", "--p-sel-bg": "#3f8ccb", - "--p-side": "#f6f4ee73", + "--p-side": "#f6f4ee00", "--p-side-flat": "#eeece6", "--p-tab-active": "#f6f4ee00", "--p-tabs": "#f6f4ee73", @@ -2311,7 +2311,7 @@ exports[`a saved opacity, as a ground alpha > github: every N from 30 to 100 pai "--p-on-accent": "#0b0b0f", "--p-preview": "#d5d3cd", "--p-sel-bg": "#3f8ccb", - "--p-side": "#f6f4ee75", + "--p-side": "#f6f4ee00", "--p-side-flat": "#eeece6", "--p-tab-active": "#f6f4ee00", "--p-tabs": "#f6f4ee75", @@ -2337,7 +2337,7 @@ exports[`a saved opacity, as a ground alpha > github: every N from 30 to 100 pai "--p-on-accent": "#0b0b0f", "--p-preview": "#d5d3cd", "--p-sel-bg": "#3f8ccb", - "--p-side": "#f6f4ee78", + "--p-side": "#f6f4ee00", "--p-side-flat": "#eeece6", "--p-tab-active": "#f6f4ee00", "--p-tabs": "#f6f4ee78", @@ -2363,7 +2363,7 @@ exports[`a saved opacity, as a ground alpha > github: every N from 30 to 100 pai "--p-on-accent": "#0b0b0f", "--p-preview": "#d5d3cd", "--p-sel-bg": "#3f8ccb", - "--p-side": "#f6f4ee7a", + "--p-side": "#f6f4ee00", "--p-side-flat": "#eeece6", "--p-tab-active": "#f6f4ee00", "--p-tabs": "#f6f4ee7a", @@ -2389,7 +2389,7 @@ exports[`a saved opacity, as a ground alpha > github: every N from 30 to 100 pai "--p-on-accent": "#0b0b0f", "--p-preview": "#d5d3cd", "--p-sel-bg": "#3f8ccb", - "--p-side": "#f6f4ee7d", + "--p-side": "#f6f4ee00", "--p-side-flat": "#eeece6", "--p-tab-active": "#f6f4ee00", "--p-tabs": "#f6f4ee7d", @@ -2415,7 +2415,7 @@ exports[`a saved opacity, as a ground alpha > github: every N from 30 to 100 pai "--p-on-accent": "#0b0b0f", "--p-preview": "#d5d3cd", "--p-sel-bg": "#3f8ccb", - "--p-side": "#f6f4ee80", + "--p-side": "#f6f4ee00", "--p-side-flat": "#eeece6", "--p-tab-active": "#f6f4ee00", "--p-tabs": "#f6f4ee80", @@ -2441,7 +2441,7 @@ exports[`a saved opacity, as a ground alpha > github: every N from 30 to 100 pai "--p-on-accent": "#0b0b0f", "--p-preview": "#d5d3cd", "--p-sel-bg": "#3f8ccb", - "--p-side": "#f6f4ee82", + "--p-side": "#f6f4ee00", "--p-side-flat": "#eeece6", "--p-tab-active": "#f6f4ee00", "--p-tabs": "#f6f4ee82", @@ -2467,7 +2467,7 @@ exports[`a saved opacity, as a ground alpha > github: every N from 30 to 100 pai "--p-on-accent": "#0b0b0f", "--p-preview": "#d5d3cd", "--p-sel-bg": "#3f8ccb", - "--p-side": "#f6f4ee85", + "--p-side": "#f6f4ee00", "--p-side-flat": "#eeece6", "--p-tab-active": "#f6f4ee00", "--p-tabs": "#f6f4ee85", @@ -2493,7 +2493,7 @@ exports[`a saved opacity, as a ground alpha > github: every N from 30 to 100 pai "--p-on-accent": "#0b0b0f", "--p-preview": "#d5d3cd", "--p-sel-bg": "#3f8ccb", - "--p-side": "#f6f4ee87", + "--p-side": "#f6f4ee00", "--p-side-flat": "#eeece6", "--p-tab-active": "#f6f4ee00", "--p-tabs": "#f6f4ee87", @@ -2519,7 +2519,7 @@ exports[`a saved opacity, as a ground alpha > github: every N from 30 to 100 pai "--p-on-accent": "#0b0b0f", "--p-preview": "#d5d3cd", "--p-sel-bg": "#3f8ccb", - "--p-side": "#f6f4ee8a", + "--p-side": "#f6f4ee00", "--p-side-flat": "#eeece6", "--p-tab-active": "#f6f4ee00", "--p-tabs": "#f6f4ee8a", @@ -2545,7 +2545,7 @@ exports[`a saved opacity, as a ground alpha > github: every N from 30 to 100 pai "--p-on-accent": "#0b0b0f", "--p-preview": "#d5d3cd", "--p-sel-bg": "#3f8ccb", - "--p-side": "#f6f4ee8c", + "--p-side": "#f6f4ee00", "--p-side-flat": "#eeece6", "--p-tab-active": "#f6f4ee00", "--p-tabs": "#f6f4ee8c", @@ -2571,7 +2571,7 @@ exports[`a saved opacity, as a ground alpha > github: every N from 30 to 100 pai "--p-on-accent": "#0b0b0f", "--p-preview": "#d5d3cd", "--p-sel-bg": "#3f8ccb", - "--p-side": "#f6f4ee8f", + "--p-side": "#f6f4ee00", "--p-side-flat": "#eeece6", "--p-tab-active": "#f6f4ee00", "--p-tabs": "#f6f4ee8f", @@ -2597,7 +2597,7 @@ exports[`a saved opacity, as a ground alpha > github: every N from 30 to 100 pai "--p-on-accent": "#0b0b0f", "--p-preview": "#d5d3cd", "--p-sel-bg": "#3f8ccb", - "--p-side": "#f6f4ee91", + "--p-side": "#f6f4ee00", "--p-side-flat": "#eeece6", "--p-tab-active": "#f6f4ee00", "--p-tabs": "#f6f4ee91", @@ -2623,7 +2623,7 @@ exports[`a saved opacity, as a ground alpha > github: every N from 30 to 100 pai "--p-on-accent": "#0b0b0f", "--p-preview": "#d5d3cd", "--p-sel-bg": "#3f8ccb", - "--p-side": "#f6f4ee94", + "--p-side": "#f6f4ee00", "--p-side-flat": "#eeece6", "--p-tab-active": "#f6f4ee00", "--p-tabs": "#f6f4ee94", @@ -2649,7 +2649,7 @@ exports[`a saved opacity, as a ground alpha > github: every N from 30 to 100 pai "--p-on-accent": "#0b0b0f", "--p-preview": "#d5d3cd", "--p-sel-bg": "#3f8ccb", - "--p-side": "#f6f4ee96", + "--p-side": "#f6f4ee00", "--p-side-flat": "#eeece6", "--p-tab-active": "#f6f4ee00", "--p-tabs": "#f6f4ee96", @@ -2675,7 +2675,7 @@ exports[`a saved opacity, as a ground alpha > github: every N from 30 to 100 pai "--p-on-accent": "#0b0b0f", "--p-preview": "#d5d3cd", "--p-sel-bg": "#3f8ccb", - "--p-side": "#f6f4ee99", + "--p-side": "#f6f4ee00", "--p-side-flat": "#eeece6", "--p-tab-active": "#f6f4ee00", "--p-tabs": "#f6f4ee99", @@ -2701,7 +2701,7 @@ exports[`a saved opacity, as a ground alpha > github: every N from 30 to 100 pai "--p-on-accent": "#0b0b0f", "--p-preview": "#d5d3cd", "--p-sel-bg": "#3f8ccb", - "--p-side": "#f6f4ee9c", + "--p-side": "#f6f4ee00", "--p-side-flat": "#eeece6", "--p-tab-active": "#f6f4ee00", "--p-tabs": "#f6f4ee9c", @@ -2727,7 +2727,7 @@ exports[`a saved opacity, as a ground alpha > github: every N from 30 to 100 pai "--p-on-accent": "#0b0b0f", "--p-preview": "#d5d3cd", "--p-sel-bg": "#3f8ccb", - "--p-side": "#f6f4ee9e", + "--p-side": "#f6f4ee00", "--p-side-flat": "#eeece6", "--p-tab-active": "#f6f4ee00", "--p-tabs": "#f6f4ee9e", @@ -2753,7 +2753,7 @@ exports[`a saved opacity, as a ground alpha > github: every N from 30 to 100 pai "--p-on-accent": "#0b0b0f", "--p-preview": "#d5d3cd", "--p-sel-bg": "#3f8ccb", - "--p-side": "#f6f4eea1", + "--p-side": "#f6f4ee00", "--p-side-flat": "#eeece6", "--p-tab-active": "#f6f4ee00", "--p-tabs": "#f6f4eea1", @@ -2779,7 +2779,7 @@ exports[`a saved opacity, as a ground alpha > github: every N from 30 to 100 pai "--p-on-accent": "#0b0b0f", "--p-preview": "#d5d3cd", "--p-sel-bg": "#3f8ccb", - "--p-side": "#f6f4eea3", + "--p-side": "#f6f4ee00", "--p-side-flat": "#eeece6", "--p-tab-active": "#f6f4ee00", "--p-tabs": "#f6f4eea3", @@ -2805,7 +2805,7 @@ exports[`a saved opacity, as a ground alpha > github: every N from 30 to 100 pai "--p-on-accent": "#0b0b0f", "--p-preview": "#d5d3cd", "--p-sel-bg": "#3f8ccb", - "--p-side": "#f6f4eea6", + "--p-side": "#f6f4ee00", "--p-side-flat": "#eeece6", "--p-tab-active": "#f6f4ee00", "--p-tabs": "#f6f4eea6", @@ -2831,7 +2831,7 @@ exports[`a saved opacity, as a ground alpha > github: every N from 30 to 100 pai "--p-on-accent": "#0b0b0f", "--p-preview": "#d5d3cd", "--p-sel-bg": "#3f8ccb", - "--p-side": "#f6f4eea8", + "--p-side": "#f6f4ee00", "--p-side-flat": "#eeece6", "--p-tab-active": "#f6f4ee00", "--p-tabs": "#f6f4eea8", @@ -2857,7 +2857,7 @@ exports[`a saved opacity, as a ground alpha > github: every N from 30 to 100 pai "--p-on-accent": "#0b0b0f", "--p-preview": "#d5d3cd", "--p-sel-bg": "#3f8ccb", - "--p-side": "#f6f4eeab", + "--p-side": "#f6f4ee00", "--p-side-flat": "#eeece6", "--p-tab-active": "#f6f4ee00", "--p-tabs": "#f6f4eeab", @@ -2883,7 +2883,7 @@ exports[`a saved opacity, as a ground alpha > github: every N from 30 to 100 pai "--p-on-accent": "#0b0b0f", "--p-preview": "#d5d3cd", "--p-sel-bg": "#3f8ccb", - "--p-side": "#f6f4eead", + "--p-side": "#f6f4ee00", "--p-side-flat": "#eeece6", "--p-tab-active": "#f6f4ee00", "--p-tabs": "#f6f4eead", @@ -2909,7 +2909,7 @@ exports[`a saved opacity, as a ground alpha > github: every N from 30 to 100 pai "--p-on-accent": "#0b0b0f", "--p-preview": "#d5d3cd", "--p-sel-bg": "#3f8ccb", - "--p-side": "#f6f4eeb0", + "--p-side": "#f6f4ee00", "--p-side-flat": "#eeece6", "--p-tab-active": "#f6f4ee00", "--p-tabs": "#f6f4eeb0", @@ -2935,7 +2935,7 @@ exports[`a saved opacity, as a ground alpha > github: every N from 30 to 100 pai "--p-on-accent": "#0b0b0f", "--p-preview": "#d5d3cd", "--p-sel-bg": "#3f8ccb", - "--p-side": "#f6f4eeb3", + "--p-side": "#f6f4ee00", "--p-side-flat": "#eeece6", "--p-tab-active": "#f6f4ee00", "--p-tabs": "#f6f4eeb3", @@ -2961,7 +2961,7 @@ exports[`a saved opacity, as a ground alpha > github: every N from 30 to 100 pai "--p-on-accent": "#0b0b0f", "--p-preview": "#d5d3cd", "--p-sel-bg": "#3f8ccb", - "--p-side": "#f6f4eeb5", + "--p-side": "#f6f4ee00", "--p-side-flat": "#eeece6", "--p-tab-active": "#f6f4ee00", "--p-tabs": "#f6f4eeb5", @@ -2987,7 +2987,7 @@ exports[`a saved opacity, as a ground alpha > github: every N from 30 to 100 pai "--p-on-accent": "#0b0b0f", "--p-preview": "#d5d3cd", "--p-sel-bg": "#3f8ccb", - "--p-side": "#f6f4eeb8", + "--p-side": "#f6f4ee00", "--p-side-flat": "#eeece6", "--p-tab-active": "#f6f4ee00", "--p-tabs": "#f6f4eeb8", @@ -3013,7 +3013,7 @@ exports[`a saved opacity, as a ground alpha > github: every N from 30 to 100 pai "--p-on-accent": "#0b0b0f", "--p-preview": "#d5d3cd", "--p-sel-bg": "#3f8ccb", - "--p-side": "#f6f4eeba", + "--p-side": "#f6f4ee00", "--p-side-flat": "#eeece6", "--p-tab-active": "#f6f4ee00", "--p-tabs": "#f6f4eeba", @@ -3039,7 +3039,7 @@ exports[`a saved opacity, as a ground alpha > github: every N from 30 to 100 pai "--p-on-accent": "#0b0b0f", "--p-preview": "#d5d3cd", "--p-sel-bg": "#3f8ccb", - "--p-side": "#f6f4eebd", + "--p-side": "#f6f4ee00", "--p-side-flat": "#eeece6", "--p-tab-active": "#f6f4ee00", "--p-tabs": "#f6f4eebd", @@ -3065,7 +3065,7 @@ exports[`a saved opacity, as a ground alpha > github: every N from 30 to 100 pai "--p-on-accent": "#0b0b0f", "--p-preview": "#d5d3cd", "--p-sel-bg": "#3f8ccb", - "--p-side": "#f6f4eebf", + "--p-side": "#f6f4ee00", "--p-side-flat": "#eeece6", "--p-tab-active": "#f6f4ee00", "--p-tabs": "#f6f4eebf", @@ -3091,7 +3091,7 @@ exports[`a saved opacity, as a ground alpha > github: every N from 30 to 100 pai "--p-on-accent": "#0b0b0f", "--p-preview": "#d5d3cd", "--p-sel-bg": "#3f8ccb", - "--p-side": "#f6f4eec2", + "--p-side": "#f6f4ee00", "--p-side-flat": "#eeece6", "--p-tab-active": "#f6f4ee00", "--p-tabs": "#f6f4eec2", @@ -3117,7 +3117,7 @@ exports[`a saved opacity, as a ground alpha > github: every N from 30 to 100 pai "--p-on-accent": "#0b0b0f", "--p-preview": "#d5d3cd", "--p-sel-bg": "#3f8ccb", - "--p-side": "#f6f4eec4", + "--p-side": "#f6f4ee00", "--p-side-flat": "#eeece6", "--p-tab-active": "#f6f4ee00", "--p-tabs": "#f6f4eec4", @@ -3143,7 +3143,7 @@ exports[`a saved opacity, as a ground alpha > github: every N from 30 to 100 pai "--p-on-accent": "#0b0b0f", "--p-preview": "#d5d3cd", "--p-sel-bg": "#3f8ccb", - "--p-side": "#f6f4eec7", + "--p-side": "#f6f4ee00", "--p-side-flat": "#eeece6", "--p-tab-active": "#f6f4ee00", "--p-tabs": "#f6f4eec7", @@ -3169,7 +3169,7 @@ exports[`a saved opacity, as a ground alpha > github: every N from 30 to 100 pai "--p-on-accent": "#0b0b0f", "--p-preview": "#d5d3cd", "--p-sel-bg": "#3f8ccb", - "--p-side": "#f6f4eec9", + "--p-side": "#f6f4ee00", "--p-side-flat": "#eeece6", "--p-tab-active": "#f6f4ee00", "--p-tabs": "#f6f4eec9", @@ -3195,7 +3195,7 @@ exports[`a saved opacity, as a ground alpha > github: every N from 30 to 100 pai "--p-on-accent": "#0b0b0f", "--p-preview": "#d5d3cd", "--p-sel-bg": "#3f8ccb", - "--p-side": "#f6f4eecc", + "--p-side": "#f6f4ee00", "--p-side-flat": "#eeece6", "--p-tab-active": "#f6f4ee00", "--p-tabs": "#f6f4eecc", @@ -3221,7 +3221,7 @@ exports[`a saved opacity, as a ground alpha > github: every N from 30 to 100 pai "--p-on-accent": "#0b0b0f", "--p-preview": "#d5d3cd", "--p-sel-bg": "#3f8ccb", - "--p-side": "#f6f4eecf", + "--p-side": "#f6f4ee00", "--p-side-flat": "#eeece6", "--p-tab-active": "#f6f4ee00", "--p-tabs": "#f6f4eecf", @@ -3247,7 +3247,7 @@ exports[`a saved opacity, as a ground alpha > github: every N from 30 to 100 pai "--p-on-accent": "#0b0b0f", "--p-preview": "#d5d3cd", "--p-sel-bg": "#3f8ccb", - "--p-side": "#f6f4eed1", + "--p-side": "#f6f4ee00", "--p-side-flat": "#eeece6", "--p-tab-active": "#f6f4ee00", "--p-tabs": "#f6f4eed1", @@ -3273,7 +3273,7 @@ exports[`a saved opacity, as a ground alpha > github: every N from 30 to 100 pai "--p-on-accent": "#0b0b0f", "--p-preview": "#d5d3cd", "--p-sel-bg": "#3f8ccb", - "--p-side": "#f6f4eed4", + "--p-side": "#f6f4ee00", "--p-side-flat": "#eeece6", "--p-tab-active": "#f6f4ee00", "--p-tabs": "#f6f4eed4", @@ -3299,7 +3299,7 @@ exports[`a saved opacity, as a ground alpha > github: every N from 30 to 100 pai "--p-on-accent": "#0b0b0f", "--p-preview": "#d5d3cd", "--p-sel-bg": "#3f8ccb", - "--p-side": "#f6f4eed6", + "--p-side": "#f6f4ee00", "--p-side-flat": "#eeece6", "--p-tab-active": "#f6f4ee00", "--p-tabs": "#f6f4eed6", @@ -3325,7 +3325,7 @@ exports[`a saved opacity, as a ground alpha > github: every N from 30 to 100 pai "--p-on-accent": "#0b0b0f", "--p-preview": "#d5d3cd", "--p-sel-bg": "#3f8ccb", - "--p-side": "#f6f4eed9", + "--p-side": "#f6f4ee00", "--p-side-flat": "#eeece6", "--p-tab-active": "#f6f4ee00", "--p-tabs": "#f6f4eed9", @@ -3351,7 +3351,7 @@ exports[`a saved opacity, as a ground alpha > github: every N from 30 to 100 pai "--p-on-accent": "#0b0b0f", "--p-preview": "#d5d3cd", "--p-sel-bg": "#3f8ccb", - "--p-side": "#f6f4eedb", + "--p-side": "#f6f4ee00", "--p-side-flat": "#eeece6", "--p-tab-active": "#f6f4ee00", "--p-tabs": "#f6f4eedb", @@ -3377,7 +3377,7 @@ exports[`a saved opacity, as a ground alpha > github: every N from 30 to 100 pai "--p-on-accent": "#0b0b0f", "--p-preview": "#d5d3cd", "--p-sel-bg": "#3f8ccb", - "--p-side": "#f6f4eede", + "--p-side": "#f6f4ee00", "--p-side-flat": "#eeece6", "--p-tab-active": "#f6f4ee00", "--p-tabs": "#f6f4eede", @@ -3403,7 +3403,7 @@ exports[`a saved opacity, as a ground alpha > github: every N from 30 to 100 pai "--p-on-accent": "#0b0b0f", "--p-preview": "#d5d3cd", "--p-sel-bg": "#3f8ccb", - "--p-side": "#f6f4eee0", + "--p-side": "#f6f4ee00", "--p-side-flat": "#eeece6", "--p-tab-active": "#f6f4ee00", "--p-tabs": "#f6f4eee0", @@ -3429,7 +3429,7 @@ exports[`a saved opacity, as a ground alpha > github: every N from 30 to 100 pai "--p-on-accent": "#0b0b0f", "--p-preview": "#d5d3cd", "--p-sel-bg": "#3f8ccb", - "--p-side": "#f6f4eee3", + "--p-side": "#f6f4ee00", "--p-side-flat": "#eeece6", "--p-tab-active": "#f6f4ee00", "--p-tabs": "#f6f4eee3", @@ -3455,7 +3455,7 @@ exports[`a saved opacity, as a ground alpha > github: every N from 30 to 100 pai "--p-on-accent": "#0b0b0f", "--p-preview": "#d5d3cd", "--p-sel-bg": "#3f8ccb", - "--p-side": "#f6f4eee6", + "--p-side": "#f6f4ee00", "--p-side-flat": "#eeece6", "--p-tab-active": "#f6f4ee00", "--p-tabs": "#f6f4eee6", @@ -3481,7 +3481,7 @@ exports[`a saved opacity, as a ground alpha > github: every N from 30 to 100 pai "--p-on-accent": "#0b0b0f", "--p-preview": "#d5d3cd", "--p-sel-bg": "#3f8ccb", - "--p-side": "#f6f4eee8", + "--p-side": "#f6f4ee00", "--p-side-flat": "#eeece6", "--p-tab-active": "#f6f4ee00", "--p-tabs": "#f6f4eee8", @@ -3507,7 +3507,7 @@ exports[`a saved opacity, as a ground alpha > github: every N from 30 to 100 pai "--p-on-accent": "#0b0b0f", "--p-preview": "#d5d3cd", "--p-sel-bg": "#3f8ccb", - "--p-side": "#f6f4eeeb", + "--p-side": "#f6f4ee00", "--p-side-flat": "#eeece6", "--p-tab-active": "#f6f4ee00", "--p-tabs": "#f6f4eeeb", @@ -3533,7 +3533,7 @@ exports[`a saved opacity, as a ground alpha > github: every N from 30 to 100 pai "--p-on-accent": "#0b0b0f", "--p-preview": "#d5d3cd", "--p-sel-bg": "#3f8ccb", - "--p-side": "#f6f4eeed", + "--p-side": "#f6f4ee00", "--p-side-flat": "#eeece6", "--p-tab-active": "#f6f4ee00", "--p-tabs": "#f6f4eeed", @@ -3559,7 +3559,7 @@ exports[`a saved opacity, as a ground alpha > github: every N from 30 to 100 pai "--p-on-accent": "#0b0b0f", "--p-preview": "#d5d3cd", "--p-sel-bg": "#3f8ccb", - "--p-side": "#f6f4eef0", + "--p-side": "#f6f4ee00", "--p-side-flat": "#eeece6", "--p-tab-active": "#f6f4ee00", "--p-tabs": "#f6f4eef0", @@ -3585,7 +3585,7 @@ exports[`a saved opacity, as a ground alpha > github: every N from 30 to 100 pai "--p-on-accent": "#0b0b0f", "--p-preview": "#d5d3cd", "--p-sel-bg": "#3f8ccb", - "--p-side": "#f6f4eef2", + "--p-side": "#f6f4ee00", "--p-side-flat": "#eeece6", "--p-tab-active": "#f6f4ee00", "--p-tabs": "#f6f4eef2", @@ -3611,7 +3611,7 @@ exports[`a saved opacity, as a ground alpha > github: every N from 30 to 100 pai "--p-on-accent": "#0b0b0f", "--p-preview": "#d5d3cd", "--p-sel-bg": "#3f8ccb", - "--p-side": "#f6f4eef5", + "--p-side": "#f6f4ee00", "--p-side-flat": "#eeece6", "--p-tab-active": "#f6f4ee00", "--p-tabs": "#f6f4eef5", @@ -3637,7 +3637,7 @@ exports[`a saved opacity, as a ground alpha > github: every N from 30 to 100 pai "--p-on-accent": "#0b0b0f", "--p-preview": "#d5d3cd", "--p-sel-bg": "#3f8ccb", - "--p-side": "#f6f4eef7", + "--p-side": "#f6f4ee00", "--p-side-flat": "#eeece6", "--p-tab-active": "#f6f4ee00", "--p-tabs": "#f6f4eef7", @@ -3663,7 +3663,7 @@ exports[`a saved opacity, as a ground alpha > github: every N from 30 to 100 pai "--p-on-accent": "#0b0b0f", "--p-preview": "#d5d3cd", "--p-sel-bg": "#3f8ccb", - "--p-side": "#f6f4eefa", + "--p-side": "#f6f4ee00", "--p-side-flat": "#eeece6", "--p-tab-active": "#f6f4ee00", "--p-tabs": "#f6f4eefa", @@ -3689,7 +3689,7 @@ exports[`a saved opacity, as a ground alpha > github: every N from 30 to 100 pai "--p-on-accent": "#0b0b0f", "--p-preview": "#d5d3cd", "--p-sel-bg": "#3f8ccb", - "--p-side": "#f6f4eefc", + "--p-side": "#f6f4ee00", "--p-side-flat": "#eeece6", "--p-tab-active": "#f6f4ee00", "--p-tabs": "#f6f4eefc", @@ -3746,7 +3746,7 @@ exports[`a saved opacity, as a ground alpha > paper: every N from 30 to 100 pain "--p-on-accent": "#0b0b0f", "--p-preview": "#d5d3cd", "--p-sel-bg": "#3f8ccb", - "--p-side": "#f6f4ee4d", + "--p-side": "#f6f4ee00", "--p-side-flat": "#eeece6", "--p-tab-active": "#f6f4ee00", "--p-tabs": "#f6f4ee4d", @@ -3772,7 +3772,7 @@ exports[`a saved opacity, as a ground alpha > paper: every N from 30 to 100 pain "--p-on-accent": "#0b0b0f", "--p-preview": "#d5d3cd", "--p-sel-bg": "#3f8ccb", - "--p-side": "#f6f4ee4f", + "--p-side": "#f6f4ee00", "--p-side-flat": "#eeece6", "--p-tab-active": "#f6f4ee00", "--p-tabs": "#f6f4ee4f", @@ -3798,7 +3798,7 @@ exports[`a saved opacity, as a ground alpha > paper: every N from 30 to 100 pain "--p-on-accent": "#0b0b0f", "--p-preview": "#d5d3cd", "--p-sel-bg": "#3f8ccb", - "--p-side": "#f6f4ee52", + "--p-side": "#f6f4ee00", "--p-side-flat": "#eeece6", "--p-tab-active": "#f6f4ee00", "--p-tabs": "#f6f4ee52", @@ -3824,7 +3824,7 @@ exports[`a saved opacity, as a ground alpha > paper: every N from 30 to 100 pain "--p-on-accent": "#0b0b0f", "--p-preview": "#d5d3cd", "--p-sel-bg": "#3f8ccb", - "--p-side": "#f6f4ee54", + "--p-side": "#f6f4ee00", "--p-side-flat": "#eeece6", "--p-tab-active": "#f6f4ee00", "--p-tabs": "#f6f4ee54", @@ -3850,7 +3850,7 @@ exports[`a saved opacity, as a ground alpha > paper: every N from 30 to 100 pain "--p-on-accent": "#0b0b0f", "--p-preview": "#d5d3cd", "--p-sel-bg": "#3f8ccb", - "--p-side": "#f6f4ee57", + "--p-side": "#f6f4ee00", "--p-side-flat": "#eeece6", "--p-tab-active": "#f6f4ee00", "--p-tabs": "#f6f4ee57", @@ -3876,7 +3876,7 @@ exports[`a saved opacity, as a ground alpha > paper: every N from 30 to 100 pain "--p-on-accent": "#0b0b0f", "--p-preview": "#d5d3cd", "--p-sel-bg": "#3f8ccb", - "--p-side": "#f6f4ee59", + "--p-side": "#f6f4ee00", "--p-side-flat": "#eeece6", "--p-tab-active": "#f6f4ee00", "--p-tabs": "#f6f4ee59", @@ -3902,7 +3902,7 @@ exports[`a saved opacity, as a ground alpha > paper: every N from 30 to 100 pain "--p-on-accent": "#0b0b0f", "--p-preview": "#d5d3cd", "--p-sel-bg": "#3f8ccb", - "--p-side": "#f6f4ee5c", + "--p-side": "#f6f4ee00", "--p-side-flat": "#eeece6", "--p-tab-active": "#f6f4ee00", "--p-tabs": "#f6f4ee5c", @@ -3928,7 +3928,7 @@ exports[`a saved opacity, as a ground alpha > paper: every N from 30 to 100 pain "--p-on-accent": "#0b0b0f", "--p-preview": "#d5d3cd", "--p-sel-bg": "#3f8ccb", - "--p-side": "#f6f4ee5e", + "--p-side": "#f6f4ee00", "--p-side-flat": "#eeece6", "--p-tab-active": "#f6f4ee00", "--p-tabs": "#f6f4ee5e", @@ -3954,7 +3954,7 @@ exports[`a saved opacity, as a ground alpha > paper: every N from 30 to 100 pain "--p-on-accent": "#0b0b0f", "--p-preview": "#d5d3cd", "--p-sel-bg": "#3f8ccb", - "--p-side": "#f6f4ee61", + "--p-side": "#f6f4ee00", "--p-side-flat": "#eeece6", "--p-tab-active": "#f6f4ee00", "--p-tabs": "#f6f4ee61", @@ -3980,7 +3980,7 @@ exports[`a saved opacity, as a ground alpha > paper: every N from 30 to 100 pain "--p-on-accent": "#0b0b0f", "--p-preview": "#d5d3cd", "--p-sel-bg": "#3f8ccb", - "--p-side": "#f6f4ee63", + "--p-side": "#f6f4ee00", "--p-side-flat": "#eeece6", "--p-tab-active": "#f6f4ee00", "--p-tabs": "#f6f4ee63", @@ -4006,7 +4006,7 @@ exports[`a saved opacity, as a ground alpha > paper: every N from 30 to 100 pain "--p-on-accent": "#0b0b0f", "--p-preview": "#d5d3cd", "--p-sel-bg": "#3f8ccb", - "--p-side": "#f6f4ee66", + "--p-side": "#f6f4ee00", "--p-side-flat": "#eeece6", "--p-tab-active": "#f6f4ee00", "--p-tabs": "#f6f4ee66", @@ -4032,7 +4032,7 @@ exports[`a saved opacity, as a ground alpha > paper: every N from 30 to 100 pain "--p-on-accent": "#0b0b0f", "--p-preview": "#d5d3cd", "--p-sel-bg": "#3f8ccb", - "--p-side": "#f6f4ee69", + "--p-side": "#f6f4ee00", "--p-side-flat": "#eeece6", "--p-tab-active": "#f6f4ee00", "--p-tabs": "#f6f4ee69", @@ -4058,7 +4058,7 @@ exports[`a saved opacity, as a ground alpha > paper: every N from 30 to 100 pain "--p-on-accent": "#0b0b0f", "--p-preview": "#d5d3cd", "--p-sel-bg": "#3f8ccb", - "--p-side": "#f6f4ee6b", + "--p-side": "#f6f4ee00", "--p-side-flat": "#eeece6", "--p-tab-active": "#f6f4ee00", "--p-tabs": "#f6f4ee6b", @@ -4084,7 +4084,7 @@ exports[`a saved opacity, as a ground alpha > paper: every N from 30 to 100 pain "--p-on-accent": "#0b0b0f", "--p-preview": "#d5d3cd", "--p-sel-bg": "#3f8ccb", - "--p-side": "#f6f4ee6e", + "--p-side": "#f6f4ee00", "--p-side-flat": "#eeece6", "--p-tab-active": "#f6f4ee00", "--p-tabs": "#f6f4ee6e", @@ -4110,7 +4110,7 @@ exports[`a saved opacity, as a ground alpha > paper: every N from 30 to 100 pain "--p-on-accent": "#0b0b0f", "--p-preview": "#d5d3cd", "--p-sel-bg": "#3f8ccb", - "--p-side": "#f6f4ee70", + "--p-side": "#f6f4ee00", "--p-side-flat": "#eeece6", "--p-tab-active": "#f6f4ee00", "--p-tabs": "#f6f4ee70", @@ -4136,7 +4136,7 @@ exports[`a saved opacity, as a ground alpha > paper: every N from 30 to 100 pain "--p-on-accent": "#0b0b0f", "--p-preview": "#d5d3cd", "--p-sel-bg": "#3f8ccb", - "--p-side": "#f6f4ee73", + "--p-side": "#f6f4ee00", "--p-side-flat": "#eeece6", "--p-tab-active": "#f6f4ee00", "--p-tabs": "#f6f4ee73", @@ -4162,7 +4162,7 @@ exports[`a saved opacity, as a ground alpha > paper: every N from 30 to 100 pain "--p-on-accent": "#0b0b0f", "--p-preview": "#d5d3cd", "--p-sel-bg": "#3f8ccb", - "--p-side": "#f6f4ee75", + "--p-side": "#f6f4ee00", "--p-side-flat": "#eeece6", "--p-tab-active": "#f6f4ee00", "--p-tabs": "#f6f4ee75", @@ -4188,7 +4188,7 @@ exports[`a saved opacity, as a ground alpha > paper: every N from 30 to 100 pain "--p-on-accent": "#0b0b0f", "--p-preview": "#d5d3cd", "--p-sel-bg": "#3f8ccb", - "--p-side": "#f6f4ee78", + "--p-side": "#f6f4ee00", "--p-side-flat": "#eeece6", "--p-tab-active": "#f6f4ee00", "--p-tabs": "#f6f4ee78", @@ -4214,7 +4214,7 @@ exports[`a saved opacity, as a ground alpha > paper: every N from 30 to 100 pain "--p-on-accent": "#0b0b0f", "--p-preview": "#d5d3cd", "--p-sel-bg": "#3f8ccb", - "--p-side": "#f6f4ee7a", + "--p-side": "#f6f4ee00", "--p-side-flat": "#eeece6", "--p-tab-active": "#f6f4ee00", "--p-tabs": "#f6f4ee7a", @@ -4240,7 +4240,7 @@ exports[`a saved opacity, as a ground alpha > paper: every N from 30 to 100 pain "--p-on-accent": "#0b0b0f", "--p-preview": "#d5d3cd", "--p-sel-bg": "#3f8ccb", - "--p-side": "#f6f4ee7d", + "--p-side": "#f6f4ee00", "--p-side-flat": "#eeece6", "--p-tab-active": "#f6f4ee00", "--p-tabs": "#f6f4ee7d", @@ -4266,7 +4266,7 @@ exports[`a saved opacity, as a ground alpha > paper: every N from 30 to 100 pain "--p-on-accent": "#0b0b0f", "--p-preview": "#d5d3cd", "--p-sel-bg": "#3f8ccb", - "--p-side": "#f6f4ee80", + "--p-side": "#f6f4ee00", "--p-side-flat": "#eeece6", "--p-tab-active": "#f6f4ee00", "--p-tabs": "#f6f4ee80", @@ -4292,7 +4292,7 @@ exports[`a saved opacity, as a ground alpha > paper: every N from 30 to 100 pain "--p-on-accent": "#0b0b0f", "--p-preview": "#d5d3cd", "--p-sel-bg": "#3f8ccb", - "--p-side": "#f6f4ee82", + "--p-side": "#f6f4ee00", "--p-side-flat": "#eeece6", "--p-tab-active": "#f6f4ee00", "--p-tabs": "#f6f4ee82", @@ -4318,7 +4318,7 @@ exports[`a saved opacity, as a ground alpha > paper: every N from 30 to 100 pain "--p-on-accent": "#0b0b0f", "--p-preview": "#d5d3cd", "--p-sel-bg": "#3f8ccb", - "--p-side": "#f6f4ee85", + "--p-side": "#f6f4ee00", "--p-side-flat": "#eeece6", "--p-tab-active": "#f6f4ee00", "--p-tabs": "#f6f4ee85", @@ -4344,7 +4344,7 @@ exports[`a saved opacity, as a ground alpha > paper: every N from 30 to 100 pain "--p-on-accent": "#0b0b0f", "--p-preview": "#d5d3cd", "--p-sel-bg": "#3f8ccb", - "--p-side": "#f6f4ee87", + "--p-side": "#f6f4ee00", "--p-side-flat": "#eeece6", "--p-tab-active": "#f6f4ee00", "--p-tabs": "#f6f4ee87", @@ -4370,7 +4370,7 @@ exports[`a saved opacity, as a ground alpha > paper: every N from 30 to 100 pain "--p-on-accent": "#0b0b0f", "--p-preview": "#d5d3cd", "--p-sel-bg": "#3f8ccb", - "--p-side": "#f6f4ee8a", + "--p-side": "#f6f4ee00", "--p-side-flat": "#eeece6", "--p-tab-active": "#f6f4ee00", "--p-tabs": "#f6f4ee8a", @@ -4396,7 +4396,7 @@ exports[`a saved opacity, as a ground alpha > paper: every N from 30 to 100 pain "--p-on-accent": "#0b0b0f", "--p-preview": "#d5d3cd", "--p-sel-bg": "#3f8ccb", - "--p-side": "#f6f4ee8c", + "--p-side": "#f6f4ee00", "--p-side-flat": "#eeece6", "--p-tab-active": "#f6f4ee00", "--p-tabs": "#f6f4ee8c", @@ -4422,7 +4422,7 @@ exports[`a saved opacity, as a ground alpha > paper: every N from 30 to 100 pain "--p-on-accent": "#0b0b0f", "--p-preview": "#d5d3cd", "--p-sel-bg": "#3f8ccb", - "--p-side": "#f6f4ee8f", + "--p-side": "#f6f4ee00", "--p-side-flat": "#eeece6", "--p-tab-active": "#f6f4ee00", "--p-tabs": "#f6f4ee8f", @@ -4448,7 +4448,7 @@ exports[`a saved opacity, as a ground alpha > paper: every N from 30 to 100 pain "--p-on-accent": "#0b0b0f", "--p-preview": "#d5d3cd", "--p-sel-bg": "#3f8ccb", - "--p-side": "#f6f4ee91", + "--p-side": "#f6f4ee00", "--p-side-flat": "#eeece6", "--p-tab-active": "#f6f4ee00", "--p-tabs": "#f6f4ee91", @@ -4474,7 +4474,7 @@ exports[`a saved opacity, as a ground alpha > paper: every N from 30 to 100 pain "--p-on-accent": "#0b0b0f", "--p-preview": "#d5d3cd", "--p-sel-bg": "#3f8ccb", - "--p-side": "#f6f4ee94", + "--p-side": "#f6f4ee00", "--p-side-flat": "#eeece6", "--p-tab-active": "#f6f4ee00", "--p-tabs": "#f6f4ee94", @@ -4500,7 +4500,7 @@ exports[`a saved opacity, as a ground alpha > paper: every N from 30 to 100 pain "--p-on-accent": "#0b0b0f", "--p-preview": "#d5d3cd", "--p-sel-bg": "#3f8ccb", - "--p-side": "#f6f4ee96", + "--p-side": "#f6f4ee00", "--p-side-flat": "#eeece6", "--p-tab-active": "#f6f4ee00", "--p-tabs": "#f6f4ee96", @@ -4526,7 +4526,7 @@ exports[`a saved opacity, as a ground alpha > paper: every N from 30 to 100 pain "--p-on-accent": "#0b0b0f", "--p-preview": "#d5d3cd", "--p-sel-bg": "#3f8ccb", - "--p-side": "#f6f4ee99", + "--p-side": "#f6f4ee00", "--p-side-flat": "#eeece6", "--p-tab-active": "#f6f4ee00", "--p-tabs": "#f6f4ee99", @@ -4552,7 +4552,7 @@ exports[`a saved opacity, as a ground alpha > paper: every N from 30 to 100 pain "--p-on-accent": "#0b0b0f", "--p-preview": "#d5d3cd", "--p-sel-bg": "#3f8ccb", - "--p-side": "#f6f4ee9c", + "--p-side": "#f6f4ee00", "--p-side-flat": "#eeece6", "--p-tab-active": "#f6f4ee00", "--p-tabs": "#f6f4ee9c", @@ -4578,7 +4578,7 @@ exports[`a saved opacity, as a ground alpha > paper: every N from 30 to 100 pain "--p-on-accent": "#0b0b0f", "--p-preview": "#d5d3cd", "--p-sel-bg": "#3f8ccb", - "--p-side": "#f6f4ee9e", + "--p-side": "#f6f4ee00", "--p-side-flat": "#eeece6", "--p-tab-active": "#f6f4ee00", "--p-tabs": "#f6f4ee9e", @@ -4604,7 +4604,7 @@ exports[`a saved opacity, as a ground alpha > paper: every N from 30 to 100 pain "--p-on-accent": "#0b0b0f", "--p-preview": "#d5d3cd", "--p-sel-bg": "#3f8ccb", - "--p-side": "#f6f4eea1", + "--p-side": "#f6f4ee00", "--p-side-flat": "#eeece6", "--p-tab-active": "#f6f4ee00", "--p-tabs": "#f6f4eea1", @@ -4630,7 +4630,7 @@ exports[`a saved opacity, as a ground alpha > paper: every N from 30 to 100 pain "--p-on-accent": "#0b0b0f", "--p-preview": "#d5d3cd", "--p-sel-bg": "#3f8ccb", - "--p-side": "#f6f4eea3", + "--p-side": "#f6f4ee00", "--p-side-flat": "#eeece6", "--p-tab-active": "#f6f4ee00", "--p-tabs": "#f6f4eea3", @@ -4656,7 +4656,7 @@ exports[`a saved opacity, as a ground alpha > paper: every N from 30 to 100 pain "--p-on-accent": "#0b0b0f", "--p-preview": "#d5d3cd", "--p-sel-bg": "#3f8ccb", - "--p-side": "#f6f4eea6", + "--p-side": "#f6f4ee00", "--p-side-flat": "#eeece6", "--p-tab-active": "#f6f4ee00", "--p-tabs": "#f6f4eea6", @@ -4682,7 +4682,7 @@ exports[`a saved opacity, as a ground alpha > paper: every N from 30 to 100 pain "--p-on-accent": "#0b0b0f", "--p-preview": "#d5d3cd", "--p-sel-bg": "#3f8ccb", - "--p-side": "#f6f4eea8", + "--p-side": "#f6f4ee00", "--p-side-flat": "#eeece6", "--p-tab-active": "#f6f4ee00", "--p-tabs": "#f6f4eea8", @@ -4708,7 +4708,7 @@ exports[`a saved opacity, as a ground alpha > paper: every N from 30 to 100 pain "--p-on-accent": "#0b0b0f", "--p-preview": "#d5d3cd", "--p-sel-bg": "#3f8ccb", - "--p-side": "#f6f4eeab", + "--p-side": "#f6f4ee00", "--p-side-flat": "#eeece6", "--p-tab-active": "#f6f4ee00", "--p-tabs": "#f6f4eeab", @@ -4734,7 +4734,7 @@ exports[`a saved opacity, as a ground alpha > paper: every N from 30 to 100 pain "--p-on-accent": "#0b0b0f", "--p-preview": "#d5d3cd", "--p-sel-bg": "#3f8ccb", - "--p-side": "#f6f4eead", + "--p-side": "#f6f4ee00", "--p-side-flat": "#eeece6", "--p-tab-active": "#f6f4ee00", "--p-tabs": "#f6f4eead", @@ -4760,7 +4760,7 @@ exports[`a saved opacity, as a ground alpha > paper: every N from 30 to 100 pain "--p-on-accent": "#0b0b0f", "--p-preview": "#d5d3cd", "--p-sel-bg": "#3f8ccb", - "--p-side": "#f6f4eeb0", + "--p-side": "#f6f4ee00", "--p-side-flat": "#eeece6", "--p-tab-active": "#f6f4ee00", "--p-tabs": "#f6f4eeb0", @@ -4786,7 +4786,7 @@ exports[`a saved opacity, as a ground alpha > paper: every N from 30 to 100 pain "--p-on-accent": "#0b0b0f", "--p-preview": "#d5d3cd", "--p-sel-bg": "#3f8ccb", - "--p-side": "#f6f4eeb3", + "--p-side": "#f6f4ee00", "--p-side-flat": "#eeece6", "--p-tab-active": "#f6f4ee00", "--p-tabs": "#f6f4eeb3", @@ -4812,7 +4812,7 @@ exports[`a saved opacity, as a ground alpha > paper: every N from 30 to 100 pain "--p-on-accent": "#0b0b0f", "--p-preview": "#d5d3cd", "--p-sel-bg": "#3f8ccb", - "--p-side": "#f6f4eeb5", + "--p-side": "#f6f4ee00", "--p-side-flat": "#eeece6", "--p-tab-active": "#f6f4ee00", "--p-tabs": "#f6f4eeb5", @@ -4838,7 +4838,7 @@ exports[`a saved opacity, as a ground alpha > paper: every N from 30 to 100 pain "--p-on-accent": "#0b0b0f", "--p-preview": "#d5d3cd", "--p-sel-bg": "#3f8ccb", - "--p-side": "#f6f4eeb8", + "--p-side": "#f6f4ee00", "--p-side-flat": "#eeece6", "--p-tab-active": "#f6f4ee00", "--p-tabs": "#f6f4eeb8", @@ -4864,7 +4864,7 @@ exports[`a saved opacity, as a ground alpha > paper: every N from 30 to 100 pain "--p-on-accent": "#0b0b0f", "--p-preview": "#d5d3cd", "--p-sel-bg": "#3f8ccb", - "--p-side": "#f6f4eeba", + "--p-side": "#f6f4ee00", "--p-side-flat": "#eeece6", "--p-tab-active": "#f6f4ee00", "--p-tabs": "#f6f4eeba", @@ -4890,7 +4890,7 @@ exports[`a saved opacity, as a ground alpha > paper: every N from 30 to 100 pain "--p-on-accent": "#0b0b0f", "--p-preview": "#d5d3cd", "--p-sel-bg": "#3f8ccb", - "--p-side": "#f6f4eebd", + "--p-side": "#f6f4ee00", "--p-side-flat": "#eeece6", "--p-tab-active": "#f6f4ee00", "--p-tabs": "#f6f4eebd", @@ -4916,7 +4916,7 @@ exports[`a saved opacity, as a ground alpha > paper: every N from 30 to 100 pain "--p-on-accent": "#0b0b0f", "--p-preview": "#d5d3cd", "--p-sel-bg": "#3f8ccb", - "--p-side": "#f6f4eebf", + "--p-side": "#f6f4ee00", "--p-side-flat": "#eeece6", "--p-tab-active": "#f6f4ee00", "--p-tabs": "#f6f4eebf", @@ -4942,7 +4942,7 @@ exports[`a saved opacity, as a ground alpha > paper: every N from 30 to 100 pain "--p-on-accent": "#0b0b0f", "--p-preview": "#d5d3cd", "--p-sel-bg": "#3f8ccb", - "--p-side": "#f6f4eec2", + "--p-side": "#f6f4ee00", "--p-side-flat": "#eeece6", "--p-tab-active": "#f6f4ee00", "--p-tabs": "#f6f4eec2", @@ -4968,7 +4968,7 @@ exports[`a saved opacity, as a ground alpha > paper: every N from 30 to 100 pain "--p-on-accent": "#0b0b0f", "--p-preview": "#d5d3cd", "--p-sel-bg": "#3f8ccb", - "--p-side": "#f6f4eec4", + "--p-side": "#f6f4ee00", "--p-side-flat": "#eeece6", "--p-tab-active": "#f6f4ee00", "--p-tabs": "#f6f4eec4", @@ -4994,7 +4994,7 @@ exports[`a saved opacity, as a ground alpha > paper: every N from 30 to 100 pain "--p-on-accent": "#0b0b0f", "--p-preview": "#d5d3cd", "--p-sel-bg": "#3f8ccb", - "--p-side": "#f6f4eec7", + "--p-side": "#f6f4ee00", "--p-side-flat": "#eeece6", "--p-tab-active": "#f6f4ee00", "--p-tabs": "#f6f4eec7", @@ -5020,7 +5020,7 @@ exports[`a saved opacity, as a ground alpha > paper: every N from 30 to 100 pain "--p-on-accent": "#0b0b0f", "--p-preview": "#d5d3cd", "--p-sel-bg": "#3f8ccb", - "--p-side": "#f6f4eec9", + "--p-side": "#f6f4ee00", "--p-side-flat": "#eeece6", "--p-tab-active": "#f6f4ee00", "--p-tabs": "#f6f4eec9", @@ -5046,7 +5046,7 @@ exports[`a saved opacity, as a ground alpha > paper: every N from 30 to 100 pain "--p-on-accent": "#0b0b0f", "--p-preview": "#d5d3cd", "--p-sel-bg": "#3f8ccb", - "--p-side": "#f6f4eecc", + "--p-side": "#f6f4ee00", "--p-side-flat": "#eeece6", "--p-tab-active": "#f6f4ee00", "--p-tabs": "#f6f4eecc", @@ -5072,7 +5072,7 @@ exports[`a saved opacity, as a ground alpha > paper: every N from 30 to 100 pain "--p-on-accent": "#0b0b0f", "--p-preview": "#d5d3cd", "--p-sel-bg": "#3f8ccb", - "--p-side": "#f6f4eecf", + "--p-side": "#f6f4ee00", "--p-side-flat": "#eeece6", "--p-tab-active": "#f6f4ee00", "--p-tabs": "#f6f4eecf", @@ -5098,7 +5098,7 @@ exports[`a saved opacity, as a ground alpha > paper: every N from 30 to 100 pain "--p-on-accent": "#0b0b0f", "--p-preview": "#d5d3cd", "--p-sel-bg": "#3f8ccb", - "--p-side": "#f6f4eed1", + "--p-side": "#f6f4ee00", "--p-side-flat": "#eeece6", "--p-tab-active": "#f6f4ee00", "--p-tabs": "#f6f4eed1", @@ -5124,7 +5124,7 @@ exports[`a saved opacity, as a ground alpha > paper: every N from 30 to 100 pain "--p-on-accent": "#0b0b0f", "--p-preview": "#d5d3cd", "--p-sel-bg": "#3f8ccb", - "--p-side": "#f6f4eed4", + "--p-side": "#f6f4ee00", "--p-side-flat": "#eeece6", "--p-tab-active": "#f6f4ee00", "--p-tabs": "#f6f4eed4", @@ -5150,7 +5150,7 @@ exports[`a saved opacity, as a ground alpha > paper: every N from 30 to 100 pain "--p-on-accent": "#0b0b0f", "--p-preview": "#d5d3cd", "--p-sel-bg": "#3f8ccb", - "--p-side": "#f6f4eed6", + "--p-side": "#f6f4ee00", "--p-side-flat": "#eeece6", "--p-tab-active": "#f6f4ee00", "--p-tabs": "#f6f4eed6", @@ -5176,7 +5176,7 @@ exports[`a saved opacity, as a ground alpha > paper: every N from 30 to 100 pain "--p-on-accent": "#0b0b0f", "--p-preview": "#d5d3cd", "--p-sel-bg": "#3f8ccb", - "--p-side": "#f6f4eed9", + "--p-side": "#f6f4ee00", "--p-side-flat": "#eeece6", "--p-tab-active": "#f6f4ee00", "--p-tabs": "#f6f4eed9", @@ -5202,7 +5202,7 @@ exports[`a saved opacity, as a ground alpha > paper: every N from 30 to 100 pain "--p-on-accent": "#0b0b0f", "--p-preview": "#d5d3cd", "--p-sel-bg": "#3f8ccb", - "--p-side": "#f6f4eedb", + "--p-side": "#f6f4ee00", "--p-side-flat": "#eeece6", "--p-tab-active": "#f6f4ee00", "--p-tabs": "#f6f4eedb", @@ -5228,7 +5228,7 @@ exports[`a saved opacity, as a ground alpha > paper: every N from 30 to 100 pain "--p-on-accent": "#0b0b0f", "--p-preview": "#d5d3cd", "--p-sel-bg": "#3f8ccb", - "--p-side": "#f6f4eede", + "--p-side": "#f6f4ee00", "--p-side-flat": "#eeece6", "--p-tab-active": "#f6f4ee00", "--p-tabs": "#f6f4eede", @@ -5254,7 +5254,7 @@ exports[`a saved opacity, as a ground alpha > paper: every N from 30 to 100 pain "--p-on-accent": "#0b0b0f", "--p-preview": "#d5d3cd", "--p-sel-bg": "#3f8ccb", - "--p-side": "#f6f4eee0", + "--p-side": "#f6f4ee00", "--p-side-flat": "#eeece6", "--p-tab-active": "#f6f4ee00", "--p-tabs": "#f6f4eee0", @@ -5280,7 +5280,7 @@ exports[`a saved opacity, as a ground alpha > paper: every N from 30 to 100 pain "--p-on-accent": "#0b0b0f", "--p-preview": "#d5d3cd", "--p-sel-bg": "#3f8ccb", - "--p-side": "#f6f4eee3", + "--p-side": "#f6f4ee00", "--p-side-flat": "#eeece6", "--p-tab-active": "#f6f4ee00", "--p-tabs": "#f6f4eee3", @@ -5306,7 +5306,7 @@ exports[`a saved opacity, as a ground alpha > paper: every N from 30 to 100 pain "--p-on-accent": "#0b0b0f", "--p-preview": "#d5d3cd", "--p-sel-bg": "#3f8ccb", - "--p-side": "#f6f4eee6", + "--p-side": "#f6f4ee00", "--p-side-flat": "#eeece6", "--p-tab-active": "#f6f4ee00", "--p-tabs": "#f6f4eee6", @@ -5332,7 +5332,7 @@ exports[`a saved opacity, as a ground alpha > paper: every N from 30 to 100 pain "--p-on-accent": "#0b0b0f", "--p-preview": "#d5d3cd", "--p-sel-bg": "#3f8ccb", - "--p-side": "#f6f4eee8", + "--p-side": "#f6f4ee00", "--p-side-flat": "#eeece6", "--p-tab-active": "#f6f4ee00", "--p-tabs": "#f6f4eee8", @@ -5358,7 +5358,7 @@ exports[`a saved opacity, as a ground alpha > paper: every N from 30 to 100 pain "--p-on-accent": "#0b0b0f", "--p-preview": "#d5d3cd", "--p-sel-bg": "#3f8ccb", - "--p-side": "#f6f4eeeb", + "--p-side": "#f6f4ee00", "--p-side-flat": "#eeece6", "--p-tab-active": "#f6f4ee00", "--p-tabs": "#f6f4eeeb", @@ -5384,7 +5384,7 @@ exports[`a saved opacity, as a ground alpha > paper: every N from 30 to 100 pain "--p-on-accent": "#0b0b0f", "--p-preview": "#d5d3cd", "--p-sel-bg": "#3f8ccb", - "--p-side": "#f6f4eeed", + "--p-side": "#f6f4ee00", "--p-side-flat": "#eeece6", "--p-tab-active": "#f6f4ee00", "--p-tabs": "#f6f4eeed", @@ -5410,7 +5410,7 @@ exports[`a saved opacity, as a ground alpha > paper: every N from 30 to 100 pain "--p-on-accent": "#0b0b0f", "--p-preview": "#d5d3cd", "--p-sel-bg": "#3f8ccb", - "--p-side": "#f6f4eef0", + "--p-side": "#f6f4ee00", "--p-side-flat": "#eeece6", "--p-tab-active": "#f6f4ee00", "--p-tabs": "#f6f4eef0", @@ -5436,7 +5436,7 @@ exports[`a saved opacity, as a ground alpha > paper: every N from 30 to 100 pain "--p-on-accent": "#0b0b0f", "--p-preview": "#d5d3cd", "--p-sel-bg": "#3f8ccb", - "--p-side": "#f6f4eef2", + "--p-side": "#f6f4ee00", "--p-side-flat": "#eeece6", "--p-tab-active": "#f6f4ee00", "--p-tabs": "#f6f4eef2", @@ -5462,7 +5462,7 @@ exports[`a saved opacity, as a ground alpha > paper: every N from 30 to 100 pain "--p-on-accent": "#0b0b0f", "--p-preview": "#d5d3cd", "--p-sel-bg": "#3f8ccb", - "--p-side": "#f6f4eef5", + "--p-side": "#f6f4ee00", "--p-side-flat": "#eeece6", "--p-tab-active": "#f6f4ee00", "--p-tabs": "#f6f4eef5", @@ -5488,7 +5488,7 @@ exports[`a saved opacity, as a ground alpha > paper: every N from 30 to 100 pain "--p-on-accent": "#0b0b0f", "--p-preview": "#d5d3cd", "--p-sel-bg": "#3f8ccb", - "--p-side": "#f6f4eef7", + "--p-side": "#f6f4ee00", "--p-side-flat": "#eeece6", "--p-tab-active": "#f6f4ee00", "--p-tabs": "#f6f4eef7", @@ -5514,7 +5514,7 @@ exports[`a saved opacity, as a ground alpha > paper: every N from 30 to 100 pain "--p-on-accent": "#0b0b0f", "--p-preview": "#d5d3cd", "--p-sel-bg": "#3f8ccb", - "--p-side": "#f6f4eefa", + "--p-side": "#f6f4ee00", "--p-side-flat": "#eeece6", "--p-tab-active": "#f6f4ee00", "--p-tabs": "#f6f4eefa", @@ -5540,7 +5540,7 @@ exports[`a saved opacity, as a ground alpha > paper: every N from 30 to 100 pain "--p-on-accent": "#0b0b0f", "--p-preview": "#d5d3cd", "--p-sel-bg": "#3f8ccb", - "--p-side": "#f6f4eefc", + "--p-side": "#f6f4ee00", "--p-side-flat": "#eeece6", "--p-tab-active": "#f6f4ee00", "--p-tabs": "#f6f4eefc", @@ -5597,7 +5597,7 @@ exports[`a saved opacity, as a ground alpha > prism: every N from 30 to 100 pain "--p-on-accent": "#0b0b0f", "--p-preview": "#28282c", "--p-sel-bg": "#4aa5f0", - "--p-side": "#0b0b0f4d", + "--p-side": "#0b0b0f00", "--p-side-flat": "#141418", "--p-tab-active": "#0b0b0f00", "--p-tabs": "#0b0b0f4d", @@ -5623,7 +5623,7 @@ exports[`a saved opacity, as a ground alpha > prism: every N from 30 to 100 pain "--p-on-accent": "#0b0b0f", "--p-preview": "#28282c", "--p-sel-bg": "#4aa5f0", - "--p-side": "#0b0b0f4f", + "--p-side": "#0b0b0f00", "--p-side-flat": "#141418", "--p-tab-active": "#0b0b0f00", "--p-tabs": "#0b0b0f4f", @@ -5649,7 +5649,7 @@ exports[`a saved opacity, as a ground alpha > prism: every N from 30 to 100 pain "--p-on-accent": "#0b0b0f", "--p-preview": "#28282c", "--p-sel-bg": "#4aa5f0", - "--p-side": "#0b0b0f52", + "--p-side": "#0b0b0f00", "--p-side-flat": "#141418", "--p-tab-active": "#0b0b0f00", "--p-tabs": "#0b0b0f52", @@ -5675,7 +5675,7 @@ exports[`a saved opacity, as a ground alpha > prism: every N from 30 to 100 pain "--p-on-accent": "#0b0b0f", "--p-preview": "#28282c", "--p-sel-bg": "#4aa5f0", - "--p-side": "#0b0b0f54", + "--p-side": "#0b0b0f00", "--p-side-flat": "#141418", "--p-tab-active": "#0b0b0f00", "--p-tabs": "#0b0b0f54", @@ -5701,7 +5701,7 @@ exports[`a saved opacity, as a ground alpha > prism: every N from 30 to 100 pain "--p-on-accent": "#0b0b0f", "--p-preview": "#28282c", "--p-sel-bg": "#4aa5f0", - "--p-side": "#0b0b0f57", + "--p-side": "#0b0b0f00", "--p-side-flat": "#141418", "--p-tab-active": "#0b0b0f00", "--p-tabs": "#0b0b0f57", @@ -5727,7 +5727,7 @@ exports[`a saved opacity, as a ground alpha > prism: every N from 30 to 100 pain "--p-on-accent": "#0b0b0f", "--p-preview": "#28282c", "--p-sel-bg": "#4aa5f0", - "--p-side": "#0b0b0f59", + "--p-side": "#0b0b0f00", "--p-side-flat": "#141418", "--p-tab-active": "#0b0b0f00", "--p-tabs": "#0b0b0f59", @@ -5753,7 +5753,7 @@ exports[`a saved opacity, as a ground alpha > prism: every N from 30 to 100 pain "--p-on-accent": "#0b0b0f", "--p-preview": "#28282c", "--p-sel-bg": "#4aa5f0", - "--p-side": "#0b0b0f5c", + "--p-side": "#0b0b0f00", "--p-side-flat": "#141418", "--p-tab-active": "#0b0b0f00", "--p-tabs": "#0b0b0f5c", @@ -5779,7 +5779,7 @@ exports[`a saved opacity, as a ground alpha > prism: every N from 30 to 100 pain "--p-on-accent": "#0b0b0f", "--p-preview": "#28282c", "--p-sel-bg": "#4aa5f0", - "--p-side": "#0b0b0f5e", + "--p-side": "#0b0b0f00", "--p-side-flat": "#141418", "--p-tab-active": "#0b0b0f00", "--p-tabs": "#0b0b0f5e", @@ -5805,7 +5805,7 @@ exports[`a saved opacity, as a ground alpha > prism: every N from 30 to 100 pain "--p-on-accent": "#0b0b0f", "--p-preview": "#28282c", "--p-sel-bg": "#4aa5f0", - "--p-side": "#0b0b0f61", + "--p-side": "#0b0b0f00", "--p-side-flat": "#141418", "--p-tab-active": "#0b0b0f00", "--p-tabs": "#0b0b0f61", @@ -5831,7 +5831,7 @@ exports[`a saved opacity, as a ground alpha > prism: every N from 30 to 100 pain "--p-on-accent": "#0b0b0f", "--p-preview": "#28282c", "--p-sel-bg": "#4aa5f0", - "--p-side": "#0b0b0f63", + "--p-side": "#0b0b0f00", "--p-side-flat": "#141418", "--p-tab-active": "#0b0b0f00", "--p-tabs": "#0b0b0f63", @@ -5857,7 +5857,7 @@ exports[`a saved opacity, as a ground alpha > prism: every N from 30 to 100 pain "--p-on-accent": "#0b0b0f", "--p-preview": "#28282c", "--p-sel-bg": "#4aa5f0", - "--p-side": "#0b0b0f66", + "--p-side": "#0b0b0f00", "--p-side-flat": "#141418", "--p-tab-active": "#0b0b0f00", "--p-tabs": "#0b0b0f66", @@ -5883,7 +5883,7 @@ exports[`a saved opacity, as a ground alpha > prism: every N from 30 to 100 pain "--p-on-accent": "#0b0b0f", "--p-preview": "#28282c", "--p-sel-bg": "#4aa5f0", - "--p-side": "#0b0b0f69", + "--p-side": "#0b0b0f00", "--p-side-flat": "#141418", "--p-tab-active": "#0b0b0f00", "--p-tabs": "#0b0b0f69", @@ -5909,7 +5909,7 @@ exports[`a saved opacity, as a ground alpha > prism: every N from 30 to 100 pain "--p-on-accent": "#0b0b0f", "--p-preview": "#28282c", "--p-sel-bg": "#4aa5f0", - "--p-side": "#0b0b0f6b", + "--p-side": "#0b0b0f00", "--p-side-flat": "#141418", "--p-tab-active": "#0b0b0f00", "--p-tabs": "#0b0b0f6b", @@ -5935,7 +5935,7 @@ exports[`a saved opacity, as a ground alpha > prism: every N from 30 to 100 pain "--p-on-accent": "#0b0b0f", "--p-preview": "#28282c", "--p-sel-bg": "#4aa5f0", - "--p-side": "#0b0b0f6e", + "--p-side": "#0b0b0f00", "--p-side-flat": "#141418", "--p-tab-active": "#0b0b0f00", "--p-tabs": "#0b0b0f6e", @@ -5961,7 +5961,7 @@ exports[`a saved opacity, as a ground alpha > prism: every N from 30 to 100 pain "--p-on-accent": "#0b0b0f", "--p-preview": "#28282c", "--p-sel-bg": "#4aa5f0", - "--p-side": "#0b0b0f70", + "--p-side": "#0b0b0f00", "--p-side-flat": "#141418", "--p-tab-active": "#0b0b0f00", "--p-tabs": "#0b0b0f70", @@ -5987,7 +5987,7 @@ exports[`a saved opacity, as a ground alpha > prism: every N from 30 to 100 pain "--p-on-accent": "#0b0b0f", "--p-preview": "#28282c", "--p-sel-bg": "#4aa5f0", - "--p-side": "#0b0b0f73", + "--p-side": "#0b0b0f00", "--p-side-flat": "#141418", "--p-tab-active": "#0b0b0f00", "--p-tabs": "#0b0b0f73", @@ -6013,7 +6013,7 @@ exports[`a saved opacity, as a ground alpha > prism: every N from 30 to 100 pain "--p-on-accent": "#0b0b0f", "--p-preview": "#28282c", "--p-sel-bg": "#4aa5f0", - "--p-side": "#0b0b0f75", + "--p-side": "#0b0b0f00", "--p-side-flat": "#141418", "--p-tab-active": "#0b0b0f00", "--p-tabs": "#0b0b0f75", @@ -6039,7 +6039,7 @@ exports[`a saved opacity, as a ground alpha > prism: every N from 30 to 100 pain "--p-on-accent": "#0b0b0f", "--p-preview": "#28282c", "--p-sel-bg": "#4aa5f0", - "--p-side": "#0b0b0f78", + "--p-side": "#0b0b0f00", "--p-side-flat": "#141418", "--p-tab-active": "#0b0b0f00", "--p-tabs": "#0b0b0f78", @@ -6065,7 +6065,7 @@ exports[`a saved opacity, as a ground alpha > prism: every N from 30 to 100 pain "--p-on-accent": "#0b0b0f", "--p-preview": "#28282c", "--p-sel-bg": "#4aa5f0", - "--p-side": "#0b0b0f7a", + "--p-side": "#0b0b0f00", "--p-side-flat": "#141418", "--p-tab-active": "#0b0b0f00", "--p-tabs": "#0b0b0f7a", @@ -6091,7 +6091,7 @@ exports[`a saved opacity, as a ground alpha > prism: every N from 30 to 100 pain "--p-on-accent": "#0b0b0f", "--p-preview": "#28282c", "--p-sel-bg": "#4aa5f0", - "--p-side": "#0b0b0f7d", + "--p-side": "#0b0b0f00", "--p-side-flat": "#141418", "--p-tab-active": "#0b0b0f00", "--p-tabs": "#0b0b0f7d", @@ -6117,7 +6117,7 @@ exports[`a saved opacity, as a ground alpha > prism: every N from 30 to 100 pain "--p-on-accent": "#0b0b0f", "--p-preview": "#28282c", "--p-sel-bg": "#4aa5f0", - "--p-side": "#0b0b0f80", + "--p-side": "#0b0b0f00", "--p-side-flat": "#141418", "--p-tab-active": "#0b0b0f00", "--p-tabs": "#0b0b0f80", @@ -6143,7 +6143,7 @@ exports[`a saved opacity, as a ground alpha > prism: every N from 30 to 100 pain "--p-on-accent": "#0b0b0f", "--p-preview": "#28282c", "--p-sel-bg": "#4aa5f0", - "--p-side": "#0b0b0f82", + "--p-side": "#0b0b0f00", "--p-side-flat": "#141418", "--p-tab-active": "#0b0b0f00", "--p-tabs": "#0b0b0f82", @@ -6169,7 +6169,7 @@ exports[`a saved opacity, as a ground alpha > prism: every N from 30 to 100 pain "--p-on-accent": "#0b0b0f", "--p-preview": "#28282c", "--p-sel-bg": "#4aa5f0", - "--p-side": "#0b0b0f85", + "--p-side": "#0b0b0f00", "--p-side-flat": "#141418", "--p-tab-active": "#0b0b0f00", "--p-tabs": "#0b0b0f85", @@ -6195,7 +6195,7 @@ exports[`a saved opacity, as a ground alpha > prism: every N from 30 to 100 pain "--p-on-accent": "#0b0b0f", "--p-preview": "#28282c", "--p-sel-bg": "#4aa5f0", - "--p-side": "#0b0b0f87", + "--p-side": "#0b0b0f00", "--p-side-flat": "#141418", "--p-tab-active": "#0b0b0f00", "--p-tabs": "#0b0b0f87", @@ -6221,7 +6221,7 @@ exports[`a saved opacity, as a ground alpha > prism: every N from 30 to 100 pain "--p-on-accent": "#0b0b0f", "--p-preview": "#28282c", "--p-sel-bg": "#4aa5f0", - "--p-side": "#0b0b0f8a", + "--p-side": "#0b0b0f00", "--p-side-flat": "#141418", "--p-tab-active": "#0b0b0f00", "--p-tabs": "#0b0b0f8a", @@ -6247,7 +6247,7 @@ exports[`a saved opacity, as a ground alpha > prism: every N from 30 to 100 pain "--p-on-accent": "#0b0b0f", "--p-preview": "#28282c", "--p-sel-bg": "#4aa5f0", - "--p-side": "#0b0b0f8c", + "--p-side": "#0b0b0f00", "--p-side-flat": "#141418", "--p-tab-active": "#0b0b0f00", "--p-tabs": "#0b0b0f8c", @@ -6273,7 +6273,7 @@ exports[`a saved opacity, as a ground alpha > prism: every N from 30 to 100 pain "--p-on-accent": "#0b0b0f", "--p-preview": "#28282c", "--p-sel-bg": "#4aa5f0", - "--p-side": "#0b0b0f8f", + "--p-side": "#0b0b0f00", "--p-side-flat": "#141418", "--p-tab-active": "#0b0b0f00", "--p-tabs": "#0b0b0f8f", @@ -6299,7 +6299,7 @@ exports[`a saved opacity, as a ground alpha > prism: every N from 30 to 100 pain "--p-on-accent": "#0b0b0f", "--p-preview": "#28282c", "--p-sel-bg": "#4aa5f0", - "--p-side": "#0b0b0f91", + "--p-side": "#0b0b0f00", "--p-side-flat": "#141418", "--p-tab-active": "#0b0b0f00", "--p-tabs": "#0b0b0f91", @@ -6325,7 +6325,7 @@ exports[`a saved opacity, as a ground alpha > prism: every N from 30 to 100 pain "--p-on-accent": "#0b0b0f", "--p-preview": "#28282c", "--p-sel-bg": "#4aa5f0", - "--p-side": "#0b0b0f94", + "--p-side": "#0b0b0f00", "--p-side-flat": "#141418", "--p-tab-active": "#0b0b0f00", "--p-tabs": "#0b0b0f94", @@ -6351,7 +6351,7 @@ exports[`a saved opacity, as a ground alpha > prism: every N from 30 to 100 pain "--p-on-accent": "#0b0b0f", "--p-preview": "#28282c", "--p-sel-bg": "#4aa5f0", - "--p-side": "#0b0b0f96", + "--p-side": "#0b0b0f00", "--p-side-flat": "#141418", "--p-tab-active": "#0b0b0f00", "--p-tabs": "#0b0b0f96", @@ -6377,7 +6377,7 @@ exports[`a saved opacity, as a ground alpha > prism: every N from 30 to 100 pain "--p-on-accent": "#0b0b0f", "--p-preview": "#28282c", "--p-sel-bg": "#4aa5f0", - "--p-side": "#0b0b0f99", + "--p-side": "#0b0b0f00", "--p-side-flat": "#141418", "--p-tab-active": "#0b0b0f00", "--p-tabs": "#0b0b0f99", @@ -6403,7 +6403,7 @@ exports[`a saved opacity, as a ground alpha > prism: every N from 30 to 100 pain "--p-on-accent": "#0b0b0f", "--p-preview": "#28282c", "--p-sel-bg": "#4aa5f0", - "--p-side": "#0b0b0f9c", + "--p-side": "#0b0b0f00", "--p-side-flat": "#141418", "--p-tab-active": "#0b0b0f00", "--p-tabs": "#0b0b0f9c", @@ -6429,7 +6429,7 @@ exports[`a saved opacity, as a ground alpha > prism: every N from 30 to 100 pain "--p-on-accent": "#0b0b0f", "--p-preview": "#28282c", "--p-sel-bg": "#4aa5f0", - "--p-side": "#0b0b0f9e", + "--p-side": "#0b0b0f00", "--p-side-flat": "#141418", "--p-tab-active": "#0b0b0f00", "--p-tabs": "#0b0b0f9e", @@ -6455,7 +6455,7 @@ exports[`a saved opacity, as a ground alpha > prism: every N from 30 to 100 pain "--p-on-accent": "#0b0b0f", "--p-preview": "#28282c", "--p-sel-bg": "#4aa5f0", - "--p-side": "#0b0b0fa1", + "--p-side": "#0b0b0f00", "--p-side-flat": "#141418", "--p-tab-active": "#0b0b0f00", "--p-tabs": "#0b0b0fa1", @@ -6481,7 +6481,7 @@ exports[`a saved opacity, as a ground alpha > prism: every N from 30 to 100 pain "--p-on-accent": "#0b0b0f", "--p-preview": "#28282c", "--p-sel-bg": "#4aa5f0", - "--p-side": "#0b0b0fa3", + "--p-side": "#0b0b0f00", "--p-side-flat": "#141418", "--p-tab-active": "#0b0b0f00", "--p-tabs": "#0b0b0fa3", @@ -6507,7 +6507,7 @@ exports[`a saved opacity, as a ground alpha > prism: every N from 30 to 100 pain "--p-on-accent": "#0b0b0f", "--p-preview": "#28282c", "--p-sel-bg": "#4aa5f0", - "--p-side": "#0b0b0fa6", + "--p-side": "#0b0b0f00", "--p-side-flat": "#141418", "--p-tab-active": "#0b0b0f00", "--p-tabs": "#0b0b0fa6", @@ -6533,7 +6533,7 @@ exports[`a saved opacity, as a ground alpha > prism: every N from 30 to 100 pain "--p-on-accent": "#0b0b0f", "--p-preview": "#28282c", "--p-sel-bg": "#4aa5f0", - "--p-side": "#0b0b0fa8", + "--p-side": "#0b0b0f00", "--p-side-flat": "#141418", "--p-tab-active": "#0b0b0f00", "--p-tabs": "#0b0b0fa8", @@ -6559,7 +6559,7 @@ exports[`a saved opacity, as a ground alpha > prism: every N from 30 to 100 pain "--p-on-accent": "#0b0b0f", "--p-preview": "#28282c", "--p-sel-bg": "#4aa5f0", - "--p-side": "#0b0b0fab", + "--p-side": "#0b0b0f00", "--p-side-flat": "#141418", "--p-tab-active": "#0b0b0f00", "--p-tabs": "#0b0b0fab", @@ -6585,7 +6585,7 @@ exports[`a saved opacity, as a ground alpha > prism: every N from 30 to 100 pain "--p-on-accent": "#0b0b0f", "--p-preview": "#28282c", "--p-sel-bg": "#4aa5f0", - "--p-side": "#0b0b0fad", + "--p-side": "#0b0b0f00", "--p-side-flat": "#141418", "--p-tab-active": "#0b0b0f00", "--p-tabs": "#0b0b0fad", @@ -6611,7 +6611,7 @@ exports[`a saved opacity, as a ground alpha > prism: every N from 30 to 100 pain "--p-on-accent": "#0b0b0f", "--p-preview": "#28282c", "--p-sel-bg": "#4aa5f0", - "--p-side": "#0b0b0fb0", + "--p-side": "#0b0b0f00", "--p-side-flat": "#141418", "--p-tab-active": "#0b0b0f00", "--p-tabs": "#0b0b0fb0", @@ -6637,7 +6637,7 @@ exports[`a saved opacity, as a ground alpha > prism: every N from 30 to 100 pain "--p-on-accent": "#0b0b0f", "--p-preview": "#28282c", "--p-sel-bg": "#4aa5f0", - "--p-side": "#0b0b0fb3", + "--p-side": "#0b0b0f00", "--p-side-flat": "#141418", "--p-tab-active": "#0b0b0f00", "--p-tabs": "#0b0b0fb3", @@ -6663,7 +6663,7 @@ exports[`a saved opacity, as a ground alpha > prism: every N from 30 to 100 pain "--p-on-accent": "#0b0b0f", "--p-preview": "#28282c", "--p-sel-bg": "#4aa5f0", - "--p-side": "#0b0b0fb5", + "--p-side": "#0b0b0f00", "--p-side-flat": "#141418", "--p-tab-active": "#0b0b0f00", "--p-tabs": "#0b0b0fb5", @@ -6689,7 +6689,7 @@ exports[`a saved opacity, as a ground alpha > prism: every N from 30 to 100 pain "--p-on-accent": "#0b0b0f", "--p-preview": "#28282c", "--p-sel-bg": "#4aa5f0", - "--p-side": "#0b0b0fb8", + "--p-side": "#0b0b0f00", "--p-side-flat": "#141418", "--p-tab-active": "#0b0b0f00", "--p-tabs": "#0b0b0fb8", @@ -6715,7 +6715,7 @@ exports[`a saved opacity, as a ground alpha > prism: every N from 30 to 100 pain "--p-on-accent": "#0b0b0f", "--p-preview": "#28282c", "--p-sel-bg": "#4aa5f0", - "--p-side": "#0b0b0fba", + "--p-side": "#0b0b0f00", "--p-side-flat": "#141418", "--p-tab-active": "#0b0b0f00", "--p-tabs": "#0b0b0fba", @@ -6741,7 +6741,7 @@ exports[`a saved opacity, as a ground alpha > prism: every N from 30 to 100 pain "--p-on-accent": "#0b0b0f", "--p-preview": "#28282c", "--p-sel-bg": "#4aa5f0", - "--p-side": "#0b0b0fbd", + "--p-side": "#0b0b0f00", "--p-side-flat": "#141418", "--p-tab-active": "#0b0b0f00", "--p-tabs": "#0b0b0fbd", @@ -6767,7 +6767,7 @@ exports[`a saved opacity, as a ground alpha > prism: every N from 30 to 100 pain "--p-on-accent": "#0b0b0f", "--p-preview": "#28282c", "--p-sel-bg": "#4aa5f0", - "--p-side": "#0b0b0fbf", + "--p-side": "#0b0b0f00", "--p-side-flat": "#141418", "--p-tab-active": "#0b0b0f00", "--p-tabs": "#0b0b0fbf", @@ -6793,7 +6793,7 @@ exports[`a saved opacity, as a ground alpha > prism: every N from 30 to 100 pain "--p-on-accent": "#0b0b0f", "--p-preview": "#28282c", "--p-sel-bg": "#4aa5f0", - "--p-side": "#0b0b0fc2", + "--p-side": "#0b0b0f00", "--p-side-flat": "#141418", "--p-tab-active": "#0b0b0f00", "--p-tabs": "#0b0b0fc2", @@ -6819,7 +6819,7 @@ exports[`a saved opacity, as a ground alpha > prism: every N from 30 to 100 pain "--p-on-accent": "#0b0b0f", "--p-preview": "#28282c", "--p-sel-bg": "#4aa5f0", - "--p-side": "#0b0b0fc4", + "--p-side": "#0b0b0f00", "--p-side-flat": "#141418", "--p-tab-active": "#0b0b0f00", "--p-tabs": "#0b0b0fc4", @@ -6845,7 +6845,7 @@ exports[`a saved opacity, as a ground alpha > prism: every N from 30 to 100 pain "--p-on-accent": "#0b0b0f", "--p-preview": "#28282c", "--p-sel-bg": "#4aa5f0", - "--p-side": "#0b0b0fc7", + "--p-side": "#0b0b0f00", "--p-side-flat": "#141418", "--p-tab-active": "#0b0b0f00", "--p-tabs": "#0b0b0fc7", @@ -6871,7 +6871,7 @@ exports[`a saved opacity, as a ground alpha > prism: every N from 30 to 100 pain "--p-on-accent": "#0b0b0f", "--p-preview": "#28282c", "--p-sel-bg": "#4aa5f0", - "--p-side": "#0b0b0fc9", + "--p-side": "#0b0b0f00", "--p-side-flat": "#141418", "--p-tab-active": "#0b0b0f00", "--p-tabs": "#0b0b0fc9", @@ -6897,7 +6897,7 @@ exports[`a saved opacity, as a ground alpha > prism: every N from 30 to 100 pain "--p-on-accent": "#0b0b0f", "--p-preview": "#28282c", "--p-sel-bg": "#4aa5f0", - "--p-side": "#0b0b0fcc", + "--p-side": "#0b0b0f00", "--p-side-flat": "#141418", "--p-tab-active": "#0b0b0f00", "--p-tabs": "#0b0b0fcc", @@ -6923,7 +6923,7 @@ exports[`a saved opacity, as a ground alpha > prism: every N from 30 to 100 pain "--p-on-accent": "#0b0b0f", "--p-preview": "#28282c", "--p-sel-bg": "#4aa5f0", - "--p-side": "#0b0b0fcf", + "--p-side": "#0b0b0f00", "--p-side-flat": "#141418", "--p-tab-active": "#0b0b0f00", "--p-tabs": "#0b0b0fcf", @@ -6949,7 +6949,7 @@ exports[`a saved opacity, as a ground alpha > prism: every N from 30 to 100 pain "--p-on-accent": "#0b0b0f", "--p-preview": "#28282c", "--p-sel-bg": "#4aa5f0", - "--p-side": "#0b0b0fd1", + "--p-side": "#0b0b0f00", "--p-side-flat": "#141418", "--p-tab-active": "#0b0b0f00", "--p-tabs": "#0b0b0fd1", @@ -6975,7 +6975,7 @@ exports[`a saved opacity, as a ground alpha > prism: every N from 30 to 100 pain "--p-on-accent": "#0b0b0f", "--p-preview": "#28282c", "--p-sel-bg": "#4aa5f0", - "--p-side": "#0b0b0fd4", + "--p-side": "#0b0b0f00", "--p-side-flat": "#141418", "--p-tab-active": "#0b0b0f00", "--p-tabs": "#0b0b0fd4", @@ -7001,7 +7001,7 @@ exports[`a saved opacity, as a ground alpha > prism: every N from 30 to 100 pain "--p-on-accent": "#0b0b0f", "--p-preview": "#28282c", "--p-sel-bg": "#4aa5f0", - "--p-side": "#0b0b0fd6", + "--p-side": "#0b0b0f00", "--p-side-flat": "#141418", "--p-tab-active": "#0b0b0f00", "--p-tabs": "#0b0b0fd6", @@ -7027,7 +7027,7 @@ exports[`a saved opacity, as a ground alpha > prism: every N from 30 to 100 pain "--p-on-accent": "#0b0b0f", "--p-preview": "#28282c", "--p-sel-bg": "#4aa5f0", - "--p-side": "#0b0b0fd9", + "--p-side": "#0b0b0f00", "--p-side-flat": "#141418", "--p-tab-active": "#0b0b0f00", "--p-tabs": "#0b0b0fd9", @@ -7053,7 +7053,7 @@ exports[`a saved opacity, as a ground alpha > prism: every N from 30 to 100 pain "--p-on-accent": "#0b0b0f", "--p-preview": "#28282c", "--p-sel-bg": "#4aa5f0", - "--p-side": "#0b0b0fdb", + "--p-side": "#0b0b0f00", "--p-side-flat": "#141418", "--p-tab-active": "#0b0b0f00", "--p-tabs": "#0b0b0fdb", @@ -7079,7 +7079,7 @@ exports[`a saved opacity, as a ground alpha > prism: every N from 30 to 100 pain "--p-on-accent": "#0b0b0f", "--p-preview": "#28282c", "--p-sel-bg": "#4aa5f0", - "--p-side": "#0b0b0fde", + "--p-side": "#0b0b0f00", "--p-side-flat": "#141418", "--p-tab-active": "#0b0b0f00", "--p-tabs": "#0b0b0fde", @@ -7105,7 +7105,7 @@ exports[`a saved opacity, as a ground alpha > prism: every N from 30 to 100 pain "--p-on-accent": "#0b0b0f", "--p-preview": "#28282c", "--p-sel-bg": "#4aa5f0", - "--p-side": "#0b0b0fe0", + "--p-side": "#0b0b0f00", "--p-side-flat": "#141418", "--p-tab-active": "#0b0b0f00", "--p-tabs": "#0b0b0fe0", @@ -7131,7 +7131,7 @@ exports[`a saved opacity, as a ground alpha > prism: every N from 30 to 100 pain "--p-on-accent": "#0b0b0f", "--p-preview": "#28282c", "--p-sel-bg": "#4aa5f0", - "--p-side": "#0b0b0fe3", + "--p-side": "#0b0b0f00", "--p-side-flat": "#141418", "--p-tab-active": "#0b0b0f00", "--p-tabs": "#0b0b0fe3", @@ -7157,7 +7157,7 @@ exports[`a saved opacity, as a ground alpha > prism: every N from 30 to 100 pain "--p-on-accent": "#0b0b0f", "--p-preview": "#28282c", "--p-sel-bg": "#4aa5f0", - "--p-side": "#0b0b0fe6", + "--p-side": "#0b0b0f00", "--p-side-flat": "#141418", "--p-tab-active": "#0b0b0f00", "--p-tabs": "#0b0b0fe6", @@ -7183,7 +7183,7 @@ exports[`a saved opacity, as a ground alpha > prism: every N from 30 to 100 pain "--p-on-accent": "#0b0b0f", "--p-preview": "#28282c", "--p-sel-bg": "#4aa5f0", - "--p-side": "#0b0b0fe8", + "--p-side": "#0b0b0f00", "--p-side-flat": "#141418", "--p-tab-active": "#0b0b0f00", "--p-tabs": "#0b0b0fe8", @@ -7209,7 +7209,7 @@ exports[`a saved opacity, as a ground alpha > prism: every N from 30 to 100 pain "--p-on-accent": "#0b0b0f", "--p-preview": "#28282c", "--p-sel-bg": "#4aa5f0", - "--p-side": "#0b0b0feb", + "--p-side": "#0b0b0f00", "--p-side-flat": "#141418", "--p-tab-active": "#0b0b0f00", "--p-tabs": "#0b0b0feb", @@ -7235,7 +7235,7 @@ exports[`a saved opacity, as a ground alpha > prism: every N from 30 to 100 pain "--p-on-accent": "#0b0b0f", "--p-preview": "#28282c", "--p-sel-bg": "#4aa5f0", - "--p-side": "#0b0b0fed", + "--p-side": "#0b0b0f00", "--p-side-flat": "#141418", "--p-tab-active": "#0b0b0f00", "--p-tabs": "#0b0b0fed", @@ -7261,7 +7261,7 @@ exports[`a saved opacity, as a ground alpha > prism: every N from 30 to 100 pain "--p-on-accent": "#0b0b0f", "--p-preview": "#28282c", "--p-sel-bg": "#4aa5f0", - "--p-side": "#0b0b0ff0", + "--p-side": "#0b0b0f00", "--p-side-flat": "#141418", "--p-tab-active": "#0b0b0f00", "--p-tabs": "#0b0b0ff0", @@ -7287,7 +7287,7 @@ exports[`a saved opacity, as a ground alpha > prism: every N from 30 to 100 pain "--p-on-accent": "#0b0b0f", "--p-preview": "#28282c", "--p-sel-bg": "#4aa5f0", - "--p-side": "#0b0b0ff2", + "--p-side": "#0b0b0f00", "--p-side-flat": "#141418", "--p-tab-active": "#0b0b0f00", "--p-tabs": "#0b0b0ff2", @@ -7313,7 +7313,7 @@ exports[`a saved opacity, as a ground alpha > prism: every N from 30 to 100 pain "--p-on-accent": "#0b0b0f", "--p-preview": "#28282c", "--p-sel-bg": "#4aa5f0", - "--p-side": "#0b0b0ff5", + "--p-side": "#0b0b0f00", "--p-side-flat": "#141418", "--p-tab-active": "#0b0b0f00", "--p-tabs": "#0b0b0ff5", @@ -7339,7 +7339,7 @@ exports[`a saved opacity, as a ground alpha > prism: every N from 30 to 100 pain "--p-on-accent": "#0b0b0f", "--p-preview": "#28282c", "--p-sel-bg": "#4aa5f0", - "--p-side": "#0b0b0ff7", + "--p-side": "#0b0b0f00", "--p-side-flat": "#141418", "--p-tab-active": "#0b0b0f00", "--p-tabs": "#0b0b0ff7", @@ -7365,7 +7365,7 @@ exports[`a saved opacity, as a ground alpha > prism: every N from 30 to 100 pain "--p-on-accent": "#0b0b0f", "--p-preview": "#28282c", "--p-sel-bg": "#4aa5f0", - "--p-side": "#0b0b0ffa", + "--p-side": "#0b0b0f00", "--p-side-flat": "#141418", "--p-tab-active": "#0b0b0f00", "--p-tabs": "#0b0b0ffa", @@ -7391,7 +7391,7 @@ exports[`a saved opacity, as a ground alpha > prism: every N from 30 to 100 pain "--p-on-accent": "#0b0b0f", "--p-preview": "#28282c", "--p-sel-bg": "#4aa5f0", - "--p-side": "#0b0b0ffc", + "--p-side": "#0b0b0f00", "--p-side-flat": "#141418", "--p-tab-active": "#0b0b0f00", "--p-tabs": "#0b0b0ffc", @@ -7448,7 +7448,7 @@ exports[`a saved opacity, as a ground alpha > pt-default: every N from 30 to 100 "--p-on-accent": "#0b0b0f", "--p-preview": "#2d2c2b", "--p-sel-bg": "#5da9f6", - "--p-side": "#1212124d", + "--p-side": "#12121200", "--p-side-flat": "#1a1a1a", "--p-tab-active": "#12121200", "--p-tabs": "#1212124d", @@ -7474,7 +7474,7 @@ exports[`a saved opacity, as a ground alpha > pt-default: every N from 30 to 100 "--p-on-accent": "#0b0b0f", "--p-preview": "#2d2c2b", "--p-sel-bg": "#5da9f6", - "--p-side": "#1212124f", + "--p-side": "#12121200", "--p-side-flat": "#1a1a1a", "--p-tab-active": "#12121200", "--p-tabs": "#1212124f", @@ -7500,7 +7500,7 @@ exports[`a saved opacity, as a ground alpha > pt-default: every N from 30 to 100 "--p-on-accent": "#0b0b0f", "--p-preview": "#2d2c2b", "--p-sel-bg": "#5da9f6", - "--p-side": "#12121252", + "--p-side": "#12121200", "--p-side-flat": "#1a1a1a", "--p-tab-active": "#12121200", "--p-tabs": "#12121252", @@ -7526,7 +7526,7 @@ exports[`a saved opacity, as a ground alpha > pt-default: every N from 30 to 100 "--p-on-accent": "#0b0b0f", "--p-preview": "#2d2c2b", "--p-sel-bg": "#5da9f6", - "--p-side": "#12121254", + "--p-side": "#12121200", "--p-side-flat": "#1a1a1a", "--p-tab-active": "#12121200", "--p-tabs": "#12121254", @@ -7552,7 +7552,7 @@ exports[`a saved opacity, as a ground alpha > pt-default: every N from 30 to 100 "--p-on-accent": "#0b0b0f", "--p-preview": "#2d2c2b", "--p-sel-bg": "#5da9f6", - "--p-side": "#12121257", + "--p-side": "#12121200", "--p-side-flat": "#1a1a1a", "--p-tab-active": "#12121200", "--p-tabs": "#12121257", @@ -7578,7 +7578,7 @@ exports[`a saved opacity, as a ground alpha > pt-default: every N from 30 to 100 "--p-on-accent": "#0b0b0f", "--p-preview": "#2d2c2b", "--p-sel-bg": "#5da9f6", - "--p-side": "#12121259", + "--p-side": "#12121200", "--p-side-flat": "#1a1a1a", "--p-tab-active": "#12121200", "--p-tabs": "#12121259", @@ -7604,7 +7604,7 @@ exports[`a saved opacity, as a ground alpha > pt-default: every N from 30 to 100 "--p-on-accent": "#0b0b0f", "--p-preview": "#2d2c2b", "--p-sel-bg": "#5da9f6", - "--p-side": "#1212125c", + "--p-side": "#12121200", "--p-side-flat": "#1a1a1a", "--p-tab-active": "#12121200", "--p-tabs": "#1212125c", @@ -7630,7 +7630,7 @@ exports[`a saved opacity, as a ground alpha > pt-default: every N from 30 to 100 "--p-on-accent": "#0b0b0f", "--p-preview": "#2d2c2b", "--p-sel-bg": "#5da9f6", - "--p-side": "#1212125e", + "--p-side": "#12121200", "--p-side-flat": "#1a1a1a", "--p-tab-active": "#12121200", "--p-tabs": "#1212125e", @@ -7656,7 +7656,7 @@ exports[`a saved opacity, as a ground alpha > pt-default: every N from 30 to 100 "--p-on-accent": "#0b0b0f", "--p-preview": "#2d2c2b", "--p-sel-bg": "#5da9f6", - "--p-side": "#12121261", + "--p-side": "#12121200", "--p-side-flat": "#1a1a1a", "--p-tab-active": "#12121200", "--p-tabs": "#12121261", @@ -7682,7 +7682,7 @@ exports[`a saved opacity, as a ground alpha > pt-default: every N from 30 to 100 "--p-on-accent": "#0b0b0f", "--p-preview": "#2d2c2b", "--p-sel-bg": "#5da9f6", - "--p-side": "#12121263", + "--p-side": "#12121200", "--p-side-flat": "#1a1a1a", "--p-tab-active": "#12121200", "--p-tabs": "#12121263", @@ -7708,7 +7708,7 @@ exports[`a saved opacity, as a ground alpha > pt-default: every N from 30 to 100 "--p-on-accent": "#0b0b0f", "--p-preview": "#2d2c2b", "--p-sel-bg": "#5da9f6", - "--p-side": "#12121266", + "--p-side": "#12121200", "--p-side-flat": "#1a1a1a", "--p-tab-active": "#12121200", "--p-tabs": "#12121266", @@ -7734,7 +7734,7 @@ exports[`a saved opacity, as a ground alpha > pt-default: every N from 30 to 100 "--p-on-accent": "#0b0b0f", "--p-preview": "#2d2c2b", "--p-sel-bg": "#5da9f6", - "--p-side": "#12121269", + "--p-side": "#12121200", "--p-side-flat": "#1a1a1a", "--p-tab-active": "#12121200", "--p-tabs": "#12121269", @@ -7760,7 +7760,7 @@ exports[`a saved opacity, as a ground alpha > pt-default: every N from 30 to 100 "--p-on-accent": "#0b0b0f", "--p-preview": "#2d2c2b", "--p-sel-bg": "#5da9f6", - "--p-side": "#1212126b", + "--p-side": "#12121200", "--p-side-flat": "#1a1a1a", "--p-tab-active": "#12121200", "--p-tabs": "#1212126b", @@ -7786,7 +7786,7 @@ exports[`a saved opacity, as a ground alpha > pt-default: every N from 30 to 100 "--p-on-accent": "#0b0b0f", "--p-preview": "#2d2c2b", "--p-sel-bg": "#5da9f6", - "--p-side": "#1212126e", + "--p-side": "#12121200", "--p-side-flat": "#1a1a1a", "--p-tab-active": "#12121200", "--p-tabs": "#1212126e", @@ -7812,7 +7812,7 @@ exports[`a saved opacity, as a ground alpha > pt-default: every N from 30 to 100 "--p-on-accent": "#0b0b0f", "--p-preview": "#2d2c2b", "--p-sel-bg": "#5da9f6", - "--p-side": "#12121270", + "--p-side": "#12121200", "--p-side-flat": "#1a1a1a", "--p-tab-active": "#12121200", "--p-tabs": "#12121270", @@ -7838,7 +7838,7 @@ exports[`a saved opacity, as a ground alpha > pt-default: every N from 30 to 100 "--p-on-accent": "#0b0b0f", "--p-preview": "#2d2c2b", "--p-sel-bg": "#5da9f6", - "--p-side": "#12121273", + "--p-side": "#12121200", "--p-side-flat": "#1a1a1a", "--p-tab-active": "#12121200", "--p-tabs": "#12121273", @@ -7864,7 +7864,7 @@ exports[`a saved opacity, as a ground alpha > pt-default: every N from 30 to 100 "--p-on-accent": "#0b0b0f", "--p-preview": "#2d2c2b", "--p-sel-bg": "#5da9f6", - "--p-side": "#12121275", + "--p-side": "#12121200", "--p-side-flat": "#1a1a1a", "--p-tab-active": "#12121200", "--p-tabs": "#12121275", @@ -7890,7 +7890,7 @@ exports[`a saved opacity, as a ground alpha > pt-default: every N from 30 to 100 "--p-on-accent": "#0b0b0f", "--p-preview": "#2d2c2b", "--p-sel-bg": "#5da9f6", - "--p-side": "#12121278", + "--p-side": "#12121200", "--p-side-flat": "#1a1a1a", "--p-tab-active": "#12121200", "--p-tabs": "#12121278", @@ -7916,7 +7916,7 @@ exports[`a saved opacity, as a ground alpha > pt-default: every N from 30 to 100 "--p-on-accent": "#0b0b0f", "--p-preview": "#2d2c2b", "--p-sel-bg": "#5da9f6", - "--p-side": "#1212127a", + "--p-side": "#12121200", "--p-side-flat": "#1a1a1a", "--p-tab-active": "#12121200", "--p-tabs": "#1212127a", @@ -7942,7 +7942,7 @@ exports[`a saved opacity, as a ground alpha > pt-default: every N from 30 to 100 "--p-on-accent": "#0b0b0f", "--p-preview": "#2d2c2b", "--p-sel-bg": "#5da9f6", - "--p-side": "#1212127d", + "--p-side": "#12121200", "--p-side-flat": "#1a1a1a", "--p-tab-active": "#12121200", "--p-tabs": "#1212127d", @@ -7968,7 +7968,7 @@ exports[`a saved opacity, as a ground alpha > pt-default: every N from 30 to 100 "--p-on-accent": "#0b0b0f", "--p-preview": "#2d2c2b", "--p-sel-bg": "#5da9f6", - "--p-side": "#12121280", + "--p-side": "#12121200", "--p-side-flat": "#1a1a1a", "--p-tab-active": "#12121200", "--p-tabs": "#12121280", @@ -7994,7 +7994,7 @@ exports[`a saved opacity, as a ground alpha > pt-default: every N from 30 to 100 "--p-on-accent": "#0b0b0f", "--p-preview": "#2d2c2b", "--p-sel-bg": "#5da9f6", - "--p-side": "#12121282", + "--p-side": "#12121200", "--p-side-flat": "#1a1a1a", "--p-tab-active": "#12121200", "--p-tabs": "#12121282", @@ -8020,7 +8020,7 @@ exports[`a saved opacity, as a ground alpha > pt-default: every N from 30 to 100 "--p-on-accent": "#0b0b0f", "--p-preview": "#2d2c2b", "--p-sel-bg": "#5da9f6", - "--p-side": "#12121285", + "--p-side": "#12121200", "--p-side-flat": "#1a1a1a", "--p-tab-active": "#12121200", "--p-tabs": "#12121285", @@ -8046,7 +8046,7 @@ exports[`a saved opacity, as a ground alpha > pt-default: every N from 30 to 100 "--p-on-accent": "#0b0b0f", "--p-preview": "#2d2c2b", "--p-sel-bg": "#5da9f6", - "--p-side": "#12121287", + "--p-side": "#12121200", "--p-side-flat": "#1a1a1a", "--p-tab-active": "#12121200", "--p-tabs": "#12121287", @@ -8072,7 +8072,7 @@ exports[`a saved opacity, as a ground alpha > pt-default: every N from 30 to 100 "--p-on-accent": "#0b0b0f", "--p-preview": "#2d2c2b", "--p-sel-bg": "#5da9f6", - "--p-side": "#1212128a", + "--p-side": "#12121200", "--p-side-flat": "#1a1a1a", "--p-tab-active": "#12121200", "--p-tabs": "#1212128a", @@ -8098,7 +8098,7 @@ exports[`a saved opacity, as a ground alpha > pt-default: every N from 30 to 100 "--p-on-accent": "#0b0b0f", "--p-preview": "#2d2c2b", "--p-sel-bg": "#5da9f6", - "--p-side": "#1212128c", + "--p-side": "#12121200", "--p-side-flat": "#1a1a1a", "--p-tab-active": "#12121200", "--p-tabs": "#1212128c", @@ -8124,7 +8124,7 @@ exports[`a saved opacity, as a ground alpha > pt-default: every N from 30 to 100 "--p-on-accent": "#0b0b0f", "--p-preview": "#2d2c2b", "--p-sel-bg": "#5da9f6", - "--p-side": "#1212128f", + "--p-side": "#12121200", "--p-side-flat": "#1a1a1a", "--p-tab-active": "#12121200", "--p-tabs": "#1212128f", @@ -8150,7 +8150,7 @@ exports[`a saved opacity, as a ground alpha > pt-default: every N from 30 to 100 "--p-on-accent": "#0b0b0f", "--p-preview": "#2d2c2b", "--p-sel-bg": "#5da9f6", - "--p-side": "#12121291", + "--p-side": "#12121200", "--p-side-flat": "#1a1a1a", "--p-tab-active": "#12121200", "--p-tabs": "#12121291", @@ -8176,7 +8176,7 @@ exports[`a saved opacity, as a ground alpha > pt-default: every N from 30 to 100 "--p-on-accent": "#0b0b0f", "--p-preview": "#2d2c2b", "--p-sel-bg": "#5da9f6", - "--p-side": "#12121294", + "--p-side": "#12121200", "--p-side-flat": "#1a1a1a", "--p-tab-active": "#12121200", "--p-tabs": "#12121294", @@ -8202,7 +8202,7 @@ exports[`a saved opacity, as a ground alpha > pt-default: every N from 30 to 100 "--p-on-accent": "#0b0b0f", "--p-preview": "#2d2c2b", "--p-sel-bg": "#5da9f6", - "--p-side": "#12121296", + "--p-side": "#12121200", "--p-side-flat": "#1a1a1a", "--p-tab-active": "#12121200", "--p-tabs": "#12121296", @@ -8228,7 +8228,7 @@ exports[`a saved opacity, as a ground alpha > pt-default: every N from 30 to 100 "--p-on-accent": "#0b0b0f", "--p-preview": "#2d2c2b", "--p-sel-bg": "#5da9f6", - "--p-side": "#12121299", + "--p-side": "#12121200", "--p-side-flat": "#1a1a1a", "--p-tab-active": "#12121200", "--p-tabs": "#12121299", @@ -8254,7 +8254,7 @@ exports[`a saved opacity, as a ground alpha > pt-default: every N from 30 to 100 "--p-on-accent": "#0b0b0f", "--p-preview": "#2d2c2b", "--p-sel-bg": "#5da9f6", - "--p-side": "#1212129c", + "--p-side": "#12121200", "--p-side-flat": "#1a1a1a", "--p-tab-active": "#12121200", "--p-tabs": "#1212129c", @@ -8280,7 +8280,7 @@ exports[`a saved opacity, as a ground alpha > pt-default: every N from 30 to 100 "--p-on-accent": "#0b0b0f", "--p-preview": "#2d2c2b", "--p-sel-bg": "#5da9f6", - "--p-side": "#1212129e", + "--p-side": "#12121200", "--p-side-flat": "#1a1a1a", "--p-tab-active": "#12121200", "--p-tabs": "#1212129e", @@ -8306,7 +8306,7 @@ exports[`a saved opacity, as a ground alpha > pt-default: every N from 30 to 100 "--p-on-accent": "#0b0b0f", "--p-preview": "#2d2c2b", "--p-sel-bg": "#5da9f6", - "--p-side": "#121212a1", + "--p-side": "#12121200", "--p-side-flat": "#1a1a1a", "--p-tab-active": "#12121200", "--p-tabs": "#121212a1", @@ -8332,7 +8332,7 @@ exports[`a saved opacity, as a ground alpha > pt-default: every N from 30 to 100 "--p-on-accent": "#0b0b0f", "--p-preview": "#2d2c2b", "--p-sel-bg": "#5da9f6", - "--p-side": "#121212a3", + "--p-side": "#12121200", "--p-side-flat": "#1a1a1a", "--p-tab-active": "#12121200", "--p-tabs": "#121212a3", @@ -8358,7 +8358,7 @@ exports[`a saved opacity, as a ground alpha > pt-default: every N from 30 to 100 "--p-on-accent": "#0b0b0f", "--p-preview": "#2d2c2b", "--p-sel-bg": "#5da9f6", - "--p-side": "#121212a6", + "--p-side": "#12121200", "--p-side-flat": "#1a1a1a", "--p-tab-active": "#12121200", "--p-tabs": "#121212a6", @@ -8384,7 +8384,7 @@ exports[`a saved opacity, as a ground alpha > pt-default: every N from 30 to 100 "--p-on-accent": "#0b0b0f", "--p-preview": "#2d2c2b", "--p-sel-bg": "#5da9f6", - "--p-side": "#121212a8", + "--p-side": "#12121200", "--p-side-flat": "#1a1a1a", "--p-tab-active": "#12121200", "--p-tabs": "#121212a8", @@ -8410,7 +8410,7 @@ exports[`a saved opacity, as a ground alpha > pt-default: every N from 30 to 100 "--p-on-accent": "#0b0b0f", "--p-preview": "#2d2c2b", "--p-sel-bg": "#5da9f6", - "--p-side": "#121212ab", + "--p-side": "#12121200", "--p-side-flat": "#1a1a1a", "--p-tab-active": "#12121200", "--p-tabs": "#121212ab", @@ -8436,7 +8436,7 @@ exports[`a saved opacity, as a ground alpha > pt-default: every N from 30 to 100 "--p-on-accent": "#0b0b0f", "--p-preview": "#2d2c2b", "--p-sel-bg": "#5da9f6", - "--p-side": "#121212ad", + "--p-side": "#12121200", "--p-side-flat": "#1a1a1a", "--p-tab-active": "#12121200", "--p-tabs": "#121212ad", @@ -8462,7 +8462,7 @@ exports[`a saved opacity, as a ground alpha > pt-default: every N from 30 to 100 "--p-on-accent": "#0b0b0f", "--p-preview": "#2d2c2b", "--p-sel-bg": "#5da9f6", - "--p-side": "#121212b0", + "--p-side": "#12121200", "--p-side-flat": "#1a1a1a", "--p-tab-active": "#12121200", "--p-tabs": "#121212b0", @@ -8488,7 +8488,7 @@ exports[`a saved opacity, as a ground alpha > pt-default: every N from 30 to 100 "--p-on-accent": "#0b0b0f", "--p-preview": "#2d2c2b", "--p-sel-bg": "#5da9f6", - "--p-side": "#121212b3", + "--p-side": "#12121200", "--p-side-flat": "#1a1a1a", "--p-tab-active": "#12121200", "--p-tabs": "#121212b3", @@ -8514,7 +8514,7 @@ exports[`a saved opacity, as a ground alpha > pt-default: every N from 30 to 100 "--p-on-accent": "#0b0b0f", "--p-preview": "#2d2c2b", "--p-sel-bg": "#5da9f6", - "--p-side": "#121212b5", + "--p-side": "#12121200", "--p-side-flat": "#1a1a1a", "--p-tab-active": "#12121200", "--p-tabs": "#121212b5", @@ -8540,7 +8540,7 @@ exports[`a saved opacity, as a ground alpha > pt-default: every N from 30 to 100 "--p-on-accent": "#0b0b0f", "--p-preview": "#2d2c2b", "--p-sel-bg": "#5da9f6", - "--p-side": "#121212b8", + "--p-side": "#12121200", "--p-side-flat": "#1a1a1a", "--p-tab-active": "#12121200", "--p-tabs": "#121212b8", @@ -8566,7 +8566,7 @@ exports[`a saved opacity, as a ground alpha > pt-default: every N from 30 to 100 "--p-on-accent": "#0b0b0f", "--p-preview": "#2d2c2b", "--p-sel-bg": "#5da9f6", - "--p-side": "#121212ba", + "--p-side": "#12121200", "--p-side-flat": "#1a1a1a", "--p-tab-active": "#12121200", "--p-tabs": "#121212ba", @@ -8592,7 +8592,7 @@ exports[`a saved opacity, as a ground alpha > pt-default: every N from 30 to 100 "--p-on-accent": "#0b0b0f", "--p-preview": "#2d2c2b", "--p-sel-bg": "#5da9f6", - "--p-side": "#121212bd", + "--p-side": "#12121200", "--p-side-flat": "#1a1a1a", "--p-tab-active": "#12121200", "--p-tabs": "#121212bd", @@ -8618,7 +8618,7 @@ exports[`a saved opacity, as a ground alpha > pt-default: every N from 30 to 100 "--p-on-accent": "#0b0b0f", "--p-preview": "#2d2c2b", "--p-sel-bg": "#5da9f6", - "--p-side": "#121212bf", + "--p-side": "#12121200", "--p-side-flat": "#1a1a1a", "--p-tab-active": "#12121200", "--p-tabs": "#121212bf", @@ -8644,7 +8644,7 @@ exports[`a saved opacity, as a ground alpha > pt-default: every N from 30 to 100 "--p-on-accent": "#0b0b0f", "--p-preview": "#2d2c2b", "--p-sel-bg": "#5da9f6", - "--p-side": "#121212c2", + "--p-side": "#12121200", "--p-side-flat": "#1a1a1a", "--p-tab-active": "#12121200", "--p-tabs": "#121212c2", @@ -8670,7 +8670,7 @@ exports[`a saved opacity, as a ground alpha > pt-default: every N from 30 to 100 "--p-on-accent": "#0b0b0f", "--p-preview": "#2d2c2b", "--p-sel-bg": "#5da9f6", - "--p-side": "#121212c4", + "--p-side": "#12121200", "--p-side-flat": "#1a1a1a", "--p-tab-active": "#12121200", "--p-tabs": "#121212c4", @@ -8696,7 +8696,7 @@ exports[`a saved opacity, as a ground alpha > pt-default: every N from 30 to 100 "--p-on-accent": "#0b0b0f", "--p-preview": "#2d2c2b", "--p-sel-bg": "#5da9f6", - "--p-side": "#121212c7", + "--p-side": "#12121200", "--p-side-flat": "#1a1a1a", "--p-tab-active": "#12121200", "--p-tabs": "#121212c7", @@ -8722,7 +8722,7 @@ exports[`a saved opacity, as a ground alpha > pt-default: every N from 30 to 100 "--p-on-accent": "#0b0b0f", "--p-preview": "#2d2c2b", "--p-sel-bg": "#5da9f6", - "--p-side": "#121212c9", + "--p-side": "#12121200", "--p-side-flat": "#1a1a1a", "--p-tab-active": "#12121200", "--p-tabs": "#121212c9", @@ -8748,7 +8748,7 @@ exports[`a saved opacity, as a ground alpha > pt-default: every N from 30 to 100 "--p-on-accent": "#0b0b0f", "--p-preview": "#2d2c2b", "--p-sel-bg": "#5da9f6", - "--p-side": "#121212cc", + "--p-side": "#12121200", "--p-side-flat": "#1a1a1a", "--p-tab-active": "#12121200", "--p-tabs": "#121212cc", @@ -8774,7 +8774,7 @@ exports[`a saved opacity, as a ground alpha > pt-default: every N from 30 to 100 "--p-on-accent": "#0b0b0f", "--p-preview": "#2d2c2b", "--p-sel-bg": "#5da9f6", - "--p-side": "#121212cf", + "--p-side": "#12121200", "--p-side-flat": "#1a1a1a", "--p-tab-active": "#12121200", "--p-tabs": "#121212cf", @@ -8800,7 +8800,7 @@ exports[`a saved opacity, as a ground alpha > pt-default: every N from 30 to 100 "--p-on-accent": "#0b0b0f", "--p-preview": "#2d2c2b", "--p-sel-bg": "#5da9f6", - "--p-side": "#121212d1", + "--p-side": "#12121200", "--p-side-flat": "#1a1a1a", "--p-tab-active": "#12121200", "--p-tabs": "#121212d1", @@ -8826,7 +8826,7 @@ exports[`a saved opacity, as a ground alpha > pt-default: every N from 30 to 100 "--p-on-accent": "#0b0b0f", "--p-preview": "#2d2c2b", "--p-sel-bg": "#5da9f6", - "--p-side": "#121212d4", + "--p-side": "#12121200", "--p-side-flat": "#1a1a1a", "--p-tab-active": "#12121200", "--p-tabs": "#121212d4", @@ -8852,7 +8852,7 @@ exports[`a saved opacity, as a ground alpha > pt-default: every N from 30 to 100 "--p-on-accent": "#0b0b0f", "--p-preview": "#2d2c2b", "--p-sel-bg": "#5da9f6", - "--p-side": "#121212d6", + "--p-side": "#12121200", "--p-side-flat": "#1a1a1a", "--p-tab-active": "#12121200", "--p-tabs": "#121212d6", @@ -8878,7 +8878,7 @@ exports[`a saved opacity, as a ground alpha > pt-default: every N from 30 to 100 "--p-on-accent": "#0b0b0f", "--p-preview": "#2d2c2b", "--p-sel-bg": "#5da9f6", - "--p-side": "#121212d9", + "--p-side": "#12121200", "--p-side-flat": "#1a1a1a", "--p-tab-active": "#12121200", "--p-tabs": "#121212d9", @@ -8904,7 +8904,7 @@ exports[`a saved opacity, as a ground alpha > pt-default: every N from 30 to 100 "--p-on-accent": "#0b0b0f", "--p-preview": "#2d2c2b", "--p-sel-bg": "#5da9f6", - "--p-side": "#121212db", + "--p-side": "#12121200", "--p-side-flat": "#1a1a1a", "--p-tab-active": "#12121200", "--p-tabs": "#121212db", @@ -8930,7 +8930,7 @@ exports[`a saved opacity, as a ground alpha > pt-default: every N from 30 to 100 "--p-on-accent": "#0b0b0f", "--p-preview": "#2d2c2b", "--p-sel-bg": "#5da9f6", - "--p-side": "#121212de", + "--p-side": "#12121200", "--p-side-flat": "#1a1a1a", "--p-tab-active": "#12121200", "--p-tabs": "#121212de", @@ -8956,7 +8956,7 @@ exports[`a saved opacity, as a ground alpha > pt-default: every N from 30 to 100 "--p-on-accent": "#0b0b0f", "--p-preview": "#2d2c2b", "--p-sel-bg": "#5da9f6", - "--p-side": "#121212e0", + "--p-side": "#12121200", "--p-side-flat": "#1a1a1a", "--p-tab-active": "#12121200", "--p-tabs": "#121212e0", @@ -8982,7 +8982,7 @@ exports[`a saved opacity, as a ground alpha > pt-default: every N from 30 to 100 "--p-on-accent": "#0b0b0f", "--p-preview": "#2d2c2b", "--p-sel-bg": "#5da9f6", - "--p-side": "#121212e3", + "--p-side": "#12121200", "--p-side-flat": "#1a1a1a", "--p-tab-active": "#12121200", "--p-tabs": "#121212e3", @@ -9008,7 +9008,7 @@ exports[`a saved opacity, as a ground alpha > pt-default: every N from 30 to 100 "--p-on-accent": "#0b0b0f", "--p-preview": "#2d2c2b", "--p-sel-bg": "#5da9f6", - "--p-side": "#121212e6", + "--p-side": "#12121200", "--p-side-flat": "#1a1a1a", "--p-tab-active": "#12121200", "--p-tabs": "#121212e6", @@ -9034,7 +9034,7 @@ exports[`a saved opacity, as a ground alpha > pt-default: every N from 30 to 100 "--p-on-accent": "#0b0b0f", "--p-preview": "#2d2c2b", "--p-sel-bg": "#5da9f6", - "--p-side": "#121212e8", + "--p-side": "#12121200", "--p-side-flat": "#1a1a1a", "--p-tab-active": "#12121200", "--p-tabs": "#121212e8", @@ -9060,7 +9060,7 @@ exports[`a saved opacity, as a ground alpha > pt-default: every N from 30 to 100 "--p-on-accent": "#0b0b0f", "--p-preview": "#2d2c2b", "--p-sel-bg": "#5da9f6", - "--p-side": "#121212eb", + "--p-side": "#12121200", "--p-side-flat": "#1a1a1a", "--p-tab-active": "#12121200", "--p-tabs": "#121212eb", @@ -9086,7 +9086,7 @@ exports[`a saved opacity, as a ground alpha > pt-default: every N from 30 to 100 "--p-on-accent": "#0b0b0f", "--p-preview": "#2d2c2b", "--p-sel-bg": "#5da9f6", - "--p-side": "#121212ed", + "--p-side": "#12121200", "--p-side-flat": "#1a1a1a", "--p-tab-active": "#12121200", "--p-tabs": "#121212ed", @@ -9112,7 +9112,7 @@ exports[`a saved opacity, as a ground alpha > pt-default: every N from 30 to 100 "--p-on-accent": "#0b0b0f", "--p-preview": "#2d2c2b", "--p-sel-bg": "#5da9f6", - "--p-side": "#121212f0", + "--p-side": "#12121200", "--p-side-flat": "#1a1a1a", "--p-tab-active": "#12121200", "--p-tabs": "#121212f0", @@ -9138,7 +9138,7 @@ exports[`a saved opacity, as a ground alpha > pt-default: every N from 30 to 100 "--p-on-accent": "#0b0b0f", "--p-preview": "#2d2c2b", "--p-sel-bg": "#5da9f6", - "--p-side": "#121212f2", + "--p-side": "#12121200", "--p-side-flat": "#1a1a1a", "--p-tab-active": "#12121200", "--p-tabs": "#121212f2", @@ -9164,7 +9164,7 @@ exports[`a saved opacity, as a ground alpha > pt-default: every N from 30 to 100 "--p-on-accent": "#0b0b0f", "--p-preview": "#2d2c2b", "--p-sel-bg": "#5da9f6", - "--p-side": "#121212f5", + "--p-side": "#12121200", "--p-side-flat": "#1a1a1a", "--p-tab-active": "#12121200", "--p-tabs": "#121212f5", @@ -9190,7 +9190,7 @@ exports[`a saved opacity, as a ground alpha > pt-default: every N from 30 to 100 "--p-on-accent": "#0b0b0f", "--p-preview": "#2d2c2b", "--p-sel-bg": "#5da9f6", - "--p-side": "#121212f7", + "--p-side": "#12121200", "--p-side-flat": "#1a1a1a", "--p-tab-active": "#12121200", "--p-tabs": "#121212f7", @@ -9216,7 +9216,7 @@ exports[`a saved opacity, as a ground alpha > pt-default: every N from 30 to 100 "--p-on-accent": "#0b0b0f", "--p-preview": "#2d2c2b", "--p-sel-bg": "#5da9f6", - "--p-side": "#121212fa", + "--p-side": "#12121200", "--p-side-flat": "#1a1a1a", "--p-tab-active": "#12121200", "--p-tabs": "#121212fa", @@ -9242,7 +9242,7 @@ exports[`a saved opacity, as a ground alpha > pt-default: every N from 30 to 100 "--p-on-accent": "#0b0b0f", "--p-preview": "#2d2c2b", "--p-sel-bg": "#5da9f6", - "--p-side": "#121212fc", + "--p-side": "#12121200", "--p-side-flat": "#1a1a1a", "--p-tab-active": "#12121200", "--p-tabs": "#121212fc", @@ -9273,7 +9273,7 @@ exports[`an opaque accent, before and after alpha > amber 1`] = ` "--p-on-accent": "#0b0b0f", "--p-preview": "#30220d", "--p-sel-bg": "#f0a030", - "--p-side": "#110b0299", + "--p-side": "#110b0200", "--p-side-flat": "#1b1206", "--p-tab-active": "#110b0200", "--p-tabs": "#110b0299", @@ -9325,7 +9325,7 @@ exports[`an opaque accent, before and after alpha > amber 1`] = ` "--p-on-accent": "#0b0b0f", "--p-preview": "#30220d", "--p-sel-bg": "#e07a2f", - "--p-side": "#110b0299", + "--p-side": "#110b0200", "--p-side-flat": "#1b1206", "--p-tab-active": "#110b0200", "--p-tabs": "#110b0299", @@ -9382,7 +9382,7 @@ exports[`an opaque accent, before and after alpha > blossom 1`] = ` "--p-on-accent": "#ffffff", "--p-preview": "#dccdd3", "--p-sel-bg": "#c64a78", - "--p-side": "#fbeef299", + "--p-side": "#fbeef200", "--p-side-flat": "#f3e6ea", "--p-tab-active": "#fbeef200", "--p-tabs": "#fbeef299", @@ -9434,7 +9434,7 @@ exports[`an opaque accent, before and after alpha > blossom 1`] = ` "--p-on-accent": "#0b0b0f", "--p-preview": "#dccdd3", "--p-sel-bg": "#be6728", - "--p-side": "#fbeef299", + "--p-side": "#fbeef200", "--p-side-flat": "#f3e6ea", "--p-tab-active": "#fbeef200", "--p-tabs": "#fbeef299", @@ -9491,7 +9491,7 @@ exports[`an opaque accent, before and after alpha > butter 1`] = ` "--p-on-accent": "#ffffff", "--p-preview": "#dcd6bb", "--p-sel-bg": "#8f6b00", - "--p-side": "#fbf5d899", + "--p-side": "#fbf5d800", "--p-side-flat": "#f3edd1", "--p-tab-active": "#fbf5d800", "--p-tabs": "#fbf5d899", @@ -9543,7 +9543,7 @@ exports[`an opaque accent, before and after alpha > butter 1`] = ` "--p-on-accent": "#0b0b0f", "--p-preview": "#dcd6bb", "--p-sel-bg": "#be6728", - "--p-side": "#fbf5d899", + "--p-side": "#fbf5d800", "--p-side-flat": "#f3edd1", "--p-tab-active": "#fbf5d800", "--p-tabs": "#fbf5d899", @@ -9600,7 +9600,7 @@ exports[`an opaque accent, before and after alpha > campbell 1`] = ` "--p-on-accent": "#0b0b0f", "--p-preview": "#252525", "--p-sel-bg": "#3b78ff", - "--p-side": "#0c0c0c99", + "--p-side": "#0c0c0c00", "--p-side-flat": "#141414", "--p-tab-active": "#0c0c0c00", "--p-tabs": "#0c0c0c99", @@ -9652,7 +9652,7 @@ exports[`an opaque accent, before and after alpha > campbell 1`] = ` "--p-on-accent": "#0b0b0f", "--p-preview": "#252525", "--p-sel-bg": "#e07a2f", - "--p-side": "#0c0c0c99", + "--p-side": "#0c0c0c00", "--p-side-flat": "#141414", "--p-tab-active": "#0c0c0c00", "--p-tabs": "#0c0c0c99", @@ -9709,7 +9709,7 @@ exports[`an opaque accent, before and after alpha > catppuccin-latte 1`] = ` "--p-on-accent": "#ffffff", "--p-preview": "#d5d7df", "--p-sel-bg": "#8839ef", - "--p-side": "#eff1f599", + "--p-side": "#eff1f500", "--p-side-flat": "#e8ebef", "--p-tab-active": "#eff1f500", "--p-tabs": "#eff1f599", @@ -9761,7 +9761,7 @@ exports[`an opaque accent, before and after alpha > catppuccin-latte 1`] = ` "--p-on-accent": "#0b0b0f", "--p-preview": "#d5d7df", "--p-sel-bg": "#be6728", - "--p-side": "#eff1f599", + "--p-side": "#eff1f500", "--p-side-flat": "#e8ebef", "--p-tab-active": "#eff1f500", "--p-tabs": "#eff1f599", @@ -9818,7 +9818,7 @@ exports[`an opaque accent, before and after alpha > catppuccin-mocha 1`] = ` "--p-on-accent": "#0b0b0f", "--p-preview": "#353648", "--p-sel-bg": "#cba6f7", - "--p-side": "#1e1e2e99", + "--p-side": "#1e1e2e00", "--p-side-flat": "#252536", "--p-tab-active": "#1e1e2e00", "--p-tabs": "#1e1e2e99", @@ -9870,7 +9870,7 @@ exports[`an opaque accent, before and after alpha > catppuccin-mocha 1`] = ` "--p-on-accent": "#0b0b0f", "--p-preview": "#353648", "--p-sel-bg": "#e07a2f", - "--p-side": "#1e1e2e99", + "--p-side": "#1e1e2e00", "--p-side-flat": "#252536", "--p-tab-active": "#1e1e2e00", "--p-tabs": "#1e1e2e99", @@ -9927,7 +9927,7 @@ exports[`an opaque accent, before and after alpha > cinder 1`] = ` "--p-on-accent": "#0b0b0f", "--p-preview": "#505358", "--p-sel-bg": "#ec9448", - "--p-side": "#383c4499", + "--p-side": "#383c4400", "--p-side-flat": "#3f434a", "--p-tab-active": "#383c4400", "--p-tabs": "#383c4499", @@ -9979,7 +9979,7 @@ exports[`an opaque accent, before and after alpha > cinder 1`] = ` "--p-on-accent": "#0b0b0f", "--p-preview": "#505358", "--p-sel-bg": "#e07a2f", - "--p-side": "#383c4499", + "--p-side": "#383c4400", "--p-side-flat": "#3f434a", "--p-tab-active": "#383c4400", "--p-tabs": "#383c4499", @@ -10036,7 +10036,7 @@ exports[`an opaque accent, before and after alpha > cobalt 1`] = ` "--p-on-accent": "#0b0b0f", "--p-preview": "#374f61", "--p-sel-bg": "#ffc600", - "--p-side": "#19354999", + "--p-side": "#19354900", "--p-side-flat": "#223d50", "--p-tab-active": "#19354900", "--p-tabs": "#19354999", @@ -10088,7 +10088,7 @@ exports[`an opaque accent, before and after alpha > cobalt 1`] = ` "--p-on-accent": "#0b0b0f", "--p-preview": "#374f61", "--p-sel-bg": "#e07a2f", - "--p-side": "#19354999", + "--p-side": "#19354900", "--p-side-flat": "#223d50", "--p-tab-active": "#19354900", "--p-tabs": "#19354999", @@ -10145,7 +10145,7 @@ exports[`an opaque accent, before and after alpha > dracula 1`] = ` "--p-on-accent": "#0b0b0f", "--p-preview": "#3a3b43", "--p-sel-bg": "#bd93f9", - "--p-side": "#1e1f2999", + "--p-side": "#1e1f2900", "--p-side-flat": "#272831", "--p-tab-active": "#1e1f2900", "--p-tabs": "#1e1f2999", @@ -10197,7 +10197,7 @@ exports[`an opaque accent, before and after alpha > dracula 1`] = ` "--p-on-accent": "#0b0b0f", "--p-preview": "#3a3b43", "--p-sel-bg": "#e07a2f", - "--p-side": "#1e1f2999", + "--p-side": "#1e1f2900", "--p-side-flat": "#272831", "--p-tab-active": "#1e1f2900", "--p-tabs": "#1e1f2999", @@ -10254,7 +10254,7 @@ exports[`an opaque accent, before and after alpha > fawn 1`] = ` "--p-on-accent": "#ffffff", "--p-preview": "#cbbca6", "--p-sel-bg": "#8a5a3c", - "--p-side": "#e6d8c099", + "--p-side": "#e6d8c000", "--p-side-flat": "#dfd1ba", "--p-tab-active": "#e6d8c000", "--p-tabs": "#e6d8c099", @@ -10306,7 +10306,7 @@ exports[`an opaque accent, before and after alpha > fawn 1`] = ` "--p-on-accent": "#ffffff", "--p-preview": "#cbbca6", "--p-sel-bg": "#af5f25", - "--p-side": "#e6d8c099", + "--p-side": "#e6d8c000", "--p-side-flat": "#dfd1ba", "--p-tab-active": "#e6d8c000", "--p-tabs": "#e6d8c099", @@ -10363,7 +10363,7 @@ exports[`an opaque accent, before and after alpha > garnet 1`] = ` "--p-on-accent": "#0b0b0f", "--p-preview": "#3b282b", "--p-sel-bg": "#e2475c", - "--p-side": "#1f0d1099", + "--p-side": "#1f0d1000", "--p-side-flat": "#271518", "--p-tab-active": "#1f0d1000", "--p-tabs": "#1f0d1099", @@ -10415,7 +10415,7 @@ exports[`an opaque accent, before and after alpha > garnet 1`] = ` "--p-on-accent": "#0b0b0f", "--p-preview": "#3b282b", "--p-sel-bg": "#e07a2f", - "--p-side": "#1f0d1099", + "--p-side": "#1f0d1000", "--p-side-flat": "#271518", "--p-tab-active": "#1f0d1000", "--p-tabs": "#1f0d1099", @@ -10472,7 +10472,7 @@ exports[`an opaque accent, before and after alpha > graphite 1`] = ` "--p-on-accent": "#0b0b0f", "--p-preview": "#373737", "--p-sel-bg": "#9a9a9a", - "--p-side": "#1f1f1f99", + "--p-side": "#1f1f1f00", "--p-side-flat": "#262626", "--p-tab-active": "#1f1f1f00", "--p-tabs": "#1f1f1f99", @@ -10524,7 +10524,7 @@ exports[`an opaque accent, before and after alpha > graphite 1`] = ` "--p-on-accent": "#0b0b0f", "--p-preview": "#373737", "--p-sel-bg": "#e07a2f", - "--p-side": "#1f1f1f99", + "--p-side": "#1f1f1f00", "--p-side-flat": "#262626", "--p-tab-active": "#1f1f1f00", "--p-tabs": "#1f1f1f99", @@ -10581,7 +10581,7 @@ exports[`an opaque accent, before and after alpha > gruvbox-dark 1`] = ` "--p-on-accent": "#0b0b0f", "--p-preview": "#413f3a", "--p-sel-bg": "#fe8019", - "--p-side": "#28282899", + "--p-side": "#28282800", "--p-side-flat": "#302f2e", "--p-tab-active": "#28282800", "--p-tabs": "#28282899", @@ -10633,7 +10633,7 @@ exports[`an opaque accent, before and after alpha > gruvbox-dark 1`] = ` "--p-on-accent": "#0b0b0f", "--p-preview": "#413f3a", "--p-sel-bg": "#e07a2f", - "--p-side": "#28282899", + "--p-side": "#28282800", "--p-side-flat": "#302f2e", "--p-tab-active": "#28282800", "--p-tabs": "#28282899", @@ -10690,7 +10690,7 @@ exports[`an opaque accent, before and after alpha > horizon 1`] = ` "--p-on-accent": "#0b0b0f", "--p-preview": "#34363d", "--p-sel-bg": "#e95678", - "--p-side": "#1c1e2699", + "--p-side": "#1c1e2600", "--p-side-flat": "#23252d", "--p-tab-active": "#1c1e2600", "--p-tabs": "#1c1e2699", @@ -10742,7 +10742,7 @@ exports[`an opaque accent, before and after alpha > horizon 1`] = ` "--p-on-accent": "#0b0b0f", "--p-preview": "#34363d", "--p-sel-bg": "#e07a2f", - "--p-side": "#1c1e2699", + "--p-side": "#1c1e2600", "--p-side-flat": "#23252d", "--p-tab-active": "#1c1e2600", "--p-tabs": "#1c1e2699", @@ -10799,7 +10799,7 @@ exports[`an opaque accent, before and after alpha > kanagawa 1`] = ` "--p-on-accent": "#0b0b0f", "--p-preview": "#38373b", "--p-sel-bg": "#7e9cd8", - "--p-side": "#1f1f2899", + "--p-side": "#1f1f2800", "--p-side-flat": "#27262e", "--p-tab-active": "#1f1f2800", "--p-tabs": "#1f1f2899", @@ -10851,7 +10851,7 @@ exports[`an opaque accent, before and after alpha > kanagawa 1`] = ` "--p-on-accent": "#0b0b0f", "--p-preview": "#38373b", "--p-sel-bg": "#e07a2f", - "--p-side": "#1f1f2899", + "--p-side": "#1f1f2800", "--p-side-flat": "#27262e", "--p-tab-active": "#1f1f2800", "--p-tabs": "#1f1f2899", @@ -10908,7 +10908,7 @@ exports[`an opaque accent, before and after alpha > lavender 1`] = ` "--p-on-accent": "#ffffff", "--p-preview": "#d2cddc", "--p-sel-bg": "#7c5cc4", - "--p-side": "#f1edfa99", + "--p-side": "#f1edfa00", "--p-side-flat": "#e9e5f3", "--p-tab-active": "#f1edfa00", "--p-tabs": "#f1edfa99", @@ -10960,7 +10960,7 @@ exports[`an opaque accent, before and after alpha > lavender 1`] = ` "--p-on-accent": "#0b0b0f", "--p-preview": "#d2cddc", "--p-sel-bg": "#be6728", - "--p-side": "#f1edfa99", + "--p-side": "#f1edfa00", "--p-side-flat": "#e9e5f3", "--p-tab-active": "#f1edfa00", "--p-tabs": "#f1edfa99", @@ -11017,7 +11017,7 @@ exports[`an opaque accent, before and after alpha > marine 1`] = ` "--p-on-accent": "#0b0b0f", "--p-preview": "#203e6a", "--p-sel-bg": "#ffd866", - "--p-side": "#01245699", + "--p-side": "#01245600", "--p-side-flat": "#0a2c5c", "--p-tab-active": "#01245600", "--p-tabs": "#01245699", @@ -11069,7 +11069,7 @@ exports[`an opaque accent, before and after alpha > marine 1`] = ` "--p-on-accent": "#0b0b0f", "--p-preview": "#203e6a", "--p-sel-bg": "#e07a2f", - "--p-side": "#01245699", + "--p-side": "#01245600", "--p-side-flat": "#0a2c5c", "--p-tab-active": "#01245600", "--p-tabs": "#01245699", @@ -11126,7 +11126,7 @@ exports[`an opaque accent, before and after alpha > mint 1`] = ` "--p-on-accent": "#ffffff", "--p-preview": "#c5d6cf", "--p-sel-bg": "#17805c", - "--p-side": "#e5f6ef99", + "--p-side": "#e5f6ef00", "--p-side-flat": "#ddeee7", "--p-tab-active": "#e5f6ef00", "--p-tabs": "#e5f6ef99", @@ -11178,7 +11178,7 @@ exports[`an opaque accent, before and after alpha > mint 1`] = ` "--p-on-accent": "#0b0b0f", "--p-preview": "#c5d6cf", "--p-sel-bg": "#be6728", - "--p-side": "#e5f6ef99", + "--p-side": "#e5f6ef00", "--p-side-flat": "#ddeee7", "--p-tab-active": "#e5f6ef00", "--p-tabs": "#e5f6ef99", @@ -11235,7 +11235,7 @@ exports[`an opaque accent, before and after alpha > mist 1`] = ` "--p-on-accent": "#ffffff", "--p-preview": "#c6c6c5", "--p-sel-bg": "#5c5c66", - "--p-side": "#e4e4e299", + "--p-side": "#e4e4e200", "--p-side-flat": "#dcdcdb", "--p-tab-active": "#e4e4e200", "--p-tabs": "#e4e4e299", @@ -11287,7 +11287,7 @@ exports[`an opaque accent, before and after alpha > mist 1`] = ` "--p-on-accent": "#ffffff", "--p-preview": "#c6c6c5", "--p-sel-bg": "#af5f25", - "--p-side": "#e4e4e299", + "--p-side": "#e4e4e200", "--p-side-flat": "#dcdcdb", "--p-tab-active": "#e4e4e200", "--p-tabs": "#e4e4e299", @@ -11344,7 +11344,7 @@ exports[`an opaque accent, before and after alpha > monokai 1`] = ` "--p-on-accent": "#0b0b0f", "--p-preview": "#42433d", "--p-sel-bg": "#a6e22e", - "--p-side": "#27282299", + "--p-side": "#27282200", "--p-side-flat": "#2f302a", "--p-tab-active": "#27282200", "--p-tabs": "#27282299", @@ -11396,7 +11396,7 @@ exports[`an opaque accent, before and after alpha > monokai 1`] = ` "--p-on-accent": "#0b0b0f", "--p-preview": "#42433d", "--p-sel-bg": "#e07a2f", - "--p-side": "#27282299", + "--p-side": "#27282200", "--p-side-flat": "#2f302a", "--p-tab-active": "#27282200", "--p-tabs": "#27282299", @@ -11453,7 +11453,7 @@ exports[`an opaque accent, before and after alpha > moss 1`] = ` "--p-on-accent": "#0b0b0f", "--p-preview": "#2d362e", "--p-sel-bg": "#78ad66", - "--p-side": "#141c1699", + "--p-side": "#141c1600", "--p-side-flat": "#1c241e", "--p-tab-active": "#141c1600", "--p-tabs": "#141c1699", @@ -11505,7 +11505,7 @@ exports[`an opaque accent, before and after alpha > moss 1`] = ` "--p-on-accent": "#0b0b0f", "--p-preview": "#2d362e", "--p-sel-bg": "#e07a2f", - "--p-side": "#141c1699", + "--p-side": "#141c1600", "--p-side-flat": "#1c241e", "--p-tab-active": "#141c1600", "--p-tabs": "#141c1699", @@ -11562,7 +11562,7 @@ exports[`an opaque accent, before and after alpha > nord 1`] = ` "--p-on-accent": "#0b0b0f", "--p-preview": "#444a56", "--p-sel-bg": "#81a1c1", - "--p-side": "#2e344099", + "--p-side": "#2e344000", "--p-side-flat": "#353b47", "--p-tab-active": "#2e344000", "--p-tabs": "#2e344099", @@ -11614,7 +11614,7 @@ exports[`an opaque accent, before and after alpha > nord 1`] = ` "--p-on-accent": "#0b0b0f", "--p-preview": "#444a56", "--p-sel-bg": "#e07a2f", - "--p-side": "#2e344099", + "--p-side": "#2e344000", "--p-side-flat": "#353b47", "--p-tab-active": "#2e344000", "--p-tabs": "#2e344099", @@ -11671,7 +11671,7 @@ exports[`an opaque accent, before and after alpha > ocean 1`] = ` "--p-on-accent": "#0b0b0f", "--p-preview": "#244049", "--p-sel-bg": "#3fb8c8", - "--p-side": "#0a263099", + "--p-side": "#0a263000", "--p-side-flat": "#122e38", "--p-tab-active": "#0a263000", "--p-tabs": "#0a263099", @@ -11723,7 +11723,7 @@ exports[`an opaque accent, before and after alpha > ocean 1`] = ` "--p-on-accent": "#0b0b0f", "--p-preview": "#244049", "--p-sel-bg": "#e07a2f", - "--p-side": "#0a263099", + "--p-side": "#0a263000", "--p-side-flat": "#122e38", "--p-tab-active": "#0a263000", "--p-tabs": "#0a263099", @@ -11780,7 +11780,7 @@ exports[`an opaque accent, before and after alpha > paper 1`] = ` "--p-on-accent": "#0b0b0f", "--p-preview": "#d5d3cd", "--p-sel-bg": "#3f8ccb", - "--p-side": "#f6f4ee99", + "--p-side": "#f6f4ee00", "--p-side-flat": "#eeece6", "--p-tab-active": "#f6f4ee00", "--p-tabs": "#f6f4ee99", @@ -11832,7 +11832,7 @@ exports[`an opaque accent, before and after alpha > paper 1`] = ` "--p-on-accent": "#0b0b0f", "--p-preview": "#d5d3cd", "--p-sel-bg": "#be6728", - "--p-side": "#f6f4ee99", + "--p-side": "#f6f4ee00", "--p-side-flat": "#eeece6", "--p-tab-active": "#f6f4ee00", "--p-tabs": "#f6f4ee99", @@ -11889,7 +11889,7 @@ exports[`an opaque accent, before and after alpha > peach 1`] = ` "--p-on-accent": "#0b0b0f", "--p-preview": "#decfc4", "--p-sel-bg": "#c05e2c", - "--p-side": "#fdeee399", + "--p-side": "#fdeee300", "--p-side-flat": "#f5e6db", "--p-tab-active": "#fdeee300", "--p-tabs": "#fdeee399", @@ -11941,7 +11941,7 @@ exports[`an opaque accent, before and after alpha > peach 1`] = ` "--p-on-accent": "#0b0b0f", "--p-preview": "#decfc4", "--p-sel-bg": "#be6728", - "--p-side": "#fdeee399", + "--p-side": "#fdeee300", "--p-side-flat": "#f5e6db", "--p-tab-active": "#fdeee300", "--p-tabs": "#fdeee399", @@ -11998,7 +11998,7 @@ exports[`an opaque accent, before and after alpha > phosphor 1`] = ` "--p-on-accent": "#0b0b0f", "--p-preview": "#152b17", "--p-sel-bg": "#3fcf5a", - "--p-side": "#050d0699", + "--p-side": "#050d0600", "--p-side-flat": "#0a160b", "--p-tab-active": "#050d0600", "--p-tabs": "#050d0699", @@ -12050,7 +12050,7 @@ exports[`an opaque accent, before and after alpha > phosphor 1`] = ` "--p-on-accent": "#0b0b0f", "--p-preview": "#152b17", "--p-sel-bg": "#e07a2f", - "--p-side": "#050d0699", + "--p-side": "#050d0600", "--p-side-flat": "#0a160b", "--p-tab-active": "#050d0600", "--p-tabs": "#050d0699", @@ -12107,7 +12107,7 @@ exports[`an opaque accent, before and after alpha > pitch 1`] = ` "--p-on-accent": "#0b0b0f", "--p-preview": "#1f1e1c", "--p-sel-bg": "#ec9448", - "--p-side": "#00000099", + "--p-side": "#00000000", "--p-side-flat": "#0a0909", "--p-tab-active": "#00000000", "--p-tabs": "#00000099", @@ -12159,7 +12159,7 @@ exports[`an opaque accent, before and after alpha > pitch 1`] = ` "--p-on-accent": "#0b0b0f", "--p-preview": "#1f1e1c", "--p-sel-bg": "#e07a2f", - "--p-side": "#00000099", + "--p-side": "#00000000", "--p-side-flat": "#0a0909", "--p-tab-active": "#00000000", "--p-tabs": "#00000099", @@ -12216,7 +12216,7 @@ exports[`an opaque accent, before and after alpha > plum 1`] = ` "--p-on-accent": "#0b0b0f", "--p-preview": "#372c41", "--p-sel-bg": "#b07ce0", - "--p-side": "#1c122699", + "--p-side": "#1c122600", "--p-side-flat": "#241a2e", "--p-tab-active": "#1c122600", "--p-tabs": "#1c122699", @@ -12268,7 +12268,7 @@ exports[`an opaque accent, before and after alpha > plum 1`] = ` "--p-on-accent": "#0b0b0f", "--p-preview": "#372c41", "--p-sel-bg": "#e07a2f", - "--p-side": "#1c122699", + "--p-side": "#1c122600", "--p-side-flat": "#241a2e", "--p-tab-active": "#1c122600", "--p-tabs": "#1c122699", @@ -12325,7 +12325,7 @@ exports[`an opaque accent, before and after alpha > prism 1`] = ` "--p-on-accent": "#ffffff", "--p-preview": "#28282c", "--p-sel-bg": "#5b5bd6", - "--p-side": "#0b0b0f99", + "--p-side": "#0b0b0f00", "--p-side-flat": "#141418", "--p-tab-active": "#0b0b0f00", "--p-tabs": "#0b0b0f99", @@ -12377,7 +12377,7 @@ exports[`an opaque accent, before and after alpha > prism 1`] = ` "--p-on-accent": "#0b0b0f", "--p-preview": "#28282c", "--p-sel-bg": "#e07a2f", - "--p-side": "#0b0b0f99", + "--p-side": "#0b0b0f00", "--p-side-flat": "#141418", "--p-tab-active": "#0b0b0f00", "--p-tabs": "#0b0b0f99", @@ -12434,7 +12434,7 @@ exports[`an opaque accent, before and after alpha > pt-default 1`] = ` "--p-on-accent": "#0b0b0f", "--p-preview": "#2d2c2b", "--p-sel-bg": "#fe8f34", - "--p-side": "#12121299", + "--p-side": "#12121200", "--p-side-flat": "#1a1a1a", "--p-tab-active": "#12121200", "--p-tabs": "#12121299", @@ -12486,7 +12486,7 @@ exports[`an opaque accent, before and after alpha > pt-default 1`] = ` "--p-on-accent": "#0b0b0f", "--p-preview": "#2d2c2b", "--p-sel-bg": "#e07a2f", - "--p-side": "#12121299", + "--p-side": "#12121200", "--p-side-flat": "#1a1a1a", "--p-tab-active": "#12121200", "--p-tabs": "#12121299", @@ -12543,7 +12543,7 @@ exports[`an opaque accent, before and after alpha > retro 1`] = ` "--p-on-accent": "#0b0b0f", "--p-preview": "#453988", "--p-sel-bg": "#9d93ea", - "--p-side": "#35287999", + "--p-side": "#35287900", "--p-side-flat": "#3a2d7e", "--p-tab-active": "#35287900", "--p-tabs": "#35287999", @@ -12595,7 +12595,7 @@ exports[`an opaque accent, before and after alpha > retro 1`] = ` "--p-on-accent": "#0b0b0f", "--p-preview": "#453988", "--p-sel-bg": "#e07a2f", - "--p-side": "#35287999", + "--p-side": "#35287900", "--p-side-flat": "#3a2d7e", "--p-tab-active": "#35287900", "--p-tabs": "#35287999", @@ -12652,7 +12652,7 @@ exports[`an opaque accent, before and after alpha > rosewood 1`] = ` "--p-on-accent": "#0b0b0f", "--p-preview": "#3f3037", "--p-sel-bg": "#e4719a", - "--p-side": "#24161d99", + "--p-side": "#24161d00", "--p-side-flat": "#2c1e25", "--p-tab-active": "#24161d00", "--p-tabs": "#24161d99", @@ -12704,7 +12704,7 @@ exports[`an opaque accent, before and after alpha > rosewood 1`] = ` "--p-on-accent": "#0b0b0f", "--p-preview": "#3f3037", "--p-sel-bg": "#e07a2f", - "--p-side": "#24161d99", + "--p-side": "#24161d00", "--p-side-flat": "#2c1e25", "--p-tab-active": "#24161d00", "--p-tabs": "#24161d99", @@ -12761,7 +12761,7 @@ exports[`an opaque accent, before and after alpha > sage 1`] = ` "--p-on-accent": "#ffffff", "--p-preview": "#c9d0c6", "--p-sel-bg": "#4c7d47", - "--p-side": "#e9efe599", + "--p-side": "#e9efe500", "--p-side-flat": "#e1e7dd", "--p-tab-active": "#e9efe500", "--p-tabs": "#e9efe599", @@ -12813,7 +12813,7 @@ exports[`an opaque accent, before and after alpha > sage 1`] = ` "--p-on-accent": "#0b0b0f", "--p-preview": "#c9d0c6", "--p-sel-bg": "#be6728", - "--p-side": "#e9efe599", + "--p-side": "#e9efe500", "--p-side-flat": "#e1e7dd", "--p-tab-active": "#e9efe500", "--p-tabs": "#e9efe599", @@ -12870,7 +12870,7 @@ exports[`an opaque accent, before and after alpha > sky 1`] = ` "--p-on-accent": "#0b0b0f", "--p-preview": "#c9d4de", "--p-sel-bg": "#2f7bd6", - "--p-side": "#eaf4fd99", + "--p-side": "#eaf4fd00", "--p-side-flat": "#e2ecf5", "--p-tab-active": "#eaf4fd00", "--p-tabs": "#eaf4fd99", @@ -12922,7 +12922,7 @@ exports[`an opaque accent, before and after alpha > sky 1`] = ` "--p-on-accent": "#0b0b0f", "--p-preview": "#c9d4de", "--p-sel-bg": "#be6728", - "--p-side": "#eaf4fd99", + "--p-side": "#eaf4fd00", "--p-side-flat": "#e2ecf5", "--p-tab-active": "#eaf4fd00", "--p-tabs": "#eaf4fd99", @@ -12979,7 +12979,7 @@ exports[`an opaque accent, before and after alpha > solarized-dark 1`] = ` "--p-on-accent": "#0b0b0f", "--p-preview": "#133a44", "--p-sel-bg": "#268bd2", - "--p-side": "#002b3699", + "--p-side": "#002b3600", "--p-side-flat": "#06303a", "--p-tab-active": "#002b3600", "--p-tabs": "#002b3699", @@ -13031,7 +13031,7 @@ exports[`an opaque accent, before and after alpha > solarized-dark 1`] = ` "--p-on-accent": "#0b0b0f", "--p-preview": "#133a44", "--p-sel-bg": "#e07a2f", - "--p-side": "#002b3699", + "--p-side": "#002b3600", "--p-side-flat": "#06303a", "--p-tab-active": "#002b3600", "--p-tabs": "#002b3699", @@ -13088,7 +13088,7 @@ exports[`an opaque accent, before and after alpha > synthwave 1`] = ` "--p-on-accent": "#0b0b0f", "--p-preview": "#403e4d", "--p-sel-bg": "#ff7edb", - "--p-side": "#26233599", + "--p-side": "#26233500", "--p-side-flat": "#2e2b3d", "--p-tab-active": "#26233500", "--p-tabs": "#26233599", @@ -13140,7 +13140,7 @@ exports[`an opaque accent, before and after alpha > synthwave 1`] = ` "--p-on-accent": "#0b0b0f", "--p-preview": "#403e4d", "--p-sel-bg": "#e07a2f", - "--p-side": "#26233599", + "--p-side": "#26233500", "--p-side-flat": "#2e2b3d", "--p-tab-active": "#26233500", "--p-tabs": "#26233599", @@ -13197,7 +13197,7 @@ exports[`an opaque accent, before and after alpha > tokyonight 1`] = ` "--p-on-accent": "#0b0b0f", "--p-preview": "#303241", "--p-sel-bg": "#7aa2f7", - "--p-side": "#1a1b2699", + "--p-side": "#1a1b2600", "--p-side-flat": "#21222e", "--p-tab-active": "#1a1b2600", "--p-tabs": "#1a1b2699", @@ -13249,7 +13249,7 @@ exports[`an opaque accent, before and after alpha > tokyonight 1`] = ` "--p-on-accent": "#0b0b0f", "--p-preview": "#303241", "--p-sel-bg": "#e07a2f", - "--p-side": "#1a1b2699", + "--p-side": "#1a1b2600", "--p-side-flat": "#21222e", "--p-tab-active": "#1a1b2600", "--p-tabs": "#1a1b2699", @@ -13306,7 +13306,7 @@ exports[`an opaque accent, before and after alpha > umber 1`] = ` "--p-on-accent": "#0b0b0f", "--p-preview": "#443930", "--p-sel-bg": "#c4966a", - "--p-side": "#2b211b99", + "--p-side": "#2b211b00", "--p-side-flat": "#332822", "--p-tab-active": "#2b211b00", "--p-tabs": "#2b211b99", @@ -13358,7 +13358,7 @@ exports[`an opaque accent, before and after alpha > umber 1`] = ` "--p-on-accent": "#0b0b0f", "--p-preview": "#443930", "--p-sel-bg": "#e07a2f", - "--p-side": "#2b211b99", + "--p-side": "#2b211b00", "--p-side-flat": "#332822", "--p-tab-active": "#2b211b00", "--p-tabs": "#2b211b99", @@ -13415,7 +13415,7 @@ exports[`an opaque accent, before and after alpha > volt 1`] = ` "--p-on-accent": "#0b0b0f", "--p-preview": "#232623", "--p-sel-bg": "#d8ff26", - "--p-side": "#05070699", + "--p-side": "#05070600", "--p-side-flat": "#0e100f", "--p-tab-active": "#05070600", "--p-tabs": "#05070699", @@ -13467,7 +13467,7 @@ exports[`an opaque accent, before and after alpha > volt 1`] = ` "--p-on-accent": "#0b0b0f", "--p-preview": "#232623", "--p-sel-bg": "#e07a2f", - "--p-side": "#05070699", + "--p-side": "#05070600", "--p-side-flat": "#0e100f", "--p-tab-active": "#05070600", "--p-tabs": "#05070699", diff --git a/src/renderer/src/lib/chromeTheme.test.ts b/src/renderer/src/lib/chromeTheme.test.ts index 9251d0f..6c97695 100644 --- a/src/renderer/src/lib/chromeTheme.test.ts +++ b/src/renderer/src/lib/chromeTheme.test.ts @@ -1,6 +1,7 @@ import { describe, expect, it } from 'vitest' import { CHROME_COLOUR_TOKENS, chromeTokens } from './chromeTheme' -import { TERM_PRESETS, resolveTermTheme, type TermTheme } from '@core/renderer/lib/termTheme' +import { TERM_PRESETS, presetAccent, resolveTermTheme, type TermTheme } from '@core/renderer/lib/termTheme' +import { SEE_THROUGH_ALPHA, seeThroughAlpha } from '@core/renderer/lib/seeThrough' import { contrastRatio } from '@core/renderer/lib/termAnsi' import { composite } from '@core/renderer/lib/colour' import { WINDOW_EDGES } from '@shared/windowEdges' @@ -83,11 +84,17 @@ describe('chromeTokens', () => { expect(chromeTokens(resolveTermTheme('prism')).vars['--p-bg']).toMatch(/^#[0-9a-f]{6}$/i) const glass = chromeTokens(resolveTermTheme('prism'), 153 / 255).vars // One sheet: the ground, the title bar and the strip carry the same alpha. - for (const name of ['--p-bg', '--p-side', '--p-title', '--p-tabs']) { + for (const name of ['--p-bg', '--p-title', '--p-tabs']) { expect(glass[name], name).toMatch(/^#[0-9a-f]{6}99$/i) } // The active tab sits ON the strip: a second coat would be a darker tab. expect(glass['--p-tab-active']).toMatch(/^#[0-9a-f]{6}00$/i) + // The settings rail sits ON the settings page, which paints the sheet: a + // second coat made the rail near solid under See-through (owner, + // 2026-10-11: "not all things change ... like the sidebar in settings"). + expect(glass['--p-side']).toMatch(/^#[0-9a-f]{6}00$/i) + // Opaque, it is the ground itself, as before. + expect(chromeTokens(resolveTermTheme('prism')).vars['--p-side']).toBe(chromeTokens(resolveTermTheme('prism')).vars['--p-bg']) // What a menu paints, and what the maths measures, stays flat. expect(glass['--p-side-flat']).toMatch(/^#[0-9a-f]{6}$/i) expect(glass['--p-bg-solid']).toMatch(/^#[0-9a-f]{6}$/i) @@ -236,6 +243,18 @@ describe('a see-through accent', () => { const open = chromeTokens(resolveTermTheme(id), 1, undefined, 'hairline', '#e07a2f80').vars expect(vars['--p-sel-bg']).toBe(composite(open['--p-sel-bg'], vars['--p-bg-solid'])) }) + // #156: the switch alone paints every preset at Prism's default see-through, + // so every preset is held to its text there, on the theme's own accent. + it.each(TERM_PRESETS.map((p) => [p.id, p.bg]))('%s: legible at its default see-through', (id, bg) => { + const a = seeThroughAlpha(bg) + const { vars } = chromeTokens(resolveTermTheme(id), a, presetAccent(id)) + expect(vars['--p-bg']).toMatch(a === SEE_THROUGH_ALPHA.dark ? /^#[0-9a-f]{6}b9$/ : /^#[0-9a-f]{6}d1$/) + for (const t of ['--p-text', '--p-dim', '--p-on-accent', '--p-accent', '--p-sel-bg']) + expect(vars[t], t).toMatch(/^#[0-9a-f]{6}$/) + expect(contrastRatio(vars['--p-text'], vars['--p-bg-solid'])).toBeGreaterThanOrEqual(4.5) + expect(contrastRatio(vars['--p-on-accent'], vars['--p-accent'])).toBeGreaterThanOrEqual(4.5) + expect(contrastRatio(vars['--p-on-accent'], vars['--p-sel-bg'])).toBeGreaterThanOrEqual(4.5) + }) it('--p-bg-solid is always flat, whatever the ground alpha (main is only ever sent it)', () => { for (const a of [0.3, 0.5, 153 / 255, 1]) { expect(chromeTokens(resolveTermTheme('prism'), a).vars['--p-bg-solid']).toMatch(/^#[0-9a-f]{6}$/) diff --git a/src/renderer/src/lib/chromeTheme.ts b/src/renderer/src/lib/chromeTheme.ts index f3b94df..c17a320 100644 --- a/src/renderer/src/lib/chromeTheme.ts +++ b/src/renderer/src/lib/chromeTheme.ts @@ -197,7 +197,11 @@ export function chromeTokens( const vars: Record = { '--p-bg-solid': bg, '--p-bg': sheet, - '--p-side': sheet, + // The settings rail sits ON the settings page, which already paints the + // sheet, so on glass it paints NOTHING, as the active tab does: a second + // coat of b9 is 92%, solid to the eye (owner, 2026-10-11: "not all things + // change when you turn on see through window, like the sidebar"). + '--p-side': glass ? bg + '00' : bg, '--p-side-flat': flat, '--p-title': sheet, '--p-tabs': sheet, diff --git a/src/renderer/src/lib/opacityMigration.test.ts b/src/renderer/src/lib/opacityMigration.test.ts index 93c4661..638731c 100644 --- a/src/renderer/src/lib/opacityMigration.test.ts +++ b/src/renderer/src/lib/opacityMigration.test.ts @@ -23,6 +23,10 @@ const custom = (extra: Record): string => /** Dracula's own ground, as the window paints it. */ const DRACULA = resolveTermTheme('dracula').background.slice(0, 7).toLowerCase() const saved = (): Record => JSON.parse(localStorage.getItem(CUSTOM) ?? 'null') +/** What an opaque dark ground paints with the switch on since #156: the + * migration leaves the ground opaque, and the switch alone makes it Prism's + * default see-through (an opaque window under acrylic on was the bug #156 fixes). */ +const DEFAULT_DARK = 0xb9 / 255 beforeEach(() => { localStorage.clear() @@ -89,25 +93,25 @@ describe('migrateOpacity', () => { // Review of #115: step 1 gave Custom.bg the saved alpha, and a live 100 was // skipped as "nothing to do", so an opaque window turned see-through. - it('a Custom saved at 60, left at a live 100 with acrylic on, stays opaque', () => { + it('a Custom saved at 60, left at a live 100 with acrylic on, keeps an opaque ground (not the saved 60)', () => { localStorage.setItem(THEME, 'custom') localStorage.setItem(ACRYLIC, '1') localStorage.setItem(LIVE, '100') localStorage.setItem(CUSTOM, custom({ acrylic: true, opacity: 60 })) migrateOpacity() - expect(termGroundAlpha()).toBe(1) + expect(termGroundAlpha()).toBe(DEFAULT_DARK) expect(windowBackground()).toBe('#1d1f21') // Picking Custom again still restores the SAVED see-through. expect(customTermTheme()?.bg).toBe('#1d1f21' + byte(60)) expect(localStorage.getItem(LIVE)).toBeNull() }) - it('a Custom saved at 60 with no live value stored (read as 100) stays opaque', () => { + it('a Custom saved at 60 with no live value stored (read as 100) keeps an opaque ground', () => { localStorage.setItem(THEME, 'custom') localStorage.setItem(ACRYLIC, '1') localStorage.setItem(CUSTOM, custom({ acrylic: true, opacity: 60 })) migrateOpacity() - expect(termGroundAlpha()).toBe(1) + expect(termGroundAlpha()).toBe(DEFAULT_DARK) const once = JSON.stringify({ ...localStorage }) migrateOpacity() expect(JSON.stringify({ ...localStorage })).toBe(once) @@ -119,7 +123,7 @@ describe('migrateOpacity', () => { localStorage.setItem(CUSTOM, custom({ acrylic: true, opacity: 60 })) migrateOpacity() expect(windowBackground()).toBeNull() - expect(termGroundAlpha()).toBe(1) + expect(termGroundAlpha()).toBe(DEFAULT_DARK) }) it('a Custom with a picked Background: the picked one takes the live value', () => { diff --git a/src/renderer/src/lib/tabMru.test.ts b/src/renderer/src/lib/tabMru.test.ts new file mode 100644 index 0000000..53ac192 --- /dev/null +++ b/src/renderer/src/lib/tabMru.test.ts @@ -0,0 +1,100 @@ +import { describe, expect, it } from 'vitest' +import { startWalk, stepWalk, syncMru, touchMru, walkHolds, walkTarget, type Walk } from './tabMru' + +/** A hold of Ctrl: the walk started from `mru`, then each Tab (1) or + * Shift+Tab (-1) pressed while it is held. Returns the tab landed on. */ +const hold = (mru: readonly string[], presses: Array<1 | -1>): string | null => { + let walk: Walk | null = startWalk(mru) + if (!walk) return null + for (const dir of presses) walk = stepWalk(walk, dir) + return walkTarget(walk) +} + +describe('touchMru', () => { + it('puts the tab in front, once', () => { + expect(touchMru(['a', 'b', 'c'], 'c')).toEqual(['c', 'a', 'b']) + expect(touchMru(['a', 'b'], 'a')).toEqual(['a', 'b']) + expect(touchMru([], 'a')).toEqual(['a']) + }) + + it('returns the same list when the tab is already in front, so nothing re-renders', () => { + const mru = ['a', 'b'] + expect(touchMru(mru, 'a')).toBe(mru) + }) +}) + +describe('syncMru', () => { + it('drops closed tabs and keeps the order of the rest', () => { + expect(syncMru(['c', 'a', 'b'], ['a', 'b'], 'a')).toEqual(['a', 'b']) + }) + + it('adds new tabs after the known ones, in strip order', () => { + expect(syncMru(['b', 'a'], ['a', 'b', 'x', 'y'], 'b')).toEqual(['b', 'a', 'x', 'y']) + }) + + it('starts an empty list from the tab in front, then the strip (a launch, a restore)', () => { + expect(syncMru([], ['a', 'b', 'c'], 'b')).toEqual(['b', 'a', 'c']) + expect(syncMru(['gone'], ['a', 'b', 'c'], 'c')).toEqual(['c', 'a', 'b']) + expect(syncMru([], [], null)).toEqual([]) + }) +}) + +describe('the walk (Most recent, #158)', () => { + const mru = ['c', 'b', 'a'] // c in front, b used before it, a before that + + it('a single Ctrl+Tab goes to the tab used before this one', () => { + expect(hold(mru, [1])).toBe('b') + }) + + it('each further Tab while Ctrl is held goes one further back, and wraps', () => { + expect(hold(mru, [1, 1])).toBe('a') + expect(hold(mru, [1, 1, 1])).toBe('c') + }) + + it('Ctrl+Shift+Tab walks the other way, from the far end on a fresh hold', () => { + expect(hold(mru, [-1])).toBe('a') + expect(hold(mru, [-1, -1])).toBe('b') + expect(hold(mru, [1, 1, -1])).toBe('b') + }) + + it('does not ping-pong: the order changes only when the hold ends', () => { + // Visit a, b, c by hand; then one Ctrl+Tab per hold. + let list: readonly string[] = [] + for (const id of ['a', 'b', 'c']) list = touchMru(list, id) + const first = hold(list, [1]) + expect(first).toBe('b') + list = touchMru(list, first!) // Ctrl released on b + const second = hold(list, [1]) + expect(second).toBe('c') // a flip back, the two last used + list = touchMru(list, second!) + // A long hold reaches the oldest, and releasing there brings it to the front. + const third = hold(list, [1, 1]) + expect(third).toBe('a') + list = touchMru(list, third!) + expect(list).toEqual(['a', 'c', 'b']) + }) + + it('the walk is a snapshot: the list it came from is not changed', () => { + const list = ['c', 'b', 'a'] + const walk = stepWalk(startWalk(list)!, 1) + expect(list).toEqual(['c', 'b', 'a']) + expect(walkTarget(walk)).toBe('b') + }) + + it('the walk holds only while the tab in front is its own and the strip is its snapshot', () => { + const walk = stepWalk(startWalk(['d', 'c', 'b', 'a'])!, 1) // landed on c + expect(walkHolds(walk, ['a', 'b', 'c', 'd'], 'c')).toBe(true) + // A click on another tab mid-hold is a use, not a step: the hold ends. + expect(walkHolds(walk, ['a', 'b', 'c', 'd'], 'a')).toBe(false) + // A tab opened without Ctrl (a folder from Explorer) is not in the snapshot. + expect(walkHolds(walk, ['a', 'b', 'c', 'd', 'x'], 'x')).toBe(false) + expect(walkHolds(walk, ['a', 'b', 'c', 'd', 'x'], 'c')).toBe(false) + // A closed tab could be its next stop. + expect(walkHolds(walk, ['b', 'c', 'd'], 'c')).toBe(false) + }) + + it('over one tab or none there is nothing to walk', () => { + expect(startWalk(['a'])).toBeNull() + expect(startWalk([])).toBeNull() + }) +}) diff --git a/src/renderer/src/lib/tabMru.ts b/src/renderer/src/lib/tabMru.ts new file mode 100644 index 0000000..ecaaee9 --- /dev/null +++ b/src/renderer/src/lib/tabMru.ts @@ -0,0 +1,72 @@ +/** + * MOST RECENT TAB SWITCHING (#158), as pure data: the most-recently-used list + * of tab ids (front = the tab in front) and the walk Ctrl+Tab takes over it. + * + * The walk is a SNAPSHOT of the list taken at the first Tab of a Ctrl hold, and + * the list is only reordered when the hold ends (Ctrl released, or the window + * losing focus), the way browsers and VS Code do it. Reordering on every press + * would make the second Tab flip straight back to where it started (a + * ping-pong), so a long hold could never reach an older tab. + */ + +/** Tab ids, the one in front first, then the one used before it, and so on. */ +export type Mru = readonly string[] + +/** One Ctrl hold: the list as it was at its first press, and where it is. */ +export interface Walk { + readonly list: Mru + readonly at: number +} + +/** The tab came to the front. The same list back when it already was. */ +export function touchMru(mru: Mru, id: string): Mru { + if (mru[0] === id) return mru + return [id, ...mru.filter((t) => t !== id)] +} + +/** + * Follow the strip: closed tabs leave, tabs the list has not seen join after + * the known ones in strip order (the effect that calls this then touches the + * one in front, so a new tab, which is activated, lands first). An empty list + * (a launch, or a restore that settled every placeholder under a new id) + * starts from the tab in front, then the strip. + */ +export function syncMru(mru: Mru, tabIds: readonly string[], activeId: string | null): Mru { + const open = new Set(tabIds) + const kept = mru.filter((id) => open.has(id)) + if (kept.length === 0) { + return activeId && open.has(activeId) ? [activeId, ...tabIds.filter((id) => id !== activeId)] : [...tabIds] + } + const known = new Set(kept) + const added = tabIds.filter((id) => !known.has(id)) + return added.length === 0 && kept.length === mru.length ? mru : [...kept, ...added] +} + +/** A walk needs somewhere to go: with one tab or none there is none. */ +export function startWalk(mru: Mru): Walk | null { + return mru.length < 2 ? null : { list: [...mru], at: 0 } +} + +/** Tab goes one further back (1), Shift+Tab the other way (-1). Wraps, so a + * fresh Shift+Tab lands on the oldest. */ +export function stepWalk(walk: Walk, dir: 1 | -1): Walk { + const n = walk.list.length + return { list: walk.list, at: (walk.at + dir + n) % n } +} + +export function walkTarget(walk: Walk): string { + return walk.list[walk.at] +} + +/** + * Whether a hold still walks the strip as it is (review of #158). Only while + * the tab in front is the one the walk landed on and the strip holds exactly + * the snapshot's tabs: a click on another tab mid-hold is a use like any + * other, and a tab opened or closed without a Ctrl key (a folder from + * Explorer) is one the next Tab press would otherwise walk away from, or to. + */ +export function walkHolds(walk: Walk, tabIds: readonly string[], activeId: string | null): boolean { + if (activeId !== walkTarget(walk) || tabIds.length !== walk.list.length) return false + const open = new Set(tabIds) + return walk.list.every((id) => open.has(id)) +} diff --git a/src/renderer/src/lib/tabSwitchPrefs.test.ts b/src/renderer/src/lib/tabSwitchPrefs.test.ts new file mode 100644 index 0000000..aa249b4 --- /dev/null +++ b/src/renderer/src/lib/tabSwitchPrefs.test.ts @@ -0,0 +1,35 @@ +import { beforeEach, describe, expect, it, vi } from 'vitest' +import { onTabSwitchChange, setTabSwitch, tabSwitch } from './tabSwitchPrefs' + +describe('tabSwitchPrefs', () => { + beforeEach(() => localStorage.clear()) + + it("is In order until somebody chooses, so nobody's keys change on update (#158)", () => { + expect(tabSwitch()).toBe('order') + }) + + it('remembers both choices under its own key', () => { + for (const m of ['recent', 'order'] as const) { + setTabSwitch(m) + expect(tabSwitch()).toBe(m) + expect(localStorage.getItem('prism.window.tabSwitch')).toBe(m) + } + }) + + it('reads a word it does not know as In order, and never stores one', () => { + localStorage.setItem('prism.window.tabSwitch', 'mru') + expect(tabSwitch()).toBe('order') + setTabSwitch('random' as never) + expect(localStorage.getItem('prism.window.tabSwitch')).toBe('order') + }) + + it('tells its listeners on a change, and stops when asked', () => { + const heard = vi.fn() + const off = onTabSwitchChange(heard) + setTabSwitch('recent') + expect(heard).toHaveBeenCalledTimes(1) + off() + setTabSwitch('order') + expect(heard).toHaveBeenCalledTimes(1) + }) +}) diff --git a/src/renderer/src/lib/tabSwitchPrefs.ts b/src/renderer/src/lib/tabSwitchPrefs.ts new file mode 100644 index 0000000..c45b661 --- /dev/null +++ b/src/renderer/src/lib/tabSwitchPrefs.ts @@ -0,0 +1,37 @@ +import { useSyncExternalStore } from 'react' + +// WHERE CTRL+TAB GOES (#158; owner, 2026-10-10: "add a new tab switching mode +// called most recent. so you can either switch chronologically or by most +// recently used"). `order` is the strip, left to right, as it always was, and +// the DEFAULT, so nobody's keys change with the update; `recent` walks the +// most-recently-used list (lib/tabMru). THIS APP'S OWN setting: the strip is +// the app's shell, so its key is not `prism.term.*`. Read defensively: +// anything unknown is In order. + +export type TabSwitch = 'order' | 'recent' + +const KEY = 'prism.window.tabSwitch' + +let listeners: Array<() => void> = [] + +export function validTabSwitch(v: unknown): TabSwitch { + return v === 'recent' ? 'recent' : 'order' +} + +export function tabSwitch(): TabSwitch { + return validTabSwitch(localStorage.getItem(KEY)) +} + +export function setTabSwitch(mode: TabSwitch): void { + localStorage.setItem(KEY, validTabSwitch(mode)) + listeners.forEach((l) => l()) +} + +export function onTabSwitchChange(cb: () => void): () => void { + listeners.push(cb) + return () => { + listeners = listeners.filter((l) => l !== cb) + } +} + +export const useTabSwitch = (): TabSwitch => useSyncExternalStore(onTabSwitchChange, tabSwitch) diff --git a/tools/e2e/run.mjs b/tools/e2e/run.mjs index 7cef8ab..8d89f63 100644 --- a/tools/e2e/run.mjs +++ b/tools/e2e/run.mjs @@ -166,7 +166,7 @@ const tabLabels = (page) => * so a row moving between pages is one line here. */ const PREF_PAGE = { - 'tab-width': 'appearance', 'tab-style': 'appearance', 'title-bar': 'appearance', 'window-edges': 'appearance', 'term-theme': 'appearance', + 'tab-width': 'appearance', 'tab-style': 'appearance', 'tab-switch': 'appearance', 'title-bar': 'appearance', 'window-edges': 'appearance', 'term-theme': 'appearance', 'window-background': 'appearance', 'window-accent': 'appearance', 'term-acrylic': 'appearance', 'term-shell': 'terminal', 'newtab-mode': 'terminal', 'explorer-verb': 'terminal', 'term-font-family': 'terminal', 'term-font': 'terminal', 'help-enabled': 'terminal', @@ -1749,6 +1749,105 @@ const scenarios = { } }, + /** + * TAB SWITCHING, MOST RECENT (#158; owner, 2026-10-10: "so you can either + * switch chronologically or by most recently used"). In order stays the + * default and steps the strip. Most recent walks the used list as browsers + * do: one Ctrl+Tab flips to the tab used before, Tab again while Ctrl is held + * goes further back, and the order changes only when Ctrl is let go, so + * repeated presses never ping-pong. A closed tab leaves the list, a new one + * enters it at the front. + */ + async tabSwitch(ok) { + const w = world() + const gamma = join(dirname(w.alpha), 'gamma') + const delta = join(dirname(w.alpha), 'delta') + mkdirSync(gamma) + mkdirSync(delta) + const { app, page } = await launch(w, { args: [w.alpha, w.beta, gamma], pick: delta }) + try { + ok(await until(async () => (await tabLabels(page)).length === 3), 'three tabs open') + const front = () => + page.evaluate(() => { + const t = [...document.querySelectorAll('[data-tab]')].find( + (el) => el.getAttribute('aria-selected') === 'true' || el.querySelector('[aria-selected="true"]') + ) + return (t?.textContent ?? '').trim() + }) + const lands = async (name, said) => ok(!!(await until(async () => (await front()).startsWith(name), 4000, 50)), `${said} (${await front()})`) + const visit = async (i) => { + await page.locator('[data-tab]').nth(i).click() + await sleep(150) + } + // A hold: Ctrl down, Tab (or Shift+Tab) per step, Ctrl up. + const hold = async (steps) => { + await page.keyboard.down('Control') + for (const s of steps) { + if (s < 0) await page.keyboard.down('Shift') + await page.keyboard.press('Tab') + if (s < 0) await page.keyboard.up('Shift') + await sleep(120) + } + await page.keyboard.up('Control') + await sleep(150) + } + + // IN ORDER, the default: the strip, left to right, wrapping. + await visit(0) + await hold([1]) + await lands('beta', 'In order: Ctrl+Tab steps to the next tab in the strip') + await hold([-1]) + await lands('alpha', 'and Ctrl+Shift+Tab back') + + // The row: right after Tab style, In order by default. + const row = await gotoPref(page, 'tab-switch') + const order = await page.evaluate(() => [...document.querySelectorAll('[data-pref]')].map((e) => e.getAttribute('data-pref'))) + ok(order.indexOf('tab-switch') === order.indexOf('tab-style') + 1, `Tab switching is right after Tab style (${order.slice(0, 4).join(' > ')})`) + ok((await row.locator('[aria-pressed="true"]').getAttribute('data-seg')) === 'order', 'In order is the default') + ok((await row.locator('[data-seg]').allTextContents()).join('|') === 'In order|Most recent', 'the choices are In order and Most recent') + await page.screenshot({ path: resolve(process.cwd(), '.e2e-shots/settings-tab-switch.png') }).catch(() => {}) + await row.locator('[data-seg="recent"]').click() + ok((await page.evaluate(() => localStorage.getItem('prism.window.tabSwitch'))) === 'recent', 'Most recent is stored') + await backToFirst(page) + + // MOST RECENT: used alpha, beta, gamma, in that order. + for (const i of [0, 1, 2]) await visit(i) + await hold([1]) + await lands('beta', 'one Ctrl+Tab goes to the tab used before this one') + await hold([1]) + await lands('gamma', 'and the next flips back: the last two used') + await hold([1, 1]) + await lands('alpha', 'Tab twice in one hold goes two back, no ping-pong') + await hold([1]) + await lands('gamma', 'released there, alpha is now the latest, so the next flip is gamma') + await hold([-1]) + await lands('beta', 'Ctrl+Shift+Tab on a fresh hold goes to the oldest') + + // A CLOSED TAB LEAVES THE LIST: close gamma (idle, so nothing asks). + await visit(2) + await lands('gamma', 'gamma in front') + await page.keyboard.press('Control+w') + ok(await until(async () => (await tabLabels(page)).length === 2), 'Ctrl+W closes it') + const after = await front() + await hold([1]) + const flip = await front() + ok(!flip.startsWith('gamma') && flip !== after && flip.length > 0, `Ctrl+Tab goes to the other open tab, never the closed one (${after} > ${flip})`) + + // A NEW TAB ENTERS AT THE FRONT: opened (asked, the chooser answers delta), + // one flip goes to the tab before it, the next comes back to it. + await page.evaluate(() => localStorage.setItem('prism.newtab.mode', 'ask')) + await page.locator('[aria-label="New tab"]').click() + ok(await until(async () => (await tabLabels(page)).length === 3), 'a new tab opens') + await lands('delta', 'and is in front') + await hold([1]) + await lands(flip, 'one Ctrl+Tab goes to the tab used before the new one') + await hold([1]) + await lands('delta', 'and the next comes back to the new tab') + } finally { + await closeApp(app) + } + }, + /** * THE INDICATOR STYLES (#143): Minimal, Ring and Full, on Volt and Paper, in * both tab styles. Measured: Ring spins by a working tab's name and leaves @@ -3417,7 +3516,11 @@ const scenarios = { chosen: chosen ? parse(getComputedStyle(chosen).backgroundColor) : null, hoverHi: parse(root.getPropertyValue('--p-hover-hi').trim()), accent: parse(root.getPropertyValue('--p-accent').trim()), - accentButtons: accentFilled.map((b) => (b.hasAttribute('data-save-term') ? 'save' : b.textContent.trim())), + // An ON switch wears the accent too, on purpose (#138, #139), so it + // is named and allowed; any other accent-filled button is a miss. + accentButtons: accentFilled.map((b) => + b.hasAttribute('data-save-term') ? 'save' : b.getAttribute('role') === 'switch' && b.getAttribute('aria-checked') === 'true' ? 'switch' : b.textContent.trim() + ), sideways: document.querySelector('[data-settings-page]').scrollWidth > document.querySelector('[data-settings-page]').clientWidth + 1 } }) @@ -3439,7 +3542,7 @@ const scenarios = { if (m.warn !== null) ok(m.warn >= 4.5, `${scheme} ${p}: a warning subtext reads 4.5:1 (${m.warn.toFixed(1)}:1)`) ok(!!m.chosen && m.chosen.rgb.join() === m.hoverHi.rgb.join() && Math.abs(m.chosen.a - m.hoverHi.a) < 0.02, `${scheme} ${p}: the chosen rail page is the grey fill (${JSON.stringify(m.chosen)})`) ok(!!m.chosen && m.chosen.rgb.join() !== m.accent.rgb.join(), `${scheme} ${p}: and not the accent`) - ok(m.accentButtons.every((b) => b === 'save'), `${scheme} ${p}: the only accent-filled buttons are Save changes (${JSON.stringify(m.accentButtons)})`) + ok(m.accentButtons.every((b) => b === 'save' || b === 'switch'), `${scheme} ${p}: the only accent-filled buttons are Save changes and on switches (${JSON.stringify(m.accentButtons)})`) ok(!m.sideways, `${scheme} ${p}: nothing scrolls sideways at 1600px`) await page.screenshot({ path: resolve(process.cwd(), `.e2e-shots/settings-${p}-${scheme}.png`) }).catch(() => {}) } @@ -3508,6 +3611,9 @@ const scenarios = { for (const file of ['core/renderer/settings/options.ts', 'core/renderer/settings/markOptions.ts', 'core/renderer/settings/dictationOptions.ts', 'core/renderer/settings/helpOptions.ts', 'src/renderer/src/components/settings/appOptions.ts']) for (const m of readFileSync(resolve(process.cwd(), file), 'utf8').matchAll(/\{\s*id: '([a-z-]+)'[^}]*\}/g)) if (!m[0].includes('onlyWhere')) labelOf[m[1]] = (m[0].match(/label: '([^']+)'/) ?? [])[1] + // options.ts keeps Prism's name for this row; Prism Terminal draws and + // indexes it as the see-through window (#156, `acrylicLabel`). + labelOf['term-acrylic'] = 'See-through window' const order = [...readFileSync(resolve(process.cwd(), 'src/renderer/src/components/settings/settingsIndex.ts'), 'utf8').matchAll(/'([a-z]+(?:-[a-z]+)+|[a-z]+-[a-z]+)'/g)].map((m) => m[1]) const ids = [...new Set(order.filter((id) => labelOf[id]))] ok(ids.length >= 30, `the index covers every row drawn on this PC (${ids.length})`) @@ -3687,7 +3793,8 @@ const scenarios = { // and the agent rows have pages of their own; Appearance keeps the // window's rows above the theme and what a theme sets under it. const rows = await page.evaluate(() => [...document.querySelectorAll('[data-pref]')].map((e) => e.getAttribute('data-pref'))) - const want = ['tab-width', 'tab-style', 'title-bar', 'window-edges', 'term-theme', 'window-background', 'window-accent', 'term-acrylic'] + // The see-through row sits right under the wall since #156, as Prism's. + const want = ['tab-width', 'tab-style', 'tab-switch', 'title-bar', 'window-edges', 'term-theme', 'term-acrylic', 'window-background', 'window-accent'] ok(JSON.stringify(rows) === JSON.stringify(want), `Appearance runs ${want.join(' > ')} (${rows.join(' > ')})`) // Font size is 50% to 200% in tens. await gotoPref(page, 'term-font') @@ -4368,6 +4475,131 @@ const scenarios = { } }, + /** + * THE SEE-THROUGH WINDOW (#156; owner, 2026-10-10: "add support for the see + * through window setting ... its in prism in style settings i want it here + * too"). The acrylic row IS it: named and worded as Prism's, right under the + * wall, and the switch ALONE makes the window see-through at Prism's own + * levels (0xb9 on a dark ground, 0xd1 on a light one), where before it + * changed the material and left a preset's ground opaque. The Background's + * Alpha shows what is in force and stops at 95 (opaque is the switch's off); + * a picked alpha wins; off is solid. + */ + async seeThrough(ok) { + const w = world() + const { app, page } = await launch(w, { args: [w.alpha] }) + const sheet = () => page.evaluate(() => getComputedStyle(document.documentElement).getPropertyValue('--p-bg').trim().toLowerCase()) + /** How much of the desktop a surface hides: its own background and every + * box behind it, composited (1 is solid, 0 is clear). */ + const coats = () => + page.evaluate(() => { + const alpha = (c) => { + const m = /rgba?\(([^)]+)\)/.exec(c) + if (!m) return 0 + const p = m[1].split(/[\s,/]+/).filter(Boolean) + return p.length > 3 ? parseFloat(p[3]) : 1 + } + const seen = (el) => { + if (!el) return -1 + let keep = 1 + for (let n = el; n; n = n.parentElement) keep *= 1 - alpha(getComputedStyle(n).backgroundColor) + return Math.round((1 - keep) * 1000) / 1000 + } + return { + strip: seen(document.querySelector('[data-tab-strip]')), + row: seen(document.querySelector('[data-title-bar]')), + rail: seen(document.querySelector('nav[aria-label="Settings pages"]')), + page: seen(document.querySelector('[data-settings-page] .p-scroll')) + } + }) + const sw = page.locator('[data-pref="term-acrylic"] [role="switch"]') + const sub = () => page.locator('[data-pref="term-acrylic"] [title]').first().getAttribute('title') + const bgRow = page.locator('[data-pref="window-background"]') + const pop = page.locator('[data-colour-popover][role="dialog"]') + /** The Background picker's Alpha, read and closed again. */ + const alphaReads = async () => { + await bgRow.scrollIntoViewIfNeeded() + await bgRow.locator('[data-colour-swatch]').click() + await pop.waitFor({ timeout: 3000 }) + const a = pop.locator('[role="slider"][aria-label="Alpha"]') + const v = { now: await a.getAttribute('aria-valuenow'), max: await a.getAttribute('aria-valuemax') } + await page.keyboard.press('Escape') + await until(async () => (await pop.count()) === 0, 3000, 50) + return v + } + /** A theme pick, answering the unsaved-changes question if it asks. */ + const pick = async (id) => { + await page.locator(`[data-term-card="${id}"]`).first().click() + const ask = page.locator('[data-theme-switch-ask]') + if (await until(async () => (await ask.count()) === 1, 1500, 50)) await page.locator('[data-ask-discard]').click() + await until(async () => (await page.locator(`[data-term-card="${id}"]`).first().getAttribute('aria-pressed')) === 'true', 4000, 50) + } + try { + await gotoPref(page, 'term-acrylic') + const more = page.locator('button[aria-label^="Show all"]') + if ((await more.count()) === 1) await more.click() + // Named and placed as Prism's: right under the wall, before the colours. + const rows = await page.evaluate(() => [...document.querySelectorAll('[data-pref]')].map((e) => e.getAttribute('data-pref'))) + const at = rows.indexOf('term-theme') + ok(rows[at + 1] === 'term-acrylic' && rows[at + 2] === 'window-background', `the row sits right under the wall (${rows.join(' > ')})`) + ok((await sw.getAttribute('aria-label')) === 'See-through window', `it is called See-through window (${await sw.getAttribute('aria-label')})`) + ok((await sub()) === 'The desktop shows behind every surface.', `with Prism's words (${await sub()})`) + + // The tabs in the top row (the owner's layout): the row and the strip + // in it are two boxes over one pixel. + const tb = await gotoPref(page, 'title-bar') + await tb.locator('[role="switch"]').click() + ok(!!(await until(async () => (await page.locator('[data-title-bar="tabs"]').count()) === 1, 4000, 50)), 'the tabs moved into the top row') + await gotoPref(page, 'term-acrylic') + if ((await more.count()) === 1) await more.click() + + // A dark preset: the switch alone paints 0xb9. + await pick('dracula') + ok(/^#[0-9a-f]{6}$/.test(await sheet()), `off, the window is solid (${await sheet()})`) + await sw.click() + ok(!!(await until(async () => /^#[0-9a-f]{6}b9$/.test(await sheet()), 4000, 50)), `on a dark preset the switch alone paints alpha b9 (${await sheet()})`) + // EVERY SURFACE IS ONE COAT (owner, 2026-10-11: "not all things change + // when you turn on see through window, like the sidebar in settings or + // the tab bar"). A translucent box over another translucent box is two + // coats, b9 twice is 92% and three times 98%: solid to the eye. + const one = 0xb9 / 255 + let seen = await coats() + await until(async () => Object.values((seen = await coats())).every((a) => Math.abs(a - one) < 0.01), 4000, 50) + ok(Object.values(seen).every((a) => Math.abs(a - one) < 0.01), `on, the strip, the top row, the settings rail and its page each show the desktop through one coat at ${one.toFixed(3)} (${JSON.stringify(seen)})`) + const dark = await alphaReads() + ok(dark.now === '73' && dark.max === '95', `the Background's Alpha reads 73 and stops at 95 (${dark.now}, max ${dark.max})`) + + // A picked alpha wins; Reset gives the default back. + const field = bgRow.locator('input:not([type])') + await field.fill('#1c233099') + await field.press('Enter') + ok(!!(await until(async () => (await sheet()) === '#1c233099', 4000, 50)), `a picked 60 wins (${await sheet()})`) + await page.locator('[data-follow-theme="background"]').click() + ok(!!(await until(async () => /^#[0-9a-f]{6}b9$/.test(await sheet()), 4000, 50)), `Reset gives the default back (${await sheet()})`) + + // Off is solid. + await sw.click() + ok(!!(await until(async () => /^#[0-9a-f]{6}$/.test(await sheet()), 4000, 50)), `switched off, the window is solid (${await sheet()})`) + await until(async () => Object.values((seen = await coats())).every((a) => a === 1), 4000, 50) + ok(Object.values(seen).every((a) => a === 1), `off, every one of them is solid (${JSON.stringify(seen)})`) + + // A light preset: 0xd1. A theme pick resets the switch, as every extra. + await pick('paper') + await sw.click() + ok(!!(await until(async () => /^#[0-9a-f]{6}d1$/.test(await sheet()), 4000, 50)), `on Paper the switch paints alpha d1 (${await sheet()})`) + const light = await alphaReads() + ok(light.now === '82', `the Background's Alpha reads 82 (${light.now})`) + await sw.scrollIntoViewIfNeeded() + await sleep(400) + await page.screenshot({ path: resolve(process.cwd(), '.e2e-shots/see-through.png') }).catch(() => {}) + + // Leave on a quiet preset, the switch off (a pick resets it): nothing holds the close. + await pick('dracula') + } finally { + await closeApp(app) + } + }, + async themeCards(ok) { // PICKING A THEME MOVES NOTHING (owner, 2026-09-22: "when I click a theme // ... the ui shifts a bit, it's not every theme but some"). Only the @@ -4398,6 +4630,18 @@ const scenarios = { return { cards, below: row ? Math.round(y(row) * 10) / 10 : -1 } }) const first = await measure() + // THE ORDER (#157, owner 2026-10-10): PT Default leads, then the neutral + // grounds black to white, then the coloured ones. The expected list is the + // unit test's snapshot of orderTermThemes, read here so the two never + // disagree (this runner cannot import the TypeScript). + const snap = readFileSync(resolve(process.cwd(), 'core/renderer/lib/__snapshots__/themeOrder.test.ts.snap'), 'utf8') + const computed = [...snap.matchAll(/^\s+"([a-z0-9-]+)",?$/gm)].map((m) => m[1]) + const wantOrder = ['pt-default', ...computed.filter((id) => id !== 'pt-default')] + const wallOrder = first.cards.map((c) => c.id).filter((id) => id !== 'custom') + ok( + computed.length >= 39 && wallOrder.join(',') === wantOrder.join(','), + `the wall runs PT Default, neutrals black to white, then coloured (${wallOrder.slice(0, 14).join(' ')} ...)` + ) const rowTops = [...new Set(first.cards.map((c) => c.top))] ok(rowTops.length >= 2, `the wall has two rows to pick across (${rowTops.length})`) const inRow = (top) => first.cards.find((c) => c.top === top)?.id @@ -4889,12 +5133,13 @@ const scenarios = { ) // BACKGROUND AND ACCENT SIT RIGHT UNDER THE THEME WALL (2026-09-28: a - // theme sets them, so they follow it; they sat under Font size before). + // theme sets them, so they follow it; they sat under Font size before), + // after the see-through window, which moved up to the wall in #156. const order = await page.evaluate(() => [...document.querySelectorAll('[data-pref]')].map((e) => e.getAttribute('data-pref'))) const at = order.indexOf('term-theme') ok( - at >= 0 && order[at + 1] === 'window-background' && order[at + 2] === 'window-accent', - `Background and Accent come right after the theme wall (${order.slice(Math.max(0, at - 1), at + 4).join(' > ')})` + at >= 0 && order[at + 1] === 'term-acrylic' && order[at + 2] === 'window-background' && order[at + 3] === 'window-accent', + `See-through, Background and Accent come right after the theme wall (${order.slice(Math.max(0, at - 1), at + 5).join(' > ')})` ) // THE BACKGROUND (owner: "let background colour be a setting"): the