@import url("https://fonts.googleapis.com/css2?family=Geist+Mono:wght@100..900&family=Geist:wght@100..900&display=swap"); @import "tailwindcss"; @import "tw-animate-css"; /* ---break--- */ @custom-variant dark (&:is(.dark *)); /* ---break--- */ @theme inline { --radius-sm: calc(var(--radius) - 4px); --radius-md: calc(var(--radius) - 2px); --radius-lg: var(--radius); --radius-xl: calc(var(--radius) + 4px); --color-background: var(--background); --color-foreground: var(--foreground); --color-card: var(--card); --color-card-foreground: var(--card-foreground); --color-popover: var(--popover); --color-popover-foreground: var(--popover-foreground); --color-primary: var(--primary); --color-primary-foreground: var(--primary-foreground); --color-secondary: var(--secondary); --color-secondary-foreground: var(--secondary-foreground); --color-muted: var(--muted); --color-muted-foreground: var(--muted-foreground); --color-accent: var(--accent); --color-accent-foreground: var(--accent-foreground); --color-destructive: var(--destructive); --color-border: var(--border); --color-input: var(--input); --color-ring: var(--ring); --color-chart-1: var(--chart-1); --color-chart-2: var(--chart-2); --color-chart-3: var(--chart-3); --color-chart-4: var(--chart-4); --color-chart-5: var(--chart-5); --color-sidebar: var(--sidebar); --color-sidebar-foreground: var(--sidebar-foreground); --color-sidebar-primary: var(--sidebar-primary); --color-sidebar-primary-foreground: var(--sidebar-primary-foreground); --color-sidebar-accent: var(--sidebar-accent); --color-sidebar-accent-foreground: var(--sidebar-accent-foreground); --color-sidebar-border: var(--sidebar-border); --color-sidebar-ring: var(--sidebar-ring); --font-sans: var(--font-sans); --font-mono: var(--font-mono); } /* ---break--- */ :root { --radius: 0.625rem; --background: oklch(1 0 0); --foreground: oklch(0.145 0 0); --card: oklch(1 0 0); --card-foreground: oklch(0.145 0 0); --popover: oklch(1 0 0); --popover-foreground: oklch(0.145 0 0); --primary: oklch(0.205 0 0); --primary-foreground: oklch(0.985 0 0); --secondary: oklch(0.97 0 0); --secondary-foreground: oklch(0.205 0 0); --muted: oklch(0.97 0 0); --muted-foreground: oklch(0.556 0 0); --accent: oklch(0.97 0 0); --accent-foreground: oklch(0.205 0 0); --destructive: oklch(0.577 0.245 27.325); --border: oklch(0.922 0 0); --input: oklch(0.922 0 0); --ring: oklch(0.708 0 0); --chart-1: oklch(0.646 0.222 41.116); --chart-2: oklch(0.6 0.118 184.704); --chart-3: oklch(0.398 0.07 227.392); --chart-4: oklch(0.828 0.189 84.429); --chart-5: oklch(0.769 0.188 70.08); --sidebar: oklch(0.985 0 0); --sidebar-foreground: oklch(0.145 0 0); --sidebar-primary: oklch(0.205 0 0); --sidebar-primary-foreground: oklch(0.985 0 0); --sidebar-accent: oklch(0.97 0 0); --sidebar-accent-foreground: oklch(0.205 0 0); --sidebar-border: oklch(0.922 0 0); --sidebar-ring: oklch(0.708 0 0); --font-sans: "Geist", sans-serif; --font-mono: "Geist Mono", monospace; } /* ---break--- */ .dark { --background: oklch(0.145 0 0); --foreground: oklch(0.985 0 0); --card: oklch(0.205 0 0); --card-foreground: oklch(0.985 0 0); --popover: oklch(0.205 0 0); --popover-foreground: oklch(0.985 0 0); --primary: oklch(0.922 0 0); --primary-foreground: oklch(0.205 0 0); --secondary: oklch(0.269 0 0); --secondary-foreground: oklch(0.985 0 0); --muted: oklch(0.269 0 0); --muted-foreground: oklch(0.708 0 0); --accent: oklch(0.269 0 0); --accent-foreground: oklch(0.985 0 0); --destructive: oklch(0.704 0.191 22.216); --border: oklch(1 0 0 / 10%); --input: oklch(1 0 0 / 15%); --ring: oklch(0.556 0 0); --chart-1: oklch(0.488 0.243 264.376); --chart-2: oklch(0.696 0.17 162.48); --chart-3: oklch(0.769 0.188 70.08); --chart-4: oklch(0.627 0.265 303.9); --chart-5: oklch(0.645 0.246 16.439); --sidebar: oklch(0.205 0 0); --sidebar-foreground: oklch(0.985 0 0); --sidebar-primary: oklch(0.488 0.243 264.376); --sidebar-primary-foreground: oklch(0.985 0 0); --sidebar-accent: oklch(0.269 0 0); --sidebar-accent-foreground: oklch(0.985 0 0); --sidebar-border: oklch(1 0 0 / 10%); --sidebar-ring: oklch(0.556 0 0); } /* ---break--- */ @layer base { * { @apply border-border outline-ring/50; } body { @apply bg-background text-foreground; } } /* ---break--- */ /* Top-down ORBAT-style tree connectors */ .org-tree-child { position: relative; padding-top: 1rem; } .org-tree-child::before { content: ""; position: absolute; top: 0; left: 50%; height: 1rem; border-left: 2px solid var(--color-border); } .org-tree-child::after { content: ""; position: absolute; top: 0; left: 0; right: 0; border-top: 2px solid var(--color-border); } .org-tree-child:first-child::after { left: 50%; } .org-tree-child:last-child::after { right: 50%; } .org-tree-child:only-child::after { display: none; } /* Locker search-result highlight */ @keyframes locker-search-pulse { 0%, 100% { box-shadow: 0 0 0 0 rgb(251 191 36 / 0.7); } 50% { box-shadow: 0 0 0 6px rgb(251 191 36 / 0); } } @keyframes xp-gain { 0% { opacity: 0; transform: translateX(0.35rem); } 15% { opacity: 1; } 75% { opacity: 1; } 100% { opacity: 0; transform: translateX(-1.1rem); } } .locker-search-highlight { animation: locker-search-pulse 1.1s ease-in-out infinite; box-shadow: 0 0 0 3px rgb(251 191 36 / 0.9); } .app-background-texture { background-image: repeating-linear-gradient( 135deg, rgb(255 255 255 / 0.018) 0 1px, transparent 1px 7px ); } .inventory-frame { background-color: rgb(7 10 12 / 0.78); background-image: linear-gradient(rgb(255 255 255 / 0.018) 1px, transparent 1px), linear-gradient(90deg, rgb(255 255 255 / 0.018) 1px, transparent 1px), radial-gradient(circle at 50% 0%, rgb(120 150 145 / 0.09), transparent 55%); /*background-size: 48px 48px, 48px 48px, 100% 100%;*/ box-shadow: inset 0 1px rgb(255 255 255 / 0.04), 0 12px 35px rgb(0 0 0 / 0.18); } @media (prefers-reduced-motion: reduce) { .locker-search-highlight { animation: none; } } @property --medal-border-angle { syntax: ""; inherits: false; initial-value: 0deg; } @keyframes border-spin-animate { from { --medal-border-angle: 0deg; } to { --medal-border-angle: 360deg; } } .medal-card { --medal-border-angle: 0deg; background: rgb(193 161 79 / 0.28); position: relative; isolation: isolate; } .medal-card::before { content: ""; position: absolute; inset: -0.125rem; z-index: 0; border-radius: inherit; border: 2px solid transparent; background: linear-gradient(var(--background), var(--background)) padding-box, repeating-conic-gradient( from var(--medal-border-angle), transparent 0deg 150deg, peru 159deg, rgb(253 224 71) 168deg, white 178deg, transparent 178deg ) border-box; animation: border-spin-animate 10s linear infinite; pointer-events: none; } @keyframes border-spin-animate { from { --medal-border-angle: 0deg; } to { --medal-border-angle: 360deg; } } .medal-card * { position: relative; z-index: 1; } .medal-card::after { content: ""; z-index: 2; background: radial-gradient(circle, transparent, rgb(253 224 71 / 0.1)); position: absolute; inset: 0; animation: pulse 5s cubic-bezier(0.4, 0, 0.6, 1) infinite; pointer-events: none; } .medal-card > .medal-card-bg, .medal-card > .medal-card-scrim { position: absolute !important; inset: 0; z-index: 0 !important; } .medal-card > .medal-card-bg { width: 100%; height: 100%; border-radius: inherit; } .medal-card > .medal-card-scrim { border-radius: inherit; background-color: rgb(0 0 0 / 0.42); box-shadow: inset 0 0 2.25rem rgb(0 0 0 / 0.38); } .medal-card.medal-card-overflow { overflow: visible; } .award-xp-high { background: linear-gradient( 110deg, rgb(245 158 11), rgb(254 249 195), rgb(250 204 21), rgb(245 158 11) ); background-size: 200% auto; background-clip: text; -webkit-background-clip: text; color: transparent; filter: drop-shadow(0 0 0.3rem rgb(250 204 21 / 0.35)); animation: award-xp-shimmer 2.5s linear infinite; } @keyframes award-xp-shimmer { to { background-position: 200% center; } } @media (prefers-reduced-motion: reduce) { .award-xp-high { animation: none; } } .commendation-card { align-self: start; gap: 0.5rem; padding: 0.625rem 0.75rem; } /* Scrollbars — styled to match the dark frontend theme */ * { scrollbar-width: thin; scrollbar-color: color-mix(in oklch, var(--foreground) 20%, transparent) transparent; } *::-webkit-scrollbar { width: 10px; height: 10px; } *::-webkit-scrollbar-track { background: transparent; } *::-webkit-scrollbar-thumb { background-color: color-mix(in oklch, var(--foreground) 20%, transparent); border-radius: 9999px; border: 2px solid transparent; background-clip: padding-box; } *::-webkit-scrollbar-thumb:hover { background-color: color-mix(in oklch, var(--foreground) 32%, transparent); } *::-webkit-scrollbar-corner { background: transparent; } /* Wiki markdown — directives, footnotes, callouts (scoped to .wiki-markdown) */ .wiki-markdown .columns { display: grid; grid-template-columns: repeat(auto-fit, minmax(0, 1fr)); gap: 1rem; } .wiki-markdown .columns.cols-2 { grid-template-columns: repeat(2, 1fr); } .wiki-markdown .columns.cols-3 { grid-template-columns: repeat(3, 1fr); } .wiki-markdown .column { min-width: 0; } .wiki-markdown .footnotes { font-size: 0.875rem; color: var(--color-muted-foreground); margin-top: 2rem; border-top: 1px solid var(--color-border); padding-top: 1rem; } .wiki-markdown .note, .wiki-markdown .warning { position: relative; border-left: 3px solid var(--color-border); border-radius: 0.375rem; padding: 0.75rem 1rem 0.75rem 2.5rem; } .wiki-markdown .note > :first-child, .wiki-markdown .warning > :first-child { margin-top: 0; } .wiki-markdown .note .callout-icon { position: absolute; left: 0.75rem; top: 1.125rem; color: var(--color-primary); } .wiki-markdown .warning .callout-icon { position: absolute; left: 0.75rem; top: 1.125rem; color: var(--color-destructive); } .wiki-markdown .note { border-left-color: var(--color-primary); background: color-mix(in oklch, var(--color-primary) 8%, transparent); } .wiki-markdown .warning { border-left-color: var(--color-destructive); background: color-mix(in oklch, var(--color-destructive) 8%, transparent); } /* Lexical rich-text typography (scoped to .lexical-content); Tailwind preflight resets headings */ .lexical-content { font-size: 0.875rem; line-height: 1.7; color: var(--color-muted-foreground); } .lexical-content > :first-child { margin-top: 0; } .lexical-content > :last-child { margin-bottom: 0; } .lexical-content h1, .lexical-content h2, .lexical-content h3, .lexical-content h4 { font-weight: 600; line-height: 1.3; color: var(--color-foreground); } .lexical-content h1 { font-size: 1.25rem; margin: 1.25rem 0 0.5rem; } .lexical-content h2 { font-size: 1.125rem; margin: 1.125rem 0 0.4375rem; } .lexical-content h3 { font-size: 1rem; margin: 1rem 0 0.375rem; } .lexical-content h4 { font-size: 0.9375rem; margin: 0.875rem 0 0.25rem; } .lexical-content p { margin: 0.5rem 0; } .lexical-content ul, .lexical-content ol { margin: 0.5rem 0; padding-left: 1.5rem; } .lexical-content ul { list-style: disc; } .lexical-content ol { list-style: decimal; } .lexical-content li + li { margin-top: 0.25rem; } .lexical-content li > ul, .lexical-content li > ol { margin: 0.25rem 0; } .lexical-content blockquote { margin: 0.75rem 0; border-left: 3px solid var(--color-border); padding-left: 1rem; color: var(--color-muted-foreground); } .lexical-content hr { margin: 1.25rem 0; border: 0; border-top: 1px solid var(--color-border); } .lexical-content strong { color: var(--color-foreground); } .lexical-content a { color: var(--color-primary); text-decoration: underline; text-underline-offset: 2px; } .lexical-content a:hover { text-decoration-color: var(--color-primary); } .lexical-content :not(pre) > code { background: var(--color-muted); border-radius: 0.25rem; padding: 0.125rem 0.375rem; font-size: 0.8125rem; } .lexical-content pre { background: var(--color-muted); border: 1px solid var(--color-border); border-radius: 0.5rem; padding: 0.875rem 1rem; overflow-x: auto; margin: 0.75rem 0; } .lexical-content pre code { background: transparent; padding: 0; font-size: 0.8125rem; } /* Wiki prose-article typography (scoped to .wiki-markdown) */ .wiki-markdown { font-size: 0.9375rem; line-height: 1.75; color: var(--color-foreground); } .wiki-markdown > :first-child { margin-top: 0; } .wiki-markdown h1, .wiki-markdown h2, .wiki-markdown h3, .wiki-markdown h4 { font-weight: 600; line-height: 1.3; color: var(--color-foreground); } .wiki-markdown h1 { font-size: 1.5rem; margin: 2rem 0 0.75rem; } .wiki-markdown h2 { font-size: 1.25rem; margin: 1.75rem 0 0.5rem; padding-bottom: 0.375rem; border-bottom: 1px solid var(--color-border); } .wiki-markdown h3 { font-size: 1.0625rem; margin: 1.5rem 0 0.375rem; } .wiki-markdown h4 { font-size: 0.9375rem; margin: 1.25rem 0 0.25rem; } .wiki-markdown p { margin: 0.75rem 0; } .wiki-markdown ul, .wiki-markdown ol { margin: 0.75rem 0; padding-left: 1.5rem; } .wiki-markdown ul { list-style: disc; } .wiki-markdown ol { list-style: decimal; } .wiki-markdown li + li { margin-top: 0.25rem; } .wiki-markdown li > ul, .wiki-markdown li > ol { margin: 0.25rem 0; } .wiki-markdown blockquote { margin: 1rem 0; border-left: 3px solid var(--color-border); padding-left: 1rem; color: var(--color-muted-foreground); } .wiki-markdown hr { margin: 1.75rem 0; border: 0; border-top: 1px solid var(--color-border); } .wiki-markdown table { width: 100%; border-collapse: collapse; font-size: 0.875rem; margin: 1rem 0; } .wiki-markdown th, .wiki-markdown td { border: 1px solid var(--color-border); padding: 0.5rem 0.75rem; text-align: left; } .wiki-markdown th { background: var(--color-muted); font-weight: 600; } .wiki-markdown img { max-width: 100%; height: auto; border-radius: 0.5rem; margin: 1rem 0; } .wiki-markdown a { color: var(--color-primary); text-decoration: underline; text-underline-offset: 2px; } .wiki-markdown a:hover { text-decoration-color: var(--color-primary); } .wiki-markdown :not(pre) > code { background: var(--color-muted); border-radius: 0.25rem; padding: 0.125rem 0.375rem; font-size: 0.8125rem; } .wiki-markdown pre { background: var(--color-muted); border: 1px solid var(--color-border); border-radius: 0.5rem; padding: 0.875rem 1rem; overflow-x: auto; margin: 1rem 0; } .wiki-markdown pre code { background: transparent; padding: 0; font-size: 0.8125rem; } /* Wiki infobox — Wikipedia-style right-hand info card (scoped to .wiki-markdown) */ .wiki-markdown .infobox { float: right; clear: right; width: 18rem; margin: 0.25rem 0 1rem 1.5rem; border: 1px solid var(--color-border); border-radius: 0.5rem; background: var(--color-card); padding: 0.875rem 1rem; font-size: 0.8125rem; line-height: 1.55; } .wiki-markdown .infobox > p:first-child { margin: 0 0 0.5rem; text-align: center; font-size: 0.9375rem; font-weight: 600; color: var(--color-foreground); } .wiki-markdown .infobox img { display: block; margin: 0.25rem auto 0.75rem; border-radius: 0.375rem; } .wiki-markdown .infobox > div { border: 0; border-radius: 0; overflow: visible; } .wiki-markdown .infobox table { width: 100%; min-width: 0; font-size: 0.8125rem; margin: 0; } .wiki-markdown .infobox th { text-align: center; } .wiki-markdown .infobox td { padding: 0.375rem 0.5rem; vertical-align: top; } .wiki-markdown .infobox td:first-child { width: 38%; font-weight: 500; white-space: nowrap; } @media (max-width: 640px) { .wiki-markdown .infobox { float: none; width: 100%; margin: 1rem 0; } } /* Syntax-highlighted code blocks (rehype-highlight / highlight.js). */ .wiki-markdown pre code { background: transparent; padding: 0; color: var(--muted-foreground); } .wiki-markdown pre code.hljs { padding: 0; background: transparent; } .wiki-markdown .hljs-keyword, .wiki-markdown .hljs-selector-tag, .wiki-markdown .hljs-literal, .wiki-markdown .hljs-section, .wiki-markdown .hljs-doctag, .wiki-markdown .hljs-name { color: #c792ea; } .wiki-markdown .hljs-string, .wiki-markdown .hljs-regexp, .wiki-markdown .hljs-addition, .wiki-markdown .hljs-attribute, .wiki-markdown .hljs-meta .hljs-string { color: #a5d6a7; } .wiki-markdown .hljs-number, .wiki-markdown .hljs-symbol, .wiki-markdown .hljs-bullet, .wiki-markdown .hljs-link, .wiki-markdown .hljs-selector-attr, .wiki-markdown .hljs-selector-pseudo { color: #f78c6c; } .wiki-markdown .hljs-comment, .wiki-markdown .hljs-quote { color: #64748b; font-style: italic; } .wiki-markdown .hljs-variable, .wiki-markdown .hljs-template-variable, .wiki-markdown .hljs-type, .wiki-markdown .hljs-selector-class, .wiki-markdown .hljs-selector-id, .wiki-markdown .hljs-title, .wiki-markdown .hljs-title.class_, .wiki-markdown .hljs-title.function_ { color: #82aaff; } .wiki-markdown .hljs-built_in, .wiki-markdown .hljs-class .hljs-title, .wiki-markdown .hljs-params { color: #ffcb6b; } .wiki-markdown .hljs-deletion { color: #ef5350; } .wiki-markdown .hljs-emphasis { font-style: italic; } .wiki-markdown .hljs-strong { font-weight: 600; } /* Glitch hover effect for official campaign card titles: fires once (~1s) on hover, then reverts. */ .glitch-hover { position: relative; } .glitch-ghost { position: absolute; inset: 0; text-wrap: balance; opacity: 0; pointer-events: none; } .glitch-shard-a { color: #22d3ee; } .glitch-shard-b { color: #f43f5e; } .glitch-shard-c { color: #ffffff; } .group:hover .glitch-hover { animation: glitch-jitter 1s ease-out 1; } .group:hover .glitch-shard-a { animation: glitch-shard-a 1s ease-out 1; } .group:hover .glitch-shard-b { animation: glitch-shard-b 1s ease-out 1; } .group:hover .glitch-shard-c { animation: glitch-shard-c 1s ease-out 1; } @keyframes glitch-jitter { 0% { transform: translate(3px, -2px) skewX(2deg); text-shadow: -4px 0 rgba(34, 211, 238, 0.7), 4px 0 rgba(244, 63, 94, 0.7); animation-timing-function: steps(1, end); } 5% { transform: translate(-3px, 2px) skewX(-2deg); text-shadow: 3px 0 rgba(34, 211, 238, 0.7), -3px 0 rgba(244, 63, 94, 0.7); animation-timing-function: steps(1, end); } 10% { transform: translate(2px, -1px) skewX(1deg); text-shadow: -2px 0 rgba(34, 211, 238, 0.6), 2px 0 rgba(244, 63, 94, 0.6); animation-timing-function: steps(1, end); } 15% { transform: translate(-1px, 1px); text-shadow: 1px 0 rgba(34, 211, 238, 0.5), -1px 0 rgba(244, 63, 94, 0.5); animation-timing-function: ease-out; } 25% { transform: translate(0, 0) skewX(0deg); text-shadow: none; } 100% { transform: translate(0, 0) skewX(0deg); text-shadow: none; } } @keyframes glitch-shard-a { 0% { opacity: 0.9; clip-path: polygon(0 0, 62% 0, 54% 34%, 0 34%); transform: translate(-8px, -4px); animation-timing-function: steps(1, end); } 8% { clip-path: polygon(6% 4%, 68% 0, 58% 38%, 0 30%); transform: translate(8px, 4px); animation-timing-function: steps(1, end); } 16% { opacity: 0.35; clip-path: polygon(0 0, 50% 6%, 44% 30%, 0 38%); transform: translate(-3px, -2px); animation-timing-function: ease-out; } 35% { opacity: 0; clip-path: polygon(0 0, 62% 0, 54% 34%, 0 34%); transform: translate(-5px, -3px); } 100% { opacity: 0; clip-path: polygon(0 0, 62% 0, 54% 34%, 0 34%); transform: translate(-5px, -3px); } } @keyframes glitch-shard-b { 0% { opacity: 0.9; clip-path: polygon(38% 66%, 100% 58%, 100% 100%, 30% 100%); transform: translate(8px, 4px); animation-timing-function: steps(1, end); } 8% { clip-path: polygon(32% 62%, 100% 66%, 100% 100%, 24% 96%); transform: translate(-8px, -4px); animation-timing-function: steps(1, end); } 16% { opacity: 0.35; clip-path: polygon(50% 70%, 100% 62%, 100% 100%, 44% 100%); transform: translate(3px, 2px); animation-timing-function: ease-out; } 35% { opacity: 0; clip-path: polygon(38% 66%, 100% 58%, 100% 100%, 30% 100%); transform: translate(5px, 3px); } 100% { opacity: 0; clip-path: polygon(38% 66%, 100% 58%, 100% 100%, 30% 100%); transform: translate(5px, 3px); } } @keyframes glitch-shard-c { 0% { opacity: 0.95; clip-path: polygon(8% 42%, 96% 38%, 88% 62%, 0 66%); transform: translate(6px, -4px); animation-timing-function: steps(1, end); } 6% { transform: translate(-6px, 4px); animation-timing-function: steps(1, end); } 12% { clip-path: polygon(0 46%, 88% 40%, 96% 58%, 4% 62%); transform: translate(4px, 2px); animation-timing-function: steps(1, end); } 20% { transform: translate(-2px, -1px); animation-timing-function: ease-out; } 35% { opacity: 0; clip-path: polygon(8% 42%, 96% 38%, 88% 62%, 0 66%); transform: translate(1px, 2px); } 100% { opacity: 0; clip-path: polygon(8% 42%, 96% 38%, 88% 62%, 0 66%); transform: translate(1px, 2px); } } .group:hover .glitch-soft { animation: glitch-soft 1s ease-out 1; } .group:hover .glitch-soft-late { animation-delay: 0.1s; } @keyframes glitch-soft { 0% { transform: translate(1px, -1px); text-shadow: 1px 0 rgba(34, 211, 238, 0.45), -1px 0 rgba(244, 63, 94, 0.45); animation-timing-function: steps(1, end); } 8% { transform: translate(-1px, 1px); text-shadow: -1px 0 rgba(34, 211, 238, 0.45), 1px 0 rgba(244, 63, 94, 0.45); animation-timing-function: steps(1, end); } 16% { transform: translate(1px, 1px); animation-timing-function: ease-out; } 30% { transform: translate(0, 0); text-shadow: none; } 100% { transform: translate(0, 0); text-shadow: none; } } .glitch-ghost-img { opacity: 0; } .group:hover .glitch-ghost-img-a { animation: glitch-img-band-a 2s ease-out 1; } .group:hover .glitch-ghost-img-b { animation: glitch-img-band-b 2s ease-out 1; } @keyframes glitch-img-band-a { 0% { opacity: 0.45; clip-path: inset(0 0 55% 0); transform: translate(-4px, 0); animation-timing-function: steps(1, end); } 6% { clip-path: inset(5% 0 60% 0); transform: translate(4px, 2px); animation-timing-function: steps(1, end); } 12% { opacity: 0.35; clip-path: inset(10% 0 62% 0); transform: translate(-2px, 0); } 100% { opacity: 0; clip-path: inset(0 0 55% 0); transform: translate(0, 0); } } @keyframes glitch-img-band-b { 0% { opacity: 0.45; clip-path: inset(45% 0 0 0); transform: translate(4px, 0); animation-timing-function: steps(1, end); } 6% { clip-path: inset(40% 0 5% 0); transform: translate(-4px, -2px); animation-timing-function: steps(1, end); } 12% { opacity: 0.35; clip-path: inset(38% 0 10% 0); transform: translate(2px, 0); } 100% { opacity: 0; clip-path: inset(45% 0 0 0); transform: translate(0, 0); } } @media (prefers-reduced-motion: reduce) { .group:hover .glitch-hover { animation: none; } .group:hover .glitch-ghost { animation: none; opacity: 0; } .group:hover .glitch-soft { animation: none; } .group:hover .glitch-ghost-img { animation: none; opacity: 0; } } /* Poker surface: the felt is the game's one custom material. */ .poker-table-stage { display: flex; flex-direction: column; align-items: center; gap: 0.75rem; } .poker-felt-table { --poker-felt-deep: #071c15; --poker-felt-mid: #0e3b29; --poker-felt-light: #1c5b3d; --poker-rim: #06130f; --poker-trim: #b08a44; --poker-chip-clay: #9b6248; isolation: isolate; width: 100%; border: 0.65rem solid var(--poker-rim); border-radius: 50% / 48%; background: radial-gradient( circle at 50% 44%, color-mix(in srgb, var(--poker-felt-light) 72%, transparent), transparent 55% ), radial-gradient(ellipse at 50% 50%, var(--poker-felt-mid) 0%, var(--poker-felt-deep) 78%); box-shadow: 0 0 0 1px var(--poker-trim), 0 0 0 0.2rem color-mix(in srgb, var(--poker-trim) 36%, transparent), inset 0 0 0 0.12rem color-mix(in srgb, var(--poker-trim) 70%, transparent), inset 0 0 2.5rem color-mix(in srgb, var(--poker-felt-deep) 80%, black), 0 0.75rem 2rem rgb(0 0 0 / 35%); } .poker-felt-table::after { position: absolute; inset: 1.05rem; z-index: -1; border: 1px solid color-mix(in srgb, var(--poker-trim) 52%, transparent); border-radius: 50% / 46%; content: ""; pointer-events: none; } .poker-seat-arc-left { top: 50%; left: 1.5%; transform: translateY(-50%); } .poker-seat-arc-center { top: 2%; left: 50%; transform: translateX(-50%); } .poker-seat-arc-right { top: 50%; right: 1.5%; transform: translateY(-50%); } .poker-seat-arc-far-left { top: 34%; left: 5%; transform: translateY(-50%); } .poker-seat-arc-center-left { top: 6%; left: 27%; transform: translateX(-50%); } .poker-seat-arc-center-right { top: 6%; right: 27%; transform: translateX(50%); } .poker-seat-arc-far-right { top: 34%; right: 5%; transform: translateY(-50%); } /* Blackjack seats hug the bottom two-thirds of the felt so the top third stays clear for the dealer. Six slots push out to the rim of the 50%/48% ellipse (three per side, bulging outward at the middle) with margins that keep even the widest seat panel fully inside the curved edge, spaced for breathing room between neighbors. */ .blackjack-seat-arc-corner-right { top: 29%; left: 74%; transform: translate(-50%, -50%); } .blackjack-seat-arc-corner-left { top: 29%; left: 26%; transform: translate(-50%, -50%); } .blackjack-seat-arc-mid-right { top: 50%; left: 83.5%; transform: translate(-50%, -50%); } .blackjack-seat-arc-mid-left { top: 50%; left: 16.5%; transform: translate(-50%, -50%); } .blackjack-seat-arc-low-right { top: 71%; left: 74%; transform: translate(-50%, -50%); } .blackjack-seat-arc-low-left { top: 71%; left: 26%; transform: translate(-50%, -50%); } /* Blackjack seats share the poker seat panel CSS, whose commit pill and hand reveal are absolutely positioned via poker-only arc classes that blackjack slots never carry. Keep the pill in the panel row and push corner-seat reveals outward, clear of the dealer block. */ .blackjack-felt .poker-seat-commit { position: static; transform: none; } .blackjack-felt .blackjack-seat-arc-corner-right .poker-seat-reveal { left: calc(50% + 4.5rem); } .blackjack-felt .blackjack-seat-arc-corner-left .poker-seat-reveal { left: calc(50% - 4.5rem); } /* Top-anchor the log below the dealer block (bottom edge reaches ~44% with the turn clock) so the newest line can never climb over the time bar. */ .blackjack-felt .poker-action-log { top: 46%; bottom: auto; } /* Same fix for poker: bottom-anchoring let the newest line climb into the center block's turn clock. The clock's bottom edge sits around 65% of the 4:3 felt during betting, so the log is top-anchored at 66.5% and capped to three visible lines (about 0.95rem each plus gaps) so it ends before the viewer card spot; the mask fades the capped tail. */ .poker-felt .poker-action-log { top: 66.5%; bottom: auto; max-height: 2.95rem; overflow: hidden; } /* Poker chip flight: every chip starts stacked at one origin and launches one after another (130ms stagger, fill-mode both holds unlaunched chips in the pile). Wins drop from the pot plaque (~40% of the felt) down to the viewer card spot (bottom 7rem, so about 14rem of travel); losses fly the reverse leg from the card spot up to the pot. Chips are the shared .bj-chip pieces; the geometry is poker-scoped because blackjack flies between different anchors. */ .poker-chip-flight { position: absolute; left: 50%; z-index: 35; width: 1.6rem; height: 0.95rem; transform: translateX(-50%); pointer-events: none; } .poker-chip-flight-win { top: 40%; } .poker-chip-flight-loss { bottom: 7.6rem; } .poker-chip-flight .bj-chip { bottom: auto; left: 0; } .poker-chip-flight-win .bj-chip { animation: poker-chip-fly-win 700ms ease-in both; } .poker-chip-flight-loss .bj-chip { animation: poker-chip-fly-loss 700ms ease-in both; } @keyframes poker-chip-fly-win { 0% { opacity: 1; transform: translateY(0) scale(1); } 70% { opacity: 1; } 100% { opacity: 0; transform: translateY(14rem) scale(0.7); } } @keyframes poker-chip-fly-loss { 0% { opacity: 1; transform: translateY(0) scale(1); } 70% { opacity: 1; } 100% { opacity: 0; transform: translateY(-14rem) scale(0.7); } } @media (prefers-reduced-motion: reduce) { .poker-chip-flight { display: none; } } /* Fullscreen contain-fit: absolute with zero insets + auto margins sizes the felt to the largest 4:3 rectangle inside the viewport area (the same rules browsers use for replaced elements), so it can never collapse to content size and never overflow. Must stay after .poker-felt-table to win the width tie. */ .poker-felt-fullscreen { position: absolute; inset: 0; margin: auto; width: auto; height: auto; max-width: 100%; max-height: 100%; aspect-ratio: 4 / 3; } .poker-seat-panel { position: relative; border: 1px solid color-mix(in srgb, white 16%, transparent); border-radius: 0.75rem; background: rgb(0 0 0 / 38%); box-shadow: 0 0.3rem 0.6rem rgb(0 0 0 / 22%); } .poker-waiting-seat { border-color: color-mix(in srgb, white 24%, transparent); border-radius: 0.65rem; background: rgb(0 0 0 / 28%); color: white; text-align: center; } .poker-waiting-seat-occupied { border-color: color-mix(in srgb, var(--poker-trim) 62%, transparent); } .poker-waiting-seat-south { bottom: 1.5%; left: 50%; transform: translateX(-50%); } .poker-waiting-name, .poker-waiting-status { max-width: 8rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .poker-seat-avatar { display: flex; width: 2.4rem; height: 2.4rem; align-items: center; justify-content: center; border: 2px solid color-mix(in srgb, white 52%, transparent); border-radius: 50%; box-shadow: inset 0 1px rgb(255 255 255 / 20%), 0 0.2rem 0.45rem rgb(0 0 0 / 34%); color: white; font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 1rem; font-weight: 700; } .poker-seat-avatar-tone-0 { background: #2f6f5a; } .poker-seat-avatar-tone-1 { background: #7b543c; } .poker-seat-avatar-tone-2 { background: #465d87; } .poker-seat-avatar-tone-3 { background: #76506f; } .poker-seat-avatar-open { border-style: dashed; background: color-mix(in srgb, var(--poker-rim) 78%, transparent); color: rgb(255 255 255 / 58%); } .poker-console-avatar { width: 2.1rem; height: 2.1rem; flex: 0 0 auto; } .poker-seat-nameplate { min-width: 0; padding-inline: 0.1rem; } .poker-seat-stack { display: inline-flex; align-items: center; gap: 0.3rem; color: #f3d28b; font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 1.35rem; font-variant-numeric: tabular-nums; font-weight: 700; line-height: 1.15; } .poker-seat-stack-chip { width: 0.85rem; height: 0.85rem; flex: 0 0 auto; border: 1px solid #d6b36a; border-radius: 50%; background: radial-gradient( circle at center, color-mix(in srgb, var(--poker-chip-clay) 60%, white) 0 0.16rem, transparent 0.17rem ), var(--poker-chip-clay); box-shadow: inset 0 1px rgb(255 255 255 / 25%); } .poker-seat-stack-flash-up { animation: poker-stack-flash-up 900ms ease-out; } .poker-seat-stack-flash-down { animation: poker-stack-flash-down 900ms ease-out; } @keyframes poker-stack-flash-up { 0% { color: #6ee7b7; transform: scale(1.16); } 100% { color: #f3d28b; transform: scale(1); } } @keyframes poker-stack-flash-down { 0% { color: #fda4af; transform: scale(0.92); } 100% { color: #f3d28b; transform: scale(1); } } .poker-seat-status-row { display: flex; flex-wrap: wrap; justify-content: flex-start; gap: 0.2rem; margin-top: 0.15rem; } .poker-seat-action-badge { border: 1px solid color-mix(in srgb, var(--poker-trim) 60%, transparent); border-radius: 9999px; padding: 0.12rem 0.45rem; background: color-mix(in srgb, var(--poker-trim) 14%, transparent); color: #f3d28b; font-size: 0.65rem; font-weight: 700; letter-spacing: 0.08em; line-height: 1.2; text-transform: uppercase; } .poker-seat-action-winner { border-color: color-mix(in srgb, #d6b36a 72%, transparent); background: color-mix(in srgb, #d6b36a 20%, transparent); } .poker-seat-cardbacks { position: absolute; top: calc(100% - 0.15rem); left: 50%; z-index: 3; display: block; width: 1.7rem; height: 1rem; transform: translateX(-50%); pointer-events: none; } .poker-seat-cardbacks span { position: absolute; top: 0.1rem; display: block; width: 0.78rem; height: 1.12rem; border: 1px solid color-mix(in srgb, white 30%, transparent); border-radius: 0.14rem; background-color: #101a33; background-image: linear-gradient(45deg, rgb(190 42 58 / 34%) 25%, transparent 25%), linear-gradient(-45deg, rgb(190 42 58 / 34%) 25%, transparent 25%), linear-gradient(45deg, transparent 75%, rgb(190 42 58 / 34%) 75%), linear-gradient(-45deg, transparent 75%, rgb(190 42 58 / 34%) 75%); background-position: 0 0, 0.2rem 0, 0.2rem -0.2rem, -0.2rem 0.2rem; background-size: 0.4rem 0.4rem; box-shadow: 0 0.15rem 0.3rem rgb(0 0 0 / 30%); } .poker-seat-cardbacks span:first-child { left: 0; transform: rotate(-10deg); } .poker-seat-cardbacks span:last-child { right: 0; transform: rotate(10deg); } .poker-seat-reveal { position: absolute; top: calc(100% + 0.25rem); left: 50%; z-index: 5; display: flex; gap: 0.2rem; transform: translateX(-50%); } .poker-seat-reveal .poker-card:first-child { --poker-card-resting-transform: rotate(-6deg); } .poker-seat-reveal .poker-card:last-child { --poker-card-resting-transform: rotate(6deg); } .poker-seat-commit { position: absolute; z-index: 4; display: flex; align-items: center; gap: 0.25rem; border: 1px solid color-mix(in srgb, var(--poker-trim) 50%, transparent); border-radius: 9999px; padding: 0.18rem 0.45rem 0.18rem 0.25rem; background: color-mix(in srgb, var(--poker-rim) 88%, transparent); color: #f3d28b; box-shadow: 0 0.2rem 0.4rem rgb(0 0 0 / 28%); white-space: nowrap; } .poker-seat-commit-label { color: rgb(255 255 255 / 55%); font-size: 0.65rem; font-weight: 500; letter-spacing: 0.16em; text-transform: uppercase; } .poker-seat-arc-left .poker-seat-commit { top: 50%; right: -4.5rem; transform: translateY(-50%); } .poker-seat-arc-right .poker-seat-commit { top: 50%; left: -4.5rem; transform: translateY(-50%); } .poker-seat-arc-center .poker-seat-commit { right: 50%; bottom: -2.5rem; transform: translateX(50%); } .poker-seat-arc-far-left .poker-seat-commit, .poker-seat-arc-center-left .poker-seat-commit { right: -4.5rem; bottom: -1.25rem; } .poker-seat-arc-far-right .poker-seat-commit, .poker-seat-arc-center-right .poker-seat-commit { bottom: -1.25rem; left: -4.5rem; } .poker-dealer-button { border-color: color-mix(in srgb, var(--poker-trim) 85%, white); background: var(--poker-trim); color: #20170b; box-shadow: 0 0.15rem 0.3rem rgb(0 0 0 / 30%); } .poker-deck-origin { position: absolute; top: -2.1rem; left: 50%; z-index: 2; display: block; width: 1.9rem; height: 1.4rem; opacity: 0.85; transform: translateX(-50%); pointer-events: none; } .poker-deck-card { position: absolute; bottom: 0; display: block; width: 1.15rem; height: 1.6rem; border: 1px solid color-mix(in srgb, white 35%, transparent); border-radius: 0.18rem; background-color: #101a33; background-image: linear-gradient(45deg, rgb(190 42 58 / 34%) 25%, transparent 25%), linear-gradient(-45deg, rgb(190 42 58 / 34%) 25%, transparent 25%), linear-gradient(45deg, transparent 75%, rgb(190 42 58 / 34%) 75%), linear-gradient(-45deg, transparent 75%, rgb(190 42 58 / 34%) 75%); background-position: 0 0, 0.25rem 0, 0.25rem -0.25rem, -0.25rem 0.25rem; background-size: 0.5rem 0.5rem; box-shadow: 0 0.16rem 0.3rem rgb(0 0 0 / 28%); } .poker-deck-card-back { left: 0.2rem; transform: translateY(-0.12rem) rotate(-9deg); } .poker-deck-card-middle { left: 0.38rem; transform: translateY(-0.2rem) rotate(-3deg); } .poker-deck-card-top { left: 0.56rem; transform: translateY(-0.26rem) rotate(4deg); } .poker-pot-plaque { display: flex; min-width: 5.5rem; flex-direction: column; align-items: center; gap: 0.1rem; border: 1px solid color-mix(in srgb, var(--poker-trim) 74%, white); border-radius: 0.45rem; padding: 0.25rem 0.85rem 0.3rem; background: color-mix(in srgb, var(--poker-rim) 92%, transparent); box-shadow: inset 0 1px rgb(255 255 255 / 10%), 0 0.25rem 0.5rem rgb(0 0 0 / 24%); } /* Big pots break down into up to seven denomination piles; let the pile row wrap so the plaque can never outgrow the center block on narrow felts. */ .poker-pot-plaque .bj-chip-stack { max-width: 100%; justify-content: center; flex-wrap: wrap; } .poker-pot-plaque .poker-console-kicker { color: #f3d28b; } .poker-table-turn-clock { width: min(12rem, 80%); color: rgb(255 255 255 / 72%); } .poker-action-console { position: relative; display: grid; grid-template-columns: minmax(9rem, 1.1fr) minmax(6rem, 0.8fr) minmax(13rem, 1.6fr); align-items: stretch; gap: 0.75rem; width: min(40rem, 96%); min-height: 9rem; margin-inline: auto; padding: 0.7rem; border: 1px solid var(--poker-trim); border-radius: 0.35rem; background: linear-gradient(135deg, rgb(0 0 0 / 34%), transparent 48%), color-mix(in srgb, var(--poker-rim) 92%, var(--poker-felt-deep)); box-shadow: inset 0 1px rgb(255 255 255 / 10%), inset 0 0.2rem 1rem rgb(0 0 0 / 24%), 0 0.35rem 1.4rem rgb(0 0 0 / 24%); color: white; } .poker-action-console-waiting { opacity: 0.86; } .poker-sound-toggle { display: flex; align-items: center; gap: 0.4rem; } .poker-sound-volume { width: 4.5rem; accent-color: var(--poker-trim); } .poker-action-console:not(.poker-action-console-complete) { grid-template-columns: minmax(0, 1.5fr) minmax(10rem, 0.8fr); } .poker-viewer-cards { position: absolute; bottom: 7rem; left: 50%; z-index: 14; display: flex; transform: translateX(-50%); pointer-events: none; } .poker-viewer-cards .poker-card-viewer-right { margin-left: -0.45rem; } .poker-viewer-cards .poker-card-folded { opacity: 0.5; } .poker-action-toolbar { position: absolute; bottom: 1.15rem; left: 50%; z-index: 15; display: flex; width: min(30rem, calc(100% - 2rem)); justify-content: center; padding: 0.45rem; border: 1px solid color-mix(in srgb, var(--poker-trim) 64%, transparent); border-radius: 0.5rem; background: color-mix(in srgb, var(--poker-rim) 88%, transparent); box-shadow: inset 0 1px rgb(255 255 255 / 10%), 0 0.35rem 0.9rem rgb(0 0 0 / 30%); transform: translateX(-50%); } .poker-action-toolbar-waiting { width: fit-content; max-width: calc(100% - 2rem); padding-inline: 0.75rem; color: rgb(255 255 255 / 64%); font-size: 0.7rem; } /* Below-felt variant: on narrow screens the toolbar renders in normal flow under the felt because the felt's overflow-hidden clips the overlay row there; static positioning cancels the overlay anchor. */ .poker-action-toolbar-below { position: static; transform: none; width: min(30rem, 100%); } .poker-action-toolbar .poker-betting-controls-compact { width: 100%; gap: 0.4rem; } .poker-betting-controls-compact .poker-compact-actions { justify-content: center; gap: 0.4rem; } .poker-betting-controls-compact .poker-chip { min-height: 2rem; padding-inline: 0.7rem; } .poker-betting-controls-compact .poker-betting-message { justify-content: center; min-height: 1rem; } .poker-wager-panel-compact { position: absolute; bottom: calc(100% + 0.5rem); left: 50%; z-index: 16; width: min(26rem, calc(100% - 1rem)); max-width: calc(100% - 1rem); max-height: min(18rem, calc(100dvh - 8rem)); margin: 0; overflow-y: auto; transform: translateX(-50%); } .poker-wager-panel-compact .poker-compact-wager-line { flex-wrap: wrap; gap: 0.45rem; } .poker-wager-panel-compact .poker-wager-range { flex: 1 1 100%; } .poker-wager-panel-compact .poker-wager-input { width: 7rem; flex: 0 1 7rem; } .poker-wager-panel-compact .poker-compact-quick-row { align-items: center; gap: 0.3rem; } .poker-wager-panel-compact .poker-quick-chip { min-height: 1.65rem; padding-inline: 0.55rem; } .poker-console-player, .poker-console-economy, .poker-console-actions { min-width: 0; } .poker-console-player { display: grid; grid-template-columns: auto auto minmax(0, 1fr); align-items: center; gap: 0.6rem; } .poker-console-identity { display: flex; min-width: 0; flex: 1; flex-direction: column; gap: 0.45rem; } .poker-console-identity > .flex { flex-direction: column; align-items: flex-start; gap: 0.35rem; min-width: 0; } .poker-console-identity > .flex > .min-w-0 { width: 100%; } .poker-console-role-row { display: flex; flex-wrap: wrap; justify-content: flex-start; gap: 0.2rem; max-width: 100%; } .poker-console-role-row > * { border-color: color-mix(in srgb, var(--poker-trim) 70%, transparent); background: color-mix(in srgb, var(--poker-trim) 18%, transparent); color: #f3d28b; font-size: 0.58rem; } .poker-hand-placard { display: block; width: fit-content; max-width: 100%; border: 1px solid color-mix(in srgb, var(--poker-trim) 78%, white); border-radius: 0.15rem; padding: 0.28rem 0.45rem; background: linear-gradient(180deg, rgb(176 138 68 / 32%), rgb(176 138 68 / 12%)); color: #f3d28b; font-size: 0.68rem; line-height: 1.2; overflow-wrap: anywhere; } /* Progressive hand-rank ladder: each tier a step brighter and glowier, from brass hints through silver (straight, flush) and gold (full house, quads) up to the royal flush prismatic treatment. */ .poker-rank-tier-1 { border-color: rgb(138 109 59 / 80%); } .poker-rank-tier-2 { border-color: rgb(163 130 63 / 85%); box-shadow: inset 0 0 0.4rem rgb(213 179 106 / 16%); } .poker-rank-tier-3 { border-color: rgb(185 138 62 / 90%); box-shadow: inset 0 0 0.5rem rgb(213 179 106 / 24%), 0 0 0.35rem rgb(213 179 106 / 18%); } .poker-rank-tier-4 { border-color: rgb(201 201 212 / 85%); box-shadow: inset 0 0 0.55rem rgb(226 232 240 / 22%), 0 0 0.45rem rgb(226 232 240 / 20%); } .poker-rank-tier-5 { border-color: rgb(214 214 228 / 95%); box-shadow: inset 0 0 0.7rem rgb(226 232 240 / 32%), 0 0 0.7rem rgb(226 232 240 / 30%); } .poker-rank-tier-6 { border-color: #cfa95c; box-shadow: inset 0 0 0.7rem rgb(214 179 106 / 30%), 0 0 0.6rem rgb(214 179 106 / 28%); } .poker-rank-tier-7 { border-color: #e0bd6f; box-shadow: inset 0 0 0.8rem rgb(224 189 111 / 44%), 0 0 0.85rem rgb(224 189 111 / 42%); } .poker-rank-tier-8 { border-color: #79a7f5; box-shadow: inset 0 0 0.9rem rgb(121 167 245 / 46%), 0 0 0.95rem rgb(121 167 245 / 48%); } .poker-rank-tier-9 { position: relative; border-color: #ffd700; background-image: linear-gradient( 115deg, rgb(255 77 77 / 7%), rgb(255 184 77 / 7%) 18%, rgb(255 249 77 / 7%) 36%, rgb(77 255 136 / 7%) 54%, rgb(77 195 255 / 7%) 72%, rgb(184 77 255 / 7%) 88%, rgb(255 77 77 / 7%) ); background-size: 300% 100%; box-shadow: inset 0 0 1rem rgb(255 215 0 / 46%), 0 0 1.1rem rgb(255 215 0 / 55%); animation: poker-royal-wash 6s ease-in-out infinite alternate; } /* The acting seat's halo: a translucent emerald glow that breathes behind the pill, rendered by a transparent pseudo so the ring never covers content. */ .poker-action-log { position: absolute; bottom: 12.5rem; left: 50%; z-index: 10; display: flex; width: min(24rem, 80%); flex-direction: column; gap: 0.2rem; transform: translateX(-50%); pointer-events: none; -webkit-mask-image: linear-gradient(to bottom, black 45%, transparent 100%); mask-image: linear-gradient(to bottom, black 45%, transparent 100%); } .poker-action-log-line { text-align: center; color: rgb(255 255 255 / 70%); font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 0.7rem; letter-spacing: 0.03em; overflow-wrap: anywhere; } .poker-log-wager { color: rgb(253 230 138 / 80%); } .poker-log-win { color: rgb(167 243 208 / 85%); } .poker-log-fold, .poker-log-leave { color: rgb(255 255 255 / 45%); } .poker-log-action { color: rgb(191 219 254 / 80%); } /* The acting seat's halo: a translucent emerald glow that breathes behind the pill, rendered by a transparent pseudo so the ring never covers content. */ .poker-seat-active { border-color: rgb(52 211 153 / 85%); } .poker-seat-active::after { content: ""; position: absolute; inset: -0.3rem; z-index: 1; border-radius: 0.9rem; pointer-events: none; animation: poker-seat-pulse 2s ease-in-out infinite; } @keyframes poker-seat-pulse { 0%, 100% { box-shadow: 0 0 0.4rem 0 rgb(52 211 153 / 18%); } 50% { box-shadow: 0 0 1.4rem 0.25rem rgb(52 211 153 / 55%); } } /* The rainbow lives only on the border ring (masked pseudo-element) and the near-transparent background wash, never on the element's content: the hue filter animates the pseudo itself, so cards and text keep their true colors. */ .poker-rank-tier-9::before { content: ""; position: absolute; inset: 0; z-index: 1; border-radius: inherit; padding: 1px; background: linear-gradient( 115deg, #ff4d4d, #ffb84d, #fff94d, #4dff88, #4dc3ff, #b84dff, #ff4d4d ); background-size: 300% 100%; -webkit-mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0); -webkit-mask-composite: xor; mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0); mask-composite: exclude; animation: poker-royal-border-hue 3.2s linear infinite; pointer-events: none; } @keyframes poker-royal-wash { 0% { background-position: 0% 0; } 100% { background-position: 100% 0; } } @keyframes poker-royal-border-hue { 0% { filter: hue-rotate(0deg); background-position: 0% 0; } 100% { filter: hue-rotate(360deg); background-position: 300% 0; } } .poker-console-economy { display: flex; flex-direction: column; justify-content: center; gap: 0.7rem; border-inline: 1px solid color-mix(in srgb, var(--poker-trim) 26%, transparent); padding-inline: 0.7rem; } .poker-chip-readout { display: flex; align-items: center; gap: 0.5rem; } .poker-chip-stack { position: relative; display: block; width: 1.7rem; height: 1.1rem; flex: 0 0 auto; border: 2px solid #d6b36a; border-radius: 50%; background: var(--poker-chip-clay); box-shadow: 0 0.16rem 0 rgb(0 0 0 / 35%); transform: rotate(-6deg); } .poker-chip-stack::before, .poker-chip-stack::after { position: absolute; left: -0.12rem; width: 1.7rem; height: 1.1rem; border: 2px solid color-mix(in srgb, #d6b36a 85%, white); border-radius: 50%; content: ""; } .poker-chip-stack::before { top: -0.32rem; background: color-mix(in srgb, var(--poker-chip-clay) 82%, white); } .poker-chip-stack::after { top: -0.64rem; background: color-mix(in srgb, var(--poker-chip-clay) 72%, var(--poker-trim)); } .poker-console-readout-copy { display: flex; min-width: 0; flex-direction: column; gap: 0.15rem; } .poker-console-kicker { color: rgb(255 255 255 / 54%); font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 0.58rem; letter-spacing: 0.12em; line-height: 1.1; text-transform: uppercase; } .poker-console-timer { min-width: 0; } .poker-console-timer [role="timer"] { color: rgb(255 255 255 / 72%); } .poker-console-timer [aria-label] > div:last-child { background: rgb(255 255 255 / 12%); } .poker-console-timer [aria-label] > div:last-child > div { background: var(--poker-trim); } .poker-console-actions { display: flex; flex-direction: column; justify-content: center; } .poker-betting-controls { min-width: 0; } .poker-chip { min-height: 2.2rem; border-radius: 9999px; padding-inline: 0.8rem; border-width: 1px; box-shadow: inset 0 1px rgb(255 255 255 / 16%), 0 0.16rem 0 rgb(0 0 0 / 28%); font-size: 0.72rem; font-weight: 700; letter-spacing: 0.02em; transition: transform 150ms ease, filter 150ms ease, background-color 150ms ease; } .poker-chip:hover:not(:disabled) { filter: brightness(1.1); transform: translateY(-1px); } .poker-chip:active:not(:disabled) { transform: translateY(1px) scale(0.98); } .poker-chip-fold { border-color: color-mix(in srgb, white 26%, transparent); background: var(--poker-rim); color: rgb(255 255 255 / 78%); } .poker-chip-call { border-color: color-mix(in srgb, var(--poker-chip-clay) 90%, white); background: var(--poker-chip-clay); color: #fff4ed; } .poker-chip-wager { border-color: #e0bd6f; background: linear-gradient(180deg, #d6b36a, var(--poker-trim)); color: #20170b; } /* The complete-console primary action must stay readable even if the gradient's var chain or the shadcn background utilities win the cascade. */ .poker-complete-actions .poker-chip-wager { color: #20170b; background-color: #d6b36a; background-image: linear-gradient(180deg, #d6b36a, color-mix(in srgb, #d6b36a 72%, #20170b)); } .poker-wager-panel { border-color: color-mix(in srgb, var(--poker-trim) 48%, transparent); background: color-mix(in srgb, var(--poker-felt-deep) 86%, black); box-shadow: inset 0 1px rgb(255 255 255 / 8%); } .poker-wager-range { accent-color: var(--poker-trim); } .poker-wager-input { border-color: color-mix(in srgb, var(--poker-trim) 45%, transparent); background: rgb(0 0 0 / 24%); } .poker-quick-chip { min-height: 1.8rem; border-color: color-mix(in srgb, var(--poker-trim) 45%, transparent); border-radius: 9999px; background: rgb(255 255 255 / 5%); color: rgb(255 255 255 / 74%); font-size: 0.65rem; } .poker-betting-message { color: rgb(255 255 255 / 54%); } .poker-complete-actions { display: flex; align-items: center; justify-content: space-between; gap: 0.8rem; } .poker-complete-copy { display: flex; min-width: 0; flex-direction: column; gap: 0.2rem; } .poker-card { --poker-card-resting-transform: none; border-radius: 0.3rem; perspective: 45rem; vertical-align: middle; transform: var(--poker-card-resting-transform); transform-origin: center bottom; } .poker-card-motion { display: block; width: 100%; height: 100%; transform-origin: center bottom; transform-style: preserve-3d; } .poker-card-viewer-left { --poker-card-resting-transform: perspective(40rem) rotate(-7deg) rotateX(5deg) translateY(0.12rem); } .poker-card-viewer-right { --poker-card-resting-transform: perspective(40rem) rotate(7deg) rotateX(5deg) translateY(0.12rem); } .poker-seat-arc-left .poker-card:nth-child(1) { --poker-card-resting-transform: rotate(7deg) rotateX(-4deg); } .poker-seat-arc-left .poker-card:nth-child(2) { --poker-card-resting-transform: rotate(11deg) rotateX(-4deg); } .poker-seat-arc-center .poker-card { --poker-card-resting-transform: rotate(1deg) rotateX(-3deg); } .poker-seat-arc-right .poker-card:nth-child(1) { --poker-card-resting-transform: rotate(-7deg) rotateX(-4deg); } .poker-seat-arc-right .poker-card:nth-child(2) { --poker-card-resting-transform: rotate(-11deg) rotateX(-4deg); } .poker-seat-arc-far-left .poker-card, .poker-seat-arc-center-left .poker-card { --poker-card-resting-transform: rotate(8deg) rotateX(-4deg); } .poker-seat-arc-far-right .poker-card, .poker-seat-arc-center-right .poker-card { --poker-card-resting-transform: rotate(-8deg) rotateX(-4deg); } .poker-card-community { --poker-card-resting-transform: rotate(-1.5deg) rotateX(2deg) translateY(0.08rem); } .poker-card-community:nth-child(2n) { --poker-card-resting-transform: rotate(1.5deg) rotateX(2deg) translateY(-0.04rem); } .poker-card-community:nth-child(3n) { --poker-card-resting-transform: rotate(-2deg) rotateX(2deg) translateY(0.12rem); } .poker-card-inner { position: relative; display: block; width: 100%; height: 100%; transform: rotateY(180deg); transform-style: preserve-3d; transition: transform 260ms ease; } .poker-card-is-face-up { transform: rotateY(0deg); } .poker-card-face { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; border-radius: 0.25rem; backface-visibility: hidden; border: 1px solid color-mix(in srgb, white 36%, transparent); } .poker-card-front { flex-direction: column; justify-content: space-between; padding: 0.25rem; background: var(--card); color: var(--foreground); } .poker-card-center { font-size: 1.25rem; line-height: 1; } .poker-card-face--light { background: #f8f6ef; color: #1d2733; border-color: rgb(0 0 0 / 30%); } .poker-card-front--svg { padding: 0; background: transparent; border-color: transparent; overflow: hidden; } .poker-card-svg { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: fill; pointer-events: none; } .poker-card-back { transform: rotateY(180deg); background-color: #101a33; background-image: linear-gradient(45deg, rgb(190 42 58 / 34%) 25%, transparent 25%), linear-gradient(-45deg, rgb(190 42 58 / 34%) 25%, transparent 25%), linear-gradient(45deg, transparent 75%, rgb(190 42 58 / 34%) 75%), linear-gradient(-45deg, transparent 75%, rgb(190 42 58 / 34%) 75%); background-position: 0 0, 0.25rem 0, 0.25rem -0.25rem, -0.25rem 0.25rem; background-size: 0.5rem 0.5rem; } .poker-card-deal { --poker-deal-x: 0rem; --poker-deal-y: -5rem; animation: poker-card-deal-in 260ms ease both; } .poker-seat-arc-left .poker-card-deal, .poker-seat-arc-far-left .poker-card-deal, .poker-seat-arc-center-left .poker-card-deal { --poker-deal-x: clamp(5rem, 18vw, 16rem); --poker-deal-y: 0rem; } .poker-seat-arc-right .poker-card-deal, .poker-seat-arc-far-right .poker-card-deal, .poker-seat-arc-center-right .poker-card-deal { --poker-deal-x: clamp(-16rem, -18vw, -5rem); --poker-deal-y: 0rem; } .poker-seat-arc-center .poker-card-deal { --poker-deal-y: clamp(4rem, 8vw, 9rem); } .poker-card-community .poker-card-deal { --poker-deal-y: -2rem; } .poker-card-viewer-left.poker-card-deal { --poker-deal-x: clamp(1rem, 4vw, 4rem); --poker-deal-y: clamp(-20rem, -25vw, -8rem); } .poker-card-viewer-right.poker-card-deal { --poker-deal-x: clamp(-4rem, -4vw, -1rem); --poker-deal-y: clamp(-20rem, -25vw, -8rem); } .poker-countdown-fill { min-width: 0; } .poker-popup-stack { position: absolute; top: -0.9rem; left: 50%; z-index: 30; display: flex; flex-direction: column; align-items: center; gap: 0.15rem; transform: translateX(-50%); pointer-events: none; } .poker-popup-viewer-spot { top: auto; bottom: 13%; } .poker-popup-stack-below { top: calc(100% + 0.5rem); } .poker-popup-stack-below .poker-popup { animation-name: poker-popup-float-down; } .poker-popup-announcements { top: 24%; z-index: 25; } .poker-popup-announcements .poker-popup { animation-name: poker-popup-float-down; } .poker-popup-leave { color: rgb(255 255 255 / 0.85); border-color: rgb(255 255 255 / 0.35); background: rgb(23 23 23 / 0.92); animation: poker-popup-float-down 3s ease-out forwards; } .poker-popup { animation: poker-popup-float 1.5s ease-out forwards; border: 1px solid; border-radius: 0.375rem; padding: 0.1rem 0.5rem; font-size: 0.7rem; font-weight: 700; letter-spacing: 0.04em; text-transform: uppercase; white-space: nowrap; } .poker-popup-action { color: #bfdbfe; border-color: rgb(147 197 253 / 0.5); background: rgb(30 58 138 / 0.85); } .poker-popup-wager { color: #fde68a; border-color: rgb(252 211 77 / 0.55); background: rgb(120 53 15 / 0.88); } .poker-popup-win { color: #a7f3d0; border-color: rgb(110 231 183 / 0.55); background: rgb(6 78 59 / 0.9); } .poker-popup-fold { color: rgb(255 255 255 / 0.75); border-color: rgb(255 255 255 / 0.25); background: rgb(0 0 0 / 0.7); } @keyframes poker-popup-float { 0% { opacity: 0; transform: translateY(0.6rem) scale(0.7); } 15% { opacity: 1; transform: translateY(0) scale(1.1); } 30% { transform: translateY(-0.3rem) scale(1); } 100% { opacity: 0; transform: translateY(-2.75rem) scale(1); } } @keyframes poker-popup-float-down { 0% { opacity: 0; transform: translateY(-0.6rem) scale(0.7); } 15% { opacity: 1; transform: translateY(0) scale(1.1); } 30% { transform: translateY(0.3rem) scale(1); } 100% { opacity: 0; transform: translateY(2.75rem) scale(1); } } @keyframes poker-popup-fade { 0% { opacity: 0; } 20% { opacity: 1; } 100% { opacity: 0; } } @keyframes poker-card-deal-in { from { opacity: 0; transform: translate3d(var(--poker-deal-x), var(--poker-deal-y), 0) scale(0.84); } to { opacity: 1; transform: var(--poker-card-resting-transform); } } @media (max-width: 640px) { .poker-felt-table::after { inset: 0.8rem 0.7rem; } .poker-seat-arc-left { left: 4.5%; } .poker-seat-arc-right { right: 4.5%; } .poker-seat-arc-far-left { left: 4%; } .poker-seat-arc-far-right { right: 4%; } } @media (max-width: 760px) { .poker-action-console { grid-template-columns: minmax(0, 1.2fr) minmax(0, 0.8fr); } .poker-console-actions { grid-column: 1 / -1; border-top: 1px solid color-mix(in srgb, var(--poker-trim) 26%, transparent); padding-top: 0.65rem; } .poker-complete-actions { align-items: flex-start; } } @media (max-width: 480px) { .poker-action-console { grid-template-columns: 1fr; gap: 0.55rem; } .poker-action-console:not(.poker-action-console-complete) { grid-template-columns: 1fr; } .poker-console-economy { flex-direction: row; align-items: center; justify-content: space-between; border-inline: 0; border-block: 1px solid color-mix(in srgb, var(--poker-trim) 26%, transparent); padding-block: 0.55rem; padding-inline: 0; } .poker-console-actions { grid-column: auto; border-top: 0; padding-top: 0; } .poker-complete-actions { flex-direction: column; } } @media (prefers-reduced-motion: reduce) { .poker-chip { transition: none; } .poker-popup { animation: poker-popup-fade 1.5s ease-out forwards; } .poker-popup-stack-below .poker-popup, .poker-popup-announcements .poker-popup { animation-name: poker-popup-fade; animation-duration: 3s; } .poker-seat-stack-flash-up, .poker-seat-stack-flash-down { animation: none; } .poker-rank-tier-9, .poker-rank-tier-9::before { animation: none; } .poker-seat-active::after { animation: none; box-shadow: 0 0 0.9rem 0.1rem rgb(52 211 153 / 40%); } .poker-card-inner, .poker-card-deal { animation: none; transition: none; } } /* Blackjack chip stacks: denomination-colored CSS chip piles. Amounts are broken into piles (1000/500/100/25/10/5/1), max 5 discs per pile; the exact number always rides alongside in a text label. Pile heights are set inline from the chip count so nothing clips or overlaps. */ .bj-chip-stack { --bj-chip-w: 1.6rem; --bj-chip-h: 0.95rem; --bj-chip-step: 0.3rem; display: inline-flex; align-items: flex-end; gap: 0.3rem; } /* Compact piles (sm) share the same markup with smaller discs so dense surfaces like poker's bet pills and console readouts keep their height. */ .bj-chip-stack-sm { --bj-chip-w: 1.15rem; --bj-chip-h: 0.68rem; --bj-chip-step: 0.2rem; gap: 0.22rem; } .bj-chip-pile { position: relative; display: inline-block; width: var(--bj-chip-w, 1.6rem); } .bj-chip { position: absolute; left: 0; width: var(--bj-chip-w, 1.6rem); height: var(--bj-chip-h, 0.95rem); border: 2px dashed rgb(255 255 255 / 72%); border-radius: 50%; box-shadow: 0 2px 3px rgb(0 0 0 / 38%), inset 0 -2px 3px rgb(0 0 0 / 22%); animation: bj-chip-pop 180ms ease-out; transition: box-shadow 150ms ease, border-color 150ms ease; } /* Hover feedback on a pile: a subtle glow in the chip's own color, hinting at the denomination tooltip. */ .bj-chip-pile:hover .bj-chip { border-color: color-mix(in srgb, white 82%, var(--bj-chip-glow, white)); box-shadow: 0 2px 3px rgb(0 0 0 / 38%), inset 0 -2px 3px rgb(0 0 0 / 22%), 0 0 0.5rem var(--bj-chip-glow, rgb(255 255 255 / 55%)), 0 0 0.2rem var(--bj-chip-glow, rgb(255 255 255 / 55%)); } /* Inner face ring so the disc reads as a chip, not a squashed circle. */ .bj-chip::after { content: ""; position: absolute; inset: 2px 4px; border: 1.5px solid rgb(255 255 255 / 35%); border-radius: 50%; } .bj-chip-gold { --bj-chip-glow: rgb(217 164 65 / 60%); background: #d9a441; } .bj-chip-purple { --bj-chip-glow: rgb(139 92 246 / 60%); background: #8b5cf6; } .bj-chip-black { --bj-chip-glow: rgb(255 255 255 / 38%); background: #27272a; border-color: rgb(255 255 255 / 5%); } .bj-chip-green { --bj-chip-glow: rgb(47 133 90 / 65%); background: #2f855a; } .bj-chip-blue { --bj-chip-glow: rgb(59 110 165 / 60%); background: #3b6ea5; } .bj-chip-red { --bj-chip-glow: rgb(185 67 65 / 60%); background: #b94341; } .bj-chip-white { --bj-chip-glow: rgb(231 224 212 / 55%); background: #e7e0d4; border-color: rgb(120 110 95 / 62%); } .bj-chip-white::after { border-color: rgb(120 110 95 / 40%); } @keyframes bj-chip-pop { 0% { opacity: 0; transform: translateY(-40%) scale(0.6); } 100% { opacity: 1; transform: translateY(0) scale(1); } } /* Blackjack readability: bump shared poker-* gameplay text inside the blackjack felt only; poker tables keep their original sizing. */ .blackjack-felt .poker-console-kicker { font-size: 0.7rem; letter-spacing: 0.16em; } .blackjack-felt .poker-pot-plaque { min-width: 6.5rem; gap: 0.2rem; padding: 0.35rem 1rem 0.4rem; } .blackjack-felt .poker-pot-plaque strong { font-size: 1.4rem; } .blackjack-felt .poker-popup { padding: 0.15rem 0.65rem; font-size: 0.8rem; } .blackjack-felt .poker-action-log { gap: 0.3rem; } .blackjack-felt .poker-action-log-line { font-size: 0.82rem; } .blackjack-felt .poker-seat-action-badge { padding: 0.16rem 0.55rem; font-size: 0.72rem; } /* Lift the viewer's hand cluster clear of the bankroll + controls column (the cluster peaks near 9.7rem when the bankroll pill carries chip piles). */ .blackjack-felt .poker-viewer-cards { bottom: 10rem; } /* Chip flight: every chip starts stacked at one origin (the hand spot) and launches one after another: payouts toward the bankroll pill, lost bets toward the dealer. Fill-mode both holds unlaunched chips in the pile. */ .bj-chip-flight { position: absolute; bottom: 11rem; left: 50%; z-index: 35; width: 1.6rem; height: 0.95rem; transform: translateX(-50%); pointer-events: none; } .bj-chip-flight .bj-chip { bottom: auto; left: 0; animation: bj-chip-fly 700ms ease-in both; } .bj-chip-flight-out .bj-chip { animation-name: bj-chip-fly-out; } @keyframes bj-chip-fly { 0% { opacity: 1; transform: translateY(0) scale(1); } 70% { opacity: 1; } 100% { opacity: 0; transform: translateY(9rem) scale(0.7); } } @keyframes bj-chip-fly-out { 0% { opacity: 1; transform: translateY(0) scale(1); } 70% { opacity: 1; } 100% { opacity: 0; transform: translateY(-18rem) scale(0.7); } } @media (prefers-reduced-motion: reduce) { .bj-chip-flight { display: none; } } /* Fullscreen contain-fit: absolute with zero insets + auto margins sizes the felt to the largest 4:3 rectangle inside the viewport area (the same rules browsers use for replaced elements), so it can never collapse to content size and never overflow. Must stay after .poker-felt-table to win the width tie. */ .blackjack-felt-fullscreen { position: absolute; inset: 0; margin: auto; width: auto; height: auto; max-width: 100%; max-height: 100%; aspect-ratio: 4 / 3; } /* Fixed Chip Bank card: dark panel, delta popup that lands large and scales down before fading, and a sign-colored flash across the card on movement. */ .chip-bank-card { background: rgb(0 0 0 / 55%); backdrop-filter: blur(6px); } .chip-bank-delta { animation: chip-bank-delta-pop 2.5s ease-out forwards; } @keyframes chip-bank-delta-pop { 0% { opacity: 1; transform: scale(1.7); } 30% { opacity: 1; transform: scale(1); } 75% { opacity: 1; } 100% { opacity: 0; transform: scale(1); } } .chip-bank-flash-up { animation: chip-bank-flash-up-anim 1.2s ease-out; } .chip-bank-flash-down { animation: chip-bank-flash-down-anim 1.2s ease-out; } @keyframes chip-bank-flash-up-anim { 0% { background: rgb(16 185 129 / 30%); border-color: #10b981; } 100% { background: rgb(0 0 0 / 55%); border-color: var(--border); } } @keyframes chip-bank-flash-down-anim { 0% { background: rgb(244 63 94 / 28%); border-color: #f43f5e; } 100% { background: rgb(0 0 0 / 55%); border-color: var(--border); } } @media (prefers-reduced-motion: reduce) { .chip-bank-delta { animation: none; } .chip-bank-flash-up, .chip-bank-flash-down { animation: none; } } /* Chip Bank card: small spinning indicator shown while waiting for the chip bank to refresh after the player leaves a table. */ .chip-bank-spinner { @apply size-5 animate-spin rounded-full border-[3px] border-white/20 border-t-white/80; } @media (prefers-reduced-motion: reduce) { .bj-chip { animation: none; } } /* World map: dossier marker family (structure / node / shipment pins). */ /* World map: give the Leaflet container its own stacking context so its panes (z-index 200-1000, applied in the root stacking context otherwise) stop painting over Radix dropdown portals (body-level, z-50) on the map page. */ .leaflet-container { isolation: isolate; } /* Map placement/authoring modes: crosshair cursor while a click mode is active (MapContainer className is mount-only, so this lives on CSS). */ .map-host[data-mode="crosshair"] .leaflet-container { cursor: crosshair; } /* World map: structure / construction-site markers (status-colored pin with an inline SVG icon and a progress bar for sites under construction). The same pin base is shared by the node and shipment badges. */ .map-structure-icon { background: transparent; border: none; } .map-structure-pin { position: relative; display: flex; align-items: center; justify-content: center; width: 26px; height: 26px; border-radius: 2px; background: rgb(8 10 14 / 90%); border: 1.5px solid rgb(255 255 255 / 25%); box-shadow: 0 0 0 1.5px rgb(0 0 0 / 65%), 0 1px 4px rgb(0 0 0 / 60%); } .map-structure-pin.map-pin-sm { width: 20px; height: 20px; border-radius: 1.5px; } .map-structure-pin.map-pin-md { width: 32px; height: 32px; } .map-structure-pin.map-pin-lg { width: 38px; height: 38px; } .map-structure-ribbon { position: absolute; left: calc(100% + 6px); top: 50%; transform: translateY(-50%); display: flex; flex-direction: column; gap: 1px; padding: 2px 8px 3px; border: 1px solid rgb(255 255 255 / 15%); border-left-width: 2px; border-radius: 1px; background: rgb(8 10 14 / 88%); box-shadow: 0 1px 4px rgb(0 0 0 / 50%); white-space: nowrap; } .map-structure-ribbon .ribbon-name { font-size: 11px; font-weight: 600; color: rgb(255 255 255 / 95%); max-width: 190px; overflow: hidden; text-overflow: ellipsis; } .map-structure-ribbon .ribbon-meta { font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; font-size: 9px; text-transform: uppercase; letter-spacing: 0.12em; color: rgb(255 255 255 / 65%); } .map-tooltip-dossier .map-tooltip-name { font-size: 11px; font-weight: 600; letter-spacing: 0.08em; color: rgb(255 255 255 / 95%); overflow-wrap: anywhere; } /* Must out-rank leaflet.css, which styles the SAME selector later (it loads in the MapClient chunk after styles.css) with a white background. */ .map-host .leaflet-container .leaflet-control-attribution { background: rgb(8 10 14 / 92%); color: rgb(255 255 255 / 55%); font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; font-size: 9px; letter-spacing: 0.08em; text-transform: uppercase; padding: 1px 6px; border: 1px solid rgb(255 255 255 / 15%); border-radius: 0; } .leaflet-container .leaflet-control-attribution a { color: rgb(148 163 184 / 85%); } .map-tooltip-dossier .map-tooltip-meta { margin-top: 1px; font-size: 9px; letter-spacing: 0.12em; color: rgb(255 255 255 / 60%); } /* A hovered structure (pin or ribbon) jumps above every other marker. The !important is required to beat Leaflet's inline z-index management. */ .map-structure-icon.leaflet-marker-icon:hover { z-index: 1200 !important; } .map-vertex-handle { width: 12px; height: 12px; border: 1.5px solid #f8fafc; border-radius: 2px; background: rgb(8 10 14 / 75%); box-shadow: 0 0 0 1px rgb(0 0 0 / 60%); } .map-midpoint-handle { width: 8px; height: 8px; border: 1.5px solid #22d3ee; border-radius: 1px; background: rgb(8 10 14 / 40%); opacity: 0.85; } .map-snap-preview { width: 12px; height: 12px; margin-left: -6px; margin-top: -6px; border-radius: 2px; border: 1.5px solid; pointer-events: none; } .map-snap-vertex { border-color: #34d399; background: rgb(52 211 153 / 25%); } .map-snap-edge { border-color: #22d3ee; background: rgb(34 211 238 / 25%); } .map-structure-progress { position: absolute; left: 3px; right: 3px; bottom: -6px; height: 3px; overflow: hidden; border-radius: 2px; background: rgb(255 255 255 / 30%); } .map-structure-progress > div { height: 100%; background: #ffffff; } /* World map: dossier-style Leaflet chrome. Tooltips and popups are Leaflet DOM (not shadcn), so they get the tactical card treatment here: dark glass, hairline borders, squared corners, mono uppercase labels. */ .leaflet-container .map-tooltip-dossier.leaflet-tooltip { background: rgb(0 0 0 / 82%); backdrop-filter: blur(6px); border: 1px solid rgb(255 255 255 / 25%); border-radius: 0; box-shadow: 0 2px 8px rgb(0 0 0 / 65%); color: rgb(255 255 255 / 85%); font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; font-size: 10px; letter-spacing: 0.16em; padding: 4px 8px; text-transform: uppercase; width: max-content; max-width: min(280px, 60vw); white-space: normal; overflow-wrap: anywhere; } .leaflet-container .map-tooltip-dossier.leaflet-tooltip-top::before { border-top-color: rgb(255 255 255 / 25%); } .leaflet-container .map-tooltip-dossier.leaflet-tooltip-bottom::before { border-bottom-color: rgb(255 255 255 / 25%); } .leaflet-container .map-tooltip-dossier.leaflet-tooltip-left::before { border-left-color: rgb(255 255 255 / 25%); } .leaflet-container .map-tooltip-dossier.leaflet-tooltip-right::before { border-right-color: rgb(255 255 255 / 25%); } .leaflet-container .leaflet-popup-content-wrapper { background: rgb(8 10 14 / 92%); backdrop-filter: blur(8px); border: 1px solid rgb(255 255 255 / 20%); border-radius: 0; box-shadow: 0 4px 16px rgb(0 0 0 / 65%); color: rgb(255 255 255 / 90%); } .leaflet-container .leaflet-popup-content { margin: 10px 12px; line-height: 1.45; } .leaflet-container .leaflet-popup-tip { background: rgb(8 10 14 / 92%); box-shadow: none; } .leaflet-container a.leaflet-popup-close-button { color: rgb(255 255 255 / 50%); } .leaflet-container a.leaflet-popup-close-button:hover { color: #ffffff; } /* Dossier popups (structure/shipment cards): zero wrapper padding so the classification strip and readout footer run edge to edge. */ .leaflet-container .map-popup-dossier .leaflet-popup-content { margin: 0; width: 100% !important; } /* World map: persistent map labels (structures, zones, roads) in the dossier style: mono uppercase, tracked, dark halo instead of a box. */ .leaflet-container .map-label.leaflet-tooltip { background: rgb(8 10 14 / 62%); border: none; box-shadow: none; border-radius: 1px; padding: 1px 5px; color: rgb(255 255 255 / 92%); font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; font-size: 10px; letter-spacing: 0.16em; text-transform: uppercase; text-shadow: 0 0 3px rgb(0 0 0 / 95%), 0 0 6px rgb(0 0 0 / 85%); white-space: nowrap; } .leaflet-container .map-label.leaflet-tooltip::before { display: none; } .map-zone-label-icon, .map-road-label-icon { background: transparent; border: none; } .map-zone-label { color: rgb(255 255 255 / 90%); font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; font-size: 10px; letter-spacing: 0.2em; text-transform: uppercase; white-space: nowrap; /* Size to the text itself: inside the 0x0 divIcon container a block div resolves to 0 width, which makes the percentage centering transform a no-op and leaves the label hanging off the road. */ width: max-content; background: rgb(8 10 14 / 62%); padding: 1px 5px; border-radius: 1px; text-shadow: 0 0 3px rgb(0 0 0 / 95%), 0 0 7px rgb(0 0 0 / 90%), 0 0 2px rgb(0 0 0 / 90%); pointer-events: none; transform: translate(-50%, -50%); } .map-road-label-svg { overflow: visible; } .map-road-label { color: rgb(255 255 255 / 94%); font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; font-size: 11px; letter-spacing: 0.2em; text-transform: uppercase; white-space: nowrap; /* Size to the text itself: inside the 0x0 divIcon container a block div resolves to 0 width, which makes the percentage centering transform a no-op and leaves the label hanging off the road. */ width: max-content; background: rgb(8 10 14 / 62%); padding: 1px 5px; border-radius: 1px; text-shadow: 0 0 3px rgb(0 0 0 / 95%), 0 0 7px rgb(0 0 0 / 90%), 0 0 2px rgb(0 0 0 / 90%); pointer-events: none; } .map-road-label-path { fill: none; stroke: none; } .map-road-label-text { fill: rgb(255 255 255 / 94%); font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; font-size: 11px; letter-spacing: 0.2em; /* Dark casing behind the glyphs (painted under the fill) for contrast on any terrain. */ stroke: rgb(0 0 0 / 82%); stroke-width: 4px; paint-order: stroke; stroke-linejoin: round; } .leaflet-container .map-zone-label-icon, .leaflet-container .map-road-label-icon { pointer-events: none; } /* Radix floating panels (Select/DropdownMenu/Popover/Tooltip) portal to and would otherwise paint below the map page's high-z overlays (authoring toolbar z-[1000], structure drawer z-[1200]). Pin every popper wrapper above them. */ [data-radix-popper-content-wrapper] { z-index: 1300 !important; } /* Book view (story reader): body prose reads left-aligned like a real book. Center alignment authored on paragraphs in the Lexical editor renders as inline text-align styles, which only an !important rule can override, so the rule is scoped to the paginated Book view body (the immersive reader keeps the authored alignment). */ .book-view-body, .book-view-body [style*="text-align"] { text-align: left !important; }