Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
419 changes: 346 additions & 73 deletions docs/features/theming.md

Large diffs are not rendered by default.

9 changes: 9 additions & 0 deletions docs/proposals/mockups/proposal-h/SPEC-display-left-rail.md
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,15 @@ Colours are the §D.0 #302 tokens.

### D.0 Palette tokens (all inherited — `styles.scss` #302 + Superhero)

> **SUPERSEDED (2026-07-24, owner ruling — "Tokyo-11" re-theme).** The
> table below is the #302 palette this section originally shipped with; it
> is kept verbatim here as a historical record of what shipped at the time
> this spec's other rows (sizing/spacing/I-N markers) were written and
> verified against. It no longer reflects the site's actual colours. The
> live, binding palette is [`docs/features/theming.md`](../../../features/theming.md)
> — edit `_theme-tokens.scss` there, not this table, for any future
> retheme.

| Token | Value | Token | Value |
| ---------------- | ------------------ | ------------------ | --------------------- |
| body bg | `#0f2537` | primary (hover) | `#df6919` (`#be5915`) |
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/components/AutofillCollapse.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ export function AutofillCollapse({
// the two tokens are one hex digit apart by design, not by accident. Do not "fix"
// this back to `#4e5d6c` again; see SPEC-display-left-rail.md §D.0 for the explicit
// note distinguishing them.
backgroundColor: headerBackground ?? "#4E5D6B",
backgroundColor: headerBackground ?? "var(--theme-card-header-bg)",
zIndex: zIndex + 1,
cursor: "pointer",
...(headerPadding != null ? { padding: headerPadding } : {}),
Expand Down
4 changes: 2 additions & 2 deletions frontend/src/features/card/Card.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ const ErrorPlaceholder = styled.div`
align-items: center;
justify-content: center;
gap: 0.4rem;
background: #4e5d6c;
background: var(--bs-secondary);
color: rgba(255, 255, 255, 0.75);
text-align: center;
padding: 0.5rem;
Expand Down Expand Up @@ -488,7 +488,7 @@ interface CardProportionWrapperProps {

const CardProportionWrapperStyle = styled.div<{ $borderWidth?: number }>`
z-index: 0;
background: #4e5d6c;
background: var(--bs-secondary);
border: solid ${(props) => props.$borderWidth ?? 0}px black;
`;

Expand Down
70 changes: 43 additions & 27 deletions frontend/src/features/card/CardbackApplyPrompt.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,30 +5,36 @@
* per-slot picker) - one component, so the two surfaces can't drift (§C.2's own binding
* requirement). Never a second stacked modal - always rendered inline by its caller.
*
* Token table E.2 (BINDING, #302 palette): `.cbprompt` panel `#22303f` / `1px #16202b` border +
* left `3px #df6919`; `.applybtn` primary-tinted (`#df6919` border / `#ffb27d` text, hover fills
* `#df6919`/`#fff`, done state `#5cb85c`/`#8fe08f`); `.defbtn` info-tinted (`#5bc0de` border /
* `#8fd7ea` text, hover fills `#5bc0de`/`#062430`, same done state); `.trapnote` `#ffd76a`
* (rail only); `.skip` `#8fa0b0` underline link (toolbar only, since the rail per-slot picker
* already IS the "no modal, ever" surface - leaving the section collapsed is itself "not now").
* Token table E.2 (BINDING, #302 palette; re-themed to Tokyo-11, 2026-07-24 - see
* docs/features/theming.md - tokens and spec tables move together, same discipline
* DisplayLeftRailFidelity.spec.ts's own re-theme pass used): `.cbprompt` panel
* $theme-raised-bg / `1px` $theme-divider border + left `3px` $primary; `.applybtn`
* primary-tinted ($primary border/text, hover fills $primary/$theme-btn-ink - Tokyo-11's
* primary is light, so the filled-hover state needs the dark ink, not white -, done state
* $success/$success); `.defbtn` info-tinted ($info border/text, hover fills $info/
* $theme-btn-ink, same done state); `.trapnote` $warning (rail only); `.skip` $theme-muted
* underline link (toolbar only, since the rail per-slot picker already IS the "no modal,
* ever" surface - leaving the section collapsed is itself "not now"). Unlike the #302 palette,
* Tokyo-11's primary/info/success tokens are all light enough to use directly as text colour -
* no separate hand-picked tint literal is needed the way `#ffb27d`/`#8fd7ea` were.
*/
import styled from "@emotion/styled";
import React, { useState } from "react";

import { CustomBackSlotThumbnail } from "@/features/card/cardbackApply";

const Panel = styled.div`
background: #22303f;
border: 1px solid #16202b;
border-left: 3px solid #df6919;
background: var(--theme-raised-bg);
border: 1px solid var(--theme-divider);
border-left: 3px solid var(--bs-primary);
padding: 10px 12px;
margin-top: 12px;
`;

const Title = styled.div`
font-size: 13px;
font-weight: 700;
color: #ebebeb;
color: var(--bs-body-color);
margin-bottom: 2px;
display: flex;
align-items: center;
Expand All @@ -37,7 +43,7 @@ const Title = styled.div`

const Intro = styled.div`
font-size: 12px;
color: #8fa0b0;
color: var(--theme-muted);
margin-bottom: 10px;
`;

Expand All @@ -46,7 +52,7 @@ const Choice = styled.div`
align-items: center;
gap: 10px;
padding: 8px 0;
border-top: 1px solid #16202b;
border-top: 1px solid var(--theme-divider);

&:first-of-type {
border-top: none;
Expand All @@ -59,19 +65,21 @@ const ChoiceLabel = styled.div`

.h {
font-size: 13px;
color: #ebebeb;
color: var(--bs-body-color);
}

.s {
font-size: 11px;
color: #8fa0b0;
color: var(--theme-muted);
}
`;

const ApplyButton = styled.button<{ $done: boolean }>`
background: transparent;
border: 1px solid ${(props) => (props.$done ? "#5cb85c" : "#df6919")};
color: ${(props) => (props.$done ? "#8fe08f" : "#ffb27d")};
border: 1px solid
${(props) => (props.$done ? "var(--bs-success)" : "var(--bs-primary)")};
color: ${(props) =>
props.$done ? "var(--bs-success)" : "var(--bs-primary)"};
font-family: inherit;
font-size: 13px;
padding: 4px 10px;
Expand All @@ -81,15 +89,20 @@ const ApplyButton = styled.button<{ $done: boolean }>`
pointer-events: ${(props) => (props.$done ? "none" : "auto")};

&:hover {
background: ${(props) => (props.$done ? "transparent" : "#df6919")};
color: ${(props) => (props.$done ? "#8fe08f" : "#fff")};
background: ${(props) =>
props.$done ? "transparent" : "var(--bs-primary)"};
/* Tokyo-11 ink flip - primary is light, so the filled-hover state needs dark ink, not
white (was #fff under the #302 palette). */
color: ${(props) =>
props.$done ? "var(--bs-success)" : "var(--theme-btn-ink)"};
}
`;

const DefaultButton = styled.button<{ $done: boolean }>`
background: transparent;
border: 1px solid ${(props) => (props.$done ? "#5cb85c" : "#5bc0de")};
color: ${(props) => (props.$done ? "#8fe08f" : "#8fd7ea")};
border: 1px solid
${(props) => (props.$done ? "var(--bs-success)" : "var(--bs-info)")};
color: ${(props) => (props.$done ? "var(--bs-success)" : "var(--bs-info)")};
font-family: inherit;
font-size: 13px;
padding: 4px 10px;
Expand All @@ -99,8 +112,11 @@ const DefaultButton = styled.button<{ $done: boolean }>`
pointer-events: ${(props) => (props.$done ? "none" : "auto")};

&:hover {
background: ${(props) => (props.$done ? "transparent" : "#5bc0de")};
color: ${(props) => (props.$done ? "#8fe08f" : "#062430")};
background: ${(props) => (props.$done ? "transparent" : "var(--bs-info)")};
/* Tokyo-11 ink flip - info is light too (was #062430 dark-navy-on-cyan under #302; the
new $theme-btn-ink token is the same idea, generalised across every filled-light role). */
color: ${(props) =>
props.$done ? "var(--bs-success)" : "var(--theme-btn-ink)"};
}
`;

Expand All @@ -109,7 +125,7 @@ const SkipRow = styled.div`
text-align: right;

a {
color: #8fa0b0;
color: var(--theme-muted);
font-size: 12px;
text-decoration: underline;
cursor: pointer;
Expand All @@ -118,7 +134,7 @@ const SkipRow = styled.div`

const TrapNote = styled.div`
font-size: 11px;
color: #ffd76a;
color: var(--bs-warning);
margin-top: 8px;
display: flex;
gap: 5px;
Expand All @@ -136,8 +152,8 @@ const ThumbPair = styled.div`
display: flex;
align-items: center;
gap: 3px;
background: #16202b;
border: 1px solid rgba(235, 235, 235, 0.15);
background: var(--theme-divider);
border: 1px solid rgba(var(--bs-body-color-rgb), 0.15);
padding: 3px;
`;

Expand All @@ -153,7 +169,7 @@ const ThumbImg = styled.div<{ $url: string | undefined }>`

const ThumbLabel = styled.div`
font-size: 9px;
color: #8fa0b0;
color: var(--theme-muted);
max-width: 90px;
white-space: nowrap;
overflow: hidden;
Expand Down
4 changes: 2 additions & 2 deletions frontend/src/features/card/RequestedPrintingBadge.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,8 @@ export function RequestedPrintingBadge({
style={{
display: "inline-block",
marginTop: "5px",
background: "#ffc107",
color: "#111",
background: "var(--bs-warning)",
color: "var(--theme-btn-ink)",
fontFamily: "monospace",
fontSize: "10px",
padding: "1px 7px",
Expand Down
12 changes: 7 additions & 5 deletions frontend/src/features/display/ConfidenceElement.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -74,15 +74,17 @@ const NotThisPrintingButton = styled(Button)`
font-weight: 600;
line-height: 1.4;
border-radius: 10px;
background: rgba(217, 83, 79, 0.12);
background: rgba(var(--bs-danger-rgb), 0.12);
color: #f0b3b1;
border: 1px solid rgba(217, 83, 79, 0.55);
border: 1px solid rgba(var(--bs-danger-rgb), 0.55);

&:hover:not(:disabled),
&:focus:not(:disabled) {
background: #d9534f;
color: #fff;
border-color: #d9534f;
background: var(--bs-danger);
/* Tokyo-11 ink flip: danger is a light red (6.46:1 with dark ink vs. 2.65:1 with white) -
see styles.scss's own $color-contrast-dark note. */
color: var(--theme-btn-ink);
border-color: var(--bs-danger);
}

&[data-confirmed="true"] {
Expand Down
Loading
Loading