trictrac/clients/web/assets/style.css

2519 lines
69 KiB
CSS
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/* ── Google Fonts ───────────────────────────────────────────────── */
@import url('https://fonts.googleapis.com/css2?family=Cormorant+Garamond:ital,wght@0,400;0,600;1,400&family=Jost:wght@300;400;500&display=swap');
/* ── Design tokens ──────────────────────────────────────────────────── */
:root {
--board-felt: #1d3d28;
--board-rail: #2a1508;
--field-ivory: #f0e6c8;
--field-burgundy: #7a1e2a;
--field-blue: #e5eadc;
--field-blue-light: #1a4f72;
--field-brown: #f2dfa0;
--field-brown-light: #6a2810;
--field-corner: #b8900a;
--checker-white: #f5edd8;
--checker-black: #1a0f06;
--checker-ring: #c8a448;
--ui-parchment: #f2e8d0;
--ui-parchment-dark: #e4d8b8;
--ui-ink: #2a1a08;
--ui-gold: #c8a448;
--ui-gold-dark: #8a6a28;
--ui-green-accent: #3a6b2a;
--ui-red-accent: #7a1e2a;
--font-display: 'Cormorant Garamond', Georgia, serif;
--font-ui: 'Jost', system-ui, sans-serif;
}
/* ── Reset & base ──────────────────────────────────────────────────── */
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
body {
font-family: var(--font-ui);
background: #8a7050;
background-image:
radial-gradient(ellipse at 20% 10%, rgba(80,48,16,0.35) 0%, transparent 60%),
radial-gradient(ellipse at 80% 90%, rgba(40,24,8,0.3) 0%, transparent 55%),
repeating-linear-gradient(
45deg, transparent, transparent 3px,
rgba(0,0,0,0.03) 3px, rgba(0,0,0,0.03) 4px
);
display: flex;
flex-direction: column;
min-height: 100vh;
}
.hidden { display: none !important; }
/* -- svg icons -- */
.icon {
width: 1.2em;
height: 1.2em;
color: var(--ui-parchment);
vertical-align: -0.25em;
margin-right: 0.7em;
}
/* ── Site navigation ─────────────────────────────────────────────── */
.site-nav {
background: var(--board-rail);
border-bottom: 2px solid var(--ui-gold-dark);
padding: 0 1.5rem;
height: 52px;
display: flex;
align-items: center;
gap: 1.5rem;
position: sticky;
top: 0;
z-index: 50;
box-shadow: 0 2px 8px rgba(0,0,0,0.4);
flex-shrink: 0;
}
.site-nav-brand {
font-family: var(--font-display);
font-size: 1.5rem;
font-weight: 600;
color: var(--ui-gold);
text-decoration: none;
letter-spacing: 0.1em;
}
.site-nav-brand:hover { color: #e0b840; }
.site-nav-spacer { flex: 1; }
.site-nav a {
font-family: var(--font-ui);
font-size: 0.9rem;
color: var(--ui-parchment);
text-decoration: none;
opacity: 0.8;
transition: opacity 0.15s, color 0.15s;
}
.site-nav a:hover { opacity: 1; }
.site-nav-btn {
padding: 0.3rem 0.9rem;
font-family: var(--font-ui);
font-size: 0.85rem;
font-weight: 500;
letter-spacing: 0.03em;
border: 1px solid rgba(200,164,72,0.4);
border-radius: 4px;
background: transparent;
color: var(--ui-parchment);
cursor: pointer;
transition: background 0.15s, border-color 0.15s;
}
.site-nav-btn:hover {
background: rgba(200,164,72,0.12);
border-color: var(--ui-gold);
}
/* ── Portal main content area ────────────────────────────────────── */
.portal-main {
flex: 1;
max-width: 900px;
width: 100%;
margin: 2rem auto;
padding: 0 1.5rem;
}
.portal-card {
background: var(--ui-parchment);
border-radius: 8px;
box-shadow:
0 20px 60px rgba(0,0,0,0.55),
0 0 3px 3px rgba(42,21,8,0.9)
;
/* box-shadow: 0 4px 16px rgba(0,0,0,0.18); */
/* border: 1px solid rgba(200,164,72,0.3); */
/* border-top: 3px solid var(--ui-gold-dark); */
padding: 1.75rem 2rem;
margin-bottom: 1.5rem;
}
.portal-card h1 {
font-family: var(--font-display);
font-size: 2rem;
font-weight: 600;
color: var(--ui-ink);
letter-spacing: 0.04em;
margin-bottom: 0.25rem;
}
.portal-card h2 {
font-family: var(--font-display);
font-size: 1.35rem;
font-weight: 600;
color: var(--ui-ink);
margin-bottom: 0.75rem;
}
.portal-meta {
font-size: 0.85rem;
color: #665544;
margin-bottom: 1.5rem;
font-family: var(--font-ui);
}
/* ── Stats grid ──────────────────────────────────────────────────── */
.stats-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 1rem;
margin-bottom: 1.5rem;
}
.stat-box {
background: var(--ui-parchment);
border: 1px solid rgba(200,164,72,0.28);
border-radius: 6px;
padding: 1rem;
text-align: center;
box-shadow: 0 1px 4px rgba(0,0,0,0.1);
}
.stat-box .value {
font-family: var(--font-display);
font-size: 2.2rem;
font-weight: 600;
color: var(--ui-gold-dark);
}
.stat-box .label {
font-size: 0.78rem;
color: #665544;
margin-top: 0.2rem;
letter-spacing: 0.04em;
text-transform: uppercase;
}
/* ── Tables ──────────────────────────────────────────────────────── */
table {
width: 100%;
border-collapse: collapse;
font-size: 0.9rem;
font-family: var(--font-ui);
}
th {
text-align: left;
padding: 0.5rem 0.75rem;
border-bottom: 2px solid rgba(200,164,72,0.4);
color: #665544;
font-weight: 500;
font-size: 0.8rem;
letter-spacing: 0.05em;
text-transform: uppercase;
}
td {
padding: 0.5rem 0.75rem;
border-bottom: 1px solid rgba(200,164,72,0.12);
color: var(--ui-ink);
}
tr:last-child td { border-bottom: none; }
tr:hover td { background: rgba(200,164,72,0.05); }
a { color: var(--ui-gold-dark); text-decoration: none; }
a:hover { text-decoration: underline; }
/* ── Outcome classes ─────────────────────────────────────────────── */
.outcome-win { color: var(--ui-green-accent); font-weight: 600; }
.outcome-loss { color: var(--ui-red-accent); font-weight: 600; }
.outcome-draw { color: #c07020; font-weight: 600; }
/* ── Portal tabs ─────────────────────────────────────────────────── */
.portal-tabs {
display: flex;
gap: 0;
margin-bottom: 1.5rem;
border-bottom: 1px solid rgba(200,164,72,0.3);
}
.portal-tab-btn {
padding: 0.55rem 1.5rem;
font-family: var(--font-ui);
font-size: 0.9rem;
background: transparent;
border: none;
cursor: pointer;
color: #665544;
border-bottom: 2px solid transparent;
margin-bottom: -1px;
transition: color 0.15s, border-color 0.15s;
}
.portal-tab-btn.active {
color: var(--ui-ink);
border-bottom-color: var(--ui-gold-dark);
font-weight: 500;
}
/* ── Portal form ─────────────────────────────────────────────────── */
.portal-label {
display: block;
font-size: 0.82rem;
color: #665544;
margin-bottom: 0.3rem;
letter-spacing: 0.03em;
}
.portal-input {
width: 100%;
padding: 0.55rem 0.85rem;
font-size: 0.95rem;
font-family: var(--font-ui);
border: 1px solid rgba(138,106,40,0.35);
border-radius: 5px;
background: rgba(255,252,240,0.8);
color: var(--ui-ink);
outline: none;
margin-bottom: 1rem;
transition: border-color 0.15s, box-shadow 0.15s;
}
.portal-input:focus {
border-color: var(--ui-gold);
box-shadow: 0 0 0 3px rgba(200,164,72,0.18);
}
.portal-submit-btn {
padding: 0.6rem 2rem;
font-family: var(--font-ui);
font-size: 0.9rem;
font-weight: 500;
background: linear-gradient(160deg, #4a7a38 0%, #2e5222 100%);
color: #e8f0e0;
border: none;
border-radius: 5px;
cursor: pointer;
box-shadow: 0 2px 5px rgba(0,0,0,0.25);
transition: opacity 0.15s;
}
.portal-submit-btn:disabled { opacity: 0.45; cursor: not-allowed; }
.portal-submit-btn:not(:disabled):hover { opacity: 0.9; }
.portal-page-btn {
padding: 0.35rem 0.9rem;
font-family: var(--font-ui);
font-size: 0.85rem;
background: var(--board-rail);
color: var(--ui-parchment);
border: none;
border-radius: 4px;
cursor: pointer;
opacity: 0.85;
transition: opacity 0.15s;
}
.portal-page-btn:hover { opacity: 1; }
.portal-loading { color: #665544; font-style: italic; padding: 1rem 0; }
.portal-empty { color: #aa9070; font-style: italic; padding: 1rem 0; }
.portal-error { color: var(--ui-red-accent); font-size: 0.875rem; margin-top: 0.5rem; }
.portal-success { color: var(--ui-green-accent); font-size: 0.875rem; margin-top: 0.5rem; }
.flash-banner {
position: fixed;
top: 1.25rem;
left: 50%;
transform: translateX(-50%);
z-index: 500;
display: flex;
align-items: center;
gap: 1rem;
padding: 0.75rem 1.25rem;
background: var(--ui-green-accent);
color: #f5edd8;
border-radius: 6px;
box-shadow: 0 4px 16px rgba(0,0,0,0.35);
font-family: var(--font-ui);
font-size: 0.95rem;
max-width: 90vw;
animation: flash-in 0.2s ease;
}
@keyframes flash-in {
from { opacity: 0; transform: translateX(-50%) translateY(-0.5rem); }
to { opacity: 1; transform: translateX(-50%) translateY(0); }
}
.flash-dismiss {
background: none;
border: none;
color: inherit;
cursor: pointer;
font-size: 1rem;
opacity: 0.75;
padding: 0;
line-height: 1;
}
.flash-dismiss:hover { opacity: 1; }
.portal-danger-zone {
border: 1px solid rgba(122, 30, 42, 0.4);
background: rgba(122, 30, 42, 0.04);
}
.portal-danger-zone h2 {
color: var(--ui-red-accent);
}
.portal-danger-btn {
padding: 0.5rem 1.25rem;
font-family: var(--font-ui);
font-size: 0.9rem;
background: var(--ui-red-accent);
color: #f5edd8;
border: none;
border-radius: 4px;
cursor: pointer;
transition: opacity 0.15s;
}
.portal-danger-btn:hover { opacity: 0.85; }
.portal-danger-btn:disabled { opacity: 0.45; cursor: not-allowed; }
.portal-link {
color: var(--ui-gold);
text-decoration: none;
font-size: 0.875rem;
}
.portal-link:hover { text-decoration: underline; }
.portal-verification-banner {
background: rgba(200,164,72,0.08);
border: 1px solid rgba(200,164,72,0.35);
border-radius: 6px;
padding: 1.25rem;
text-align: center;
}
.portal-verification-banner p {
margin-bottom: 0.75rem;
font-size: 0.9rem;
}
/* ── Share URL row (lobby waiting card + game top bar) ──────────── */
.share-url-row {
display: flex;
align-items: center;
gap: 0.5rem;
background: rgba(0,0,0,0.18);
border: 1px solid rgba(200,164,72,0.25);
border-radius: 5px;
padding: 0.4rem 0.6rem;
}
.share-url-text {
flex: 1;
font-family: var(--font-ui);
font-size: 0.72rem;
color: rgba(242,232,208,0.75);
word-break: break-all;
user-select: all;
}
.share-copy-btn {
flex-shrink: 0;
font-family: var(--font-ui);
font-size: 0.72rem;
padding: 0.2rem 0.6rem;
border: 1px solid rgba(200,164,72,0.4);
border-radius: 3px;
background: rgba(200,164,72,0.1);
color: var(--ui-parchment);
cursor: pointer;
transition: background 0.15s;
white-space: nowrap;
}
.share-copy-btn:hover { background: rgba(200,164,72,0.22); }
/* ── QR code container ───────────────────────────────────────────── */
.qr-container {
width: 160px;
height: 160px;
margin: 0 auto;
border-radius: 4px;
overflow: hidden;
}
.qr-container svg { width: 100%; height: 100%; display: block; }
/* ── Share popover (in-game top bar) ─────────────────────────────── */
.share-popover {
width: 100%;
background: rgba(0,0,0,0.3);
border: 1px solid rgba(200,164,72,0.2);
border-radius: 6px;
padding: 0.75rem 1rem;
display: flex;
flex-direction: column;
align-items: center;
gap: 0.4rem;
margin-bottom: 0.5rem;
}
.share-popover .qr-container { width: 120px; height: 120px; }
.share-popover-label {
font-size: 0.75rem;
color: rgba(242,232,208,0.6);
text-align: center;
margin: 0;
}
/* ── Game overlay (full-screen, covers portal during play) ───────── */
.game-overlay {
position: fixed;
inset: 0;
background: #8a7050;
background-image:
radial-gradient(ellipse at 20% 10%, rgba(80,48,16,0.35) 0%, transparent 60%),
radial-gradient(ellipse at 80% 90%, rgba(40,24,8,0.3) 0%, transparent 55%),
repeating-linear-gradient(
45deg, transparent, transparent 3px,
rgba(0,0,0,0.03) 3px, rgba(0,0,0,0.03) 4px
);
z-index: 200;
display: flex;
justify-content: center;
align-items: flex-start;
padding: 1.5rem;
overflow-y: auto;
}
/* ── Login card (§11) ───────────────────────────────────────────────── */
.login-card {
background: var(--ui-parchment);
border-radius: 8px;
box-shadow:
0 20px 60px rgba(0,0,0,0.55),
0 0 3px 3px rgba(42,21,8,0.9)
;
/* box-shadow:
0 20px 60px rgba(0,0,0,0.55),
0 0 0 1px rgba(200,164,72,0.35),
0 0 0 5px rgba(42,21,8,0.9),
0 0 0 6px rgba(200,164,72,0.2);
*/
/* border-top: 3px solid var(--ui-gold-dark); */
width: 340px;
margin-top: 5vh;
overflow: hidden;
}
/* Decorative header — row of triangular flèches like the actual board */
.login-card-header {
height: 52px;
background: var(--board-felt);
position: relative;
overflow: hidden;
}
.login-board-stripe {
position: absolute;
inset: 0;
background:
repeating-linear-gradient(
90deg,
var(--field-burgundy) 0, var(--field-burgundy) 50%,
var(--field-ivory) 50%, var(--field-ivory) 100%
);
background-size: 34px 100%;
clip-path: polygon(
0% 0%, 2.94% 100%, 5.88% 0%, 8.82% 100%, 11.76% 0%,
14.7% 100%, 17.65% 0%, 20.59% 100%, 23.53% 0%,
26.47% 100%, 29.41% 0%, 32.35% 100%, 35.29% 0%,
38.24% 100%, 41.18% 0%, 44.12% 100%, 47.06% 0%,
50% 100%, 52.94% 0%, 55.88% 100%, 58.82% 0%,
61.76% 100%, 64.71% 0%, 67.65% 100%, 70.59% 0%,
73.53% 100%, 76.47% 0%, 79.41% 100%, 82.35% 0%,
85.29% 100%, 88.24% 0%, 91.18% 100%, 94.12% 0%,
97.06% 100%, 100% 0%
);
opacity: 0.9;
}
.login-card-body {
display: flex;
flex-direction: column;
align-items: center;
gap: 0;
padding: 1.5rem 2rem 2rem;
}
.login-lang-switcher {
align-self: flex-end;
margin-bottom: 0.75rem;
}
/* Override lang-switcher colours for the parchment card */
.login-card .lang-switcher button {
color: var(--ui-ink);
border-color: rgba(42,21,8,0.2);
opacity: 0.5;
}
.login-card .lang-switcher button.lang-active {
opacity: 1;
background: rgba(42,21,8,0.08);
border-color: rgba(42,21,8,0.35);
}
.login-title {
font-family: var(--font-display);
font-size: 3.25rem;
font-weight: 600;
color: var(--ui-ink);
letter-spacing: 0.12em;
text-align: center;
line-height: 1;
margin-bottom: 0.3rem;
}
.login-subtitle {
font-family: var(--font-display);
font-size: 0.85rem;
color: rgba(42,26,8,0.55);
text-align: center;
letter-spacing: 0.06em;
font-style: italic;
margin-bottom: 1.25rem;
}
.login-subtitle sup {
font-size: 0.65em;
vertical-align: super;
}
.login-ornament {
color: var(--ui-gold);
font-size: 1rem;
opacity: 0.7;
margin-bottom: 1.25rem;
letter-spacing: 0.3em;
text-align: center;
}
.error-msg {
color: #c03030;
font-size: 0.85rem;
text-align: center;
margin-bottom: 0.5rem;
}
.login-input {
width: 100%;
padding: 0.55rem 0.85rem;
font-size: 0.95rem;
font-family: var(--font-ui);
border: 1px solid rgba(138,106,40,0.4);
border-radius: 5px;
background: rgba(255,252,240,0.8);
color: var(--ui-ink);
outline: none;
transition: border-color 0.15s, box-shadow 0.15s;
margin-bottom: 1rem;
}
.login-input:focus {
border-color: var(--ui-gold);
box-shadow: 0 0 0 3px rgba(200,164,72,0.2);
}
.login-actions {
display: flex;
flex-direction: column;
gap: 0.55rem;
width: 100%;
}
/* Login buttons styled as embossed wooden tiles */
.login-btn {
width: 100%;
padding: 0.65rem 1rem;
font-family: var(--font-ui);
font-size: 0.9rem;
font-weight: 500;
letter-spacing: 0.04em;
border: none;
border-radius: 5px;
cursor: pointer;
transition: opacity 0.15s, transform 0.1s, box-shadow 0.15s;
position: relative;
}
.login-btn:disabled { opacity: 0.35; cursor: default; }
.login-btn:not(:disabled):hover { opacity: 0.92; transform: translateY(-1px); }
.login-btn:not(:disabled):active { transform: translateY(0); }
.login-btn-primary {
background: linear-gradient(160deg, #4a7a38 0%, #2e5222 100%);
color: #e8f0e0;
box-shadow: 0 2px 6px rgba(0,0,0,0.3), inset 0 1px 0 rgba(255,255,255,0.12);
}
.login-btn-secondary {
background: linear-gradient(160deg, #3a2010 0%, #241408 100%);
color: #e4d4b4;
box-shadow: 0 2px 6px rgba(0,0,0,0.3), inset 0 1px 0 rgba(255,255,255,0.08);
}
.login-btn-bot {
background: linear-gradient(160deg, #2a4a6a 0%, #183050 100%);
color: #d0e0f0;
box-shadow: 0 2px 6px rgba(0,0,0,0.3), inset 0 1px 0 rgba(255,255,255,0.08);
}
/* ── Connecting screen ──────────────────────────────────────────────── */
.connecting {
font-family: var(--font-display);
font-size: 1.4rem;
font-style: italic;
margin-top: 4rem;
text-align: center;
color: var(--ui-parchment);
text-shadow: 0 1px 4px rgba(0,0,0,0.4);
}
/* ── Game-action buttons ─────────────────────────────────────────────── */
.btn {
padding: 0.5rem 1.25rem;
font-size: 0.95rem;
font-family: var(--font-ui);
font-weight: 500;
letter-spacing: 0.03em;
border: none;
border-radius: 4px;
cursor: pointer;
transition: opacity 0.15s, box-shadow 0.15s;
}
.btn:disabled { opacity: 0.4; cursor: default; }
.btn-primary { background: var(--ui-green-accent); color: #fff; }
.btn-secondary { background: var(--board-rail); color: #e8d8b8; }
.btn-bot { background: #2a5a7a; color: #fff; }
.btn:not(:disabled):hover {
opacity: 0.9;
box-shadow: 0 2px 6px rgba(0,0,0,0.25);
}
/* ── Game container ─────────────────────────────────────────────────── */
.game-container {
display: flex;
flex-direction: column;
align-items: center;
gap: 0.6rem;
}
/* ── Language switcher (in-game) ────────────────────────────────────── */
.lang-switcher { display: flex; gap: 0.25rem; }
.lang-switcher button {
font-size: 0.7rem;
font-family: var(--font-ui);
letter-spacing: 0.05em;
padding: 0.15rem 0.4rem;
border: 1px solid rgba(200,164,72,0.3);
border-radius: 3px;
background: transparent;
cursor: pointer;
color: var(--ui-parchment);
opacity: 0.55;
}
.lang-switcher button.lang-active {
opacity: 1;
font-weight: 500;
background: rgba(200,164,72,0.15);
border-color: rgba(200,164,72,0.6);
}
/* ── Top bar ─────────────────────────────────────────────────────────── */
.top-bar {
display: flex;
justify-content: space-between;
align-items: center;
width: 100%;
color: var(--ui-parchment);
font-size: 0.85rem;
opacity: 0.8;
}
.quit-link {
font-size: 0.8rem;
color: var(--ui-parchment);
text-decoration: underline;
text-underline-offset: 2px;
cursor: pointer;
opacity: 0.7;
}
.quit-link:hover { opacity: 1; }
.playing-as {
font-size: 0.75rem;
color: rgba(242,232,208,0.7);
font-family: var(--font-ui);
}
.playing-as strong { color: rgba(242,232,208,0.9); }
/* ── Game status bar (§10b) — above board ───────────────────────────── */
.game-status {
font-family: var(--font-display);
font-size: 1.2rem;
font-style: italic;
color: var(--ui-parchment);
text-align: center;
letter-spacing: 0.04em;
padding: 0.2rem 1rem 0;
width: 100%;
text-shadow: 0 1px 4px rgba(0,0,0,0.4);
}
/* ── Contextual sub-prompt (§8a) ────────────────────────────────────── */
.game-sub-prompt {
font-family: var(--font-ui);
font-size: 0.72rem;
color: rgba(240,228,192,0.5);
text-align: center;
letter-spacing: 0.04em;
padding: 0.15rem 1rem 0;
width: 100%;
}
/* ── Player score panel ─────────────────────────────────────────────── */
.player-score-panel {
background: var(--ui-parchment);
border-radius: 5px;
padding: 0.45rem 1.25rem;
font-size: 0.88rem;
box-shadow: 0 2px 6px rgba(0,0,0,0.25);
width: 100%;
border-top: 2px solid var(--ui-gold-dark);
display: flex;
align-items: center;
gap: 1.5rem;
}
.player-score-header {
flex-shrink: 0;
min-width: 90px;
}
.player-name {
font-family: var(--font-display);
font-weight: 600;
font-size: 1.05rem;
color: var(--ui-ink);
letter-spacing: 0.02em;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
min-width: 0;
}
.score-bars { display: flex; flex-direction: row; gap: 1.5rem; flex: 1; align-items: center; }
.score-bar-row {
display: flex;
align-items: center;
gap: 0.5rem;
flex: 1;
}
.score-bar-label {
font-size: 0.75rem;
color: #665544;
width: 3rem;
text-align: right;
flex-shrink: 0;
}
/* ── Points bar ─────────────────────────────────────────────────────── */
.score-bar {
flex: 1;
max-width: 220px;
height: 8px;
background: rgba(0,0,0,0.1);
border-radius: 4px;
overflow: hidden;
flex-shrink: 0;
}
.score-bar-fill {
height: 100%;
border-radius: 4px;
transition: width 0.35s ease-out;
}
.score-bar-points { background: linear-gradient(90deg, var(--ui-green-accent), #5a9b3a); }
.score-bar-value {
font-size: 0.75rem;
color: #665544;
min-width: 2.5rem;
font-variant-numeric: tabular-nums;
}
/* ── Hole peg tracker (§7a) ─────────────────────────────────────────── */
.peg-track {
display: flex;
align-items: center;
gap: 3px;
flex-shrink: 0;
}
.peg-hole {
width: 10px;
height: 10px;
border-radius: 50%;
border: 1.5px solid rgba(138,106,40,0.45);
background: rgba(0,0,0,0.06);
flex-shrink: 0;
transition: background 0.3s ease-out, border-color 0.3s, box-shadow 0.3s;
}
.peg-hole.filled {
background: var(--ui-gold);
border-color: var(--ui-gold-dark);
box-shadow: 0 0 4px rgba(200,164,72,0.6);
}
.bredouille-badge {
font-size: 0.62rem;
font-weight: 500;
color: #fff8e0;
background: linear-gradient(135deg, #c88800, #8a5800);
border: 1px solid rgba(200,164,72,0.5);
border-radius: 3px;
padding: 0.1em 0.4em;
letter-spacing: 0.06em;
cursor: default;
box-shadow: 0 1px 3px rgba(0,0,0,0.25);
}
/* ── Merged scoreboard (both players, above board) ──────────────────── */
.merged-score-panel {
background: var(--ui-parchment);
border-radius: 5px;
padding: 0.5rem 1.25rem 0.45rem;
font-size: 0.88rem;
box-shadow: 0 2px 6px rgba(0,0,0,0.25);
width: 100%;
border-top: 2px solid var(--ui-gold-dark);
display: flex;
flex-direction: column;
gap: 0.2rem;
}
.score-row {
display: flex;
align-items: center;
gap: 1rem;
}
.score-row-name {
width: 120px;
flex-shrink: 0;
display: flex;
align-items: baseline;
gap: 0.35rem;
overflow: hidden;
}
.you-tag {
font-family: var(--font-ui);
font-size: 0.7rem;
color: #887766;
font-style: italic;
white-space: nowrap;
flex-shrink: 0;
}
/* ── Jackpot points counter ─────────────────────────────────────────── */
.pts-counter-wrap {
position: relative;
display: flex;
flex-direction: column;
align-items: center;
width: 72px;
flex-shrink: 0;
padding-bottom: 4px;
}
.pts-ghost-bar-track {
position: absolute;
bottom: 0;
left: 0;
right: 0;
height: 3px;
background: rgba(0,0,0,0.07);
border-radius: 2px;
overflow: hidden;
}
.pts-ghost-bar-fill {
height: 100%;
background: rgba(58,107,42,0.45);
border-radius: 2px;
}
.pts-ghost-bar-opp {
background: rgba(122,30,42,0.4);
}
.pts-counter-row {
display: flex;
align-items: baseline;
gap: 0.1rem;
}
.pts-counter {
font-family: var(--font-display);
font-size: 1.9rem;
font-weight: 600;
color: var(--ui-ink);
line-height: 1;
font-variant-numeric: tabular-nums;
min-width: 1.4em;
text-align: right;
}
.pts-max {
font-family: var(--font-ui);
font-size: 0.7rem;
color: #998877;
line-height: 1;
padding-bottom: 2px;
}
/* ── Hole pegs — larger and coloured (me = green, opp = red) ─────────── */
.merged-score-panel .peg-track {
gap: 4px;
}
.merged-score-panel .peg-hole {
width: 14px;
height: 14px;
border-radius: 50%;
border: 1.5px solid rgba(138,106,40,0.3);
background: rgba(0,0,0,0.06);
flex-shrink: 0;
transition: background 0.3s ease-out, border-color 0.3s, box-shadow 0.3s;
}
.merged-score-panel .peg-hole.filled {
background: #5aab38;
border-color: #3a7828;
box-shadow: 0 0 5px rgba(90,171,56,0.55);
}
.merged-score-panel .peg-hole.peg-opp.filled {
background: #c05030;
border-color: #8a3018;
box-shadow: 0 0 5px rgba(192,80,48,0.55);
}
/* Peg pop-in animation when a new hole is scored */
@keyframes peg-pop {
0% { transform: scale(0.15); opacity: 0; }
45% { transform: scale(1.55); }
70% { transform: scale(0.88); }
100% { transform: scale(1.0); opacity: 1; }
}
.merged-score-panel .peg-hole.peg-new {
animation: peg-pop 0.52s cubic-bezier(0.22, 0.61, 0.36, 1) forwards;
}
/* Thin separator between the two player rows */
.score-row-sep {
height: 1px;
background: rgba(0,0,0,0.07);
margin: 0.05rem 0;
}
/* ── Non-blocking hole flash (replaces old toast) ───────────────────── */
@keyframes hole-flash-in-out {
0% { opacity: 0; transform: translateY(-3px); }
14% { opacity: 1; transform: translateY(0); }
65% { opacity: 1; }
100% { opacity: 0; transform: translateY(2px); }
}
.hole-flash {
margin-left: auto;
flex-shrink: 0;
white-space: nowrap;
font-family: var(--font-display);
font-size: 0.88rem;
font-weight: 600;
color: var(--ui-green-accent);
letter-spacing: 0.05em;
animation: hole-flash-in-out 2.5s ease-out forwards;
pointer-events: none;
}
.hole-flash.hole-flash-bredouille {
color: var(--ui-gold-dark);
}
/* ── Game bottom strip — status, hints, buttons on cream ────────────── */
.game-bottom-strip {
background: var(--ui-parchment);
border-radius: 5px;
padding: 0.55rem 1.25rem 0.65rem;
width: 100%;
box-shadow: 0 2px 6px rgba(0,0,0,0.2);
border-top: 2px solid var(--ui-gold-dark);
display: flex;
flex-direction: column;
align-items: center;
gap: 0.35rem;
min-height: 3.2rem;
}
/* Override text colours for the parchment background context */
.game-bottom-strip .game-status {
color: var(--ui-ink);
text-shadow: none;
padding: 0;
font-size: 1.05rem;
width: auto;
}
.game-bottom-strip .game-sub-prompt {
color: #887766;
padding: 0;
width: auto;
}
/* ── Board + side panel ─────────────────────────────────────────────── */
.board-and-panel {
position: relative;
}
.side-panel {
position: absolute;
right: -8px;
top: 10px;
z-index: 20;
display: flex;
flex-direction: column;
gap: 0.5rem;
padding-top: 0.15rem;
pointer-events: none;
}
.action-buttons { display: flex; flex-direction: column; gap: 0.5rem; }
/* ── Dice bar ───────────────────────────────────────────────────────── */
.dice-bar {
display: flex;
align-items: center;
gap: 0.6rem;
padding: 0.4rem 0.6rem;
background: rgba(42,21,8,0.15);
border-radius: 6px;
border: 1px solid rgba(200,164,72,0.2);
width: fit-content;
}
/* ── Die face (SVG) ─────────────────────────────────────────────────── */
@keyframes die-tumble {
0% { transform: rotate(-45deg) scale(0.4) translateY(-8px); opacity: 0; }
25% { transform: rotate(18deg) scale(1.22) translateY(0); opacity: 1; }
45% { transform: rotate(-10deg) scale(0.91); }
62% { transform: rotate(6deg) scale(1.06); }
76% { transform: rotate(-3deg) scale(0.98); }
88% { transform: rotate(1.5deg) scale(1.01); }
100% { transform: rotate(0deg) scale(1); opacity: 1; }
}
.die-face {
filter: drop-shadow(0 2px 3px rgba(0,0,0,0.3));
animation: die-tumble 0.55s cubic-bezier(0.22, 0.61, 0.36, 1) both;
}
.die-face rect {
fill: #fffef0;
stroke: #2a1a00;
stroke-width: 2;
transition: fill 0.18s, stroke 0.18s;
}
.die-face circle {
fill: #1a0a00;
transition: fill 0.18s;
}
.bar-die-slot {
display: flex;
align-items: center;
justify-content: center;
}
.die-face.die-double rect { stroke: var(--ui-gold); stroke-width: 2.5; }
.die-face.die-double {
filter: drop-shadow(0 0 6px rgba(200,164,72,0.7)) drop-shadow(0 2px 3px rgba(0,0,0,0.3));
}
.die-face.die-used { animation: none; opacity: 0.55; }
.die-face.die-used rect { fill: #d4d0c4; stroke: #9a8a70; }
.die-face.die-used circle { fill: #9a8a70; }
.die-face .die-question { fill: #1a0a00; font-family: sans-serif; }
.die-face.die-used .die-question { fill: #9a8a70; }
/* ── Jan panel ──────────────────────────────────────────────────────── */
.jan-panel {
display: flex;
flex-direction: column;
gap: 2px;
background: var(--ui-parchment);
border-radius: 5px;
padding: 0.4rem 0.9rem;
font-size: 0.88rem;
box-shadow: 0 1px 4px rgba(0,0,0,0.15);
min-width: 260px;
border-top: 2px solid rgba(138,106,40,0.35);
}
.jan-row {
display: flex;
align-items: center;
gap: 0.5rem;
padding: 2px 4px;
border-radius: 3px;
}
.jan-expandable { cursor: pointer; }
.jan-expandable:hover { background: rgba(0,0,0,0.05); }
.jan-positive { color: #1a5c1a; }
.jan-negative { color: #8b1a1a; }
.jan-label { flex: 1; }
.jan-tag {
font-size: 0.72rem;
padding: 0.1em 0.4em;
border-radius: 3px;
background: rgba(0,0,0,0.07);
color: #665544;
white-space: nowrap;
}
.jan-pts { font-weight: 600; text-align: right; min-width: 3rem; }
.jan-moves { padding: 1px 4px 4px 1rem; display: flex; flex-direction: column; gap: 2px; }
.jan-moves.hidden { display: none; }
.jan-move-line { font-family: monospace; font-size: 0.78rem; color: #555; }
/* ── Game-over overlay (§12) ────────────────────────────────────────── */
.game-over-overlay {
position: fixed;
inset: 0;
background: rgba(0,0,0,0.65);
display: flex;
align-items: center;
justify-content: center;
z-index: 100;
}
@keyframes game-over-appear {
from { transform: translateY(-24px) scale(0.94); opacity: 0; }
to { transform: translateY(0) scale(1); opacity: 1; }
}
.game-over-box {
background: var(--ui-parchment);
border-radius: 8px;
padding: 2.5rem 3rem;
text-align: center;
box-shadow: 0 12px 40px rgba(0,0,0,0.5), 0 0 0 2px var(--ui-gold-dark);
display: flex;
flex-direction: column;
gap: 1.1rem;
min-width: 300px;
animation: game-over-appear 0.4s cubic-bezier(0.22, 0.61, 0.36, 1);
}
.game-over-box h2 {
font-family: var(--font-display);
font-size: 2rem;
font-weight: 600;
color: var(--ui-ink);
letter-spacing: 0.06em;
}
.game-over-winner {
font-family: var(--font-display);
font-size: 1.25rem;
color: var(--ui-green-accent);
font-style: italic;
}
.game-over-score {
display: flex;
align-items: center;
justify-content: center;
gap: 0.75rem;
padding: 0.6rem 1rem;
background: rgba(0,0,0,0.05);
border-radius: 5px;
border: 1px solid rgba(138,106,40,0.2);
}
.game-over-score-name {
font-family: var(--font-display);
font-size: 0.9rem;
color: #665544;
font-style: italic;
max-width: 80px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.game-over-score-nums {
font-family: var(--font-display);
font-size: 2.25rem;
font-weight: 600;
color: var(--ui-ink);
letter-spacing: 0.08em;
line-height: 1;
}
.game-over-actions { display: flex; gap: 0.75rem; justify-content: center; }
/* ── Score-area: position:relative wrapper for merged panel + scoring ── */
.score-area {
position: relative;
width: 100%;
}
/* ── Scoring panels container — right of the hole counter ───────────── */
/* Stacked column, right-aligned, covering the free space in each row. */
/* overflow:visible lets tall panels float over the board below. */
.scoring-panels-container {
position: absolute;
top: 0;
bottom: 0;
right: 0;
display: flex;
flex-direction: column;
justify-content: space-around;
align-items: flex-end;
padding: 4px 8px;
z-index: 10;
pointer-events: none;
overflow: visible;
}
/* ── Scoring notification panel (§6b) ───────────────────────────────── */
@keyframes scoring-panel-enter {
from { opacity: 0; transform: translateX(10px); }
to { opacity: 1; transform: translateX(0); }
}
.scoring-panel-wrapper {
pointer-events: auto;
display: flex;
flex-direction: column;
align-items: center;
gap: 3px;
animation: scoring-panel-enter 0.3s ease-out;
}
/* "+" expand button: hidden while the panel is expanded */
.scoring-panel-wrapper:not(.scoring-minimized) .scoring-expand-btn {
display: none;
}
/* Full panel card: hidden once minimised */
.scoring-panel-wrapper.scoring-minimized .scoring-panel {
display: none;
}
/* "+" expand button ─────────────────────────────────────────────────── */
.scoring-expand-btn {
font-family: var(--font-display);
font-size: 0.9rem;
line-height: 1;
background: var(--ui-parchment);
border: 1.5px solid var(--ui-gold-dark);
border-radius: 3px;
padding: 2px 7px;
cursor: pointer;
color: var(--ui-ink);
opacity: 0.72;
box-shadow: 0 1px 3px rgba(0,0,0,0.18);
transition: opacity 0.15s;
}
.scoring-expand-btn:hover { opacity: 1; }
/* ── Panel head: scoring total + "" collapse link ──────────────────── */
.scoring-panel-head {
display: flex;
align-items: baseline;
gap: 0.5rem;
}
.scoring-collapse-btn {
font-size: 0.78rem;
line-height: 1;
background: none;
border: none;
cursor: pointer;
color: rgba(0,0,0,0.35);
padding: 0 1px;
margin-left: auto;
flex-shrink: 0;
transition: color 0.15s;
}
.scoring-collapse-btn:hover { color: rgba(0,0,0,0.65); }
/* ── Inner scoring card ─────────────────────────────────────────────── */
.scoring-panel {
background: var(--ui-parchment);
border-radius: 5px;
padding: 0.45rem 0.85rem;
font-size: 0.84rem;
box-shadow: 0 2px 8px rgba(0,0,0,0.22);
border-left: 3px solid var(--ui-green-accent);
display: flex;
flex-direction: column;
gap: 4px;
width: 320px;
}
.scoring-total {
font-family: var(--font-display);
font-weight: 600;
font-size: 1rem;
color: #1a5c1a;
white-space: nowrap;
}
.scoring-jan-row {
display: flex;
align-items: center;
gap: 0.4rem;
padding: 2px 3px;
border-radius: 3px;
cursor: default;
white-space: nowrap;
}
.scoring-jan-row:hover { background: rgba(0,0,0,0.05); }
.scoring-panel-opp { border-left-color: var(--board-rail); }
.scoring-panel-opp .scoring-total { color: var(--ui-red-accent); }
.scoring-hole {
display: flex;
align-items: center;
gap: 0.4rem;
font-weight: 600;
color: var(--ui-red-accent);
margin-top: 3px;
padding-top: 4px;
border-top: 1px solid rgba(0,0,0,0.1);
}
.hold-go-buttons { display: flex; gap: 0.5rem; margin-top: 4px; }
@media (min-width: 1492px) {
.side-panel {
right: auto;
left: calc(100% + 1rem);
}
}
/* ── Board wrapper ──────────────────────────────────────────────────── */
.board-wrapper {
display: flex;
flex-direction: column;
gap: 3px;
}
/* ── Zone labels (§2a) ──────────────────────────────────────────────── */
.zone-labels-row {
display: flex;
gap: 4px;
padding: 0 8px;
}
.zone-label {
font-family: var(--font-display);
font-size: 0.57rem;
font-style: italic;
color: rgba(240,228,192,0.48);
letter-spacing: 0.1em;
text-align: center;
pointer-events: none;
line-height: 1;
}
.zone-label-quarter { width: 370px; flex-shrink: 0; }
.zone-label-bar { width: 68px; flex-shrink: 0; }
/* ── Board ──────────────────────────────────────────────────────────── */
.board {
background: var(--board-felt);
border: 4px solid var(--board-rail);
border-radius: 6px;
padding: 4px;
display: flex;
flex-direction: column;
gap: 4px;
user-select: none;
box-shadow:
0 6px 16px rgba(0,0,0,0.5),
inset 0 1px 0 rgba(255,255,255,0.04);
position: relative;
}
.board-row { display: flex; gap: 4px; }
.board-quarter { display: flex; gap: 2px; }
.board-bar {
width: 68px;
background: var(--board-rail);
border-radius: 4px;
box-shadow: inset 0 0 6px rgba(0,0,0,0.5);
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
overflow: visible;
}
.board-center-bar {
height: 12px;
background: var(--board-rail);
border-radius: 2px;
box-shadow: inset 0 0 4px rgba(0,0,0,0.4);
}
/* ── Fields (§1) ────────────────────────────────────────────────────── */
.field {
--fc: var(--field-ivory);
width: 60px;
height: 180px;
background: transparent;
isolation: isolate;
border-radius: 3px;
display: flex;
flex-direction: column;
align-items: center;
justify-content: flex-end;
padding: 4px 2px;
position: relative;
}
.field::before {
content: '';
position: absolute;
inset: 0;
z-index: -1;
background: var(--fc);
clip-path: polygon(0% 100%, 50% 0%, 100% 100%);
transition: background 0.12s;
}
.top-row .field::before {
clip-path: polygon(0% 0%, 100% 0%, 50% 100%);
}
.top-row .field { justify-content: flex-start; }
/* ── Zone alternating colours ────────────────────────────────── */
.board-quarter .field.zone-petit:nth-child(odd),
.board-quarter .field.zone-grand:nth-child(odd) { --fc: var(--field-burgundy); }
.board-quarter .field.zone-petit:nth-child(even),
.board-quarter .field.zone-grand:nth-child(even) { --fc: var(--field-ivory); }
.board-quarter .field.zone-opponent:nth-child(odd),
.board-quarter .field.zone-retour:nth-child(odd) { --fc: var(--field-burgundy); }
.board-quarter .field.zone-opponent:nth-child(even),
.board-quarter .field.zone-retour:nth-child(even) { --fc: var(--field-ivory); }
/* ── Point indicator: first N fields reflect each player's score & bredouille */
.board-quarter .field.zone-petit.point-bredouille:nth-child(odd),
.board-quarter .field.zone-grand.point-bredouille:nth-child(odd) { --fc: var(--field-blue-light); }
.board-quarter .field.zone-petit.point-bredouille:nth-child(even),
.board-quarter .field.zone-grand.point-bredouille:nth-child(even) { --fc: var(--field-blue); }
.board-quarter .field.zone-petit.point-no-bredouille:nth-child(odd),
.board-quarter .field.zone-grand.point-no-bredouille:nth-child(odd) { --fc: var(--field-blue-light); }
.board-quarter .field.zone-petit.point-no-bredouille:nth-child(even),
.board-quarter .field.zone-grand.point-no-bredouille:nth-child(even) { --fc: var(--field-blue); }
.board-quarter .field.zone-opponent.point-bredouille:nth-child(odd),
.board-quarter .field.zone-retour.point-bredouille:nth-child(odd) { --fc: var(--field-blue-light); }
.board-quarter .field.zone-opponent.point-bredouille:nth-child(even),
.board-quarter .field.zone-retour.point-bredouille:nth-child(even) { --fc: var(--field-blue); }
.board-quarter .field.zone-opponent.point-no-bredouille:nth-child(odd),
.board-quarter .field.zone-retour.point-no-bredouille:nth-child(odd) { --fc: var(--field-blue-light); }
.board-quarter .field.zone-opponent.point-no-bredouille:nth-child(even),
.board-quarter .field.zone-retour.point-no-bredouille:nth-child(even) { --fc: var(--field-blue); }
.field.corner::after {
content: '♛';
position: absolute;
z-index: -1;
bottom: 22px;
font-size: 0.7rem;
color: rgba(255,248,210,0.38);
pointer-events: none;
line-height: 1;
}
.top-row .field.corner::after { bottom: auto; top: 22px; }
@keyframes corner-pulse {
0%, 100% { filter: drop-shadow(0 0 0px rgba(200,164,72,0)); }
50% { filter: drop-shadow(0 0 7px rgba(200,164,72,0.55)); }
}
.field.corner.corner-available {
animation: corner-pulse 1.5s ease-in-out infinite;
}
@keyframes exit-glow {
0%, 100% { filter: drop-shadow(0 0 0px rgba(232,192,96,0)); }
50% { filter: drop-shadow(0 0 5px rgba(232,192,96,0.5)); }
}
.field.exit-eligible {
animation: exit-glow 2s ease-in-out infinite;
}
/* ── Exit sign (§8c) — circle+arrow outside the board ──────────────── */
.exit-btn {
pointer-events: none;
opacity: 0.3;
transition: opacity 0.2s, transform 0.15s;
}
.exit-btn.exit-active {
pointer-events: auto;
cursor: pointer;
opacity: 1;
animation: exit-btn-pulse 1.4s ease-in-out infinite;
}
.exit-btn.exit-active:hover {
transform: scale(1.1);
}
@keyframes exit-btn-pulse {
0%, 100% { filter: drop-shadow(0 0 3px rgba(200,160,20,0.3)); }
50% { filter: drop-shadow(0 0 9px rgba(200,160,20,0.85)); }
}
.field.jan-hovered {
--fc: rgba(190, 140, 35, 0.8) !important;
}
@keyframes hit-ripple {
from { transform: translate(-50%, -50%) scale(0.4); opacity: 0.9; }
to { transform: translate(-50%, -50%) scale(2.2); opacity: 0; }
}
.hit-ripple {
position: absolute;
left: 50%;
width: 36px;
height: 36px;
border-radius: 50%;
border: 2px solid rgba(200, 164, 72, 0.9);
pointer-events: none;
animation: hit-ripple 0.5s ease-out forwards;
}
.hit-ripple-top { top: 26px; }
.hit-ripple-bot { bottom: 26px; }
.field.clickable {
cursor: pointer;
}
.field.clickable:hover {
--fc: rgba(200,170,50,0.18) !important;
}
.field.selected {
/* natural triangle color; tab is the indicator */
}
/* ── Tab indicators: small markers at the field's wide base ──────── */
/* Bot-row: tabs hang below; top-row: tabs hang above. */
/* The tab sits at ≈ -6px which lands on the board's wooden rail. */
.field.clickable::after,
.field.selected::after {
content: '';
position: absolute;
left: 50%;
transform: translateX(-50%);
width: 22px;
height: 8px;
pointer-events: none;
z-index: 2;
}
.bot-row .field.clickable::after,
.bot-row .field.selected::after {
bottom: -6px;
top: auto;
border-radius: 0 0 10px 10px;
}
.top-row .field.clickable::after,
.top-row .field.selected::after {
top: -6px;
bottom: auto;
border-radius: 10px 10px 0 0;
}
/* Possible origin: hollow gold outline */
.field.clickable:not(.dest):not(.selected)::after {
background: rgba(210,170,30,0.15);
border: 1.5px solid rgba(210,170,30,0.75);
box-shadow: 0 0 4px rgba(210,170,30,0.3);
}
/* Selected origin: filled amber, breathing glow */
.field.selected::after {
background: linear-gradient(to bottom, #e8b020, #c07808);
border: 1px solid rgba(255,225,65,0.55);
animation: tab-pulse 1.2s ease-in-out infinite;
}
@keyframes tab-pulse {
0%, 100% { box-shadow: 0 0 5px rgba(220,155,15,0.55), 0 0 2px rgba(255,220,50,0.3); }
50% { box-shadow: 0 0 13px rgba(240,178,22,0.88), 0 0 6px rgba(255,230,60,0.6); }
}
/* Valid destination: soft ivory/pearl */
.field.clickable.dest:not(.selected)::after {
background: rgba(240,230,205,0.88);
border: 1.5px solid rgba(190,165,105,0.65);
box-shadow: 0 0 3px rgba(190,165,105,0.2);
}
.field.clickable.dest:not(.selected):hover::after {
background: rgba(228,210,162,0.95);
border-color: rgba(210,175,40,0.72);
box-shadow: 0 0 7px rgba(210,175,40,0.42);
}
.field-num {
font-size: 0.58rem;
color: rgba(0,0,0,0.28);
position: absolute;
bottom: 3px;
line-height: 1;
font-variant-numeric: tabular-nums;
}
.board-quarter .field.zone-petit:nth-child(odd) .field-num,
.board-quarter .field.zone-grand:nth-child(odd) .field-num,
.board-quarter .field.zone-retour:nth-child(odd) .field-num,
.board-quarter .field.zone-opponent:nth-child(odd) .field-num {
color: rgba(240,215,190,0.38);
}
.field.corner .field-num { color: rgba(255,248,200,0.4); }
.top-row .field-num { bottom: auto; top: 3px; }
/* ── Checkers ───────────────────────────────────────────────────────── */
.checker-stack {
display: flex;
flex-direction: column;
align-items: center;
}
.checker {
width: 40px;
height: 40px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-size: 0.78rem;
font-weight: 600;
flex-shrink: 0;
}
.checker + .checker { margin-top: -4px; }
.checker.white {
background-image:
radial-gradient(ellipse 50% 35% at 36% 30%,
rgba(255,255,255,0.65) 0%, transparent 100%),
radial-gradient(circle,
transparent 68%, rgba(160,130,70,0.22) 68.5%,
rgba(160,130,70,0.22) 71.5%, transparent 72%),
radial-gradient(circle,
transparent 43%, rgba(160,130,70,0.17) 43.5%,
rgba(160,130,70,0.17) 46.5%, transparent 47%),
radial-gradient(circle at 38% 32%,
#ffffff 0%, var(--checker-white) 52%, #c0b288 100%);
border: 1.8px solid var(--checker-ring);
box-shadow:
0 2px 6px rgba(0,0,0,0.4),
inset 0 -1px 3px rgba(0,0,0,0.15);
color: #443322;
}
.checker.black {
background-image:
radial-gradient(ellipse 40% 28% at 36% 30%,
rgba(110,65,30,0.38) 0%, transparent 100%),
radial-gradient(circle,
transparent 68%, rgba(200,164,72,0.18) 68.5%,
rgba(200,164,72,0.18) 71.5%, transparent 72%),
radial-gradient(circle,
transparent 43%, rgba(200,164,72,0.13) 43.5%,
rgba(200,164,72,0.13) 46.5%, transparent 47%),
radial-gradient(circle at 38% 32%,
#4a2e1a 0%, #1c1008 45%, var(--checker-black) 100%);
border: 1.8px solid var(--checker-ring);
box-shadow:
0 2px 6px rgba(0,0,0,0.55),
inset 0 -1px 3px rgba(0,0,0,0.4);
color: #c8b898;
}
/* ── Hole toast (§6a) ───────────────────────────────────────────────── */
@keyframes toast-rise {
from { transform: translate(-50%, -40%); opacity: 0; }
to { transform: translate(-50%, -50%); opacity: 1; }
}
@keyframes toast-fade {
from { opacity: 1; }
to { opacity: 0; pointer-events: none; }
}
.hole-toast {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background: rgba(22,10,2,0.93);
border: 2px solid var(--ui-gold);
border-radius: 8px;
padding: 1.5rem 3.5rem;
text-align: center;
z-index: 50;
pointer-events: none;
box-shadow:
0 12px 40px rgba(0,0,0,0.65),
0 0 0 1px rgba(200,164,72,0.25),
inset 0 1px 0 rgba(200,164,72,0.1);
animation:
toast-rise 0.25s cubic-bezier(0.22, 0.61, 0.36, 1),
toast-fade 0.5s ease-in 1.4s forwards;
}
.hole-toast-title {
font-family: var(--font-display);
font-size: 3.25rem;
font-weight: 600;
color: var(--ui-gold);
letter-spacing: 0.1em;
line-height: 1;
}
.hole-toast-count {
font-family: var(--font-display);
font-size: 1.1rem;
color: rgba(200,164,72,0.68);
margin-top: 0.35rem;
letter-spacing: 0.06em;
}
.hole-toast-bredouille {
font-family: var(--font-ui);
font-size: 0.75rem;
letter-spacing: 0.08em;
color: rgba(200,164,72,0.55);
margin-top: 0.4rem;
text-transform: uppercase;
}
@keyframes bredouille-shimmer {
0%, 100% { box-shadow: 0 12px 40px rgba(0,0,0,0.65), 0 0 0 2px rgba(200,164,72,0.4), inset 0 0 0 rgba(200,164,72,0); }
50% { box-shadow: 0 12px 40px rgba(0,0,0,0.65), 0 0 0 4px rgba(200,164,72,0.7), inset 0 0 24px rgba(200,164,72,0.08); }
}
.hole-toast.hole-toast-bredouille {
border-width: 2.5px;
border-color: var(--ui-gold);
padding: 2rem 4rem;
animation:
toast-rise 0.3s cubic-bezier(0.22, 0.61, 0.36, 1),
bredouille-shimmer 0.9s ease-in-out 0.3s 2,
toast-fade 0.5s ease-in 2.2s forwards;
}
.hole-toast.hole-toast-bredouille .hole-toast-title { font-size: 3.75rem; }
.hole-toast.hole-toast-bredouille .hole-toast-bredouille {
font-size: 0.85rem;
color: rgba(200,164,72,0.8);
letter-spacing: 0.14em;
}
/* ── Checker slide animation (§4a) ─────────────────────────────────── */
@keyframes checker-slide-in {
from { transform: translate(var(--slide-dx, 0px), var(--slide-dy, 0px)); }
to { transform: none; }
}
.checker.arriving {
animation: checker-slide-in 0.28s cubic-bezier(0.25, 0.46, 0.45, 0.94);
}
.field:has(.checker.arriving) {
isolation: auto;
z-index: 10;
position: relative;
}
/* ── Checker lift on selected field (§4b) ───────────────────────────── */
.field.selected .checker-stack {
transform: translateY(-5px);
filter: drop-shadow(0 8px 12px rgba(0,0,0,0.6));
transition: transform 0.12s ease-out, filter 0.12s ease-out;
}
/* ── Action buttons below board (§10c) ──────────────────────────────── */
.board-actions {
display: flex;
gap: 0.55rem;
justify-content: center;
align-items: center;
flex-wrap: wrap;
min-height: 2rem;
}
/* ── Free-play mode ─────────────────────────────────────────────────────── */
.free-mode-toggle {
display: flex;
align-items: center;
gap: 0.4rem;
font-family: var(--font-ui);
font-size: 0.78rem;
color: #887766;
cursor: pointer;
user-select: none;
padding-top: 0.1rem;
}
.free-mode-toggle input[type="checkbox"] {
accent-color: var(--ui-gold);
cursor: pointer;
width: 0.85rem;
height: 0.85rem;
}
.free-mode-help {
display: inline-flex;
align-items: center;
justify-content: center;
width: 1rem;
height: 1rem;
border-radius: 50%;
border: 1px solid #a89880;
font-size: 0.65rem;
font-style: normal;
color: #a89880;
cursor: help;
flex-shrink: 0;
}
.free-mode-error {
text-align: center;
gap: 0.75rem;
background: rgba(180, 60, 30, 0.12);
border: 1px solid rgba(180, 60, 30, 0.4);
border-radius: 4px;
padding: 0.4rem 0.75rem;
width: 100%;
box-sizing: border-box;
}
.free-mode-error-msg {
font-family: var(--font-ui);
font-size: 0.85rem;
color: #8b2000;
font-style: italic;
}
/* ── Pre-game ceremony overlay ──────────────────────────────────────────── */
.ceremony-overlay {
position: fixed;
inset: 0;
background: rgba(0,0,0,0.65);
display: flex;
align-items: center;
justify-content: center;
z-index: 100;
}
.ceremony-box {
background: var(--ui-parchment);
border-radius: 8px;
padding: 2.5rem 3rem;
text-align: center;
box-shadow: 0 12px 40px rgba(0,0,0,0.5), 0 0 0 2px var(--ui-gold-dark);
display: flex;
flex-direction: column;
align-items: center;
gap: 1.4rem;
min-width: 300px;
animation: game-over-appear 0.4s cubic-bezier(0.22, 0.61, 0.36, 1);
}
.ceremony-box h2 {
font-family: var(--font-display);
font-size: 1.8rem;
font-weight: 600;
color: var(--ui-ink);
letter-spacing: 0.06em;
}
.ceremony-dice {
display: flex;
gap: 3rem;
align-items: flex-end;
}
.ceremony-die-slot {
display: flex;
flex-direction: column;
align-items: center;
gap: 0.5rem;
}
.ceremony-die-label {
font-family: var(--font-ui);
font-size: 0.85rem;
color: var(--ui-ink);
font-weight: 500;
}
.ceremony-tie {
font-family: var(--font-display);
font-size: 1rem;
color: var(--ui-red-accent);
font-style: italic;
}
.ceremony-result {
font-family: var(--font-display);
font-size: 1.15rem;
font-weight: 600;
color: var(--ui-gold-dark);
letter-spacing: 0.04em;
}
/* ── Nickname modal (anonymous player name chooser) ─────────────────── */
.nickname-backdrop {
position: fixed;
inset: 0;
background: rgba(0,0,0,0.6);
display: flex;
align-items: center;
justify-content: center;
z-index: 300;
}
.nickname-modal {
background: var(--ui-parchment);
border-radius: 8px;
padding: 2rem 2rem 1.75rem;
width: min(360px, 90vw);
display: flex;
flex-direction: column;
gap: 1rem;
box-shadow:
0 20px 60px rgba(0,0,0,0.55),
0 0 0 1px rgba(200,164,72,0.35),
0 0 0 5px rgba(42,21,8,0.9),
0 0 0 6px rgba(200,164,72,0.2);
animation: game-over-appear 0.25s cubic-bezier(0.22, 0.61, 0.36, 1);
}
.nickname-modal-title {
font-family: var(--font-display);
font-size: 1.5rem;
font-weight: 600;
color: var(--ui-ink);
text-align: center;
letter-spacing: 0.04em;
}
.nickname-modal-hint {
font-family: var(--font-ui);
font-size: 0.8rem;
color: rgba(42,26,8,0.6);
text-align: center;
margin-bottom: -0.25rem;
}
.nickname-modal-alt {
text-align: center;
font-size: 0.8rem;
color: rgba(42,26,8,0.55);
padding-top: 0.5rem;
border-top: 1px solid rgba(138,106,40,0.2);
}
.nickname-modal-alt a {
color: var(--ui-gold-dark);
text-decoration: none;
font-weight: 500;
}
.nickname-modal-alt a:hover { text-decoration: underline; }
/* ── Game hamburger button (☰ → ✕ animation) ────────────────────────── */
.game-hamburger {
position: fixed;
top: 0.6rem;
left: 0.6rem;
z-index: 251;
width: 36px;
height: 36px;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 5px;
background: var(--board-rail);
border: 1px solid rgba(200,164,72,0.35);
border-radius: 5px;
cursor: pointer;
transition: background 0.15s, border-color 0.15s;
}
.game-hamburger:hover {
background: #3d1f0a;
border-color: rgba(200,164,72,0.65);
}
.hb-bar {
display: block;
width: 16px;
height: 2px;
background: var(--ui-parchment);
border-radius: 1px;
transition: transform 0.25s cubic-bezier(0.22, 0.61, 0.36, 1), opacity 0.2s;
transform-origin: center;
}
/* Top bar rotates down to form \ */
.game-hamburger-open .hb-top { transform: translateY(7px) rotate(45deg); }
/* Middle bar fades out */
.game-hamburger-open .hb-mid { opacity: 0; transform: scaleX(0); }
/* Bottom bar rotates up to form / */
.game-hamburger-open .hb-bot { transform: translateY(-7px) rotate(-45deg); }
/* ── Game sidebar ────────────────────────────────────────────────────── */
.game-sidebar {
position: fixed;
top: 0;
left: 0;
height: 100vh;
width: 280px;
z-index: 250;
background: var(--board-rail);
border-right: 1px solid rgba(200,164,72,0.25);
display: flex;
flex-direction: column;
transform: translateX(-100%);
transition: transform 0.25s cubic-bezier(0.22, 0.61, 0.36, 1);
overflow-y: auto;
}
.game-sidebar-open {
transform: translateX(0);
}
.game-sidebar-header {
display: flex;
align-items: center;
justify-content: space-between;
padding: 1rem 1rem;
border-bottom: 1px solid rgba(200,164,72,0.2);
flex-shrink: 0;
}
.game-sidebar-brand {
font-family: var(--font-display);
font-size: 1.3rem;
font-weight: 600;
color: var(--ui-gold);
letter-spacing: 0.06em;
margin-left: 45px;
}
.game-sidebar-close {
width: 28px;
height: 28px;
display: flex;
align-items: center;
justify-content: center;
background: transparent;
border: 1px solid rgba(200,164,72,0.25);
border-radius: 4px;
color: var(--ui-parchment);
font-size: 0.85rem;
cursor: pointer;
opacity: 0.65;
transition: opacity 0.15s;
}
.game-sidebar-close:hover { opacity: 1; }
.game-sidebar-section {
padding: 0.9rem 1rem;
border-bottom: 1px solid rgba(200,164,72,0.12);
display: flex;
flex-direction: row;
gap: 0.55rem;
}
.game-sidebar-label {
font-size: 0.7rem;
font-family: var(--font-ui);
letter-spacing: 0.07em;
text-transform: uppercase;
color: rgba(242,232,208,0.45);
}
.game-sidebar-link {
font-family: var(--font-ui);
font-size: 0.85rem;
color: var(--ui-parchment);
text-decoration: none;
opacity: 0.8;
transition: opacity 0.15s;
cursor: pointer;
}
.game-sidebar-link:hover { opacity: 1; text-decoration: underline; text-underline-offset: 2px; }
.game-sidebar-btn {
font-family: var(--font-ui);
font-size: 0.82rem;
padding: 0.4rem 0.75rem;
border: 1px solid rgba(200,164,72,0.35);
border-radius: 4px;
background: rgba(200,164,72,0.1);
color: var(--ui-parchment);
cursor: pointer;
text-align: left;
transition: background 0.15s;
}
.game-sidebar-btn:hover { background: rgba(200,164,72,0.22); }
.game-sidebar-btn-newgame {
background: rgba(58,107,42,0.25);
border-color: rgba(58,107,42,0.55);
font-weight: 500;
}
.game-sidebar-btn-newgame:hover { background: rgba(58,107,42,0.42); }
.game-sidebar-qr {
width: 100%;
height: auto;
aspect-ratio: 1;
max-width: 200px;
margin: 0 auto;
}
/* Push the version wrapper to the bottom of the sidebar flex column */
.sidebar-footer {
margin-top: auto;
border-top: 1px solid rgba(200,164,72,0.12);
}
.site-nav-infolinks {
margin: 2em 0 1em;
text-align: center;
font-size: 0.9rem;
color: rgba(200,164,72,0.4);
display: flex;
flex-direction: row;
align-items: center;
}
.site-nav-infolinks > a {
width: 100%;
}
.site-nav-version {
margin: 2em 0 1em;
display: block;
text-align: center;
font-family: var(--font-ui);
font-size: 0.7rem;
letter-spacing: 0.06em;
color: rgba(200,164,72,0.4);
}
/* ── Content pages (markdown-rendered) ─────────────────────────────────────── */
.content-page h1 {
font-family: var(--font-display);
font-size: 2rem;
font-weight: 600;
color: var(--ui-ink);
letter-spacing: 0.04em;
margin-bottom: 0.5rem;
}
.content-page h2 {
font-family: var(--font-display);
font-size: 1.4rem;
font-weight: 600;
color: var(--ui-ink);
margin: 1.75rem 0 0.5rem;
border-bottom: 1px solid rgba(200,164,72,0.25);
padding-bottom: 0.25rem;
}
.content-page h3 {
font-family: var(--font-display);
font-size: 1.1rem;
font-weight: 600;
color: var(--ui-ink);
margin: 1.25rem 0 0.4rem;
}
.content-page p {
line-height: 1.7;
margin-bottom: 0.9rem;
color: var(--ui-ink);
}
.content-page ul,
.content-page ol {
margin: 0.5rem 0 1rem 1.5rem;
line-height: 1.7;
color: var(--ui-ink);
}
.content-page li {
margin-bottom: 0.25rem;
}
.content-page a {
color: var(--ui-gold-dark);
text-decoration: underline;
}
.content-page a:hover {
color: var(--ui-ink);
}
.content-page code {
font-family: monospace;
background: rgba(0,0,0,0.07);
border-radius: 3px;
padding: 0.1em 0.35em;
font-size: 0.88em;
}
.content-page pre {
background: rgba(0,0,0,0.07);
border-radius: 5px;
padding: 1rem 1.25rem;
overflow-x: auto;
margin-bottom: 1rem;
}
.content-page pre code {
background: none;
padding: 0;
}
.content-page blockquote {
border-left: 3px solid rgba(200,164,72,0.5);
margin: 0.75rem 0;
padding: 0.25rem 1rem;
color: #665544;
font-style: italic;
}
.content-page table {
border-collapse: collapse;
width: 100%;
margin-bottom: 1rem;
}
.content-page th,
.content-page td {
border: 1px solid rgba(200,164,72,0.3);
padding: 0.4rem 0.75rem;
text-align: left;
}
.content-page th {
background: rgba(200,164,72,0.1);
font-weight: 600;
}
/* Prevent horizontal scrollbar from the full-bleed strip */
.game-overlay { overflow-x: hidden !important; }
/* Board bar: hide die slots, keep the rail as a thin divider */
.bar-die-slot { display: none !important; }
.board-bar { width: 5px; overflow: hidden; }
/* ── Full-width in-flow player strip ─────────────────────────────────── */
.players-strip {
width: 100vw;
margin-top: -1.5rem; /* undo game-overlay top padding */
display: flex;
align-items: center;
background: var(--ui-parchment);
border-bottom: 2px solid var(--ui-gold-dark);
box-shadow: 0 2px 8px rgba(0,0,0,0.18);
padding: 0.35rem 1.5rem;
gap: 0.5rem;
}
.strip-player { display: flex; align-items: center; flex: 1; min-width: 0; }
.strip-player-left { justify-content: flex-end; }
.strip-player-right { justify-content: flex-start; }
.strip-active-zone {
display: flex;
align-items: center;
gap: 0.7rem;
border-radius: 8px;
padding: 0.28rem 0.5rem;
transition: background 0.15s;
}
.strip-active-zone.active { background: rgba(58,42,10,0.08); }
/* Checker-style circles */
.strip-avatar {
width: 38px; height: 38px;
border-radius: 50%;
flex-shrink: 0;
}
.strip-avatar-me {
background-image:
radial-gradient(ellipse 50% 35% at 36% 30%, rgba(255,255,255,0.65) 0%, transparent 100%),
radial-gradient(circle, transparent 68%, rgba(160,130,70,0.22) 68.5%, rgba(160,130,70,0.22) 71.5%, transparent 72%),
radial-gradient(circle, transparent 43%, rgba(160,130,70,0.17) 43.5%, rgba(160,130,70,0.17) 46.5%, transparent 47%),
radial-gradient(circle at 38% 32%, #ffffff 0%, var(--checker-white) 52%, #c0b288 100%);
border: 1.8px solid var(--checker-ring);
box-shadow: 0 2px 6px rgba(0,0,0,0.35), inset 0 -1px 3px rgba(0,0,0,0.15);
}
.strip-avatar-opp {
background-image:
radial-gradient(ellipse 40% 28% at 36% 30%, rgba(110,65,30,0.38) 0%, transparent 100%),
radial-gradient(circle, transparent 68%, rgba(200,164,72,0.18) 68.5%, rgba(200,164,72,0.18) 71.5%, transparent 72%),
radial-gradient(circle, transparent 43%, rgba(200,164,72,0.13) 43.5%, rgba(200,164,72,0.13) 46.5%, transparent 47%),
radial-gradient(circle at 38% 32%, #4a2e1a 0%, #1c1008 45%, var(--checker-black) 100%);
border: 1.8px solid var(--checker-ring);
box-shadow: 0 2px 6px rgba(0,0,0,0.5), inset 0 -1px 3px rgba(0,0,0,0.4);
}
/* Strip peg overrides */
.players-strip .peg-track { gap: 3px; }
.players-strip .peg-hole { width: 12px; height: 12px; }
.players-strip .peg-hole.filled {
background: #5aab38; border-color: #3a7828;
box-shadow: 0 0 5px rgba(90,171,56,0.55);
}
.players-strip .peg-hole.peg-opp.filled {
background: #c05030; border-color: #8a3018;
box-shadow: 0 0 5px rgba(192,80,48,0.55);
}
/* Strip score-row-name: remove fixed width from v01 */
.players-strip .score-row-name { width: auto; }
/* No ghost bar below pts-counter in the strip */
.players-strip .pts-counter-wrap { padding-bottom: 0; }
/* Center "Trictrac" title */
.players-strip-center {
flex-shrink: 0;
padding: 0 1rem;
border-left: 1px solid rgba(138,106,40,0.2);
border-right: 1px solid rgba(138,106,40,0.2);
}
.strip-title {
font-family: var(--font-display);
font-size: 1.4rem;
font-weight: 600;
font-style: italic;
color: var(--ui-ink);
letter-spacing: 0.03em;
white-space: nowrap;
}
/* ── Body: board + controls ──────────────────────────────────────────── */
.main-body {
display: flex;
align-items: flex-start;
gap: 0.5rem;
}
/* ── Controls column (sidebar on wide, row on narrow) ────────────────── */
.controls {
display: flex;
flex-direction: column;
gap: 0.5rem;
align-self: stretch;
}
@media (min-width: 920px) {
.controls {
width: 200px;
}
}
.ctrl-dice {
background: var(--board-rail);
border-radius: 5px;
border-top: 2px solid var(--ui-gold-dark);
box-shadow: 0 2px 6px rgba(0,0,0,0.2);
padding: 0.6rem 0.75rem 0.75rem;
display: flex;
flex-direction: column;
align-items: center;
gap: 0.5rem;
flex-shrink: 0;
}
.ctrl-dice-row {
display: flex;
gap: 0.55rem;
align-items: center;
justify-content: center;
}
/* Free-mode toggle: light text on dark board-rail background */
.ctrl-dice .free-mode-toggle {
color: var(--ui-parchment);
font-size: 0.7rem;
flex-wrap: wrap;
justify-content: center;
text-align: center;
gap: 0.3rem;
}
.ctrl-dice .free-mode-help {
border-color: rgba(242,232,208,0.35);
color: rgba(242,232,208,0.5);
}
.ctrl-status {
background: var(--ui-parchment);
border-radius: 5px;
border-top: 2px solid var(--ui-gold-dark);
box-shadow: 0 2px 6px rgba(0,0,0,0.2);
padding: 0.65rem 0.75rem 0.75rem;
display: flex;
flex-direction: column;
justify-content: space-around;
align-items: center;
gap: 0.4rem;
flex: 1;
min-width: 0;
}
.ctrl-status .game-status {
color: var(--ui-ink);
text-shadow: none;
font-size: 1rem;
padding: 0;
width: auto;
text-align: center;
line-height: 1.3;
}
.ctrl-status .board-actions {
flex-wrap: wrap;
justify-content: center;
min-height: 0;
}
.ctrl-status .game-sub-prompt {
color: #887766;
padding: 0;
width: auto;
text-align: center;
font-size: 0.67rem;
line-height: 1.4;
margin: 0;
}
.scoring-row .scoring-panels-container {
position: static;
top: auto; left: auto; right: auto; bottom: auto;
z-index: auto;
padding: 0;
pointer-events: auto;
display: flex;
flex-direction: column;
align-items: stretch;
gap: 4px;
}
.scoring-row .scoring-panel {
box-sizing: border-box;
margin: 0;
}
/* ── Responsive: ≤919px → controls becomes a bottom bar ─────────────── */
@media (max-width: 919px) {
.main-body {
flex-direction: column;
align-items: stretch;
}
.controls {
flex-direction: row;
width: 100%;
}
.ctrl-status { flex: 1; }
/* Hide pegs on small screens to save space in the strip */
.players-strip .peg-track { display: none; }
}