/* system/apps/wordflex/styles.css
 *
 * This app's own business, nothing else's (see start-here.md's three-
 * CSS-tiers note). Fills the shell's own card directly -- no border/
 * background/radius of its own, matching every other app. Class names
 * still say "scrabble-*" throughout (this file and app.js) -- kept as-
 * is on the WordFlex rename rather than a pure find/replace across
 * both files for no functional gain.
 *
 * One base font-size on the app's own top-level wrapper + a blanket
 * `font: inherit` on native controls, from the start -- see
 * start-here.md's "Native form controls don't inherit font-size" gotcha
 * (bit Manage Repo Files badly once; applying the fix up front here
 * rather than waiting for it to visibly break first).
 *
 * The .scrabble-tb-* rules near the top style content that does NOT
 * live inside .scrabble-app at all -- it's injected into the shell's
 * own title bar via ctx.chrome.setTitleBarExtra() (see AppShell.js and
 * this app's app.js). Still fair game for this stylesheet: panel
 * content and, now, title-bar-extra content are both just DOM this
 * app's markup ends up in, with every app stylesheet linked globally
 * (see start-here.md) -- no container-boundary scoping either way.
 */

.scrabble-tb-chip {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 2px 8px;
  border-radius: 999px;
  font-size: var(--fs-2xs);
  font-weight: 600;
  color: var(--chip-color);
  background: color-mix(in srgb, var(--chip-color) 14%, transparent);
}
.scrabble-tb-chip-turn {
  box-shadow: 0 0 0 2px color-mix(in srgb, var(--chip-color) 65%, transparent);
}
.scrabble-tb-bag {
  font-size: var(--fs-2xs);
  color: var(--slate);
}

/* Sept 2026 bugfix -- Ron's own root-cause find, nailed via three
   screenshots and a process of elimination: #appMainContent (index.html)
   is `display:flex; flex-direction:column; align-items:center;` --
   for a COLUMN flex container, align-items governs the CROSS axis,
   which is WIDTH. `center` (not the flex default, `stretch`) means a
   child with no explicit width of its own is sized to its own
   shrink-to-fit (max-content) width and then centered, not stretched
   to fill the available space. .scrabble-app never set a width, so
   its rendered width was whatever its widest DETERMINISTIC line of
   content happened to demand at that exact moment: with no player
   selected, only the board's own width formula and a short hint line
   are in play, so it read close to full width; Player 1's empty
   status line left only the rack's own small intrinsic width as the
   widest candidate, shrinking everything down to that; Player 2's
   long "Not your turn -- X is playing" sentence became the new
   widest candidate, and the board matched IT instead. Fixed the
   right way: give .scrabble-app an explicit width so it always fills
   #appMainContent regardless of what any sibling's text happens to
   be, opting this one app out of the shared shrink-to-fit/centering
   behavior other, genuinely content-sized apps still rely on -- a
   local, scoped fix in this app's own stylesheet, not a change to
   the shared #appMainContent rule every other app also depends on. */
.scrabble-app {
  display: flex;
  flex-direction: column;
  width: 100%;
  height: 100%;
  min-height: 0;
  gap: 10px;
  font-size: var(--fs-sm);
  font-family: var(--font-sans);
  color: var(--ink);
}
.scrabble-app select,
.scrabble-app input,
.scrabble-app textarea,
.scrabble-app button {
  font: inherit;
}

/* ---------- header: turn/bag status ----------
   Scores and the player name used to live here as their own row; both
   moved out (scores dropped from the visible UI, the player's name/turn
   state now lives in the shell's own title bar via ctx.chrome.setTitle,
   see updateTitle() in app.js) so this is down to one compact status
   line -- kept deliberately small since board real estate is the
   priority (Ron's item 10). */

.scrabble-status {
  flex: 0 0 auto;
  color: var(--slate);
  font-size: var(--fs-2xs);
  line-height: 1.2;
  min-height: 1.2em; /* reserve the line's height so nothing shifts when it empties out */
}
/* The live points-preview readout (Ron: only shown for a currently-
   legal placement -- see renderStatus() in app.js). */
.scrabble-status-points {
  color: #1c7c3f;
  font-weight: 700;
}
/* "Not your turn" -- Ron's report: a player kept mistaking their own
   freshly-dealt rack for something actionable right now. Deliberately
   louder than the plain slate status line (background chip, not just
   colored text) since it's meant to be impossible to miss with a
   whole rack of tiles sitting in front of you. */
.scrabble-status-wait {
  color: #9a5b12;
  font-weight: 700;
  background: color-mix(in srgb, #e3a63a 18%, transparent);
  padding: 3px 8px;
  border-radius: 6px;
  display: inline-block;
}

/* ---------- board ---------- */

.scrabble-board-wrap {
  position: relative;
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
  touch-action: none; /* we own pinch/pan ourselves -- see app.js */
  background: color-mix(in srgb, var(--line) 40%, transparent);
  border-radius: 10px;
  /* Sept 2026 bugfix -- Ron, testing on a laptop: "the board doesn't
     make itself fit on the screen when the screen is wider than it is
     tall." The board's own width formula (below) used to cap out at
     92vh -- 92% of the FULL WINDOW height -- as a stand-in for "however
     tall this wrap actually is." That's a fine approximation on a
     phone, where the title bar/status/rack/toolbar around the board
     are all a small, fairly fixed slice of a TALL window. On a wide,
     short window (a laptop, landscape), that same chrome eats a much
     bigger relative share of a much shorter window, so board-wrap's
     ACTUAL available height ends up well under 92% of the full window
     -- but the formula never knew that, so the board (a fixed square
     via aspect-ratio, so width and height move together) sized itself
     too tall and overflowed straight out of the wrap, top and bottom.
     `container-type: size` turns this element into a query container,
     so a descendant can size itself in cqw/cqh -- percentages of THIS
     element's own actual width/height, not the page's -- which is
     what board-wrap's real available space actually is, on any screen
     shape. */
  container-type: size;
}

.scrabble-board {
  display: grid;
  grid-template-columns: repeat(15, 1fr);
  grid-template-rows: repeat(15, 1fr);
  /* min(100cqw, 100cqh, 640px) -- the largest square that fits inside
     board-wrap's own actual box, capped at 640px -- replaces the old
     min(100%, 92vh, 640px), which only ever accounted for width
     correctly; see the container-type comment above for why 92vh
     wasn't a safe stand-in for "board-wrap's own height." */
  width: min(100cqw, 100cqh, 640px);
  aspect-ratio: 1 / 1;
  gap: 1px;
  background: var(--brand-deep);
  padding: 3px;
  border-radius: 6px;
  transform-origin: center center;
}
/* Sept 2026: will-change now toggles on/off with the actual gesture
   (see the pointerdown/endPinchPointer handlers in app.js) instead of
   sitting on permanently -- Ron: tiles/letters looked blurry once
   zoomed in. Promoting the board to its own composited layer at ALL
   times meant it could settle back to a resting scale without ever
   getting cleanly re-rasterized at that resolution on some browsers;
   only asking for the layer while a pinch/pan is actually live, then
   dropping it right after, keeps the board crisp at rest. */
.scrabble-board-gesture {
  will-change: transform;
}

.scrabble-cell {
  position: relative;
  background: var(--card);
  display: flex;
  align-items: center;
  justify-content: center;
  min-width: 0;
  min-height: 0;
  overflow: hidden;
}
.scrabble-cell::before {
  content: attr(data-premium-label);
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--font-mono);
  /* Bigger + bolder (Ron's item: "larger text" on point squares), now
     that PREMIUM_LABEL (app.js) reads "2W"/"3L" instead of "DW"/"TL" --
     two characters either way, so the same clamp still fits. */
  font-size: clamp(7px, 2.4vw, 13px);
  font-weight: 800;
  color: color-mix(in srgb, var(--ink) 65%, transparent);
  pointer-events: none;
}
.scrabble-cell-tw { background: #d9704f; }
.scrabble-cell-tl { background: #4f8fd9; }
.scrabble-cell-dw { background: #e3a6a6; }
.scrabble-cell-dl { background: #a8cdf0; }
.scrabble-cell-star {
  background: var(--amber);
}
.scrabble-cell-star::before {
  content: "★";
  font-size: clamp(7px, 2.4vw, 14px);
  color: color-mix(in srgb, var(--ink) 70%, transparent);
}

/* Once a premium square is covered by a tile, that tile borrows the
   square's own color for ITS border -- a lingering clue about what's
   underneath even once the text label is hidden (Ron's ask). Higher
   specificity than .scrabble-tile's own base border, no !important
   needed since these are more specific selectors. */
.scrabble-cell-tw .scrabble-tile { border-color: #d9704f; }
.scrabble-cell-tl .scrabble-tile { border-color: #4f8fd9; }
.scrabble-cell-dw .scrabble-tile { border-color: #c96b6b; }
.scrabble-cell-dl .scrabble-tile { border-color: #5f96c9; }
.scrabble-cell-star .scrabble-tile { border-color: color-mix(in srgb, var(--amber) 70%, #4a3418); }

/* Sept 2026, take 3 -- Ron: "there is currently no way to tell which
   tiles are being placed by the current player, and which tiles have
   already been locked in." Take 1 put a thick border on each pending
   TILE individually, squeezing the letter/number inward. Take 2 tried
   an inset box-shadow on the CELL instead (to trace the outside of the
   whole pending GROUP, not each tile, the way NYT does it) -- but Ron
   caught that it rendered NOTHING at all, and he was right: box-shadow
   is part of an element's own background layer, painted BEHIND its
   children -- and the tile inside fills the cell 100% with its own
   opaque background, so the shadow was being computed correctly every
   render and just sitting invisibly underneath the tile the entire
   time.
   Take 3: a dedicated ::after overlay instead of trying to paint on
   the cell's own background. Generated content paints AFTER an
   element's real children in the normal painting order -- i.e. on TOP
   of the tile, not behind it -- so this is the one that actually
   shows. position:absolute + inset:0 keeps it exactly matching the
   cell's own bounds (never clipped by the cell's own overflow:hidden,
   since it never extends past those bounds), and pointer-events:none
   keeps it from ever intercepting a drag/tap meant for the tile
   underneath. Each side's color comes from a CSS custom property set
   per cell in renderBoard() (isPendingMine() decides, per edge,
   whether that side borders something OTHER than one of this same
   player's own other pending cells -- committed tile, empty cell, or
   the board edge all count as "outside" the group) -- which edges are
   "outside" depends on that cell's own neighbors, so it can't be one
   static rule the way most of this file's other selectors are. */
.scrabble-cell-pending-mine {
  z-index: 1;
}
.scrabble-cell-pending-mine::after {
  content: '';
  position: absolute;
  inset: 0;
  pointer-events: none;
  border-radius: 3px;
  border-style: solid;
  border-width: 3px;
  border-top-color: var(--pm-top, transparent);
  border-right-color: var(--pm-right, transparent);
  border-bottom-color: var(--pm-bottom, transparent);
  border-left-color: var(--pm-left, transparent);
}
.scrabble-cell-pending-theirs .scrabble-tile {
  opacity: 0.45;
}
/* Sept 2026, Ron: "highlight each square so I know where the tile is
   going to drop", especially useful zoomed in where the ghost's own
   position can obscure exactly which cell is underneath it. Tracked
   in app.js's onDragMove()/setDragHoverCell() -- a plain inset outline
   is enough here since, unlike the pending-group outline above, this
   only ever highlights one cell at a time. */
.scrabble-cell-drop-target {
  box-shadow: inset 0 0 0 3px var(--brand);
  background: color-mix(in srgb, var(--brand) 16%, var(--card));
  z-index: 2;
}

/* ---------- tiles (rack + board) ---------- */

.scrabble-tile {
  position: relative;
  width: 100%;
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  background: linear-gradient(160deg, #f3dcb2, #e2bd85);
  border: 1px solid #b8925a;
  border-radius: 3px;
  box-shadow: 0 1px 0 rgba(0, 0, 0, 0.15), inset 0 1px 0 rgba(255, 255, 255, 0.5);
  color: #4a3418;
  font-family: var(--font-display);
  font-weight: 700;
  user-select: none;
  /* Sept 2026: likely explanation for the stray rounded blue ring Ron
     caught sticking to a just-dragged tile in a screenshot -- iOS
     Safari's own default tap-highlight overlay (a translucent blue-ish
     wash with rounded corners matching the element) on whatever was
     last touched, unrelated to any of this app's own CSS/JS. Standard
     fix for a touch-driven UI that doesn't want that system highlight
     competing with its own feedback (the drag ghost, the selection
     outline, etc.). */
  -webkit-tap-highlight-color: transparent;
}
.scrabble-tile-letter {
  /* Sept 2026: the previous bump ("even bigger than they are now")
     made the letter and the point-value number genuinely overlap on
     the board, especially zoomed in (Ron's screenshots). Backed the
     board's own max down slightly and nudged the letter up-and-left
     off dead-center -- real Scrabble tiles aren't centered either,
     they leave the bottom-right corner clear for the number. .scrabble-
     rack overrides this size below with its own, bigger clamp (rack
     tiles are read close-up, not across a zoomed-out board) but
     inherits this same nudge, which is harmless there too. */
  font-size: clamp(11px, 4vw, 20px);
  line-height: 1;
  transform: translate(-8%, -8%);
}
.scrabble-tile-value {
  position: absolute;
  right: 2px;
  bottom: 1px;
  font-family: var(--font-mono);
  font-weight: 700;
  font-size: clamp(6px, 1.8vw, 11px);
  /* A small translucent backing so the number stays legible even where
     a big letter's stroke reaches into its corner -- belt-and-
     suspenders alongside the letter's own nudge above, not a
     replacement for it. */
  background: rgba(255, 255, 255, 0.55);
  border-radius: 2px;
  padding: 0 1px;
  line-height: 1.15;
}
.scrabble-tile-blank .scrabble-tile-value {
  background: transparent; /* blanks render this span empty -- nothing to back */
}
/* Blank tiles get a bolder, distinctly-gold treatment + their own
   border color -- Ron wanted them to read as visually different, not
   just a slightly paler tan next to a real letter tile. */
.scrabble-tile-blank {
  background: linear-gradient(160deg, #ffe9a8, #f0c04d);
  border-color: #c99a1f;
  color: #6b4f0a;
}
.scrabble-tile-draggable {
  cursor: grab;
  touch-action: none;
}
.scrabble-tile-dragging-source {
  opacity: 0.25;
}
.scrabble-tile-ghost {
  position: fixed;
  z-index: 500;
  pointer-events: none;
  box-shadow: 0 6px 16px rgba(0, 0, 0, 0.35);
  transition: transform 0.08s ease-out;
}
.scrabble-tile-swappable {
  cursor: pointer;
}
.scrabble-tile-selected {
  outline: 3px solid var(--brand);
  outline-offset: 1px;
}

/* ---------- rack ----------
   Was two rows (a dashed zone with padding around a wrapping flex row)
   -- now a single fixed-width-slot grid sitting right above the
   toolbar, per Ron's item 7 ("no more than one row", "close to right
   above the toolbar"). RACK_SIZE (app.js) is 7, matching
   grid-template-columns below. */

.scrabble-rack-zone {
  flex: 0 0 auto;
  min-height: 0;
  padding: 2px 0;
}
.scrabble-hint {
  margin: 0;
  color: var(--slate-light);
  text-align: center;
  font-size: var(--fs-2xs);
}
.scrabble-rack {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  gap: 4px;
  width: 100%;
}
.scrabble-rack.hidden,
.scrabble-hint.hidden {
  display: none;
}
.scrabble-rack-slot {
  position: relative;
  aspect-ratio: 1 / 1;
  min-width: 0;
}
.scrabble-rack-slot:empty {
  border: 1px dashed color-mix(in srgb, var(--line) 70%, transparent);
  border-radius: 4px;
}
.scrabble-rack .scrabble-tile {
  width: 100%;
  height: 100%;
}
/* Rack tiles read close-up, not across a room the way board tiles do
   (the board's own clamp() below has to stay legible when the whole
   15x15 grid is zoomed out) -- so give the rack its own much larger,
   simpler letter size instead of sharing the board's clamp (item 5). */
.scrabble-rack .scrabble-tile-letter {
  font-size: clamp(18px, 8vw, 32px);
}
.scrabble-rack .scrabble-tile-value {
  font-size: clamp(8px, 2.2vw, 12px);
}

/* ---------- blank-tile letter picker ---------- */

.scrabble-blank-picker {
  position: absolute;
  inset: 0;
  z-index: 50;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(10, 12, 20, 0.5);
}
.scrabble-blank-picker.hidden { display: none; }
.scrabble-blank-picker-inner {
  background: var(--card);
  border-radius: 12px;
  padding: 16px;
  max-width: 320px;
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.3);
}
.scrabble-blank-picker-inner p {
  margin: 0 0 10px;
  font-size: var(--fs-sm);
  color: var(--ink);
  text-align: center;
}
.scrabble-blank-letters {
  display: grid;
  grid-template-columns: repeat(6, 1fr);
  gap: 6px;
}
.scrabble-blank-letter-btn {
  width: 40px;
  height: 40px;
  border-radius: 6px;
  border: 1px solid var(--line);
  background: linear-gradient(160deg, #f3dcb2, #e2bd85);
  color: #4a3418;
  font-weight: 700;
  font-family: var(--font-display);
}
.scrabble-blank-cancel {
  margin-top: 12px;
  width: 100%;
  padding: 8px;
  border-radius: 8px;
  border: 1px solid var(--line);
  background: var(--paper);
  color: var(--slate);
}

/* ---------- bookmark panel (rendered into ctx.panels' content) ----------
   Note: this DOM lives inside a panel, not #appMainContent, but panel
   content isn't style-scoped away from app stylesheets (they're all
   just linked in <head> -- see start-here.md), so these rules are
   still scoped by the .scrabble-bm-* prefix rather than relying on
   any container boundary. */

.scrabble-bm-panel {
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.scrabble-bm-empty {
  color: var(--slate-light);
  font-size: var(--fs-sm);
  text-align: center;
  padding: 16px 0;
}
.scrabble-bm-row {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px;
  border: 1px solid var(--line);
  border-radius: 8px;
}
.scrabble-bm-row-selected {
  border-color: var(--brand);
}
/* Currently-previewed row (tap-to-toggle -- see previewBookmark() in
   app.js) -- distinct from -selected (the trash-enabling tap target)
   since either or both can be true on the same row at once. */
.scrabble-bm-row-previewing {
  background: color-mix(in srgb, var(--brand) 12%, transparent);
  border-color: var(--brand);
}
.scrabble-bm-row-spent {
  opacity: 0.55;
}
.scrabble-bm-row-broken {
  opacity: 0.8;
}
.scrabble-bm-row {
  flex-wrap: wrap;
}
/* Rack line: one fixed-width cell per saved slot, gaps rendered as an
   empty cell -- Ron: "have all seven tiles in their actual positions...
   I use the gaps to show words or partial words." */
.scrabble-bm-rackline {
  display: flex;
  gap: 2px;
  flex: 1 1 auto;
  min-width: 140px;
}
.scrabble-bm-rackcell {
  width: 20px;
  height: 20px;
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 3px;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: var(--fs-xs);
}
.scrabble-bm-tile-letter {
  background: linear-gradient(160deg, #f3dcb2, #e2bd85);
  border: 1px solid #b8925a;
  color: #4a3418;
}
/* A referenced tile this bookmark can no longer find (swapped away,
   or the board cell it expected now holds something else) -- ghosted
   red rather than graying out the whole row (Ron's ask). */
.scrabble-bm-tile-ghost {
  background: transparent;
  border: 1px dashed #c0392b;
  color: #c0392b;
  opacity: 0.7;
}
/* Board lines: Ron's "cluster" notation -- each run of the board a
   monospace line, longest first, mixing uppercase (this bookmark's own
   tiles) with lowercase (any other already-committed tile sharing that
   run -- see Engine.bookmarkBoardLines' own header on what "lowercase"
   actually means here). */
.scrabble-bm-boardlines {
  flex: 1 1 100%;
  display: flex;
  flex-direction: column;
  gap: 2px;
  font-family: var(--font-mono);
  font-size: var(--fs-sm);
  font-weight: 700;
  color: var(--ink);
  letter-spacing: 1px;
}
.scrabble-bm-boardline {
  word-break: break-all;
}
.scrabble-bm-boardlines-empty {
  color: var(--slate-light);
  font-weight: 400;
  font-family: var(--font-sans);
  letter-spacing: normal;
}
.scrabble-bm-tag {
  flex: 0 0 auto;
  padding: 2px 8px;
  border-radius: 999px;
  font-size: var(--fs-2xs);
  font-weight: 600;
  background: var(--paper);
  color: var(--slate);
}
.scrabble-bm-tag-broken {
  background: color-mix(in srgb, #c0392b 14%, transparent);
  color: #c0392b;
}
.scrabble-bm-trash {
  flex: 0 0 auto;
  width: 36px;
  height: 36px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 8px;
  border: 1px solid var(--line);
  background: var(--paper);
  color: var(--slate-light);
}
.scrabble-bm-trash:not(:disabled) {
  color: #c0392b;
  border-color: #c0392b;
}

/* ---------- history panel ---------- */

.scrabble-hist-panel {
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.scrabble-hist-row {
  display: flex;
  justify-content: space-between;
  gap: 10px;
  padding: 8px;
  border: 1px solid var(--line);
  border-radius: 8px;
  font-size: var(--fs-sm);
}
.scrabble-hist-when {
  color: var(--slate-light);
  font-size: var(--fs-xs);
  flex: 0 0 auto;
}
.scrabble-hist-scores {
  color: var(--ink);
  font-weight: 600;
  text-align: right;
}

/* ---------- settings panel ---------- */

.scrabble-settings-panel {
  display: flex;
  flex-direction: column;
  gap: 4px;
}
/* Sept 2026 fix -- Ron: "please left align the entries". These used to
   be justify-content: space-between, so the checkbox sat at the far
   left edge and its label got pushed all the way to the right,
   leaving a big gap in between that read as messy, uncurated spacing
   -- not the same bug as the monospace-<p> one (see index.html), but
   easy to mistake for it since both show up as "too much space between
   things" in the same panel. Left-aligned now: checkbox, then its
   label, directly next to each other on the left, same order the
   markup already puts them in (the old order:-1 was redundant --
   checkbox was already first -- and is dropped along with it). The
   stepper row (Extra blanks) is the one exception that KEEPS space-
   between -- a label on the left and a +/- control on the right is the
   right shape for a stepper, not a bug to fix. */
.scrabble-settings-row {
  display: flex;
  align-items: center;
  justify-content: flex-start;
  gap: 10px;
  padding: 10px 4px;
  border-bottom: 1px solid var(--line);
  font-size: var(--fs-sm);
}
.scrabble-settings-row input[type="checkbox"] {
  width: 20px;
  height: 20px;
  flex: 0 0 auto;
}
.scrabble-settings-stepper {
  justify-content: space-between;
}
.scrabble-stepper {
  display: flex;
  align-items: center;
  gap: 10px;
}
.scrabble-stepper button {
  width: 32px;
  height: 32px;
  border-radius: 8px;
  border: 1px solid var(--line);
  background: var(--paper);
  color: var(--ink);
  font-size: var(--fs-md);
  font-weight: 700;
}
.scrabble-stepper button:disabled {
  opacity: 0.4;
}
.scrabble-stepper-value {
  min-width: 1.5em;
  text-align: center;
  font-weight: 700;
}
.scrabble-settings-soon-header {
  margin: 10px 0 0;
  color: var(--slate-light);
  font-size: var(--fs-xs);
  text-transform: uppercase;
  letter-spacing: 1px;
}
.scrabble-settings-row-soon {
  color: var(--slate-light);
}
