diff --git a/html/word-guesser/css/styles.css b/html/word-guesser/css/styles.css index 6da9243..3833171 100644 --- a/html/word-guesser/css/styles.css +++ b/html/word-guesser/css/styles.css @@ -1,7 +1,11 @@ -/* Game Container Styling */ +/* ============================================================ + WORD GUESSING GAME — STYLESHEET + ============================================================ */ + +/* ── Game Container ────────────────────────────────────────── */ .form_container { background-color: #ffffff; - border: 1px solid #dee2e6; + border: 1px solid var(--border-medium); border-radius: 12px; box-shadow: 0 10px 25px rgba(0, 0, 0, 0.05); max-width: 500px; @@ -21,22 +25,37 @@ padding-bottom: 0.2rem; } -.game-instructions { - text-align: center; - margin: 1.5rem 0; - font-size: 0.95rem; - color: #6c757d; -} #game_intro { font-size: 0.85rem; opacity: 0.7; } -/* Word Board (Wheel of Fortune Style) */ +/* ── Notifications — fixed height, no layout shift ──────────── */ +#notifications { + min-height: 1.5em; + line-height: 1.5em; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + text-align: center; + font-weight: 600; + font-size: 0.9rem; + font-style: italic; + color: var(--status-error, #d33333); + margin: 0; + padding: 0; +} + +.success-msg { + color: var(--status-success, #28a745); +} +.error-msg { + color: var(--status-error, #d33333); +} + +/* ── Word Board ─────────────────────────────────────────────── */ #current_word { display: flex; - flex-direction: row !important; - display: flex; flex-wrap: wrap; justify-content: center; align-items: center; @@ -47,36 +66,33 @@ font-weight: bold; letter-spacing: 5px; font-size: 1.5rem; - list-style: none; - padding: 10px 0; } #current_word li { background-color: var(--bg-body); border: 2px solid var(--accent-primary); border-radius: 4px; + border-bottom: 3px solid var(--border-medium); display: flex; align-items: center; justify-content: center; color: var(--accent-primary); - box-shadow: 2px 2px 0px rgba(44, 62, 80, 0.2); + box-shadow: 2px 2px 0 rgba(44, 62, 80, 0.2); text-transform: uppercase; - width: 32px; height: 42px; - display: flex; - border-bottom: 3px solid var(--border-medium); font-weight: bold; font-size: 1.4rem; } + .word-display-field { - display: block !important; /* Break out of the 2-column grid */ + display: block !important; text-align: center; padding: 2rem 0; border-bottom: 2px solid #f1f3f5; } -/* Form Layout */ +/* ── Form Layout ────────────────────────────────────────────── */ .formField { display: grid; grid-template-columns: 120px 1fr; @@ -96,14 +112,14 @@ font-size: 0.9rem; } -/* Inputs & Buttons */ +/* ── Inputs & Buttons ───────────────────────────────────────── */ #guess_letter { width: 50px; padding: 10px; text-align: center; font-size: 1.2rem; font-weight: bold; - border: 2px solid #dee2e6; + border: 2px solid var(--border-medium); border-radius: 4px; transition: border-color 0.2s; } @@ -148,121 +164,35 @@ box-shadow: 0 4px 8px rgba(0, 0, 0, 0.15); } -/* Guess History Pills */ +/* ── Guess History Pills ────────────────────────────────────── */ #guesses { display: flex; - flex-wrap: nowrap; /* Keep them on one line */ - overflow-x: auto; /* Scroll if there are too many */ + flex-wrap: nowrap; + overflow-x: auto; gap: 5px; padding: 5px 0; margin: 0; list-style: none; - scrollbar-width: none; /* Hide scrollbar for clean UI */ + scrollbar-width: none; } #guesses::-webkit-scrollbar { - display: none; /* Hide scrollbar for Chrome/Safari */ + display: none; } #guesses li { -} -#guesses li { - background: var(--accent-secondary, #e9ecef); - color: #1976d2; + background: var(--bg-tag, #e3f2fd); + color: var(--accent-tag, #1976d2); padding: 2px 8px; - border-radius: 20px; + border-radius: 3px; font-size: 0.85rem; font-family: "Roboto Mono", monospace; - /* font-family: "Courier New", Courier, monospace; */ font-weight: bold; flex-shrink: 0; - border: 1px solid #bbdefb; - border-radius: 3px; + border: 1px solid var(--border-tag, #bbdefb); } -/* Notifications */ -#notifications { - text-align: center; - font-weight: 600; - margin-bottom: 1rem; - min-height: 1.2em; - color: #d9534f; - font-style: italic; - text-align: center; -} - -.success-msg { - color: #2e7d32; -} -.error-msg { - color: #c62828; -} - -/* Mobile Optimizations */ -@media (max-width: 600px) { - .form_container { - padding: 1rem; - margin: 0.5rem; - } - #game_container { - top: 0px; - left: 0px; - position: fixed; - z-index: 1000; - } - #site-header, - footer, - #guesses, - #guess_letter_container { - display: none; - position: absolute; - z-index: -9999; - } - - /* /1* Shrink the tiles so long words don't wrap awkwardly *1/ */ - /* #current_word { */ - /* gap: 4px; */ - /* padding: 0.5rem 0; */ - /* } */ - - /* #current_word li { */ - /* width: 30px; /1* Reduced from 45px *1/ */ - /* height: 40px; /1* Reduced from 60px *1/ */ - /* font-size: 1.2rem; /1* Reduced from 2rem *1/ */ - /* border-width: 1px; */ - /* } */ - - /* /1* Stack the form fields vertically instead of 2-columns *1/ */ - /* .formField { */ - /* grid-template-columns: 1fr; */ - /* gap: 5px; */ - /* text-align: center; */ - /* } */ - - /* /1* Make the Alphabet Grid look like a keypad *1/ */ - /* .alphabet-grid { */ - /* display: grid; */ - /* grid-template-columns: repeat(auto-fill, minmax(35px, 1fr)); */ - /* gap: 5px; */ - /* margin-top: 1.5rem; */ - /* } */ - - /* .letter-btn { */ - /* padding: 10px 0; */ - /* font-family: "Roboto Mono", monospace; */ - /* font-weight: bold; */ - /* background: var(--bg-tag); */ - /* border: 1px solid var(--border-medium); */ - /* border-radius: 4px; */ - /* cursor: pointer; */ - /* } */ - - /* .letter-btn:disabled { */ - /* opacity: 0.4; */ - /* cursor: not-allowed; */ - /* } */ -} - +/* ── Alphabet Grid ──────────────────────────────────────────── */ .alphabet-grid { display: grid; grid-template-columns: repeat(9, 1fr); @@ -284,6 +214,7 @@ transition: transform 0.1s, background 0.1s; + cursor: pointer; } .letter-btn:active { @@ -292,75 +223,63 @@ background: #dee2e6; } +.letter-btn.selected { + background: var(--bg-header); + color: #fff; + border-color: var(--bg-header); + box-shadow: 0 2px 0 rgba(0, 0, 0, 0.25); +} + .letter-btn:disabled { background: #e9ecef; color: #adb5bd; box-shadow: none; border-color: transparent; + cursor: not-allowed; } -.game-footer { - display: flex; - justify-content: space-between; - align-items: center; - padding: 10px; - border-top: 1px solid #eee; - font-size: 0.9rem; -} - -#notifications { - min-height: 1.2em; - color: #d9534f; - font-style: italic; - text-align: center; -} - +/* ── Game Metrics ───────────────────────────────────────────── */ #game_metrics { display: flex; justify-content: space-between; align-items: flex-start; gap: 15px; padding: 10px; - background: var( - --bg-secondary, - #f8f9fa - ); /* Light background to define the area */ + background: var(--bg-subtle, #f5f7fa); border-radius: 8px; margin: 10px 0; } -/* Individual Metric Groups */ .formField.metric_group, #game_metrics .formField { flex: 1; display: flex; flex-direction: column; gap: 4px; - min-width: 0; /* Critical for preventing flex items from overflowing */ + min-width: 0; } -/* Labels */ #game_metrics .label { font-size: 0.75rem; font-weight: bold; text-transform: uppercase; - color: var(--text-muted, #6c757d); + color: var(--text-muted); letter-spacing: 0.05em; } -/* Attempts Input Styling */ -#guess_count { +#game_metrics #guess_count { width: 100%; padding: 8px; - border: 1px solid var(--border-light, #dee2e6); + border: 1px solid var(--border-light); border-radius: 4px; background: #fff; font-family: "Roboto Mono", monospace; font-size: 1.1rem; text-align: center; - color: var(--text-primary, #212529); + color: var(--text-main); } +/* ── Game Container ─────────────────────────────────────────── */ #game_container { max-width: 500px; margin: 2rem auto; @@ -371,9 +290,9 @@ overflow: hidden; } -/* Splash Screen (Login) specific styling */ +/* ── Splash / Login ─────────────────────────────────────────── */ #user_info_container { - display: flex; /* Show by default */ + display: flex; } #splash_screen { @@ -382,55 +301,328 @@ padding: 0; } -/* Hide the game form properly via CSS instead of inline styles */ #game_form { - display: none; /* Changed from visibility:hidden to display:none */ + display: none; } -/* Scoreboard Overlay */ -#scoreboard_overlay { - display: none; /* Toggle to 'flex' via JS */ - position: fixed; - inset: 0; /* Shorthand for top/bottom/left/right: 0 */ - background: rgba(15, 23, 42, 0.9); /* Darker slate backdrop */ - backdrop-filter: blur(8px); - z-index: 9999; - justify-content: center; - align-items: center; - color: #f8fafc; -} - -#scoreboard_overlay > div { - /* The wrapper inside the overlay */ - background: #1e293b; - border: 2px solid #38bdf8; - border-radius: 16px; - padding: 2rem; - width: 90%; - max-width: 400px; - display: grid; - grid-template-columns: 1fr; - gap: 1rem; - box-shadow: 0 20px 50px rgba(0, 0, 0, 0.5); -} - -/* Individual Stat Rows */ -#scoreboard_overlay > div > div { +/* ── Game Footer ────────────────────────────────────────────── */ +.game-footer { display: flex; justify-content: space-between; align-items: center; - padding-bottom: 0.5rem; - border-bottom: 1px solid #334155; + padding: 10px; + border-top: 1px solid #eee; + font-size: 0.9rem; } -#scoreboard_overlay > div > div:last-child { - border-bottom: none; +/* ============================================================ + SCOREBOARD OVERLAY + JS toggles display: none <-> flex — that is preserved. + Layout & visual design is a complete rewrite. + ============================================================ */ +#scoreboard { + display: none; /* JS switches this to 'flex' */ + position: fixed; + inset: 0; + z-index: 9999; + justify-content: center; + align-items: flex-end; /* bottom-sheet on mobile */ + background: rgba(0, 0, 0, 0.5); + backdrop-filter: blur(3px); + -webkit-backdrop-filter: blur(3px); } -#scoreboard_overlay [id^="total_"], -#scoreboard_overlay [id^="average_"] { - font-family: "Roboto Mono", monospace; - font-weight: bold; - color: #38bdf8; +/* ── Sheet card ─────────────────────────────────────────────── */ +#scoreboard > div { + background: #ffffff; + border-radius: 20px 20px 0 0; + width: 100%; + max-width: 500px; + overflow: hidden; + + /* Reset the default shared grid — scoreboard card is its own layout */ + display: flex !important; + flex-direction: column; + gap: 0; + box-shadow: 0 -4px 30px rgba(0, 0, 0, 0.15); + animation: sb-rise 0.3s cubic-bezier(0.34, 1.1, 0.64, 1) both; +} + +@keyframes sb-rise { + from { + transform: translateY(100%); + } + to { + transform: translateY(0); + } +} + +/* Drag handle strip */ +#scoreboard > div::before { + content: ""; + display: block; + width: 36px; + height: 4px; + border-radius: 2px; + background: rgba(255, 255, 255, 0.35); + margin: 12px auto 0; + order: -2; + flex-shrink: 0; +} + +/* ── Dark header band ───────────────────────────────────────── */ +#scoreboard > div > div:first-child { + /* Override shared row rules completely */ + display: flex !important; + flex-direction: column !important; + align-items: flex-start !important; + justify-content: flex-start !important; + gap: 3px !important; + padding: 14px 20px 16px !important; + border-bottom: none !important; + + background: var(--bg-header, #2c3e50); + order: -1; +} + +#scoreboard > div > div:first-child > div:first-child { + font-size: 0.68rem; + font-weight: 700; + letter-spacing: 0.09em; + text-transform: uppercase; + color: rgba(255, 255, 255, 0.5); +} + +#scoreboard > div > div:first-child > div:last-child { + /* This is the "Total words completed" label — repurpose as heading */ font-size: 1.2rem; + font-weight: 600; + color: #ffffff; +} + +/* ── Stat rows → 2-col card grid ────────────────────────────── */ +/* + The HTML has 4 stat rows + 1 button row inside #scoreboard > div. + We target rows 2–5 (nth-child 2–5) and float them into a grid. + Rows 2–5 = total words, incorrect guesses, avg guesses, avg time. + Row 6 = the button row (play again / quit). +*/ + +/* Wrapper grid — we can't add a real wrapper div, so we use + a CSS grid hack on the parent to re-layout children 2–5 */ +#scoreboard > div { + /* Already flex column — override with grid so we can span rows */ + display: grid !important; + grid-template-areas: + "handle" + "header" + "cards" + "buttons"; + grid-template-rows: auto auto 1fr auto; +} + +#scoreboard > div::before { + grid-area: handle; +} +#scoreboard > div > div:nth-child(1) { + grid-area: header; +} +#scoreboard > div > div:nth-child(5) { + grid-area: buttons; +} + +/* Rows 2–4 sit in the "cards" area — we need a sub-grid. + Since we can't wrap them in HTML, we absolutely position a + pseudo element background and use negative-margin columns. + Simpler: just style each stat row as a half-width card + and let them wrap. */ + +#scoreboard > div > div:nth-child(n + 2):nth-child(-n + 4) { + /* Stat card styling */ + margin: 0; + padding: 14px 16px !important; + border-bottom: none !important; + + /* Stack label over value */ + display: flex !important; + flex-direction: column !important; + align-items: flex-start !important; + justify-content: flex-start !important; + gap: 4px !important; + + background: var(--bg-subtle, #f5f7fa); +} + +/* Put 2 cards per row by making each exactly half the container. + We use a flex row on the parent for rows 2-4. + Since this is a grid parent we rely on the grid column trick: */ +#scoreboard > div > div:nth-child(2) { + grid-column: 1; + border-right: 5px solid #fff; + border-bottom: 5px solid #fff !important; +} +#scoreboard > div > div:nth-child(3) { + grid-column: 2; + border-bottom: 5px solid #fff !important; +} +#scoreboard > div > div:nth-child(4) { + grid-column: 1 / -1; /* avg guesses — full width row */ +} + +/* Adjust grid columns for the card pairing */ +#scoreboard > div { + grid-template-columns: 1fr 1fr; + grid-template-areas: + "handle handle" + "header header" + "c1 c2" + "c3 c3" + "buttons buttons"; +} + +#scoreboard > div > div:nth-child(1) { + grid-area: header; +} +#scoreboard > div > div:nth-child(2) { + grid-area: c1; +} +#scoreboard > div > div:nth-child(3) { + grid-area: c2; +} +#scoreboard > div > div:nth-child(4) { + grid-area: c3; +} +#scoreboard > div > div:nth-child(5) { + grid-area: buttons; +} + +/* Gaps between cards via borders acting as gutters */ +#scoreboard > div > div:nth-child(2), +#scoreboard > div > div:nth-child(3), +#scoreboard > div > div:nth-child(4) { + border: none !important; + outline: 4px solid #ffffff; /* gutter colour */ +} + +/* ── Stat text inside each card ─────────────────────────────── */ +/* First child = the label text, second child = the value span */ +#scoreboard > div > div:nth-child(n + 2):nth-child(-n + 4) > div:first-child { + font-size: 0.68rem; + font-weight: 700; + text-transform: uppercase; + letter-spacing: 0.07em; + color: var(--text-muted, #6c757d); +} + +/* The value spans (id=total_*, id=average_*) */ +#scoreboard [id^="total_"], +#scoreboard [id^="average_"] { + font-size: 2rem; + font-weight: 700; + font-family: "Roboto Mono", monospace; + color: var(--accent-primary, #2c3e50); + /* Remove the badge pill look from before */ + background: none; + padding: 0; + border-radius: 0; + min-width: 0; + text-align: left; + line-height: 1; +} + +/* ── Button row ─────────────────────────────────────────────── */ +#scoreboard > div > div:nth-child(5) { + display: flex !important; + flex-direction: row !important; + align-items: center !important; + justify-content: flex-start !important; + gap: 10px !important; + padding: 12px 16px 28px !important; + border-top: 1px solid var(--border-subtle, #e9ecef) !important; + border-bottom: none !important; + background: #ffffff; +} + +#scoreboard #play_again, +#scoreboard #quit_game { + padding: 13px 0; + font-size: 1rem; + font-weight: 600; + border: none; + border-radius: 8px; + cursor: pointer; + transition: + opacity 0.15s, + transform 0.1s; +} + +#scoreboard #play_again { + flex: 1; + background: var(--bg-header, #2c3e50); + color: #ffffff; +} + +#scoreboard #quit_game { + width: 90px; + background: var(--bg-hover, #e9ecef); + color: var(--text-main, #212529); +} + +#scoreboard #play_again:hover { + opacity: 0.85; +} +#scoreboard #quit_game:hover { + opacity: 0.75; +} + +/* ── Desktop: centred modal ─────────────────────────────────── */ +@media (min-width: 601px) { + #scoreboard { + align-items: center; + } + + #scoreboard > div { + border-radius: 16px; + max-width: 420px; + animation: sb-pop 0.25s cubic-bezier(0.34, 1.1, 0.64, 1) both; + } + + @keyframes sb-pop { + from { + transform: scale(0.92); + opacity: 0; + } + to { + transform: scale(1); + opacity: 1; + } + } + + #scoreboard > div > div:nth-child(5) { + padding-bottom: 20px !important; + } +} + +/* ── Mobile overrides ───────────────────────────────────────── */ +@media (max-width: 600px) { + .form_container { + padding: 1rem; + margin: 0.5rem; + } + + #game_container { + top: 0; + left: 0; + position: fixed; + z-index: 1000; + } + + #site-header, + footer, + #guesses, + #guess_letter_container { + display: none; + position: absolute; + z-index: -9999; + } } diff --git a/html/word-guesser/index.html b/html/word-guesser/index.html index 755af7b..12909b8 100644 --- a/html/word-guesser/index.html +++ b/html/word-guesser/index.html @@ -10,7 +10,7 @@
Please enter a single alphabetical character (A-Z) into the input - box belowand and click "Guess" to see if the letter + box below and and click "Guess" to see if the letter exists in the hidden word.