258 lines
8.7 KiB
CSS
258 lines
8.7 KiB
CSS
/* =========================================================
|
|
🔧 Controls (tweak these)
|
|
========================================================= */
|
|
:root {
|
|
--sudoku-size-multiplier: 3;
|
|
--cell-size: calc(32px * var(--sudoku-size-multiplier));
|
|
--cell-font-size: calc(16px * var(--sudoku-size-multiplier));
|
|
--grid-gap: calc(2px * var(--sudoku-size-multiplier));
|
|
--box-separator: calc(3px * var(--sudoku-size-multiplier));
|
|
}
|
|
|
|
/* =========================================================
|
|
Container & Grid Base
|
|
========================================================= */
|
|
#sudoku_container {
|
|
position: relative;
|
|
margin: 1em auto;
|
|
width: fit-content;
|
|
}
|
|
|
|
#sudoku {
|
|
position: relative;
|
|
background-color: var(--card, #1e2030);
|
|
border-radius: 0.5rem;
|
|
box-shadow: 0 0 10px rgba(27, 29, 43, 0.6), inset 0 0 6px rgba(130, 170, 255, 0.05);
|
|
padding: 0.5rem;
|
|
width: fit-content;
|
|
}
|
|
|
|
/* =========================================================
|
|
Grid Layout
|
|
========================================================= */
|
|
#sudoku .sudoku-grid {
|
|
display: grid;
|
|
grid-template-columns:
|
|
var(--cell-size) var(--cell-size) var(--cell-size)
|
|
var(--cell-size) var(--cell-size) var(--cell-size)
|
|
var(--cell-size) var(--cell-size) var(--cell-size);
|
|
grid-template-rows:
|
|
var(--cell-size) var(--cell-size) var(--cell-size)
|
|
var(--cell-size) var(--cell-size) var(--cell-size)
|
|
var(--cell-size) var(--cell-size) var(--cell-size);
|
|
column-gap: var(--grid-gap);
|
|
row-gap: var(--grid-gap);
|
|
user-select: none;
|
|
}
|
|
|
|
/* =========================================================
|
|
Cell Base Styles
|
|
========================================================= */
|
|
#sudoku .sudoku-cell {
|
|
width: var(--cell-size);
|
|
height: var(--cell-size);
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
border-radius: 4px;
|
|
font-family: "Fira Code", monospace;
|
|
font-size: var(--cell-font-size);
|
|
background: var(--muted, #2f334d);
|
|
color: var(--foreground, #c8d3f5);
|
|
transition: all 0.15s ease;
|
|
box-shadow: inset 0 0 3px rgba(27, 29, 43, 0.4);
|
|
}
|
|
|
|
/* =========================================================
|
|
3x3 Box Separators
|
|
========================================================= */
|
|
/* Right borders (end of each 3x3 box horizontally) */
|
|
#sudoku .sudoku-cell[data-c="2"],
|
|
#sudoku .sudoku-cell[data-c="5"],
|
|
#sudoku .sudoku-cell[data-c="8"] {
|
|
border-right: 2px solid color-mix(in srgb, var(--primary, #82aaff) 30%, transparent);
|
|
}
|
|
|
|
/* Left borders (start of each 3x3 box horizontally) */
|
|
#sudoku .sudoku-cell[data-c="0"],
|
|
#sudoku .sudoku-cell[data-c="3"],
|
|
#sudoku .sudoku-cell[data-c="6"] {
|
|
border-left: 2px solid color-mix(in srgb, var(--primary, #82aaff) 30%, transparent);
|
|
}
|
|
|
|
/* Bottom borders (end of each 3x3 box vertically) */
|
|
#sudoku .sudoku-cell[data-r="2"],
|
|
#sudoku .sudoku-cell[data-r="5"],
|
|
#sudoku .sudoku-cell[data-r="8"] {
|
|
border-bottom: 2px solid color-mix(in srgb, var(--primary, #82aaff) 30%, transparent);
|
|
}
|
|
|
|
/* Top borders (start of each 3x3 box vertically) */
|
|
#sudoku .sudoku-cell[data-r="0"],
|
|
#sudoku .sudoku-cell[data-r="3"],
|
|
#sudoku .sudoku-cell[data-r="6"] {
|
|
border-top: 2px solid color-mix(in srgb, var(--primary, #82aaff) 30%, transparent);
|
|
}
|
|
|
|
/* =========================================================
|
|
User-Entered Cells
|
|
========================================================= */
|
|
#sudoku .sudoku-cell.user-entered {
|
|
color: var(--primary, #82aaff);
|
|
font-weight: 600;
|
|
}
|
|
|
|
/* =========================================================
|
|
Active Cell Highlight (Navigation Mode)
|
|
========================================================= */
|
|
#sudoku .sudoku-cell.active {
|
|
outline: 2px solid var(--primary, #82aaff);
|
|
outline-offset: -2px;
|
|
background: color-mix(in srgb, var(--primary, #82aaff) 20%, var(--muted, #2f334d));
|
|
box-shadow:
|
|
0 0 8px color-mix(in srgb, var(--primary, #82aaff) 40%, transparent),
|
|
0 0 12px color-mix(in srgb, var(--primary, #82aaff) 20%, transparent),
|
|
inset 0 0 6px color-mix(in srgb, var(--primary, #82aaff) 15%, transparent);
|
|
}
|
|
|
|
/* =========================================================
|
|
Editing Cell Highlight (Edit Mode)
|
|
========================================================= */
|
|
#sudoku .sudoku-cell.editing {
|
|
outline: 2px solid var(--accent, #ffc777);
|
|
outline-offset: -2px;
|
|
background: color-mix(in srgb, var(--accent, #ffc777) 15%, var(--muted, #2f334d));
|
|
box-shadow:
|
|
0 0 16px color-mix(in srgb, var(--accent, #ffc777) 70%, transparent),
|
|
0 0 24px color-mix(in srgb, var(--accent, #ffc777) 40%, transparent),
|
|
inset 0 0 12px color-mix(in srgb, var(--accent, #ffc777) 30%, transparent);
|
|
animation: editing-cell-glow 1.5s ease-in-out infinite;
|
|
}
|
|
|
|
@keyframes editing-cell-glow {
|
|
0%, 100% {
|
|
box-shadow:
|
|
0 0 16px color-mix(in srgb, var(--accent, #ffc777) 70%, transparent),
|
|
0 0 24px color-mix(in srgb, var(--accent, #ffc777) 40%, transparent),
|
|
inset 0 0 12px color-mix(in srgb, var(--accent, #ffc777) 30%, transparent);
|
|
}
|
|
50% {
|
|
box-shadow:
|
|
0 0 20px color-mix(in srgb, var(--accent, #ffc777) 90%, transparent),
|
|
0 0 32px color-mix(in srgb, var(--accent, #ffc777) 60%, transparent),
|
|
inset 0 0 16px color-mix(in srgb, var(--accent, #ffc777) 40%, transparent);
|
|
}
|
|
}
|
|
|
|
/* =========================================================
|
|
Visual Feedback Effects
|
|
========================================================= */
|
|
/* Invalid move effect */
|
|
#sudoku .sudoku-cell.invalid-move {
|
|
animation: sudoku-invalid-pulse 180ms ease-out;
|
|
box-shadow:
|
|
0 0 12px color-mix(in srgb, var(--destructive, #c53b53) 85%, transparent),
|
|
0 0 24px color-mix(in srgb, var(--destructive, #c53b53) 45%, transparent);
|
|
}
|
|
|
|
@keyframes sudoku-invalid-pulse {
|
|
0% {
|
|
transform: scale(1.05);
|
|
box-shadow:
|
|
0 0 16px color-mix(in srgb, var(--destructive, #c53b53) 95%, transparent),
|
|
0 0 28px color-mix(in srgb, var(--destructive, #c53b53) 55%, transparent);
|
|
}
|
|
100% {
|
|
transform: none;
|
|
box-shadow: none;
|
|
}
|
|
}
|
|
|
|
/* Locked cell effect (pre-filled clues) */
|
|
#sudoku .sudoku-cell.locked-cell {
|
|
animation: sudoku-locked-pulse 300ms ease-out;
|
|
}
|
|
|
|
@keyframes sudoku-locked-pulse {
|
|
0% {
|
|
transform: scale(1.08);
|
|
background: rgba(255, 85, 85, 0.3);
|
|
box-shadow:
|
|
0 0 20px rgba(255, 85, 85, 0.9),
|
|
0 0 32px rgba(255, 85, 85, 0.6),
|
|
inset 0 0 16px rgba(255, 85, 85, 0.4);
|
|
}
|
|
50% {
|
|
transform: scale(1.05);
|
|
background: rgba(255, 85, 85, 0.2);
|
|
box-shadow:
|
|
0 0 16px rgba(255, 85, 85, 0.8),
|
|
0 0 28px rgba(255, 85, 85, 0.5),
|
|
inset 0 0 12px rgba(255, 85, 85, 0.3);
|
|
}
|
|
100% {
|
|
transform: none;
|
|
background: transparent;
|
|
box-shadow: none;
|
|
}
|
|
}
|
|
|
|
/* Trail effect for moves */
|
|
#sudoku .sudoku-cell.trail {
|
|
box-shadow:
|
|
inset 0 0 6px color-mix(in srgb, var(--primary, #82aaff) 60%, transparent),
|
|
0 0 6px color-mix(in srgb, var(--primary, #82aaff) 35%, transparent);
|
|
animation: sudoku-trail-fade 220ms ease-out;
|
|
}
|
|
|
|
@keyframes sudoku-trail-fade {
|
|
from { background-color: color-mix(in srgb, var(--primary, #82aaff) 25%, transparent); }
|
|
to { background-color: transparent; }
|
|
}
|
|
|
|
/* Valid move flash */
|
|
#sudoku .sudoku-cell.valid-move {
|
|
animation: sudoku-valid-flash 300ms ease-out;
|
|
}
|
|
|
|
@keyframes sudoku-valid-flash {
|
|
0% {
|
|
background: color-mix(in srgb, var(--success, #4fd6be) 40%, transparent);
|
|
box-shadow:
|
|
0 0 12px color-mix(in srgb, var(--success, #4fd6be) 80%, transparent),
|
|
0 0 20px color-mix(in srgb, var(--success, #4fd6be) 50%, transparent),
|
|
inset 0 0 8px color-mix(in srgb, var(--success, #4fd6be) 35%, transparent);
|
|
}
|
|
100% {
|
|
background: transparent;
|
|
box-shadow: none;
|
|
}
|
|
}
|
|
|
|
/* Conflict highlighting */
|
|
#sudoku .sudoku-cell.conflict {
|
|
outline: 2px solid var(--destructive, #c53b53);
|
|
outline-offset: -2px;
|
|
background: color-mix(in srgb, var(--destructive, #c53b53) 25%, var(--muted, #2f334d));
|
|
box-shadow:
|
|
0 0 10px color-mix(in srgb, var(--destructive, #c53b53) 70%, transparent),
|
|
0 0 18px color-mix(in srgb, var(--destructive, #c53b53) 40%, transparent),
|
|
inset 0 0 8px color-mix(in srgb, var(--destructive, #c53b53) 30%, transparent);
|
|
animation: sudoku-conflict-pulse 1s ease-in-out infinite;
|
|
}
|
|
|
|
@keyframes sudoku-conflict-pulse {
|
|
0%, 100% {
|
|
box-shadow:
|
|
0 0 10px color-mix(in srgb, var(--destructive, #c53b53) 70%, transparent),
|
|
0 0 18px color-mix(in srgb, var(--destructive, #c53b53) 40%, transparent),
|
|
inset 0 0 8px color-mix(in srgb, var(--destructive, #c53b53) 30%, transparent);
|
|
}
|
|
50% {
|
|
box-shadow:
|
|
0 0 14px color-mix(in srgb, var(--destructive, #c53b53) 85%, transparent),
|
|
0 0 24px color-mix(in srgb, var(--destructive, #c53b53) 55%, transparent),
|
|
inset 0 0 12px color-mix(in srgb, var(--destructive, #c53b53) 40%, transparent);
|
|
}
|
|
}
|