/* ===========================================================================
   The analyzer, reshaped for the iOS app.
   ===========================================================================

   The web analyzer is a board with a side panel, and on a phone that panel
   collapses into a stack of rows under the board: a move ticker, a step-arrow
   row, a header carrying two tabs plus four controls, a caption, and a "Back to
   game" button. Every one of them earns its place on a desktop. Together, on a
   390px screen, they leave the board about half the height it could have and
   give the player six places to look.

   This file is the app's answer: ONE row above the board (the evaluation, the
   number, and the two controls that change how the board is drawn), the board
   itself as large as the screen allows, two one-line player rows, and ONE bar
   at the foot of the screen holding every action - the same shape as the tab
   bar the player already knows from everywhere else in the app.

   Nothing here is loaded by the website: every rule is gated on
   `body.app-analyzer`, which js/analyzer-app.js sets only when Net.isNative()
   is true. The web analyzer is untouched.

   Companion: js/analyzer-app.js, which builds the two bars and keeps them in
   step with analysis.js. Read that file's header for how the two talk.
   ======================================================================== */

/* --- the two bars this file adds ---------------------------------------
   Real heights are published from JS (they depend on the safe-area inset,
   which CSS can read but cannot do arithmetic on across elements). These are
   the fallbacks used for the first paint, before the observer fires. */
body.app-analyzer {
  --aa-top-h: 56px;
  --aa-tab-h: 68px;
  /* The two seat rows plus the gaps around them. Kept here rather than inlined
     into the board calc so the seat padding below and this number can only ever
     be changed together. */
  --aa-seats-h: 68px;
}

/* =======================================================================
   1. What the analyzer screen stops showing
   =======================================================================
   The app's analyzer is one screen with one job, so everything that is a
   second way to do something already on it goes. Listed one per line with
   the reason, because "why is this hidden" is the question this file will
   be opened to answer. */

/* The site chrome. There is no room for a brand bar above a board, and the
   bottom bar leads out of here. */
body.app-analyzer.review-mode .topbar,
body.app-analyzer.review-mode .site-footer,
body.app-analyzer.review-mode .side-rail,
body.app-analyzer.review-mode .rail-brand,
body.app-analyzer.review-mode .streak-rail { display: none !important; }

/* The app's own Play/Puzzles/Bots/Ranks bar. Those are destinations, and this
   screen is not a destination - it is a thing you are doing. The analyzer's bar
   takes its place at the foot of the screen and leads back to the game. */
body.app-analyzer.review-mode #tabbar { display: none !important; }
/* ...and with it the room the page was reserving for it (tabbar.js puts
   `has-tabbar` on the body, which pads the page's foot). */
body.app-analyzer.review-mode.has-tabbar .app,
body.app-analyzer.review-mode.has-tabbar .layout { padding-bottom: 0 !important; }

/* The vertical eval bar beside the board. Replaced by the horizontal one in the
   top row - see section 2. */
body.app-analyzer.review-mode #eval-bar { display: none !important; }
/* The seat cards were being shifted right to stay centred on a board that the
   vertical bar had pushed off-centre. No bar, no offset. */
body.app-analyzer.review-mode .board-wrap .seat-bar { margin-left: 0 !important; }

/* Both move tickers. The strip is a horizontal scroller directly above a row of
   arrows that does the same stepping, and it is the single biggest block of
   height under the board. The arrows moved to the bottom bar; the moves
   themselves are in the Game review sheet. */
body.app-analyzer.review-mode .move-strip,
body.app-analyzer.review-mode .rv-strip { display: none !important; }

/* The old step-arrow row, the wall/rotate controls (nothing is placed on an
   analysis board through them) and the emote bar (nobody is here to chat). */
body.app-analyzer.review-mode #review-nav,
body.app-analyzer.review-mode .touch-controls,
body.app-analyzer.review-mode .emote-bar { display: none !important; }

/* The board's own corner flip chip: flip lives in the top row now. */
body.app-analyzer.review-mode .board-flip-btn { display: none !important; }

/* The home screen's furniture. Both of these are gated on `not(.in-game)`
   upstream, and review mode is not a game - so opening the analyzer from
   anywhere the body has not also been marked in-game (a shared game link, a
   profile's game list) drops the signed-out landing card straight onto the
   analysis board and the pitch section below it. They belong to the home
   screen; this screen is not it, whatever else the body happens to say. */
body.app-analyzer.review-mode .board-cta,
body.app-analyzer.review-mode .signup-pitch,
body.app-analyzer.review-mode .home-panel { display: none !important; }

/* --- the review panel ---------------------------------------------------
   It cannot simply be hidden: the Game review REPORT lives inside it, and on a
   phone that report is a full-screen fixed sheet. So the panel is reduced to a
   0x0 anchor that paints nothing and reserves nothing, its card stops being a
   card (display:contents), and the two views it holds are dealt with
   individually - the moves view goes, the report sheet stays and still works.

   Deliberately NOT pointer-events:none: the report sheet is a descendant and
   would inherit it, leaving a visible sheet that ignores every tap. A 0x0 box
   cannot intercept anything anyway. */
body.app-analyzer.review-mode #review-panel {
  position: absolute; width: 0; height: 0;
  padding: 0; margin: 0; border: 0; gap: 0;
  background: none; box-shadow: none; overflow: visible;
}
body.app-analyzer.review-mode #review-panel .play-card { display: contents; }
/* The header row (two tabs + eval + gear + engine switch): its controls are in
   the top row now, and its tabs address views this screen does not show. */
body.app-analyzer.review-mode .rv-tabs,
/* The move list view - the report sheet carries the moves. */
body.app-analyzer.review-mode #rv-moves-view,
/* "Back to game" - now the right-hand action in the bottom bar. */
body.app-analyzer.review-mode .rv-card > .controls { display: none !important; }

/* =======================================================================
   2. The top row: the evaluation, the number, and the board's controls
   =======================================================================
   Above the board AND above the player rows, so the first thing on the screen
   is who is winning and by how much. The bar flexes to fill whatever the two
   icon buttons leave, which keeps the readout and the controls at the two ends
   of one line instead of on two rows. */
.aa-top {
  display: none;                      /* only ever shown in review mode */
  position: relative;
  align-items: center;
  justify-content: center;
  width: 100%;
  box-sizing: border-box;
  padding: 6px 0 5px;
  padding-top: calc(6px + env(safe-area-inset-top));
}
body.app-analyzer.review-mode .aa-top { display: flex; }

/* The two controls are taken OUT of the row's flow and pinned to its right
   edge. In flow they were flex items, so their width came off one side of the
   bar and the bar could never be centred on the screen no matter what it was
   given - it was always pushed left by exactly their width. Pinned, they cost
   the row nothing, and the bar's own symmetric side reserve (below) is what
   keeps them from ever meeting. */
.aa-actions {
  position: absolute;
  right: 8px;
  top: 50%;
  transform: translateY(-50%);
  /* Sits in the same band as the safe-area padding the row above it carries. */
  margin-top: calc(env(safe-area-inset-top) / 2);
  display: flex;
  align-items: center;
  gap: 4px;
}

/* The track is the TOP player's colour; the fill is the BOTTOM player's and
   grows from the left. That is the vertical bar's own convention turned on its
   side (bottom of the board = left of the bar), so a player who has used the
   web analyzer reads it the same way. The colours swap with the board - see
   .is-flipped below and toggleFlip in analysis.js. */
.aa-eval {
  position: relative;
  flex: none;
  display: flex;
  align-items: center;
  justify-content: center;
  /* Centred on the SCREEN, not on the space the controls happen to leave. The
     reserve is mirrored on both sides - the controls occupy the right one, and
     the left one is empty and exists only to hold the middle in place. Keep it
     in step with .aa-actions: two 26px buttons + their 4px gap + the 8px inset,
     plus 2px so the bar's shadow never touches them. */
  width: calc(100% - 2 * 66px);
  min-width: 190px;
  max-width: 440px;
  height: 34px;
  border-radius: 999px;
  overflow: hidden;
  background: var(--p2);
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .12), 0 2px 6px rgba(0, 0, 0, .38);
}
.aa-eval-fill {
  position: absolute;
  top: 0; bottom: 0; left: 0;
  width: 50%;
  background: var(--p1);
  /* Same curve and duration as the vertical bar it replaces, so the movement
     reads as the same object. */
  transition: width .4s cubic-bezier(.22, .61, .36, 1);
}
.aa-eval.is-flipped { background: var(--p1); }
.aa-eval.is-flipped .aa-eval-fill { background: var(--p2); }
/* A soft sheen over the fills, matching the vertical bar's finish. */
.aa-eval::after {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: inherit;
  pointer-events: none;
  background: linear-gradient(180deg, rgba(255, 255, 255, .18) 0%, rgba(255, 255, 255, 0) 55%, rgba(0, 0, 0, .16) 100%);
}

/* The number rides INSIDE the bar, dead centre.
 *
 * Beside it, the number was a flex item, so the bar could only ever be centred
 * on what the number and the controls left over. Inside, the bar is the whole
 * element and the reading is part of it.
 *
 * It sits on a dark lozenge rather than taking a player's colour, because it
 * has to stay readable wherever the boundary between the two fills happens to
 * fall - and at 50% that boundary is directly under it. Light text on one
 * player's colour is unreadable on the other's; light text on its own scrim is
 * readable on both. Tabular figures so it does not jitter as it counts. */
.aa-pct {
  position: relative;                 /* above the fills */
  z-index: 1;
  padding: 3px 12px;
  border-radius: 999px;
  background: rgba(10, 12, 9, .58);
  font-size: 18px;
  font-weight: 800;
  line-height: 1.15;
  letter-spacing: -.2px;
  font-variant-numeric: tabular-nums;
  color: #fff;
  text-shadow: 0 1px 2px rgba(0, 0, 0, .5);
}
/* Engine off: analysis.js hides the eval bar entirely, and a stale number would
   be a lie. The row keeps its height so the board does not jump. */
.aa-pct.is-idle { color: rgba(255, 255, 255, .5); }

/* Flip and the gear: deliberately quiet. They change how the board is DRAWN,
   which is a thing you do once and then forget, so they take the least room
   that is still hittable and let the reading have the row.
   26px is under Apple's 44pt target, so the tap area is pushed back out to
   44px with a transparent ::before rather than by growing the button - the
   mark stays small, the thing you can hit does not. */
.aa-icon {
  position: relative;
  flex: none;
  width: 26px; height: 26px;
  display: inline-flex; align-items: center; justify-content: center;
  padding: 0;
  border: 1px solid var(--color-border);
  border-radius: 8px;
  background: var(--color-surface-raised);
  color: var(--color-text-muted);
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: transform .12s ease, background .12s ease, color .12s ease;
}
.aa-icon::before {
  content: '';
  position: absolute;
  top: 50%; left: 50%;
  width: 44px; height: 44px;
  transform: translate(-50%, -50%);
}
.aa-icon:active {
  transform: scale(.9);
  background: var(--color-surface);
  color: var(--color-text-primary);
}

/* =======================================================================
   3. The player rows
   =======================================================================
   One line each, and only what identifies the player and what they have left
   to play with: the pawn colour, the name, the wall count. Everything else the
   seat card can carry is a live-game concern that the analyzer inherited by
   sharing the markup - rating, stake, connection dot, turn flag, clock - and
   every one of them is height the board could have had. */
body.app-analyzer.review-mode .board-wrap.seats-on .seat-bar {
  padding: 3px 12px;
  gap: 8px;
  min-height: 0;
  border-radius: 10px;
  background: transparent;
  border: 0;
  box-shadow: none;
}
body.app-analyzer.review-mode .seat-bar .seat-avatar,
body.app-analyzer.review-mode .seat-bar .seat-elo,
body.app-analyzer.review-mode .seat-bar .seat-stake,
body.app-analyzer.review-mode .seat-bar .conn-dot,
body.app-analyzer.review-mode .seat-bar .turn-flag,
body.app-analyzer.review-mode .seat-bar .player-time { display: none !important; }

/* Name and walls on ONE line (the phone layout stacks them). */
body.app-analyzer.review-mode .board-wrap.seats-on .seat-bar .seat-main {
  display: flex; flex-direction: row; align-items: center;
  gap: 8px; width: 100%; min-width: 0;
}
body.app-analyzer.review-mode .board-wrap.seats-on .seat-bar .seat-line {
  gap: 7px; min-width: 0; flex: 1 1 auto;
}
body.app-analyzer.review-mode .board-wrap.seats-on .seat-bar .player-name {
  font-size: 13px; font-weight: 700;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
body.app-analyzer.review-mode .seat-bar .pawn-chip { width: 11px; height: 11px; flex: none; }

/* The wall pips go; the number stays. Ten little fences read as decoration at
   this size - the count is the fact, and it is the fact a player checks. The
   fence glyph beside it says what the number counts, which the pips were doing
   before. */
body.app-analyzer.review-mode .seat-bar .walls-row { display: none !important; }
body.app-analyzer.review-mode .board-wrap.seats-on .seat-bar .bar-walls {
  margin-left: auto; flex: none; gap: 5px;
  display: inline-flex; align-items: center;
}
/* The fence rides INSIDE the count rather than beside it, so it inherits the
   count's colour instead of picking its own. The site already colours these
   per seat (`#count-1` is gold), and a mark in a second colour beside the
   number it labels reads as two separate facts. */
body.app-analyzer.review-mode .seat-bar .walls-count {
  display: inline-flex; align-items: center; gap: 5px;
  font-size: 13px; font-weight: 800;
  font-variant-numeric: tabular-nums;
}
/* The fence mark, drawn in CSS so it costs no markup and no request: two short
   uprights under a rail, in whatever colour the count is wearing. */
body.app-analyzer.review-mode .seat-bar .walls-count::after {
  content: '';
  width: 9px; height: 11px;
  flex: none;
  opacity: .72;
  background: currentColor;
  -webkit-mask: linear-gradient(#000 0 0) 0 0/9px 3px no-repeat,
                linear-gradient(#000 0 0) 1px 4px/2px 7px no-repeat,
                linear-gradient(#000 0 0) 6px 4px/2px 7px no-repeat;
          mask: linear-gradient(#000 0 0) 0 0/9px 3px no-repeat,
                linear-gradient(#000 0 0) 1px 4px/2px 7px no-repeat,
                linear-gradient(#000 0 0) 6px 4px/2px 7px no-repeat;
}

/* =======================================================================
   4. The board
   =======================================================================
   Everything above exists to give the board the rest of the screen. It runs
   edge to edge and is capped only by what the two bars and the two seat rows
   actually occupy - measured, not guessed, since the safe-area inset differs
   between an iPhone with a notch and one without.

   The top row is a child of .board-wrap (order 0, ahead of the top seat card)
   so it is part of the same column and needs no separate positioning; the
   bottom bar is fixed to the foot of the screen and so is subtracted here. */
body.app-analyzer.review-mode .layout {
  padding: 0;
  align-content: start;
}
/* Exactly the screen, less the fixed bar at its foot. Nothing on this screen
   scrolls: a board you have to scroll to is not a board you can read a game
   off, and the step arrows are tapped over and over - if the page can move
   under them, eventually it does. */
body.app-analyzer.review-mode .app { min-height: 0; padding-bottom: 0; }
body.app-analyzer.review-mode .board-wrap {
  gap: 4px;
  --strip-h: 0px;
  --bar-h: 0px;
  min-height: calc(100dvh - var(--aa-tab-h));
  /* A square board on a phone is capped by the WIDTH almost always (390px wide
     against ~660px of usable height), so the height term is the guard for
     landscape and for the short screens, not the usual binding constraint. */
  --board-size: min(
      100vw,
      600px,
      calc(100dvh - var(--aa-top-h) - var(--aa-tab-h) - var(--aa-seats-h)
           - env(safe-area-inset-top) - env(safe-area-inset-bottom))
  );
}
/* The top row is measured to its own content, not stretched to the board. */
body.app-analyzer.review-mode .board-wrap > .aa-top { order: 0; }

/* --- where the leftover height goes -------------------------------------
   The board is square and the screen is not, so on a phone there are always
   ~150px spare. The bar, the two name rows and the board move as ONE block,
   centred in what the fixed bottom bar leaves, and the slack falls outside it.

   The bar was previously pinned to the top of the screen with the slack
   between it and the board - which put the reading about 150px from the thing
   it was a reading OF. Distance is what made it feel detached; it belongs with
   the board, so it travels with it. */
body.app-analyzer.review-mode .board-wrap { justify-content: center; }
body.app-analyzer.review-mode .board-row { gap: 0; }
body.app-analyzer.review-mode .board,
body.app-analyzer.review-mode .board-frame { border-radius: 0; }

/* --- coordinates ON the board -------------------------------------------
   The web analyzer reserves 22px gutters down the left and along the bottom for
   the rank digits and file letters. That is 22px of board given up on a phone,
   and it is not what the player just spent the whole game looking at: a live
   game on a phone already tucks the coordinates inside the board. The analyzer
   matches it exactly - same corners, same size, same opacity - so stepping from
   the game into the review does not redraw the board under them.

   Non-interactive, so a label can never swallow a tap meant for the cell it
   sits on. */
body.app-analyzer.review-mode .board-frame { padding: 0; }
body.app-analyzer.review-mode .labels {
  display: grid;
  z-index: 2;
  pointer-events: none;
  font-size: 9px; font-weight: 700;
  color: rgba(255, 255, 255, .62);
  text-shadow: 0 1px 1px rgba(0, 0, 0, .45);
}
body.app-analyzer.review-mode .labels.ranks {
  left: 0; top: 0; bottom: 0; width: 11%;
}
body.app-analyzer.review-mode .labels.ranks span {
  align-items: flex-start; justify-content: flex-start; padding: 3px 0 0 4px;
}
body.app-analyzer.review-mode .labels.files {
  left: 0; right: 0; bottom: 0; height: 11%;
}
body.app-analyzer.review-mode .labels.files span {
  align-items: flex-end; justify-content: flex-end; padding: 0 4px 2px 0;
}

/* =======================================================================
   5. The bottom bar: every action on this screen
   =======================================================================
   Fixed to the foot, wearing the same surface, border and safe-area padding as
   the app's own tab bar, because it stands in that bar's place - a player's
   thumb should find the same thing in the same spot.

   Three groups: stepping on the left (where the eye goes first and where it is
   used most), Game review in the middle, and the way out on the right. */
.aa-tabbar {
  display: none;
  position: fixed;
  left: 0; right: 0; bottom: 0;
  z-index: 60;
  align-items: center;
  gap: 8px;
  padding: 7px 10px;
  padding-bottom: calc(7px + env(safe-area-inset-bottom));
  background: var(--color-surface);
  border-top: 1px solid var(--color-border);
  box-shadow: 0 -6px 18px rgba(0, 0, 0, .22);
}
body.app-analyzer.review-mode .aa-tabbar { display: flex; }

/* Widths here are a budget, not a preference: the four arrows, Game review and
   Back all have to fit one 390px row (and still fit a 360px one), so the
   arrows take the least that stays comfortably tappable and Game review takes
   whatever is left. Changing one of these means re-checking the other two. */
.aa-steps { display: flex; align-items: center; gap: 4px; flex: none; }
.aa-step {
  width: 34px; height: 42px;
  display: inline-flex; align-items: center; justify-content: center;
  padding: 0;
  border: 1px solid var(--color-border);
  border-radius: 11px;
  background: var(--color-surface-raised);
  color: var(--color-text-primary);
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: transform .12s ease, opacity .12s ease;
}
.aa-step:active:not(:disabled) { transform: scale(.9); }
/* Faded, not removed: the row must not change width at the ends of the game or
   the arrows move under the thumb that is repeatedly tapping them. */
.aa-step:disabled { opacity: .3; cursor: default; }
/* Prev/next are the two that get used move after move, so they are the wide
   ones; first/last are occasional. */
.aa-step.is-major { width: 40px; }

/* Game review. Takes the slack in the middle so it reads as the screen's one
   substantial action, and doubles as its own progress bar while the review
   runs - which is why the fill is a child and not a background. */
.aa-review {
  position: relative;
  flex: 1 1 auto;
  min-width: 0;
  height: 42px;
  display: inline-flex; align-items: center; justify-content: center;
  gap: 6px;
  padding: 0 10px;
  border: 1px solid var(--color-border);
  border-radius: 11px;
  background: var(--color-surface-raised);
  color: var(--color-text-primary);
  font-size: 13px; font-weight: 700;
  overflow: hidden;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}
.aa-review-fill {
  position: absolute;
  left: 0; top: 0; bottom: 0;
  width: 0%;
  background: color-mix(in srgb, var(--p1) 34%, transparent);
  transition: width .25s linear;
  pointer-events: none;
}
.aa-review-star, .aa-review-label { position: relative; }
.aa-review-star { color: #f0c674; font-size: 13px; }
.aa-review-label {
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* Once the game HAS been reviewed the button is the way to the report rather
   than a thing to start, so it stops asking for attention. */
.aa-review.is-graded { border-color: color-mix(in srgb, var(--p1) 45%, var(--color-border)); }
.aa-review.is-running { pointer-events: none; }
.aa-review.hidden { display: none; }

/* Back to game. Coloured, because it is the one control here that LEAVES, and
   an uncoloured row of five identical buttons hides that. */
.aa-back {
  flex: none;
  height: 42px;
  display: inline-flex; align-items: center; gap: 5px;
  padding: 0 11px;
  border: 0;
  border-radius: 11px;
  background: var(--p1);
  color: #10130f;
  font-size: 13px; font-weight: 800;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: transform .12s ease, filter .12s ease;
}
.aa-back:active { transform: scale(.95); filter: brightness(.92); }
/* On the narrowest phones the word goes and the arrow carries it, so the step
   arrows never lose width to it. */
@media (max-width: 360px) {
  .aa-back { padding: 0 11px; }
  .aa-back .aa-back-label { display: none; }
  .aa-step.is-major { width: 44px; }
}

/* =======================================================================
   6. The Game review sheet
   =======================================================================
   Left working exactly as the web app builds it - a full-screen fixed sheet
   with its own title and close button - because that is already the right
   shape here. It only needs to clear the bottom bar, which is fixed above it. */
body.app-analyzer.review-mode #rv-report-view:not(.hidden) {
  z-index: 90;
  padding-bottom: calc(var(--aa-tab-h) + env(safe-area-inset-bottom));
}

/* Reduced motion: the bar still moves (its position IS the information) but
   nothing springs or scales. */
@media (prefers-reduced-motion: reduce) {
  .aa-eval-fill, .aa-review-fill { transition: none; }
  .aa-icon:active, .aa-step:active:not(:disabled), .aa-back:active { transform: none; }
}
