/* base css file — desktop first.

The selectors outside the media queries are the desktop layout, targeting viewports of
1200px and wider. They also act as the fallback every narrower breakpoint starts from,
so a property left unset in a media query keeps its desktop value.

The media queries at the bottom of this file handle everything below 1200px. They are
ordered widest to narrowest and each one overrides both the desktop base and any wider
breakpoint above it. Adding a rule to a narrow block therefore never affects wider
screens, but adding one to a wide block does affect every screen below it.

Those blocks come in two groups, one per axis, and the axes want opposite things — a
narrow portrait phone can spend vertical space to save horizontal space, while a short
landscape phone must do the reverse. So each group owns different properties:

  width blocks   horizontal compaction: card width, wrapping, column sizing
  height blocks  vertical compaction, including undoing any vertical cost a width
                 block introduced (e.g. stacking a row into a column)

The height group comes last in the file so it wins when a viewport matches both — which
a small window does. Do not reach for (orientation: landscape) as a substitute: it only
means width > height, so it is true of nearly every desktop monitor and tells you
nothing about size.
*/

/* Card geometry. These two values decide how wide the whole board is, so the width media
   queries scale the layout by overriding them here rather than by touching .cardBox,
   .tableauColumn or .tableauCont individually.

   A tableau column is sized by the card it holds — see .tableauColumn — and .cardBox is
   content-box, since nothing in this file sets box-sizing on it (only .feedback and the bottom
   buttons do, and neither is part of the board). So one column is
   card + horizontal padding + border + margin, and the board is eight of those:

     90 + 14*2 + 1*2 + 1*2  = 122px per column
     122 * 8 + 10 + 2       = 988px of board   (10 .tableauCont padding, 2 border)

   .tableauCont has no flex-wrap, so whatever this works out to must stay under the
   narrowest viewport the breakpoint serves or the board overflows horizontally. Allow
   ~20px for a classic scrollbar.

   Override both together in a media query. Setting one and letting the other inherit picks
   up whatever the next block up left behind, which is not usually the base value. */
:root {
  --card-w: 90px;
  --card-pad-x: 14px;

  /* How far each tableau card is pulled up over the one above it — see the fan rules under
     .tableauColumn. Vertical, so it belongs to the height blocks rather than the width ones: a
     short viewport can deepen the fan here to trade card face for stack height. Keep it below the
     card's own height or a column collapses into a single stack. */
  --card-fan: 5px;
}

a {
  text-decoration: none;
  font-weight: bold;
}
body {
  margin-left: 0;
  margin-right: 0;
  /*background-color: #843a2f;*/
  font-family: Verdana, Arial, Helvetica, sans-serif;
}

.suit{
  margin-left: auto;
}

.cardBox {
  padding: 4px var(--card-pad-x);
  width: var(--card-w);
  min-height: 30px;
  height: auto;
  border: 1px solid black;
  border-radius:5px;
  margin: 1px;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
}

.suitLargeCont {
  flex-basis: 100%;
  display: flex;
  justify-content: center;
  margin-top: 4px;
  width: 80px;
  /* Sized from --card-w so the badge follows the card when a width block scales it. The
     ratio is the original 80px expressed against the original 90px card, so this is exactly
     80px at the default and needs no per-breakpoint override. Note that width above is
     already inert on the main axis — flex-basis: 100% wins — so the badge is as wide as the
     card's content box regardless. */
  height: calc(var(--card-w) * 8 / 9);
  background-color: #f0f0f0;
  border-radius: 15px;
}

.suitLarge {
  /* As with .suitLargeCont height: the original 70px as a ratio of the original 90px card,
     so the glyph scales with --card-w instead of overflowing a narrowed badge. */
  font-size: calc(var(--card-w) * 7 / 9);
  display: flex;
  justify-content: center;
  align-items: center;
}

.freecellCont {
  display: flex;
  flex-wrap: wrap;
}

.foundationPilesCont {
  display: flex;
  flex-wrap: wrap;
}

.foundationPileEmptySuit {
  font-size: 24px;
  margin-left: auto;
}

.topPilesCont {
  display: flex;
  justify-content: center;
  align-items: flex-start;
  margin-bottom: 10px;
}

.topPilesDivider {
  padding-top: 2px;
}

.tableauCont {
  border-radius: 5px;
  /* border and background-color are written inline from themeObj — see Board.jsx. */
  display: flex;
  justify-content: center;
  padding: 5px;
  width: fit-content;
  margin-left: auto;
  margin-right: auto;
  min-height: 260px;

  /*background-color: #f4da01;*/
  /*background-image: url('/img/doors_yellowbg_lawoman.jpg');*/
  /*background-repeat: no-repeat;*/
  /*background-position: center;*/
  /*background-size: contain;*/

}

.tableauColumn {
  display: flex;
  flex-direction: column;
  /* Deliberately no min-width. The column is a flex item, so its automatic minimum size
     is already the outer width of the .cardBox it contains, and an empty column still
     renders a placeholder .cardBox — the floor is redundant in every state. Worse, an
     explicit value below that width replaces the automatic minimum with a smaller one,
     which lets the column squash under a constrained .tableauCont while the cards inside
     overflow it. Size the column by sizing .cardBox. */
}

/* THE TABLEAU FAN
   Each card in a column laps over the bottom of the one above it, so a long column costs far
   less height than tiling the cards would.

   The pull-up is scoped to a card that follows another card in a tableau column, which is what
   keeps the top of the column where it belongs: the first card in every column keeps the plain
   1px margin from .cardBox, so the gap to the top border is .tableauCont's 5px padding plus that
   1px in every view — .tableauCont's padding is 5px at the base and restated as 5px in the phone
   block, and no height block touches it, so the 6px holds everywhere without a per-breakpoint
   rule. This is also why the negative margin cannot live on .cardBox itself: that reaches the
   first card of each column, and the freecells and foundation piles besides, pulling all of them
   up out of their containers.

   An empty column renders exactly one placeholder .cardBox, so the sibling selector never
   matches it and empty columns keep their full height.

   position: relative is what makes the overlap legible. Overlapping in-flow siblings paint in two
   passes — every background first, then every text run — so without it the covered card's rank
   and suit show through the face of the card in front. Positioned cards paint as whole units
   instead, and with z-index left at auto they stack in document order, meaning each card lands on
   top of the one above it: exactly the direction a fan wants. .feedback carries z-index: 10 to
   stay above them. */
.tableauColumn .cardBox {
  position: relative;
}

.tableauColumn .cardBox + .cardBox {
  margin-top: calc(var(--card-fan) * -1);
}

.emptyTableauCard {
  background-color: #f0f0f0;
  border: 1px dashed #aaa;
  cursor: pointer;
}

/* Applied to the empty-column placeholders only while the won-game reward image is showing on
   .tableauCont. visibility rather than display, so each column keeps its width and the board holds
   its shape behind the image instead of collapsing to nothing. */
.hiddenTableauCard {
  visibility: hidden;
}

.playingCard {
  background-color: #ffffff;
  cursor: pointer;
}

.selectedCard {
  background-color: #cccccc;
  cursor: pointer;
}

.errorCard {
  background-color: #ffcccc;
}

/* Marks a card the board is about to auto-play to a foundation pile. Two 0.25s pulses read as a
   flash rather than a fade; the total must stay equal to autoMoveFlashSeconds in Board.jsx, which
   is how long the card is left in place before it moves. */
.flashCard {
  background-color: #cbc3e3;
  animation: cardFlashPurple 0.25s ease-in-out 2;
}

/* One half of the rank-mismatch sequence: the card being moved, then the card it was aimed at.
   Red rather than the purple above, because purple already means "this is on its way to a
   foundation" and the two must not be mistaken for each other. Duration matches
   errorFlashSeconds in Board.jsx, which is how long each half is held. */
.errorFlashCard {
  background-color: #ffcccc;
  animation: cardFlashRed 0.25s ease-in-out 2;
}

@keyframes cardFlashRed {
  0% { background-color: #ffffff; }
  50% { background-color: #e04a4a; }
  100% { background-color: #ffffff; }
}

/* Transparent lid over the viewport while the endgame sweep runs, so nothing can be clicked or
   dragged out from under the cards mid-flight. Only mounted for the duration of the sweep.

   Fixed rather than absolute so it keeps covering the screen at any scroll position, and so its
   offsets resolve against the viewport instead of the page. The four offsets are spelled out
   rather than using inset, which the older end of the browserslist does not have.

   z-index has to clear .feedback's 10: .feedbackLayer is position: relative with z-index auto, so
   it opens no stacking context of its own and that 10 competes here at the root. */
.inputBlocker {
  position: fixed;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  z-index: 100;
  background: transparent;
  cursor: progress;
}

@keyframes cardFlashPurple {
  0% { background-color: #ffffff; }
  50% { background-color: #8a5cd6; }
  100% { background-color: #ffffff; }
}


/* One row of four while there is room for it. The buttons are border-box at 140px, so that is
   their whole outer width including border and padding, and three 8px gaps bring a row of four
   to 584px. The (width < 600px) block drops to two per row once that no longer fits. */
.bottomControls {
  margin-top: 20px;
  width: 100%;
  display: flex;
  flex-direction: row;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 8px;
}

.statsRow {
  display: flex;
  justify-content: center;
  gap: 8px;
  margin-top: 10px;
  margin-bottom: 4px;
}

/* The three boxes in the stats row are identical. box-sizing is set here so the 100px is the whole
   box, padding and border included, rather than 100px of text plus 22px of trim. */
.timerBox,
.movesBox,
.howToPlay {
  box-sizing: border-box;
  width: 100px;
  padding: 10px;
  border: 1px solid #ccc;
  background-color: #f9f9f9;
  font-size: 15px;
  text-align: center;
}

/* The four bottom buttons, matched by element rather than by their class names. Those names
   used to be listed twice over, in two rules that each set a different half of the same
   button; they stay on the markup as hooks, and .bottomControls contains nothing else.

   box-sizing is set explicitly rather than left to the UA stylesheet, which does make buttons
   border-box, because the one-row arithmetic over in .bottomControls depends on 140px being
   the outer width. */
.bottomControls button {
  width: 140px;
  box-sizing: border-box;
  padding: 10px 16px;
  font-size: 14px;
  border: 1px solid #000;
  border-radius: 10px;
  background-color: #fff;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.4);
  cursor: pointer;
}

/* Pressed and hovered share one look: grey, and flat where the shadow was. box-shadow is not
   part of layout, so dropping it shifts nothing around it. */
.bottomControls button:active {
  background-color: #ccc;
  box-shadow: none;
}

/* The hover half sits behind a capability query. Touch browsers keep :hover on the last thing
   tapped, so unguarded this would leave a button stuck grey after every press; :active is
   outside it, and is what gives touch its press feedback. A capability query is not a
   breakpoint, so it belongs next to the rule it modifies rather than in the width groups at
   the bottom of this file. */
@media (hover: hover) {

  .bottomControls button:hover {
    background-color: #ccc;
    box-shadow: none;
  }

}

.debugBox {
  display: none;
  margin: 20px auto;
  width: 280px;
  padding: 8px;
  border: 1px solid #bbb;
  background-color: #f5f5f5;
  font-family: monospace;
  font-size: 13px;
}

.tipsBox {
  margin: 20px auto;
  width:260px;
  padding: 10px;
  border: 1px solid #ccc;
  background-color: #f9f9f9;
  font-size:18px;
  text-align:center;
}

/* Wraps the tableau in App.jsx to give .feedback something to anchor to.

   fit-content shrinks this to the tableau, which lets the overlay cap itself at the board's
   width with a plain max-width: 100% instead of restating the column arithmetic from :root.
   The tableau is the only in-flow child — the overlay is absolute — so this tracks the board
   at every breakpoint on its own. The auto margins take over the centering .tableauCont used
   to do for itself; its own auto margins now resolve to zero inside this box. */
.feedbackLayer {
  position: relative;
  width: fit-content;
  margin-left: auto;
  margin-right: auto;
}

/* A dismissible layer over the top of the board, not a row in the stack. Being out of flow
   is the point: as an in-flow element this reserved 28px plus a 10px margin at all times and
   shoved the whole board down and back up as messages came and went.

   z-index is not needed against the cards today, since a positioned element already paints
   above static siblings. It is here for the tableau fan noted at the bottom of this file,
   which gives the cards position: relative and would otherwise let them cover this. */
.feedback {
  position: absolute;
  z-index: 10;
  top: 10px;
  left: 0;
  right: 0;

  /* Shrink to the message, then center. 100% here is the tableau's width, not the viewport's,
     because .feedbackLayer shrinks to the board — so the overlay never outruns the board it
     covers, at any breakpoint, without a media query.

     The 20px comes off the cap rather than going on as margins: the auto margins below
     already center the box, so subtracting the full inset once leaves 10px of board showing
     down each side. A fixed value rather than a percentage on purpose — 5% a side would be
     49px at the 988px board and 16px at the 316px one, which reads as a different design at
     each breakpoint. */
  width: fit-content;
  max-width: calc(100% - 20px);
  margin-left: auto;
  margin-right: auto;

  /* The only border-box element in this file. It has to be, because max-width is a
     percentage and the padding below would otherwise push the box past that cap. */
  box-sizing: border-box;

  /* Right padding clears the close button: its 4px inset, its 48px box, then the same 12px
     gap the other sides use. Every value here is double what it was. */
  padding: 16px 64px 16px 24px;

  /* Room for the close button's 48px plus its insets. A one-line message on its own would
     leave the button hanging past the bottom edge. */
  min-height: 56px;

  border: 1px solid #000;
  border-radius: 10px;
  background-color: #fff;
  color: #000;

  display: flex;
  align-items: center;
  justify-content: center;
  text-align: center;

  /* The overlay covers the top row of tableau cards, and messages arrive mid-interaction in a
     tap-to-move game, so a solid box would swallow taps on those cards for five seconds. Let
     pointer events through the box and re-enable them on the close button only. Side effect:
     the message text cannot be selected. */
  pointer-events: none;
}

.feedbackClose {
  position: absolute;
  pointer-events: auto;

  /* Inset from the corner rather than flush to it, so this radius and the box's own 10px do
     not sit inside one another. The overlay's right padding accounts for the 4px. */
  top: 4px;
  right: 4px;

  /* Square target; the glyph is centered by the flex centering below, so the box sizes for
     the thumb without moving the x off the corner. At 48px this clears the usual 44px touch
     minimum on its own, which is why there is no longer a phone-specific override. */
  width: 48px;
  height: 48px;
  padding: 0;
  border: 1px solid #000;
  border-radius: 10px;
  background: none;
  color: #000;
  font-size: 36px;
  line-height: 1;
  cursor: pointer;

  display: flex;
  align-items: center;
  justify-content: center;
}

/* MEDIA QUERIES
Ordered widest to narrowest. Every block below matches whenever a narrower one does,
so a rule in a later block always wins over the same rule in an earlier one.

The bounds use range syntax — (width < 1200px) — rather than (max-width: 1199.98px).
Both keep the bound exclusive so a viewport of exactly 1200px stays on the desktop base,
but the fractional form leaves a dead zone: a 1199.99px viewport (reachable via browser
zoom or a fractional device pixel ratio) matches neither. Range syntax has no gap.
Requires Chrome 104+ / Safari 16.4+ / Firefox 104+.
*/

/* Small desktop / large tablet. */
@media (width < 1200px) {

}

/* Tablet, portrait tablet, landscape phone.
   The desktop board needs 988px, so it no longer fits by the time this block applies and
   .tableauCont has no flex-wrap to save it.

   Sized for 768px, not for 992px: desktop-first means this block stays in force all the way
   down to where the next one takes over, so it has to fit the bottom of its own range.

     72 + 8*2 + 1*2 + 1*2 = 92px per column
     92 * 8 + 10 + 2      = 748px of board, inside 768 with 20px left for a scrollbar */
@media (width < 992px) {

  :root {
    --card-w: 72px;
    --card-pad-x: 8px;
  }

}

/* Large phone / small tablet. Sized for 576px, the bottom of this block's range.

     54 + 5*2 + 1*2 + 1*2 = 68px per column
     68 * 8 + 10 + 2      = 556px of board, inside 576 with 20px left for a scrollbar

   54px is the narrowest the card can go while the rank and suit still sit side by side at
   the base 16px font — a two-character rank plus a glyph needs roughly 34px of the 54. */
@media (width < 768px) {

  :root {
    --card-w: 54px;
    --card-pad-x: 5px;
  }

}

/* Bottom controls, two per row. Its own breakpoint because the row of four needs 584px, which
   falls between the two blocks either side of this one; 600 leaves the ~20px of scrollbar
   slack the rest of the file allows for.

   This caps the container at two buttons and lets flex-wrap break after the second, rather
   than giving each button a 50% flex-basis. Keeping them at a fixed 140px means the pair reads
   as the same control at both layouts instead of stretching to half of whatever is available,
   and it keeps the button width in one place. Below 288px they stack one per row. */
@media (width < 600px) {

  .bottomControls {
    max-width: 288px;
    margin-left: auto;
    margin-right: auto;
  }

}

/* Phone. */
@media (width < 576px) {

  /* Both tokens have to be set here, not just the width. This block used to hard-code
     width: 6px and inherit the base 14px padding for a 38px card. Once the width blocks
     above began overriding --card-pad-x, that inheritance became 5px from the 768 block and
     the card silently dropped to 20px:

     6 + 14*2 + 1*2 + 1*2 = 38px per column, the footprint this block has always had
     38 * 8 + 10 + 2      = 316px of board

     316px inside a 320px viewport is only 4px of slack, which holds because mobile
     scrollbars are overlays and take no layout width. It is tight because of the 6px width
     plus wide padding, not by design — see the note on .tableauColumn. */
  :root {
    --card-w: 6px;
    --card-pad-x: 14px;
  }

  #root {
    width: 100%;
  }

  .cardBox {
    flex-wrap: nowrap;
    flex-direction: column;
    justify-content: center;
    /* Pin the box to its occupied height so filling a slot never resizes the row.

       flex-direction: column above gives the rank and the suit a line each, so an occupied
       card holds two lines of the base 16px font — about 36px, past the base 30px floor.
       That made an occupied box 46px tall against an empty box's 40px, and because
       .freecellCont and .foundationPilesCont leave align-items at its default of stretch,
       the tallest box set the row height and dragged the empty ones up with it: dropping
       one card visibly grew all four cells.

       Raising the floor to the occupied height makes both states 46px. Stretch then acts as
       a safety net rather than a surprise — if a platform's fonts make the two lines taller
       than 36px, every box in the row still matches, just at a slightly greater height.

       This applies to every .cardBox, so it also squares the empty tableau slot with the
       cards below it; those were 40px against 46px for the same reason. */
    min-height: 36px;
  }

  /* Keep after .cardBox. This rule already wins on specificity, so source order was not
     load-bearing before — but the two disagreeing made the block unsafe to reorder.
     Centering is inherited from the rules above.

     Zero the horizontal padding only. This used to be padding: 0, which also dropped the
     4px top and bottom that base .cardBox gives every other card, leaving the foundation
     piles 8px shorter than the freecells sitting next to them. The vertical value has to
     track the base; only the horizontal one is free to collapse to the 34px slot. */
  .cardBox.FoundationPile {
    width: 34px;
    padding: 4px 0;
  }

  .foundationPileEmptySuit {
    margin: 0 auto;
  }

  .tableauCont {
    min-height: auto;
    border-radius: 10px;
    padding: 5px;
  }

  /* Both groups fit on one row, so this no longer stacks them. Freecells and foundations are
     four 38px cards each — the foundation's narrower 34px card is padded back to the same
     outer width — so the pair needs 304px of the 320px this block is sized for.

     The 16px left over lands in the auto margins on .freecellCont and .foundationPilesCont
     below: four auto margins split it evenly, giving 4px outside each group and 8px between
     them. Below about 304px those margins collapse to zero and the two groups shrink instead,
     wrapping their cards onto a second line rather than overflowing. */
  .topPilesCont {
    display: flex;
    flex-direction: row;
    align-items: center;
    justify-content: center;
    width: 100%;
  }

  .freecellCont {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    width: fit-content;
    margin-left: auto;
    margin-right: auto;
  }

  .foundationPilesCont {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    width: fit-content;
    margin-left: auto;
    margin-right: auto;
  }

  .topPilesDivider {
    display: none;
  }

  /* No .bottomControls rule here. It restated the base declaration by declaration, so once the
     base became a wrapping row this block was the thing forcing a single column back on the
     narrowest screens — overriding the two-per-row cap set at 640px, since this block is
     later in the file. The base plus that cap covers this width. */

  .tipsBox {
    display: block;
    width: fit-content;
    margin-left: auto;
    margin-right: auto;
    text-align: center;
  }

  .suitLargeCont {
    display: none;
  }

  .suit {
    margin-left: 0;
  }

  .debugBox {
    width:300px;
  }

}

/* HEIGHT QUERIES
Last in the file, so these override the width blocks above whenever both axes match.

Height is the binding constraint the width blocks cannot see. A landscape phone reports
roughly 844x390: wide enough that only the widest width block applies, but far too short
for the layout the desktop base hands it. The vertical stack — top piles, tableau, stats
row, controls, tips, debug — runs well past 700px. This block trims the chrome.

The tableau is now fanned at every breakpoint rather than only here — see the fan rules under
.tableauColumn — which takes --card-fan off each card after the first in a column. A long column
can still outgrow a short viewport, and the lever for that is --card-fan in :root: raise it in
this block to lap the cards further over one another. Card height is the ceiling.

If you add a height cap here, use dvh rather than vh. Mobile browsers resolve vh against
the expanded viewport, and on a 390px-tall screen the collapsing URL bar is a large
enough share of that to overflow.
*/

/* Landscape phone, split-screen tablet, short desktop window. */
@media (height < 600px) {

  /* No .topPilesCont override here any more. It existed to undo the portrait phone block's
     flex-direction: column on a small landscape phone — an SE in landscape is 568x320, inside
     both bounds — and that block now lays the top piles out as a row itself, so there is
     nothing left to undo on either axis. */

  /* The 80px suit badge is the single largest piece of chrome in the vertical stack, and
     it is decoration — the card already shows its suit. The portrait phone block hides it
     too; this covers the wider landscape phones that block never reaches. */
  .suitLargeCont {
    display: none;
  }

  /* Non-essential to play. Reinstate either one if you would rather scroll for it. */
  .tipsBox,
  .debugBox {
    display: none;
  }

  /* Let the board shrink to its cards. The 260px floor is dead weight once columns are
     short, and it cannot help while they are long. */
  .tableauCont {
    min-height: auto;
  }

}