/* * Sudoku Tools application styles. * * The Toolbox shell owns the base theme tokens. Everything here derives from * those tokens so standalone, connected, light, dark, and system appearances * remain visually aligned. */ :root { --sudoku-success: #15735a; --sudoku-warning: #9a5b0b; --sudoku-info: #3560a8; --sudoku-board-radius: clamp(0.55rem, 1.2vw, 0.9rem); } html { min-width: 20rem; min-height: 100%; background: var(--toolbox-background); scrollbar-gutter: stable; } body { min-width: 20rem; min-height: 100vh; margin: 0; background: var(--toolbox-background); color: var(--toolbox-text); font-family: var(--toolbox-font); text-rendering: optimizeLegibility; -webkit-font-smoothing: antialiased; } #root { min-height: 100vh; } ::selection { background: color-mix(in srgb, var(--toolbox-focus) 44%, transparent); color: var(--toolbox-text); } .toolbox-shell__main { width: min(100%, 90rem); padding: clamp(0.75rem, 1.7vw, 1.5rem); } .sudoku-workbench, .modal, .fatal-error { --sudoku-success: color-mix(in srgb, #06805d 78%, var(--toolbox-text)); --sudoku-warning: color-mix(in srgb, #bf730a 78%, var(--toolbox-text)); --sudoku-info: color-mix(in srgb, #3268bd 76%, var(--toolbox-text)); --sudoku-line: color-mix( in srgb, var(--toolbox-text) 38%, var(--toolbox-border) ); --sudoku-line-strong: color-mix( in srgb, var(--toolbox-text) 78%, var(--toolbox-border) ); color: var(--toolbox-text); font-family: var(--toolbox-font); } /* Help is mounted next to the shell, so bridge its selected dark theme. */ body:has(.toolbox-shell[data-toolbox-theme="dark"]) .modal, body:has(.toolbox-shell[data-toolbox-theme="dark"]) .fatal-error { color-scheme: dark; --toolbox-background: #0f1422; --toolbox-surface: #171d2d; --toolbox-surface-soft: #20283a; --toolbox-text: #edf1fb; --toolbox-muted: #a9b3ca; --toolbox-border: #303a50; --toolbox-accent: #a9b7ff; --toolbox-accent-hover: #c3ccff; --toolbox-accent-soft: #252f55; --toolbox-accent-contrast: #11182a; --toolbox-focus: #66cdbd; --toolbox-danger: #ff8fa3; --toolbox-shadow: 0 14px 42px rgb(0 0 0 / 24%); } @media (prefers-color-scheme: dark) { body:has(.toolbox-shell[data-toolbox-theme="system"]) .modal, body:has(.toolbox-shell[data-toolbox-theme="system"]) .fatal-error { color-scheme: dark; --toolbox-background: #0f1422; --toolbox-surface: #171d2d; --toolbox-surface-soft: #20283a; --toolbox-text: #edf1fb; --toolbox-muted: #a9b3ca; --toolbox-border: #303a50; --toolbox-accent: #a9b7ff; --toolbox-accent-hover: #c3ccff; --toolbox-accent-soft: #252f55; --toolbox-accent-contrast: #11182a; --toolbox-focus: #66cdbd; --toolbox-danger: #ff8fa3; --toolbox-shadow: 0 14px 42px rgb(0 0 0 / 24%); } } /* Shared type and control language */ .sudoku-workbench :where(h1, h2, h3), .modal :where(h2, h3), .fatal-error :where(h1, h2) { margin: 0; color: var(--toolbox-text); font-weight: 760; letter-spacing: -0.027em; line-height: 1.16; } .sudoku-workbench h1 { font-size: clamp(1.65rem, 3.2vw, 2.65rem); } .sudoku-workbench h2, .modal h2 { font-size: clamp(1.25rem, 2.1vw, 1.65rem); } .sudoku-workbench h3, .modal h3 { font-size: 1rem; letter-spacing: -0.015em; } .sudoku-workbench :where(p, ul, ol, dl), .modal :where(p, ul, ol, dl), .fatal-error p { margin-block: 0; } .sudoku-workbench p, .modal p, .fatal-error p { line-height: 1.58; } .stack { display: grid; align-content: start; gap: 1rem; } .eyebrow { margin: 0 0 0.28rem !important; color: var(--toolbox-accent); font-size: 0.68rem; font-weight: 800; letter-spacing: 0.115em; line-height: 1.35 !important; text-transform: uppercase; } .muted { color: var(--toolbox-muted); font-size: 0.88rem; } .sr-only { position: absolute !important; width: 1px !important; height: 1px !important; padding: 0 !important; overflow: hidden !important; clip: rect(0, 0, 0, 0) !important; white-space: nowrap !important; border: 0 !important; } :where(.sudoku-workbench, .modal, .fatal-error) :where(button, input, select, textarea) { font: inherit; } :where(.sudoku-workbench, .modal, .fatal-error) button { min-height: 2.65rem; display: inline-flex; align-items: center; justify-content: center; gap: 0.45rem; padding: 0.6rem 0.85rem; border: 1px solid var(--toolbox-border); border-radius: 0.62rem; background: var(--toolbox-surface); box-shadow: 0 1px 1px rgb(20 30 60 / 4%); color: var(--toolbox-text); font-size: 0.82rem; font-weight: 700; line-height: 1.2; text-align: center; cursor: pointer; touch-action: manipulation; transition: border-color 140ms ease, background-color 140ms ease, color 140ms ease, box-shadow 140ms ease, transform 140ms ease; -webkit-tap-highlight-color: transparent; } :where(.sudoku-workbench, .modal, .fatal-error) button.is-active, :where(.sudoku-workbench, .modal) button[aria-pressed="true"], :where(.sudoku-workbench, .modal) [role="tab"][aria-selected="true"], :where(.sudoku-workbench, .modal) .primary-button, .fatal-error .primary-button { border-color: var(--toolbox-accent); background: var(--toolbox-accent); box-shadow: 0 0.2rem 0.7rem color-mix(in srgb, var(--toolbox-accent) 16%, transparent); color: var(--toolbox-accent-contrast); } :where(.sudoku-workbench, .modal, .fatal-error) button:disabled { box-shadow: none; cursor: not-allowed; opacity: 0.46; } :where(.sudoku-workbench, .modal, .fatal-error) .text-button { min-height: 2.1rem; padding: 0.3rem 0.45rem; border-color: transparent; background: transparent; box-shadow: none; } :where(.sudoku-workbench, .modal, .fatal-error) .danger { color: var(--toolbox-danger); } :where(.sudoku-workbench, .modal, .fatal-error) button.danger:not(.text-button) { border-color: color-mix( in srgb, var(--toolbox-danger) 34%, var(--toolbox-border) ); background: color-mix( in srgb, var(--toolbox-danger) 7%, var(--toolbox-surface) ); } :where(.sudoku-workbench, .modal) :where(input:not([type="checkbox"]):not([type="radio"]), select, textarea) { width: 100%; min-width: 0; min-height: 2.65rem; padding: 0.58rem 0.7rem; border: 1px solid var(--toolbox-border); border-radius: 0.58rem; outline: none; background: var(--toolbox-surface); box-shadow: inset 0 1px 1px rgb(20 30 60 / 3%); color: var(--toolbox-text); line-height: 1.35; transition: border-color 140ms ease, box-shadow 140ms ease, background-color 140ms ease; } :where(.sudoku-workbench, .modal) textarea { min-height: 5.75rem; resize: vertical; } :where(.sudoku-workbench, .modal) select { padding-right: 2rem; cursor: pointer; } :where(.sudoku-workbench, .modal) input::placeholder, :where(.sudoku-workbench, .modal) textarea::placeholder { color: color-mix(in srgb, var(--toolbox-muted) 72%, transparent); } :where(.sudoku-workbench, .modal) input:disabled, :where(.sudoku-workbench, .modal) select:disabled, :where(.sudoku-workbench, .modal) textarea:disabled { cursor: not-allowed; opacity: 0.58; } :where(.sudoku-workbench, .modal) input[type="checkbox"], :where(.sudoku-workbench, .modal) input[type="radio"] { width: 1.05rem; height: 1.05rem; flex: none; margin: 0; accent-color: var(--toolbox-accent); } :where(.sudoku-workbench, .modal) label { min-width: 0; display: grid; gap: 0.38rem; color: var(--toolbox-muted); font-size: 0.74rem; font-weight: 720; letter-spacing: 0.015em; line-height: 1.35; } :where(.sudoku-workbench, .modal) .check-row { min-height: 2rem; display: flex; align-items: center; gap: 0.55rem; color: var(--toolbox-text); font-size: 0.82rem; font-weight: 620; letter-spacing: 0; cursor: pointer; } :where(.sudoku-workbench, .modal) :where(button, input, select, textarea, [tabindex]):focus-visible, .fatal-error button:focus-visible { outline: 3px solid color-mix(in srgb, var(--toolbox-focus) 74%, var(--toolbox-accent)); outline-offset: 2px; } :where(.sudoku-workbench, .modal) :where( input:not([type="checkbox"]):not([type="radio"]), select, textarea ):focus-visible { border-color: color-mix( in srgb, var(--toolbox-focus) 70%, var(--toolbox-accent) ); outline: none; box-shadow: 0 0 0 3px color-mix(in srgb, var(--toolbox-focus) 22%, transparent); } @media (hover: hover) { :where(.sudoku-workbench, .modal, .fatal-error) button:not(:disabled):not(.sudoku-cell):hover { border-color: color-mix( in srgb, var(--toolbox-accent) 46%, var(--toolbox-border) ); background: var(--toolbox-accent-soft); color: var(--toolbox-accent); } :where(.sudoku-workbench, .modal, .fatal-error) button.is-active:not(:disabled):hover, :where(.sudoku-workbench, .modal) button[aria-pressed="true"]:not(:disabled):hover, :where(.sudoku-workbench, .modal) [role="tab"][aria-selected="true"]:not(:disabled):hover, :where(.sudoku-workbench, .modal) .primary-button:not(:disabled):hover, .sudoku-workbench .hero-actions button:first-child:not(:disabled):hover, .fatal-error .primary-button:not(:disabled):hover { border-color: var(--toolbox-accent-hover); background: var(--toolbox-accent-hover); color: var(--toolbox-accent-contrast); } :where(.sudoku-workbench, .modal, .fatal-error) button:not(:disabled):not(.sudoku-cell):active { transform: translateY(1px); } :where(.sudoku-workbench, .modal, .fatal-error) .text-button:hover { border-color: transparent; background: var(--toolbox-surface-soft); } :where(.sudoku-workbench, .modal, .fatal-error) .danger:hover { background: color-mix( in srgb, var(--toolbox-danger) 10%, var(--toolbox-surface) ) !important; color: var(--toolbox-danger) !important; } } /* Workbench shell */ .sudoku-workbench { width: min(100%, 90rem); display: grid; gap: clamp(0.8rem, 1.5vw, 1.2rem); margin-inline: auto; } .workbench-hero { position: relative; isolation: isolate; min-width: 0; display: flex; align-items: center; justify-content: space-between; gap: 1rem 2rem; overflow: hidden; padding: clamp(1rem, 2.3vw, 1.75rem); border: 1px solid var(--toolbox-border); border-radius: calc(var(--toolbox-radius) + 0.25rem); background: radial-gradient( circle at 82% 12%, color-mix(in srgb, var(--toolbox-focus) 18%, transparent), transparent 30% ), linear-gradient( 135deg, color-mix( in srgb, var(--toolbox-accent-soft) 72%, var(--toolbox-surface) ), var(--toolbox-surface) 62% ); box-shadow: var(--toolbox-shadow); } .workbench-hero::after { position: absolute; z-index: -1; right: clamp(-2.5rem, -1vw, -0.75rem); bottom: clamp(-4.8rem, -5vw, -2.75rem); width: clamp(10rem, 20vw, 17rem); aspect-ratio: 1; border: 2px solid color-mix(in srgb, var(--toolbox-accent) 11%, transparent); background-image: linear-gradient( to right, transparent 32.8%, color-mix(in srgb, var(--toolbox-accent) 10%, transparent) 33%, color-mix(in srgb, var(--toolbox-accent) 10%, transparent) 33.7%, transparent 34%, transparent 66.1%, color-mix(in srgb, var(--toolbox-accent) 10%, transparent) 66.3%, color-mix(in srgb, var(--toolbox-accent) 10%, transparent) 67%, transparent 67.2% ), linear-gradient( to bottom, transparent 32.8%, color-mix(in srgb, var(--toolbox-accent) 10%, transparent) 33%, color-mix(in srgb, var(--toolbox-accent) 10%, transparent) 33.7%, transparent 34%, transparent 66.1%, color-mix(in srgb, var(--toolbox-accent) 10%, transparent) 66.3%, color-mix(in srgb, var(--toolbox-accent) 10%, transparent) 67%, transparent 67.2% ); border-radius: 1.5rem; content: ""; opacity: 0.9; transform: rotate(10deg); } .hero-copy { min-width: 0; max-width: 51rem; } .hero-copy > p:not(.eyebrow) { max-width: 64ch; margin-top: 0.55rem; color: var(--toolbox-muted); font-size: clamp(0.86rem, 1.2vw, 0.96rem); } .hero-actions, .action-row, .toolbar-group, .export-actions { display: flex; align-items: center; flex-wrap: wrap; gap: 0.55rem; } .hero-actions { position: relative; z-index: 1; justify-content: flex-end; } .hero-actions button:first-child { border-color: var(--toolbox-accent); background: var(--toolbox-accent); color: var(--toolbox-accent-contrast); } .workspace-tabs, .subtabs, .mode-switcher { display: grid; gap: 0.3rem; padding: 0.32rem; border: 1px solid var(--toolbox-border); border-radius: 0.78rem; background: color-mix( in srgb, var(--toolbox-surface-soft) 78%, var(--toolbox-surface) ); } .workspace-tabs { grid-template-columns: repeat(4, minmax(0, 1fr)); } .workspace-tabs button, .subtabs button, .mode-switcher button { min-height: 2.45rem; border-color: transparent; background: transparent; box-shadow: none; color: var(--toolbox-muted); } .workspace-tabs button.is-active, .workspace-tabs button[aria-selected="true"], .subtabs button.is-active, .mode-switcher button.is-active { border-color: var(--toolbox-border); background: var(--toolbox-surface); box-shadow: 0 0.15rem 0.55rem rgb(20 30 60 / 8%); color: var(--toolbox-accent); } .workbench-status { min-height: 2.25rem; display: flex; align-items: center; justify-content: space-between; gap: 0.6rem 1rem; padding: 0.35rem 0.2rem; color: var(--toolbox-muted); font-size: 0.78rem; } .timer-display { display: inline-flex; align-items: center; gap: 0.4rem; padding: 0.3rem 0.55rem; border: 1px solid var(--toolbox-border); border-radius: 999px; background: var(--toolbox-surface); color: var(--toolbox-text); font-family: ui-monospace, SFMono-Regular, Consolas, "Liberation Mono", monospace; font-size: 0.78rem; font-variant-numeric: tabular-nums; font-weight: 720; letter-spacing: 0.04em; } .workbench-grid { min-width: 0; display: grid; grid-template-columns: minmax(0, 1.65fr) minmax(19.5rem, 0.82fr); align-items: start; gap: clamp(0.85rem, 1.6vw, 1.35rem); } .workbench-grid--helpers { grid-template-columns: minmax(24rem, 0.92fr) minmax(31rem, 1.08fr); } .board-column, .side-panel, .play-panel, .setter-panel, .solve-workspace, .helpers-workspace { min-width: 0; } .board-column { display: grid; align-content: start; gap: 0.75rem; } .board-toolbar { min-height: 2.8rem; display: flex; align-items: center; justify-content: space-between; gap: 0.55rem 1rem; } .board-toolbar > span { color: var(--toolbox-muted); font-family: ui-monospace, SFMono-Regular, Consolas, "Liberation Mono", monospace; font-size: 0.75rem; font-variant-numeric: tabular-nums; } .select-wrap { min-width: min(100%, 11rem); } .select-wrap select { min-height: 2.45rem !important; } .board-surface, .side-panel { border: 1px solid var(--toolbox-border); border-radius: calc(var(--toolbox-radius) + 0.2rem); background: var(--toolbox-surface); box-shadow: var(--toolbox-shadow); } .board-surface { position: relative; display: grid; justify-items: center; padding: clamp(0.5rem, 1.7vw, 1.15rem); overflow: hidden; } .board-surface.is-paused .sudoku-board-frame { opacity: 0.72; filter: saturate(0.6); } .side-panel { padding: clamp(0.85rem, 1.7vw, 1.2rem); } .paused-cover { position: absolute; z-index: 12; inset: 0; display: grid; align-content: center; justify-items: center; gap: 0.65rem; padding: 1.5rem; border-radius: inherit; background: color-mix(in srgb, var(--toolbox-surface) 78%, transparent); color: var(--toolbox-text); text-align: center; backdrop-filter: blur(12px); } .paused-cover::before { width: 3.5rem; height: 3.5rem; display: grid; place-items: center; border: 1px solid var(--toolbox-border); border-radius: 50%; background: var(--toolbox-surface); box-shadow: var(--toolbox-shadow); color: var(--toolbox-accent); content: "Ⅱ"; font-size: 1.25rem; font-weight: 800; } .board-meta { display: flex; align-items: flex-start; justify-content: space-between; flex-wrap: wrap; gap: 0.55rem 1rem; color: var(--toolbox-muted); font-size: 0.78rem; } .board-meta .rule-card { flex: 1 1 100%; } .rule-card, .panel-section, .helper-card, .analysis-summary, .logical-results { min-width: 0; padding: clamp(0.8rem, 1.45vw, 1rem); border: 1px solid var(--toolbox-border); border-radius: 0.78rem; background: color-mix( in srgb, var(--toolbox-surface-soft) 43%, var(--toolbox-surface) ); } .rule-card { display: grid; gap: 0.45rem; } .rule-card p:not(.eyebrow) { color: var(--toolbox-muted); font-size: 0.84rem; white-space: pre-wrap; } .constraint-chips { display: flex; flex-wrap: wrap; gap: 0.35rem; margin: 0; padding: 0; list-style: none; } .constraint-chips :where(li, span) { display: inline-flex; align-items: center; padding: 0.25rem 0.5rem; border: 1px solid color-mix(in srgb, var(--toolbox-accent) 24%, var(--toolbox-border)); border-radius: 999px; background: var(--toolbox-accent-soft); color: var(--toolbox-accent); font-size: 0.7rem; font-weight: 720; } .option-row { display: flex; align-items: center; justify-content: space-between; gap: 0.75rem; padding-block: 0.35rem; color: var(--toolbox-text) !important; font-size: 0.8rem !important; font-weight: 610 !important; letter-spacing: 0 !important; cursor: pointer; } .option-row + .option-row { border-top: 1px solid color-mix(in srgb, var(--toolbox-border) 68%, transparent); } .section-heading { display: flex; align-items: flex-start; justify-content: space-between; gap: 0.65rem 1rem; } .field-grid, .inline-fields, .helper-controls { display: grid; gap: 0.7rem; } .field-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } .inline-fields { grid-template-columns: minmax(6rem, 0.7fr) minmax(7.5rem, 1fr); align-items: end; } .compact-field { width: min(100%, 9rem); } .button-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 0.45rem; } .panel-section { display: grid; gap: 0.72rem; } .panel-section.action-row { display: flex; } .feedback-callout, .status-line, .error-callout, .callout { margin: 0; padding: 0.68rem 0.78rem; border: 1px solid var(--toolbox-border); border-radius: 0.62rem; background: var(--toolbox-surface-soft); color: var(--toolbox-text); font-size: 0.8rem; line-height: 1.48 !important; } .feedback-success { border-color: color-mix( in srgb, var(--sudoku-success) 34%, var(--toolbox-border) ); background: color-mix( in srgb, var(--sudoku-success) 9%, var(--toolbox-surface) ); color: var(--sudoku-success); } .feedback-error, .error-callout { border-color: color-mix( in srgb, var(--toolbox-danger) 38%, var(--toolbox-border) ); background: color-mix( in srgb, var(--toolbox-danger) 9%, var(--toolbox-surface) ); color: var(--toolbox-danger); } .feedback-info, .status-line { border-color: color-mix( in srgb, var(--sudoku-info) 30%, var(--toolbox-border) ); background: color-mix(in srgb, var(--sudoku-info) 8%, var(--toolbox-surface)); color: var(--sudoku-info); } .callout { border-color: color-mix( in srgb, var(--sudoku-warning) 30%, var(--toolbox-border) ); background: color-mix( in srgb, var(--sudoku-warning) 8%, var(--toolbox-surface) ); color: color-mix(in srgb, var(--sudoku-warning) 84%, var(--toolbox-text)); } /* Sudoku board */ .sudoku-board-frame { --board-pad: clamp(0.28rem, 0.75vw, 0.48rem); --board-edge: clamp(2px, 0.35vw, 3px); position: relative; isolation: isolate; width: min(100%, 43rem); padding: var(--board-pad); border: 1px solid var(--toolbox-border); border-radius: var(--sudoku-board-radius); background: color-mix( in srgb, var(--toolbox-surface-soft) 74%, var(--toolbox-surface) ); box-shadow: 0 0.6rem 1.8rem rgb(20 30 60 / 9%), inset 0 1px 0 color-mix(in srgb, white 38%, transparent); container-type: inline-size; user-select: none; -webkit-user-select: none; } .sudoku-board { position: relative; width: 100%; display: grid; grid-template-columns: repeat(var(--sudoku-size), minmax(0, 1fr)); grid-template-rows: repeat(var(--sudoku-size), minmax(0, 1fr)); aspect-ratio: 1; overflow: hidden; border: var(--board-edge) solid var(--sudoku-line-strong); border-radius: clamp(0.22rem, 0.55vw, 0.42rem); background: var(--sudoku-line); box-shadow: 0 1px 0 color-mix(in srgb, white 22%, transparent); touch-action: none; } .sudoku-cell { --cell-fill: var(--toolbox-surface); position: relative; min-width: 0 !important; min-height: 0 !important; overflow: hidden; padding: 0 !important; border: 0.5px solid var(--sudoku-line) !important; border-radius: 0 !important; outline-offset: -3px !important; background: var(--cell-fill) !important; box-shadow: none !important; color: var(--toolbox-accent) !important; font-variant-numeric: tabular-nums; cursor: pointer; transition: background-color 100ms ease, color 100ms ease; } .sudoku-cell.is-given { color: var(--toolbox-text) !important; cursor: default; } .sudoku-cell[class*="has-color-"] { --cell-fill: color-mix( in srgb, var(--sudoku-mark-color) 24%, var(--toolbox-surface) ); } .sudoku-cell.is-selected { background: color-mix( in srgb, var(--toolbox-accent) 20%, var(--cell-fill) ) !important; } .sudoku-cell.is-selected::after { position: absolute; z-index: 5; inset: max(1px, 5%); border: max(1.5px, 0.25cqi) solid color-mix(in srgb, var(--toolbox-accent) 82%, transparent); border-radius: max(1px, 0.25cqi); content: ""; pointer-events: none; } .sudoku-cell.has-conflict { background: color-mix( in srgb, var(--toolbox-danger) 18%, var(--cell-fill) ) !important; color: var(--toolbox-danger) !important; } .sudoku-cell.has-conflict::before { position: absolute; z-index: 4; inset: 10%; border-radius: 50%; background: color-mix(in srgb, var(--toolbox-danger) 10%, transparent); content: ""; pointer-events: none; } .sudoku-cell:focus-visible { outline: none !important; } .sudoku-cell:focus-visible::after { position: absolute; z-index: 6; inset: max(1px, 4%); border: max(2px, 0.3cqi) solid var(--toolbox-focus); border-radius: max(1px, 0.25cqi); content: ""; pointer-events: none; } @media (hover: hover) { .sudoku-cell:not(.is-selected):not(.has-conflict):hover { background: color-mix( in srgb, var(--toolbox-accent) 8%, var(--cell-fill) ) !important; } } .cell-value, .corner-marks, .center-marks { position: relative; z-index: 4; pointer-events: none; } .cell-value { display: block; font-size: clamp(0.74rem, 4.2cqi, 2rem); font-weight: 650; line-height: 1; } .is-given .cell-value { font-weight: 820; } .corner-marks { position: absolute; inset: 7%; display: flex; align-content: flex-start; align-items: flex-start; flex-wrap: wrap; justify-content: flex-start; gap: 0 0.14em; overflow: hidden; color: color-mix(in srgb, var(--toolbox-text) 77%, var(--toolbox-muted)); font-size: clamp(0.34rem, 1.38cqi, 0.64rem); font-weight: 720; line-height: 1.05; text-align: left; } .center-marks { max-width: 88%; display: block; overflow: hidden; color: color-mix(in srgb, var(--toolbox-text) 72%, var(--toolbox-muted)); font-size: clamp(0.38rem, 1.48cqi, 0.68rem); font-weight: 650; letter-spacing: 0.035em; line-height: 1.08; overflow-wrap: anywhere; } .constraint-layer { position: absolute; z-index: 3; top: var(--board-pad); left: var(--board-pad); width: calc(100% - var(--board-pad) - var(--board-pad)); height: calc(100% - var(--board-pad) - var(--board-pad)); overflow: visible; pointer-events: none; shape-rendering: geometricPrecision; } .constraint-layer :where(path, polyline, line, circle) { vector-effect: non-scaling-stroke; } .region-boundaries path { fill: none; stroke: var(--sudoku-line-strong); stroke-linecap: square; stroke-linejoin: miter; stroke-width: clamp(1.8px, 0.28cqi, 3px); } .constraint-diagonal { stroke: color-mix(in srgb, var(--toolbox-accent) 68%, var(--toolbox-text)); stroke-linecap: round; stroke-width: clamp(2px, 0.34cqi, 3.5px); opacity: 0.66; } .constraint-cage path { fill: none; stroke: color-mix(in srgb, var(--toolbox-text) 76%, var(--toolbox-muted)); stroke-dasharray: 3 2.5; stroke-linecap: round; stroke-linejoin: round; stroke-width: clamp(1px, 0.17cqi, 1.7px); } .constraint-cage text { fill: var(--toolbox-text); font-family: var(--toolbox-font); font-size: 0.22px; font-weight: 760; paint-order: stroke; stroke: var(--toolbox-surface); stroke-width: 0.035px; } .constraint-thermo polyline { fill: none; stroke: color-mix(in srgb, var(--toolbox-muted) 48%, var(--toolbox-surface)); stroke-linecap: round; stroke-linejoin: round; stroke-width: clamp(8px, 2.05cqi, 17px); } .constraint-thermo circle { fill: color-mix(in srgb, var(--toolbox-muted) 42%, var(--toolbox-surface)); stroke: color-mix(in srgb, var(--toolbox-muted) 67%, var(--toolbox-surface)); stroke-width: clamp(1px, 0.15cqi, 1.5px); } .constraint-arrow polyline { fill: none; stroke: color-mix(in srgb, var(--toolbox-text) 62%, var(--toolbox-muted)); stroke-linecap: round; stroke-linejoin: round; stroke-width: clamp(2px, 0.34cqi, 3px); } .constraint-arrow circle:first-child { fill: color-mix(in srgb, var(--toolbox-surface) 78%, transparent); stroke: color-mix(in srgb, var(--toolbox-text) 62%, var(--toolbox-muted)); stroke-width: clamp(1.5px, 0.27cqi, 2.5px); } .constraint-arrow circle:last-child { fill: color-mix(in srgb, var(--toolbox-text) 66%, var(--toolbox-muted)); stroke: none; } .constraint-renban polyline, .constraint-palindrome polyline { fill: none; stroke-linecap: round; stroke-linejoin: round; stroke-width: clamp(8px, 2.1cqi, 18px); } .constraint-renban polyline { stroke: color-mix(in srgb, #d973b4 44%, transparent); } .constraint-palindrome polyline { stroke: color-mix(in srgb, #8f9aae 48%, transparent); } .constraint-palindrome circle { fill: color-mix(in srgb, var(--toolbox-surface) 82%, transparent); stroke: color-mix(in srgb, #657087 65%, var(--toolbox-muted)); stroke-width: clamp(1px, 0.15cqi, 1.5px); } .constraint-kropki { stroke: color-mix(in srgb, var(--toolbox-text) 80%, var(--toolbox-muted)); stroke-width: clamp(1.2px, 0.2cqi, 2px); } .constraint-kropki--white { fill: var(--toolbox-surface); } .constraint-kropki--black { fill: color-mix(in srgb, var(--toolbox-text) 88%, black); } .constraint-label { dominant-baseline: central; fill: var(--toolbox-text); font-family: var(--toolbox-font); font-size: 0.28px; font-weight: 850; paint-order: stroke; stroke: var(--toolbox-surface); stroke-linejoin: round; stroke-width: 0.07px; text-anchor: middle; } .constraint-label--inequality { font-size: 0.38px; } /* Number and colour entry */ .number-pad { display: grid; gap: 0.65rem; } .mode-switcher { grid-template-columns: repeat(4, minmax(0, 1fr)); } .mode-switcher button { padding-inline: 0.35rem; font-size: 0.72rem; } .digit-pad { display: grid; grid-template-columns: repeat(auto-fit, minmax(2.75rem, 1fr)); gap: 0.42rem; } .digit-pad--wide { grid-template-columns: repeat(auto-fit, minmax(2.5rem, 1fr)); } .digit-pad button { min-width: 0; min-height: 2.9rem; padding-inline: 0.35rem; font-size: 1rem; font-variant-numeric: tabular-nums; } .digit-pad .erase-key { padding-inline: 0.65rem; color: var(--toolbox-muted); font-size: 0.76rem; } .color-choice > span:first-child { width: 1.35rem; height: 1.35rem; display: block; border: 2px solid color-mix(in srgb, var(--sudoku-mark-color) 75%, white); border-radius: 50%; background: var(--sudoku-mark-color); box-shadow: 0 0 0 1px color-mix(in srgb, var(--sudoku-mark-color) 72%, black), inset 0 0.18rem 0.28rem rgb(255 255 255 / 22%); } .color-1, .has-color-1 { --sudoku-mark-color: #e56f65; } .color-2, .has-color-2 { --sudoku-mark-color: #eca73f; } .color-3, .has-color-3 { --sudoku-mark-color: #e0c84f; } .color-4, .has-color-4 { --sudoku-mark-color: #62b77a; } .color-5, .has-color-5 { --sudoku-mark-color: #4bb8b4; } .color-6, .has-color-6 { --sudoku-mark-color: #5d93dd; } .color-7, .has-color-7 { --sudoku-mark-color: #9a7cda; } .color-8, .has-color-8 { --sudoku-mark-color: #ce78b0; } /* Setter, solver, and helper result surfaces */ .constraint-list, .library-list, .cell-possibilities { margin: 0; padding: 0; list-style: none; } .constraint-list { display: grid; gap: 0.35rem; } .constraint-list li { min-width: 0; display: flex; align-items: center; justify-content: space-between; gap: 0.55rem; padding: 0.38rem 0.45rem 0.38rem 0.65rem; border: 1px solid var(--toolbox-border); border-radius: 0.58rem; background: var(--toolbox-surface); color: var(--toolbox-text); font-size: 0.78rem; } .constraint-list li > span { min-width: 0; overflow-wrap: anywhere; } .subtabs { grid-template-columns: repeat(3, minmax(0, 1fr)); } .helper-controls { grid-template-columns: repeat(3, minmax(0, 1fr)); align-items: end; } .helper-controls .check-row { align-self: center; } .helper-result { display: grid; gap: 0.8rem; margin-top: 0.9rem; } .metric-row { display: grid; grid-template-columns: repeat(auto-fit, minmax(8rem, 1fr)); gap: 0.45rem; } .metric-row > span { min-width: 0; padding: 0.55rem 0.65rem; border: 1px solid var(--toolbox-border); border-radius: 0.58rem; background: var(--toolbox-surface); color: var(--toolbox-muted); font-size: 0.75rem; line-height: 1.35; } .metric-row strong { color: var(--toolbox-text); font-size: 0.9rem; } .cell-possibilities { display: grid; grid-template-columns: repeat(auto-fit, minmax(9rem, 1fr)); gap: 0.35rem; counter-reset: none; } .cell-possibilities li { padding: 0.42rem 0.55rem; border-radius: 0.48rem; background: var(--toolbox-surface-soft); color: var(--toolbox-text); font-family: ui-monospace, SFMono-Regular, Consolas, "Liberation Mono", monospace; font-size: 0.72rem; } .combination-cloud, .pair-table { max-height: 17rem; display: flex; align-content: flex-start; flex-wrap: wrap; gap: 0.35rem; overflow: auto; padding: 0.65rem; border: 1px solid var(--toolbox-border); border-radius: 0.62rem; background: color-mix( in srgb, var(--toolbox-background) 52%, var(--toolbox-surface) ); scrollbar-color: var(--toolbox-border) transparent; } .combination-cloud code, .pair-table code { padding: 0.28rem 0.44rem; border: 1px solid color-mix(in srgb, var(--toolbox-accent) 18%, var(--toolbox-border)); border-radius: 0.42rem; background: var(--toolbox-surface); color: var(--toolbox-accent); font-family: ui-monospace, SFMono-Regular, Consolas, "Liberation Mono", monospace; font-size: 0.72rem; font-weight: 720; } .residual-equation { color: var(--toolbox-muted); font-family: ui-monospace, SFMono-Regular, Consolas, "Liberation Mono", monospace; font-size: clamp(1.15rem, 3vw, 1.65rem); letter-spacing: -0.035em; text-align: center; } .residual-equation strong { color: var(--toolbox-accent); } .analysis-summary, .logical-results { display: grid; gap: 0.8rem; } .status-pill { display: inline-flex; align-items: center; align-self: flex-start; padding: 0.28rem 0.55rem; border: 1px solid var(--toolbox-border); border-radius: 999px; background: var(--toolbox-surface); color: var(--toolbox-muted); font-size: 0.67rem; font-weight: 800; letter-spacing: 0.06em; text-transform: uppercase; } .status-solved { border-color: color-mix( in srgb, var(--sudoku-success) 35%, var(--toolbox-border) ); background: color-mix( in srgb, var(--sudoku-success) 9%, var(--toolbox-surface) ); color: var(--sudoku-success); } .status-invalid { border-color: color-mix( in srgb, var(--toolbox-danger) 38%, var(--toolbox-border) ); background: color-mix( in srgb, var(--toolbox-danger) 9%, var(--toolbox-surface) ); color: var(--toolbox-danger); } .status-stuck, .status-limit, .status-step-limit { border-color: color-mix( in srgb, var(--sudoku-warning) 36%, var(--toolbox-border) ); background: color-mix( in srgb, var(--sudoku-warning) 8%, var(--toolbox-surface) ); color: var(--sudoku-warning); } .solve-steps { max-height: 32rem; display: grid; gap: 0.42rem; overflow: auto; padding: 0.15rem; scrollbar-color: var(--toolbox-border) transparent; } .solve-step { width: 100%; min-height: 0 !important; display: grid !important; grid-template-columns: 2rem minmax(0, 1fr); align-items: start !important; gap: 0.65rem !important; padding: 0.68rem !important; text-align: left !important; } .solve-step > span:last-child { min-width: 0; display: grid; gap: 0.18rem; } .solve-step small, .step-effects { display: block; color: var(--toolbox-muted); font-size: 0.72rem; font-weight: 500; line-height: 1.45; overflow-wrap: anywhere; } .step-number { width: 2rem; height: 2rem; display: grid; place-items: center; border-radius: 50%; background: var(--toolbox-surface-soft); color: var(--toolbox-muted); font-size: 0.72rem; font-variant-numeric: tabular-nums; font-weight: 800; } .solve-step.is-active .step-number { background: var(--toolbox-accent-contrast); color: var(--toolbox-accent); } .solve-step.is-active :where(strong, small, .step-effects) { color: var(--toolbox-accent-contrast); } .shortcut-note { padding-top: 0.65rem; border-top: 1px solid var(--toolbox-border); font-size: 0.72rem; } /* Dialogs and local library */ .modal { width: min(calc(100% - 2rem), 40rem); max-width: none; max-height: min(calc(100dvh - 2rem), 52rem); margin: auto; padding: 0; overflow: hidden; border: 1px solid var(--toolbox-border); border-radius: 0.95rem; outline: none; background: var(--toolbox-surface); box-shadow: 0 1.3rem 4.5rem rgb(5 10 25 / 28%); color: var(--toolbox-text); } .modal--wide { width: min(calc(100% - 2rem), 68rem); } .modal::backdrop { background: rgb(8 13 28 / 58%); backdrop-filter: blur(4px); } .modal[open] { animation: modal-enter 150ms ease-out both; } @keyframes modal-enter { from { opacity: 0; transform: translateY(0.45rem) scale(0.985); } to { opacity: 1; transform: none; } } .modal__surface { max-height: inherit; display: grid; grid-template-rows: auto minmax(0, 1fr); } .modal__header { min-height: 4rem; display: flex; align-items: center; justify-content: space-between; gap: 1rem; padding: 0.85rem 1rem 0.85rem 1.2rem; border-bottom: 1px solid var(--toolbox-border); background: color-mix( in srgb, var(--toolbox-surface) 90%, var(--toolbox-background) ); } .modal__header .icon-button { width: 2.45rem; min-width: 2.45rem; height: 2.45rem; min-height: 2.45rem; padding: 0; border-radius: 50%; font-size: 1.35rem; font-weight: 450; } .modal__body { min-height: 0; overflow: auto; overscroll-behavior: contain; padding: clamp(0.9rem, 2.2vw, 1.3rem); scrollbar-color: var(--toolbox-border) transparent; } .import-export-grid, .help-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 1rem; } .import-export-grid > section, .help-grid > section { min-width: 0; padding: 0.9rem; border: 1px solid var(--toolbox-border); border-radius: 0.75rem; background: color-mix( in srgb, var(--toolbox-surface-soft) 46%, var(--toolbox-surface) ); } .import-export-grid textarea { font-family: ui-monospace, SFMono-Regular, Consolas, "Liberation Mono", monospace; font-size: 0.76rem; line-height: 1.5; } .export-actions { align-items: stretch; } .export-actions button { flex: 1 1 11rem; } .library-toolbar { display: flex; align-items: flex-start; justify-content: space-between; gap: 0.8rem 1.25rem; margin-bottom: 1rem; } .library-list { display: grid; gap: 0.45rem; } .library-list li { min-width: 0; display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: center; gap: 0.5rem; padding: 0.38rem; border: 1px solid var(--toolbox-border); border-radius: 0.68rem; background: var(--toolbox-surface); } .library-open { min-width: 0; display: grid !important; justify-items: start !important; gap: 0.18rem !important; border-color: transparent !important; background: transparent !important; box-shadow: none !important; text-align: left !important; } .library-open strong { max-width: 100%; overflow: hidden; color: var(--toolbox-text); text-overflow: ellipsis; white-space: nowrap; } .library-open span { color: var(--toolbox-muted); font-size: 0.7rem; font-weight: 520; } .empty-state { display: grid; justify-items: center; gap: 0.4rem; padding: clamp(2rem, 8vw, 4.5rem) 1rem; border: 1px dashed var(--toolbox-border); border-radius: 0.8rem; background: var(--toolbox-surface-soft); color: var(--toolbox-muted); text-align: center; } .empty-state::before { width: 3rem; height: 3rem; display: grid; place-items: center; margin-bottom: 0.25rem; border: 1px solid var(--toolbox-border); border-radius: 0.8rem; background: var(--toolbox-surface); color: var(--toolbox-accent); content: "▦"; font-size: 1.35rem; } .danger-zone { display: flex; justify-content: flex-end; margin-top: 1rem; padding-top: 1rem; border-top: 1px solid var(--toolbox-border); } .help-grid section { display: grid; align-content: start; gap: 0.55rem; } .help-grid p { color: var(--toolbox-muted); font-size: 0.84rem; } .help-grid p strong { color: var(--toolbox-text); } .shortcut-list { display: grid; gap: 0.28rem; } .shortcut-list > div { display: grid; grid-template-columns: minmax(7rem, 0.62fr) minmax(0, 1fr); gap: 0.65rem; padding-block: 0.3rem; border-bottom: 1px solid color-mix(in srgb, var(--toolbox-border) 66%, transparent); font-size: 0.76rem; } .shortcut-list dt { color: var(--toolbox-text); font-weight: 720; } .shortcut-list dd { margin: 0; color: var(--toolbox-muted); } /* Loading and fatal recovery */ .workbench-loading { min-height: min(34rem, calc(100dvh - 10rem)); display: grid; grid-auto-flow: column; justify-content: center; place-items: center; margin: 0; color: var(--toolbox-muted); font-size: 0.88rem; } .workbench-loading::before { width: 1.15rem; height: 1.15rem; margin-right: 0.65rem; border: 2px solid var(--toolbox-border); border-top-color: var(--toolbox-accent); border-radius: 50%; content: ""; animation: loading-spin 700ms linear infinite; } @keyframes loading-spin { to { transform: rotate(1turn); } } .fatal-error { width: min(calc(100% - 2rem), 36rem); display: grid; gap: 1rem; margin: clamp(2rem, 10vh, 7rem) auto; padding: clamp(1.2rem, 4vw, 2rem); border: 1px solid var(--toolbox-border); border-radius: 1rem; background: var(--toolbox-surface); box-shadow: var(--toolbox-shadow); } .fatal-error p { color: var(--toolbox-muted); } .fatal-error button { justify-self: start; } /* Responsive composition */ @media (max-width: 67rem) { .workbench-grid, .workbench-grid--helpers { grid-template-columns: minmax(0, 1fr); } .side-panel { width: 100%; } .board-toolbar, .board-meta { width: min(100%, 45rem); margin-inline: auto; } .helper-controls { grid-template-columns: repeat(2, minmax(0, 1fr)); } } @media (max-width: 48rem) { .toolbox-shell__main { padding-inline: 0.75rem; } .workbench-hero { align-items: flex-start; flex-direction: column; } .workbench-hero::after { opacity: 0.58; } .hero-actions { justify-content: flex-start; } .workbench-status, .board-toolbar { align-items: flex-start; flex-direction: column; } .board-toolbar > :where(.toolbar-group, .action-row) { width: 100%; } .side-panel { padding: 0.75rem; } .subtabs, .import-export-grid, .help-grid { grid-template-columns: minmax(0, 1fr); } .library-toolbar { flex-direction: column; } } @media (max-width: 38rem) { .workspace-tabs { grid-template-columns: repeat(2, minmax(0, 1fr)); } .field-grid, .helper-controls { grid-template-columns: minmax(0, 1fr); } .section-heading { align-items: stretch; flex-direction: column; } .compact-field { width: 100%; } .panel-section.action-row, .action-row, .hero-actions { align-items: stretch; } .panel-section.action-row > button, .action-row > button, .hero-actions > button { flex: 1 1 9rem; } .modal { width: calc(100% - 1rem); max-height: calc(100dvh - 1rem); border-radius: 0.78rem; } .modal__header { min-height: 3.6rem; padding-left: 0.9rem; } .modal__body { padding: 0.75rem; } .library-list li { grid-template-columns: minmax(0, 1fr); } .library-list li > .text-button { justify-self: end; } } @media (max-width: 30rem) { .toolbox-shell__main { padding: 0.55rem; } .sudoku-workbench { gap: 0.65rem; } .workbench-hero, .side-panel { border-radius: 0.72rem; } .workbench-hero { padding: 0.9rem; } .workspace-tabs button { min-height: 2.7rem; } .board-surface { padding: 0.25rem; } .sudoku-board-frame { --board-pad: 0.2rem; border-radius: 0.55rem; } .mode-switcher { grid-template-columns: repeat(2, minmax(0, 1fr)); } .inline-fields { grid-template-columns: minmax(0, 1fr); } .button-grid { gap: 0.35rem; } .button-grid button { padding-inline: 0.4rem; font-size: 0.75rem; } .shortcut-list > div { grid-template-columns: minmax(0, 1fr); gap: 0.12rem; } } @media (pointer: coarse) { :where(.sudoku-workbench, .modal, .fatal-error) button:not(.sudoku-cell), :where(.sudoku-workbench, .modal) :where(input:not([type="checkbox"]):not([type="radio"]), select) { min-height: 2.75rem; } .sudoku-cell { -webkit-tap-highlight-color: transparent; } } @media (prefers-reduced-motion: reduce) { *, *::before, *::after { scroll-behavior: auto !important; animation-duration: 0.01ms !important; animation-iteration-count: 1 !important; transition-duration: 0.01ms !important; } } @media (forced-colors: active) { .sudoku-cell.is-selected::after, .sudoku-cell.has-conflict::before { border: 2px solid Highlight; background: transparent; } .sudoku-cell.has-conflict { outline: 2px dashed Mark; outline-offset: -4px; } .constraint-layer :where(path, polyline, line, circle), .region-boundaries path { stroke: CanvasText; } } /* A print is a clean puzzle sheet, not a snapshot of the controls. */ @media print { @page { size: auto; margin: 1.2cm; } :root, body { background: #fff !important; color: #000 !important; } .toolbox-shell { min-height: 0; background: #fff !important; color: #000 !important; } .toolbox-shell__header, .toolbox-shell__footer, .hero-actions, .workspace-tabs, .workbench-status, .board-toolbar, .side-panel, .number-pad, .paused-cover, .feedback-callout, .status-line, .modal { display: none !important; } .toolbox-shell__main, .sudoku-workbench, .workbench-grid, .board-column { width: 100% !important; max-width: none !important; display: block !important; margin: 0 !important; padding: 0 !important; } .workbench-hero { margin-bottom: 0.6cm; padding: 0 !important; border: 0 !important; background: transparent !important; box-shadow: none !important; } .workbench-hero::after { display: none; } .hero-copy > p:not(.eyebrow) { color: #333 !important; } .board-surface { display: block; padding: 0 !important; border: 0 !important; background: #fff !important; box-shadow: none !important; } .sudoku-board-frame { --toolbox-surface: #fff; --toolbox-text: #000; --toolbox-muted: #444; --toolbox-accent: #111; --toolbox-danger: #000; --sudoku-line: #888; --sudoku-line-strong: #000; width: min(100%, 18cm); margin-inline: auto; padding: 0; border: 0; background: #fff !important; box-shadow: none; break-inside: avoid; print-color-adjust: exact; } .sudoku-cell, .sudoku-cell.is-selected, .sudoku-cell.has-conflict, .sudoku-cell[class*="has-color-"] { --cell-fill: #fff; background: #fff !important; color: #000 !important; } .sudoku-cell::before, .sudoku-cell::after { display: none !important; } .constraint-layer { top: 0; left: 0; width: 100%; height: 100%; } .board-meta, .rule-card { width: min(100%, 18cm); margin: 0.5cm auto 0; color: #222 !important; } .rule-card { padding: 0; border: 0; background: transparent !important; } }