feat: nový vzhled Apothecary Diaries
CI / Generate TypeScript types (push) Successful in 10s
CI / Server unit tests (push) Successful in 27s
CI / Build server (push) Successful in 29s
CI / Build client (push) Successful in 42s
CI / Playwright E2E tests (push) Successful in 1m56s
CI / Build and push Docker image (push) Successful in 48s
CI / Notify (push) Successful in 2s

This commit is contained in:
mates committed 2026-10-25 19:45:22 +01:00
1 parent 0cf2ddc3ce
commit 20b937cdc2
10 files changed
+876 -5

No files matched your search

+1
View File
@@ -18,6 +18,7 @@ import './themes/bocchi.scss';
import './themes/evangelion.scss';
import './themes/yurucamp.scss';
import './themes/spyfamily.scss';
import './themes/apothecary.scss';
import { faCircleCheck, faNoteSticky, faTrashCan, faComment } from '@fortawesome/free-regular-svg-icons';
import { useSettings } from './context/settings';
import Footer from './components/Footer';
+11
View File
@@ -105,6 +105,17 @@
box-shadow: 0 0 0 2px #1e6f6c;
}
// Styl Apothecary Diaries: emoji na nefritovém disku se zlatým lemem
.eater-badge-apothecary {
display: inline-grid;
place-items: center;
font-size: 15px;
line-height: 1;
border-color: #d9b65e;
background: radial-gradient(circle at 40% 35%, #cfe9dc, #6fae92);
box-shadow: 0 0 0 2px #a8322a;
}
// Odznak a jméno drží na jednom řádku (úzký sloupec „Člen" na stránce objednávek)
.user-info:has(.eater-badge) {
display: inline-flex;
+8 -1
View File
@@ -55,6 +55,12 @@ const SXF_LEVELS = [
{ minItems: 2, emoji: '🥜', title: 'Úroveň Anya — k obědu ještě hrst buráků (waku waku!)' },
];
/** Úrovně ve stylu Apothecary Diaries — emoji na nefritovém disku se zlatým lemem. Seřazeno od nejvyšší úrovně. */
const APO_LEVELS = [
{ minItems: 3, emoji: '🧪', title: 'Úroveň Maomao — ochutná úplně všechno, hlavně kdyby to bylo otrávené' },
{ minItems: 2, emoji: '🍡', title: 'Úroveň Xiaolan — k obědu ještě sladkosti a klepy z paláce' },
];
/** Úrovně podle stylu pro odznaky s emoji. */
const EMOJI_LEVELS: Partial<Record<StyleTheme, typeof MLP_LEVELS>> = {
mlp: MLP_LEVELS,
@@ -64,6 +70,7 @@ const EMOJI_LEVELS: Partial<Record<StyleTheme, typeof MLP_LEVELS>> = {
evangelion: EVA_LEVELS,
yurucamp: YC_LEVELS,
spyfamily: SXF_LEVELS,
apothecary: APO_LEVELS,
};
type Props = {
@@ -71,7 +78,7 @@ type Props = {
items: number,
};
/** Odznak s postavou u strávníků s více jídly — jen ve stylech Umamusume, My Little Pony, Hell Girl, K-ON!, Bocchi the Rock!, Evangelion, Yuru Camp△ a Spy × Family. */
/** Odznak s postavou u strávníků s více jídly — jen ve stylech Umamusume, My Little Pony, Hell Girl, K-ON!, Bocchi the Rock!, Evangelion, Yuru Camp△, Spy × Family a Apothecary Diaries. */
export default function EaterBadge({ items }: Readonly<Props>) {
const styleTheme = useSettings()?.styleTheme;
const isUma = styleTheme === 'umamusume';
+72
View File
@@ -716,3 +716,75 @@
}
}
}
// ============================================
// Konfety ve stylu Apothecary Diaries
// ============================================
.confetti-apo {
filter: drop-shadow(0 3px 3px rgb(58 31 20 / 0.28));
}
// Štítky jako papírky na šuplících s léky — mincho a zlatý vnitřní lem
.confetti-apo-badge {
padding: 4px 14px;
border-radius: 3px;
color: #fdf6e6;
box-shadow: inset 0 0 0 2px rgb(217 182 94 / 0.7);
font-family: 'Shippori Mincho', 'Noto Serif JP', serif;
font-weight: 800;
font-size: 1.1rem;
white-space: nowrap;
}
// Nápis „薬屋のひとりごと" — lakovaná deska se zlatým kováním, vyjede jako svitek
.confetti-apo-banner {
position: absolute;
top: 38%;
left: 50%;
transform: translate(-50%, -50%);
padding: 14px 44px 16px;
font-family: 'Shippori Mincho', 'Noto Serif JP', serif;
font-weight: 800;
font-size: clamp(1.6rem, 6vw, 3.6rem);
letter-spacing: 0.08em;
white-space: nowrap;
color: #fdf6e6;
text-shadow: 0 0 14px rgb(232 165 74 / 0.6);
background: linear-gradient(180deg, #b63a30, #84241d);
border: 2px solid #d9b65e;
outline: 1px solid #d9b65e;
outline-offset: 4px;
border-radius: 4px;
box-shadow: 0 14px 30px rgb(0 0 0 / 0.35);
animation: apo-banner 2.6s ease both;
}
@keyframes apo-banner {
0% { clip-path: inset(0 50% 0 50%); opacity: 0; }
8% { opacity: 1; }
24%, 80% { clip-path: inset(-20px -20px -20px -20px); opacity: 1; }
100% { clip-path: inset(-20px -20px -20px -20px); opacity: 0; }
}
// Postava s hláškou — nefritový disk se zlatým lemem a bublina jako lékařský záznam
.confetti-apothecary-voice {
.confetti-mlp-avatar {
border: 4px solid #d9b65e;
background: radial-gradient(circle at 40% 35%, #cfe9dc, #6fae92);
box-shadow: 0 0 0 3px var(--mlp-speaker, #2f7d62), 0 4px 10px rgb(0 0 0 / 0.3);
}
.confetti-mlp-bubble {
background: #fbf6ea;
color: #24201c;
border: 1px solid #c9a24a;
border-left: 5px solid var(--mlp-speaker, #a8322a);
border-radius: 4px;
box-shadow: 0 6px 14px rgb(0 0 0 / 0.25);
font-family: 'Shippori Mincho', 'Noto Serif JP', serif;
p {
font-weight: 700;
}
}
}
+17 -1
View File
@@ -121,6 +121,21 @@ const SXF_SPEAKERS = [
{ name: 'Becky Blackbell', emoji: '🎀', color: '#d9a441', quote: 'Anyo, vždyť tohle je úplně jako z romantického dramatu!' },
{ name: 'Henry Henderson', emoji: '🎩', color: '#5a4a3a', quote: 'Elegantní volba! Vskutku elegantní!' },
];
const APO_EMOJI = ['🌿', '🧪', '🍵', '🏮', '🌸', '🐸', '🍄', '📜', '🪷', '🌙', '💮', '🍡', '🪭', '🐛'];
// Hlášky z Apothecary Diaries (ochutnávání jedů, Nefritový pavilon, zahradní slavnost, Maomaův pohled jako na slimáka...)
const APO_BADGES = ['薬屋のひとりごと', 'Ochutnáno ✓', 'Jed nenalezen', 'Jinshi-sama', 'Nefritový pavilon', 'Zahradní slavnost', 'Bylinky!', 'Vnitřní palác', 'Pohled jako na slimáka', 'Housenice čínská'];
const APO_BADGE_COLORS = ['#a8322a', '#2f7d62', '#b8902e', '#24201c', '#6b5aa6', '#c76a86'];
/** Maomao a obyvatelé vnitřního paláce s „hláškou" po finálním výsledku. */
const APO_SPEAKERS = [
{ name: 'Maomao', emoji: '🧪', color: '#6f8f6b', quote: 'Žádný jed. Škoda… ale chutnat to bude i tak.' },
{ name: 'Jinshi', emoji: '🌙', color: '#6b5aa6', quote: 'Výborná volba. Jen se na mě, Maomao, nedívej jako na slimáka.' },
{ name: 'Gaoshun', emoji: '🍵', color: '#4f5d6b', quote: 'Zařídím to. Mistře Jinshi, prosím, jezte tentokrát včas.' },
{ name: 'Konkubína Gyokuyou', emoji: '💎', color: '#a8322a', quote: 'Jak báječné! Maomao, ochutnáš to nejdřív za mě, že ano?' },
{ name: 'Xiaolan', emoji: '🍡', color: '#d97a95', quote: 'Maomao, Maomao! Prý tam dávají sladkosti navíc!' },
{ name: 'Luomen', emoji: '🌿', color: '#8a7a5a', quote: 'Moudrá volba. Jen nezapomeň, že i lék může být jedem.' },
{ name: 'Lakan', emoji: '♟️', color: '#7a5c3a', quote: 'Lidi vidím jen jako figurky na desce… ale tahle figurka je k snědku.' },
{ name: 'Konkubína Lishu', emoji: '🌸', color: '#c98fb0', quote: 'J-já si dám to samé… když to Maomao ochutnala.' },
];
/** Styly, jejichž konfety tvoří emoji a samolepky s hláškami (a po finále promluví postava s emoji). */
const EMOJI_CONFETTI: Partial<Record<WheelTheme, {
prefix: string, badges: string[], colors: string[], emoji: string[],
@@ -134,6 +149,7 @@ const EMOJI_CONFETTI: Partial<Record<WheelTheme, {
evangelion: { prefix: 'confetti-eva', badges: EVA_BADGES, colors: EVA_BADGE_COLORS, emoji: EVA_EMOJI, speakers: EVA_SPEAKERS, banner: '👏 おめでとう 👏' },
yurucamp: { prefix: 'confetti-yc', badges: YC_BADGES, colors: YC_BADGE_COLORS, emoji: YC_EMOJI, speakers: YC_SPEAKERS, banner: '⛺ ゆるキャン△ 🔥' },
spyfamily: { prefix: 'confetti-sxf', badges: SXF_BADGES, colors: SXF_BADGE_COLORS, emoji: SXF_EMOJI, speakers: SXF_SPEAKERS, banner: '🥜 わくわく! 🥜' },
apothecary: { prefix: 'confetti-apo', badges: APO_BADGES, colors: APO_BADGE_COLORS, emoji: APO_EMOJI, speakers: APO_SPEAKERS, banner: '🏮 薬屋のひとりごと 🏮' },
};
const DURATION_MS = 6400;
@@ -287,7 +303,7 @@ export default function WheelConfetti({ theme, burstKey, big = false }: Readonly
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [burstKey]);
// Ostatní tematické styly: hlášku pronese náhodná postava (Mane 6, Ai Enma, Houkago Tea Time, Kessoku Band, piloti NERV, Nokuru, Forgerovi...)
// Ostatní tematické styly: hlášku pronese náhodná postava (Mane 6, Ai Enma, Houkago Tea Time, Kessoku Band, piloti NERV, Nokuru, Forgerovi, vnitřní palác...)
const emojiConfetti = EMOJI_CONFETTI[theme];
const emojiSpeaker = useMemo(
() => big && emojiConfetti ? pick(emojiConfetti.speakers) : undefined,
@@ -2349,6 +2349,252 @@
}
}
// ============================================
// STYL APOTHECARY DIARIES kola štěstí (dle stylu zvoleného v nastavení).
// Výseče v barvách vnitřního paláce (rumělka, nefrit, zlato, inkoust,
// fialová Jinshiho, švestkový květ), zlaté linky a střed jako zlatá pečeť.
// ============================================
.spin-wheel-modal.spin-theme-apothecary {
--apo-font: 'Nunito', sans-serif;
--apo-display: 'Shippori Mincho', 'Noto Serif JP', serif;
--apo-vermilion: #a8322a;
--apo-vermilion-deep: #84241d;
--apo-jade: #2f7d62;
--apo-gold: #c9a24a;
--apo-line: #e0d4bb;
--apo-panel: #fffcf4;
--apo-text: #24201c;
--wheel-c0: #a8322a;
--wheel-c1: #2f7d62;
--wheel-c2: #c9a24a;
--wheel-c3: #24201c;
--wheel-c4: #6b5aa6;
--wheel-c5: #c76a86;
--wheel-rim: #3a1f14;
--wheel-hub: #d9b65e;
font-family: var(--apo-font);
.modal-content {
border: 1px solid var(--apo-gold);
border-radius: 10px;
overflow: hidden;
background: #f5efe1;
color: var(--apo-text);
}
.modal-header {
background:
linear-gradient(var(--apo-gold), var(--apo-gold)) left bottom / 100% 2px no-repeat,
linear-gradient(var(--apo-gold), var(--apo-gold)) left bottom 4px / 100% 1px no-repeat,
#24201c;
border-bottom: none;
h2 {
color: #fdf6e6;
font-family: var(--apo-display);
font-weight: 800;
}
.btn-close {
filter: invert(1) grayscale(1) brightness(2);
opacity: 0.9;
}
}
.modal-footer {
border-top: 3px double var(--apo-gold);
}
.spin-steps span {
font-family: var(--apo-display);
font-weight: 800;
background: #ece3d0;
color: #8b7f70;
border-radius: 3px;
padding: 4px 16px;
&.active {
background: var(--apo-vermilion);
color: #fdf6e6;
box-shadow: inset 0 0 0 2px rgb(201 162 74 / 0.6);
}
&.done {
background: var(--apo-jade);
color: #fff;
}
}
.btn {
font-family: var(--apo-font);
font-weight: 800;
border-radius: 3px;
}
.btn-primary {
background: var(--apo-vermilion);
border: 1px solid var(--apo-vermilion-deep);
color: #fdf6e6;
box-shadow: inset 0 0 0 2px rgb(201 162 74 / 0.55);
&:hover:not(:disabled) {
background: var(--apo-vermilion-deep);
color: #fdf6e6;
box-shadow: inset 0 0 0 2px var(--apo-gold), 0 0 12px rgb(201 162 74 / 0.45);
}
&:disabled {
background: #d8cfbf;
border-color: #d8cfbf;
color: #8b7f70;
box-shadow: none;
}
}
// Tlačítko roztočení — zlatá pečeť
.spin-button {
font-family: var(--apo-display);
font-size: 1.2rem;
padding: 10px 38px;
}
.btn-outline-primary {
background: var(--apo-panel);
border: 1px solid var(--apo-gold);
color: var(--apo-vermilion);
&:hover {
background: #f6e2dc;
color: var(--apo-vermilion);
}
}
.btn-secondary {
background: var(--apo-jade);
border: 1px solid #22604a;
color: #fff;
}
.spin-source {
background: #ece3d0;
border-radius: 4px;
> .btn {
border-radius: 3px !important;
}
> .btn-outline-primary {
background: transparent;
color: var(--apo-text);
&:hover {
background: var(--apo-panel);
}
}
}
.spin-result {
font-weight: 800;
strong {
color: var(--apo-vermilion);
}
}
.spin-options {
background: var(--apo-panel);
border: 1px solid var(--apo-line);
border-radius: 8px;
li:hover {
background: #f4ead6;
}
}
.spin-options-header {
border-bottom: 3px double var(--apo-gold);
color: var(--apo-vermilion);
font-family: var(--apo-display);
}
.spin-empty {
border-color: var(--apo-line);
}
.spin-wheel-pointer {
border-top-color: var(--apo-vermilion);
filter: drop-shadow(0 2px 1px rgb(58 31 20 / 0.4));
}
.spin-seg {
stroke: #d9b65e;
stroke-width: 2;
}
.spin-seg-label {
font-family: var(--apo-display);
font-weight: 800;
}
}
// Tmavý režim — noc v paláci pod lampiony
[data-bs-theme="dark"] .spin-wheel-modal.spin-theme-apothecary {
--apo-vermilion: #d6503f;
--apo-vermilion-deep: #b53b2d;
--apo-jade: #3f9474;
--apo-gold: #d9b65e;
--apo-line: #3a2e2a;
--apo-panel: #1e1a22;
--apo-text: #f2eadb;
--wheel-c0: #b53b2d;
--wheel-c3: #3a3036;
--wheel-rim: #0e0c10;
.modal-content {
background:
radial-gradient(circle at 8% 0%, rgb(214 80 63 / 0.22), transparent 35%),
radial-gradient(circle at 92% 0%, rgb(232 165 74 / 0.16), transparent 32%),
#14121a;
}
.modal-header {
background-color: #0e0c10;
}
.spin-steps span:not(.active):not(.done) {
background: #29232d;
color: #948a80;
}
.btn-primary:disabled {
background: #3a3036;
border-color: #3a3036;
color: #948a80;
}
.btn-outline-primary {
color: #e8a54a;
&:hover {
background: #3a2618;
color: #f2bd6a;
}
}
.spin-source {
background: #29232d;
}
.spin-options li:hover {
background: #29232d;
}
.spin-options-header {
color: #d9b65e;
}
}
// Ikona kola se při najetí pootočí
.spin-wheel-icon {
transition: transform 0.4s ease !important;
+3 -2
View File
@@ -13,7 +13,7 @@ const AUTO_ORDER_CHOICE_KEY = 'auto_order_choice';
export type ThemePreference = 'system' | 'light' | 'dark';
/** Vizuální styl aplikace (nezávislý na světlém/tmavém režimu). */
export type StyleTheme = 'simple' | 'umamusume' | 'mlp' | 'hellgirl' | 'kon' | 'bocchi' | 'evangelion' | 'yurucamp' | 'spyfamily';
export type StyleTheme = 'simple' | 'umamusume' | 'mlp' | 'hellgirl' | 'kon' | 'bocchi' | 'evangelion' | 'yurucamp' | 'spyfamily' | 'apothecary';
export const STYLE_THEMES: { value: StyleTheme, label: string }[] = [
{ value: 'simple', label: 'Jednoduchý' },
@@ -25,6 +25,7 @@ export const STYLE_THEMES: { value: StyleTheme, label: string }[] = [
{ value: 'evangelion', label: 'Neon Genesis Evangelion' },
{ value: 'yurucamp', label: 'Yuru Camp△' },
{ value: 'spyfamily', label: 'Spy × Family' },
{ value: 'apothecary', label: 'Apothecary Diaries' },
];
export type SettingsContextProps = {
@@ -256,7 +257,7 @@ function useProvideSettings(): SettingsContextProps {
}, [autoOrderChoice]);
// Aplikuje accent barvy při změně hue nebo přepnutí světlý/tmavý.
// Tematické styly (Umamusume, My Little Pony, Hell Girl, K-ON!, Bocchi the Rock!, Evangelion, Yuru Camp△, Spy × Family) mají vlastní pevnou paletu, accent barvu proto uplatňuje jen jednoduchý styl.
// Tematické styly (Umamusume, My Little Pony, Hell Girl, K-ON!, Bocchi the Rock!, Evangelion, Yuru Camp△, Spy × Family, Apothecary Diaries) mají vlastní pevnou paletu, accent barvu proto uplatňuje jen jednoduchý styl.
useEffect(() => {
localStorage.setItem(ACCENT_HUE_KEY, String(accentHue));
if (styleTheme === 'simple') {
+2
View File
@@ -21,6 +21,8 @@ const ICONS: Record<StyleTheme, Record<GameId, string>> = {
yurucamp: { drawing: '🗺️' },
// Forgerovi: pastelky, kterými Anya kreslí
spyfamily: { drawing: '🖍️' },
// Lékárna Maomao: pero a tuš na recepty
apothecary: { drawing: '🖋️' },
};
/** Styl z <html data-luncher-theme> — pro místa mimo React kontext nastavení. */
+515
View File
@@ -0,0 +1,515 @@
// ============================================
// STYL "APOTHECARY DIARIES" (volitelný, výchozí je jednoduchý styl)
// Inspirováno anime Kusuriya no Hitorigoto (薬屋のひとりごと).
// Vnitřní palác ve dne: rýžový papír s čínskou mřížkou oken, rumělkově
// červený lak sloupů, nefrit Nefritového pavilonu a zlaté kování.
// Titulek dne jako šuplík lékárnické skříňky Maomao se štítkem a pečetí 薬.
// Tmavý režim = noc v paláci pod červenými lampiony.
// Aktivní, pokud má <html> atribut data-luncher-theme="apothecary".
// ============================================
$apo: 'html[data-luncher-theme="apothecary"]';
// Čínská mřížka okna — rámeček s vnitřním čtvercem a spojkami (barva jako parametr)
@function apo-lattice($color) {
@return url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='40' height='40'%3E%3Cpath d='M0 0H40V40H0ZM10 10H30V30H10ZM0 20H10M30 20H40M20 0V10M20 30V40' fill='none' stroke='#{$color}'/%3E%3C/svg%3E");
}
// Zlaté kování — dvě tenké zlaté linky (pod hlavičkami a na footeru)
$apo-gold-trim:
linear-gradient(var(--apo-gold), var(--apo-gold)) left bottom / 100% 2px no-repeat,
linear-gradient(var(--apo-gold), var(--apo-gold)) left bottom 4px / 100% 1px no-repeat;
#{$apo} {
--apo-font: 'Nunito', -apple-system, sans-serif;
--apo-display: 'Shippori Mincho', 'Noto Serif JP', Georgia, serif;
--apo-vermilion: #a8322a; // lakované sloupy paláce
--apo-vermilion-deep: #84241d;
--apo-jade: #2f7d62; // Nefritový pavilon konkubíny Gyokuyou
--apo-jade-deep: #22604a;
--apo-gold: #c9a24a;
--apo-ink: #24201c;
--apo-wood: #5a311f; // lékárnická skříňka
--apo-wood-dark: #3a1f14;
--apo-paper: #f5efe1;
--apo-label: #fbf6ea;
--apo-line: #e0d4bb;
--luncher-primary: var(--apo-vermilion);
--luncher-primary-hover: var(--apo-vermilion-deep);
--luncher-primary-light: #f6e2dc;
--luncher-bg: var(--apo-paper);
--luncher-bg-card: #fffcf4;
--luncher-bg-hover: #f4ead6;
--luncher-text: var(--apo-ink);
--luncher-text-secondary: #554a3f;
--luncher-text-muted: #8b7f70;
--luncher-border: var(--apo-line);
--luncher-border-light: #ece3d0;
--luncher-navbar-bg: var(--apo-vermilion);
--luncher-navbar-text: #fdf6e6;
--luncher-action-icon: var(--apo-vermilion);
--luncher-buyer-icon: var(--apo-jade);
--luncher-success: var(--apo-jade);
--luncher-warning: #c98d1c;
--luncher-danger: #b3261e;
--luncher-radius-sm: 3px;
--luncher-radius: 6px;
--luncher-radius-lg: 8px;
--luncher-radius-xl: 10px;
--luncher-shadow: 0 2px 8px rgb(58 31 20 / 0.10);
--luncher-shadow-lg: 0 10px 24px rgb(58 31 20 / 0.18);
&[data-bs-theme="dark"] {
// Noc v paláci — lampiony a zlato
--apo-vermilion: #d6503f;
--apo-vermilion-deep: #b53b2d;
--apo-jade: #5fb894;
--apo-jade-deep: #3f9474;
--apo-gold: #d9b65e;
--apo-label: #e9dfc8;
--apo-line: #3a2e2a;
--luncher-primary: #e8a54a; // teplé světlo lampionu
--luncher-primary-hover: #f2bd6a;
--luncher-primary-light: #3a2618;
--luncher-bg: #14121a;
--luncher-bg-card: #1e1a22;
--luncher-bg-hover: #29232d;
--luncher-text: #f2eadb;
--luncher-text-secondary: #cdc1ae;
--luncher-text-muted: #948a80;
--luncher-border: var(--apo-line);
--luncher-border-light: #29232a;
--luncher-navbar-bg: #5e1a15;
--luncher-action-icon: #e8a54a;
--luncher-buyer-icon: #5fb894;
--luncher-success: #5fb894;
--luncher-warning: #e8b84a;
--luncher-danger: #e0594a;
--luncher-shadow: 0 4px 14px rgb(0 0 0 / 0.4);
--luncher-shadow-lg: 0 10px 30px rgb(214 80 63 / 0.18);
}
body {
font-family: var(--apo-font);
background-color: var(--luncher-bg);
// Rýžový papír s mřížkou okna, nahoře teplé denní světlo
background-image:
apo-lattice('%23a8322a14'),
linear-gradient(180deg, #fbf3e0 0, var(--luncher-bg) 360px);
background-size: 40px 40px, 100% 100%;
background-attachment: fixed;
}
&[data-bs-theme="dark"] body {
// Zlatá mřížka a záře červených lampionů v rozích
background-image:
apo-lattice('%23d9b65e12'),
radial-gradient(circle at 8% 0%, rgb(214 80 63 / 0.28), transparent 32%),
radial-gradient(circle at 92% 0%, rgb(232 165 74 / 0.20), transparent 30%),
linear-gradient(180deg, #1d151a 0, var(--luncher-bg) 420px);
background-size: 40px 40px, 100% 100%, 100% 100%, 100% 100%;
}
.app-container {
background: transparent;
}
h1, h2, h3, h4, .navbar-brand {
font-family: var(--apo-display);
font-weight: 800;
}
.btn {
font-family: var(--apo-font);
}
// ---------- Navbar: rumělkový lak se zlatým kováním ----------
.navbar {
background:
$apo-gold-trim,
linear-gradient(180deg, #b63a30, var(--luncher-navbar-bg)) !important;
padding-bottom: calc(var(--bs-navbar-padding-y, 0.5rem) + 5px);
.navbar-brand {
letter-spacing: 0.04em;
// Bylinka z lékárny Maomao
&::after {
content: '🌿';
display: inline-block;
margin-left: 6px;
margin-right: 0.6em;
font-size: 0.75em;
}
}
.dropdown-menu {
border: 1px solid var(--apo-gold);
border-radius: var(--luncher-radius);
box-shadow: var(--luncher-shadow-lg);
}
}
&[data-bs-theme="dark"] .navbar {
background:
$apo-gold-trim,
linear-gradient(180deg, #6e2018, var(--luncher-navbar-bg)) !important;
}
// ---------- Titulek dne: šuplík lékárnické skříňky se štítkem ----------
.day-navigator .title {
position: relative;
display: inline-block;
margin: 10px 0 22px;
padding: 6px 26px 8px 18px;
font-family: var(--apo-display);
font-weight: 800;
font-size: 1.55rem;
color: var(--apo-ink) !important;
background: var(--apo-label);
border: 1px solid #c9b48a;
border-radius: 2px;
// Dřevěné čelo šuplíku kolem štítku (dole víc místa pro úchyt)
box-shadow:
0 6px 0 10px var(--apo-wood),
0 6px 0 12px var(--apo-wood-dark),
0 14px 22px 12px rgb(58 31 20 / 0.22);
// Červená pečeť 薬 na štítku
&::before {
content: '薬';
display: inline-block;
margin-right: 12px;
padding: 2px 5px;
font-size: 0.6em;
line-height: 1.2;
vertical-align: middle;
color: #fff6ea;
background: #b3261e;
border-radius: 3px;
transform: rotate(-5deg);
}
// Mosazný úchyt šuplíku
&::after {
content: '';
position: absolute;
left: 50%;
bottom: -17px;
width: 22px;
height: 10px;
margin-left: -11px;
border: 3px solid var(--apo-gold);
border-top: none;
border-radius: 0 0 12px 12px;
box-shadow: 0 2px 2px rgb(0 0 0 / 0.35);
}
&.text-muted {
color: #6b6257 !important;
background: #e7e0d2;
&::before {
background: #8b7f70;
}
}
}
// ---------- Karty podniků: rýžový papír, hlavička jako lakovaný trám ----------
.restaurant-card {
border: 1px solid var(--apo-line);
border-radius: var(--luncher-radius-lg);
box-shadow: var(--luncher-shadow);
overflow: hidden;
&:hover {
transform: translateY(-2px);
border-color: var(--apo-gold);
box-shadow: var(--luncher-shadow-lg);
}
.restaurant-header {
background:
$apo-gold-trim,
apo-lattice('%23ffffff14') 0 0 / 40px 40px,
var(--apo-vermilion);
padding-bottom: 20px;
// Při najetí nefritová zeleň Nefritového pavilonu
&:hover {
background:
$apo-gold-trim,
apo-lattice('%23ffffff14') 0 0 / 40px 40px,
var(--apo-jade);
}
h3 {
letter-spacing: 0.03em;
}
small {
color: rgb(255 255 255 / 0.8);
}
}
}
&[data-bs-theme="dark"] .restaurant-card .restaurant-header {
&:not(:hover) {
background:
$apo-gold-trim,
apo-lattice('%23d9b65e1a') 0 0 / 40px 40px,
#5e1a15;
}
&:hover {
background:
$apo-gold-trim,
apo-lattice('%23ffffff14') 0 0 / 40px 40px,
#22604a;
}
}
.food-table tbody tr:hover > td {
background: #f4ead6;
}
&[data-bs-theme="dark"] .food-table tbody tr:hover > td {
background: #29232d;
}
.food-price {
color: var(--apo-vermilion);
font-weight: 800;
}
&[data-bs-theme="dark"] .food-price {
color: var(--apo-gold);
}
// ---------- Panely a tabulka voleb ----------
.choice-section,
.choices-table,
.pizza-section,
.no-votes {
border: 1px solid var(--apo-line);
border-radius: var(--luncher-radius-lg);
box-shadow: var(--luncher-shadow);
}
.choices-table {
border-collapse: separate;
border-spacing: 0;
}
// Sloupec s podnikem: štítek na šuplíku s léky
.choices-table > tbody > tr > td:first-child {
background: var(--apo-label);
color: var(--apo-ink);
font-family: var(--apo-display);
font-weight: 800;
border-right: 3px double var(--apo-gold);
}
&[data-bs-theme="dark"] .choices-table > tbody > tr > td:first-child {
background: #2a2018;
color: var(--apo-gold);
}
// Bootstrap karty (skupinové objednávky apod.) a seznamy
.card {
border: 1px solid var(--apo-line);
border-radius: var(--luncher-radius-lg);
box-shadow: var(--luncher-shadow);
overflow: hidden;
background: var(--luncher-bg-card);
// Rozbalovací výběr z nabídky nesmí karta oříznout
&:has(.select-search-container) {
overflow: visible;
}
> .card-header {
background: var(--luncher-primary-light);
border-bottom: 3px double var(--apo-gold);
font-weight: 800;
&:first-child {
border-radius: calc(var(--luncher-radius-lg) - 1px) calc(var(--luncher-radius-lg) - 1px) 0 0;
}
}
.table {
--bs-table-bg: transparent;
margin-bottom: 0;
> :last-child > tr:last-child > * {
border-bottom-width: 0;
}
}
}
.list-group {
border-radius: var(--luncher-radius);
overflow: hidden;
border: 1px solid var(--apo-line);
> .list-group-item {
border-left: none;
border-right: none;
&:first-child {
border-top: none;
}
&:last-child {
border-bottom: none;
}
}
}
.form-select, .form-control,
input[type="text"], input[type="email"], input[type="password"] {
border-radius: var(--luncher-radius-sm);
border: 1px solid var(--apo-line);
&:focus {
border-color: var(--apo-gold);
box-shadow: 0 0 0 3px rgb(201 162 74 / 0.28);
}
}
// ---------- Tlačítka: lakovaná červeň se zlatým vnitřním lemem ----------
.btn {
border-radius: var(--luncher-radius-sm);
font-weight: 800;
letter-spacing: 0.02em;
transition: transform 0.15s ease, box-shadow 0.2s ease, background 0.2s ease;
}
.btn-primary {
background: var(--apo-vermilion);
border: 1px solid var(--apo-vermilion-deep);
color: #fdf6e6;
box-shadow: inset 0 0 0 2px rgb(201 162 74 / 0.55);
&:hover {
background: var(--apo-vermilion-deep);
border-color: var(--apo-vermilion-deep);
color: #fdf6e6;
box-shadow: inset 0 0 0 2px var(--apo-gold), 0 0 12px rgb(201 162 74 / 0.45);
}
&:active {
transform: translateY(1px) !important;
}
&:disabled {
background: #d8cfbf;
border-color: #d8cfbf;
color: #8b7f70;
box-shadow: none;
}
}
&[data-bs-theme="dark"] .btn-primary {
color: #fff3e4;
&:disabled {
background: #3a3036;
border-color: #3a3036;
color: #948a80;
}
}
.btn-outline-primary {
background: var(--luncher-bg-card);
border: 1px solid var(--apo-gold);
color: var(--luncher-primary);
&:hover {
background: var(--luncher-primary-light);
border-color: var(--apo-gold);
color: var(--luncher-primary);
}
}
.btn-secondary {
background: var(--apo-jade);
border: 1px solid var(--apo-jade-deep);
color: #fff;
&:hover {
background: var(--apo-jade-deep);
color: #fff;
}
}
&[data-bs-theme="dark"] .btn-secondary {
background: #22604a;
border-color: #1a4a39;
&:hover {
background: #2a7259;
}
}
.btn-danger {
background: #b3261e;
border: 1px solid #861a14;
}
.action-icon:hover {
background: var(--luncher-primary-light);
color: var(--luncher-primary);
}
// ---------- Modaly: inkoustová deska se zlatou mřížkou ----------
.modal-content {
border: 1px solid var(--apo-gold);
border-radius: var(--luncher-radius-xl);
box-shadow: 0 16px 40px rgb(58 31 20 / 0.3);
overflow: hidden;
}
.modal-header {
background:
$apo-gold-trim,
apo-lattice('%23c9a24a24') 0 0 / 40px 40px,
#24201c;
border-bottom: none;
padding-bottom: calc(var(--bs-modal-header-padding-y, 1rem) + 5px);
.modal-title, .modal-title h2 {
color: #fdf6e6;
font-family: var(--apo-display);
font-weight: 800;
}
.btn-close {
filter: invert(1) grayscale(1) brightness(2);
}
}
.footer {
border-top: none;
background-image:
linear-gradient(var(--apo-gold), var(--apo-gold)),
linear-gradient(var(--apo-gold), var(--apo-gold));
background-size: 100% 2px, 100% 1px;
background-position: top, 0 4px;
background-repeat: no-repeat;
a {
color: #f2d58a;
}
}
}
@media (max-width: 575.98px) {
#{$apo} .day-navigator .title {
font-size: 1.2rem;
padding: 5px 18px 6px 12px;
}
}