/* ===========================================================================
   The app's own chrome: the home screen, and the header every inner page
   wears.
   ===========================================================================

   Companion to js/app-home.js. Everything here is gated the same way that
   file's own rules in styles.css are - `body.has-tabbar` (set only by
   tabbar.js, which is native-only) plus signed-in and not in a game - so the
   website matches none of it.

   It lives in its own file rather than in styles.css because the app home is
   under active work in more than one place at once, and a separate sheet
   cannot collide with an edit to that one.
   ======================================================================== */

/* The home screen's own gate, spelled once. Every rule below rides on it:
   the tab bar exists (so this is the app), a player is signed in (the
   signed-out home is the pitch, which has its own shape), and neither a game
   nor the analyzer is on screen. */

/* =======================================================================
   1. Room for the docked Play now button
   =======================================================================
   The dock is position:fixed, so the panel it floats over reserves nothing
   for it and the panel's last section simply disappeared underneath. At
   390x844 that was the Tournaments row clipped by 36px and the whole "Recent
   games" section - the one part of this screen that shows the game being
   PLAYED by anyone - hidden completely.

   --apph-dock-h is measured and published by app-home.js (publishDockHeight);
   the tab bar's own height and the safe-area inset are already accounted for
   by the dock's `bottom`, so this only has to clear the dock itself. */
body.has-tabbar.signed-in:not(.in-game):not(.review-mode) .home-panel {
  padding-bottom: calc(var(--apph-dock-h, 82px) + 14px);
}

/* =======================================================================
   2. The daily puzzle, captioning the board
   =======================================================================
   The board directly above is showing the daily's position, so this row is its
   caption: what you are looking at, how it went, and the way in.

   No card. It used to be a bordered strip on a raised panel, which made a
   caption look like a widget - and put a rounded box immediately under a board
   that runs edge to edge. On the page it is simply the first line under the
   picture, which is what a caption is.

   The negative margin is the move the board, the ladder and the game rows all
   make on this screen: step out over .layout's 16px gutter and put the content
   back with padding, so the hairline and the press highlight reach both edges
   of the phone while the words stay in line with everything else. */
body.has-tabbar.signed-in:not(.in-game):not(.review-mode) .apph-daily {
  display: flex;
  align-items: center;
  gap: 12px;
  margin: 0 -16px;
  padding: 11px 16px 12px;
  border-bottom: 1px solid var(--color-border);
  color: var(--color-text-primary);
  text-decoration: none;
  -webkit-tap-highlight-color: transparent;
  transition: background .12s ease;
}
.apph-daily:active { background: rgba(255, 255, 255, .05); }

/* The state badge. Open is the gold star the puzzles UI already uses for a
   daily; played is a tick or a cross, because which one you got is the fact
   worth carrying back to this screen. */
.apph-daily-mark {
  flex: none;
  width: 34px; height: 34px;
  display: inline-flex; align-items: center; justify-content: center;
  border-radius: 11px;
  font-size: 16px; font-weight: 800; line-height: 1;
}
.apph-daily-mark.is-open { background: rgba(240, 198, 116, .16); color: #f0c674; }
.apph-daily-mark.is-won  { background: color-mix(in srgb, var(--p1) 20%, transparent); color: var(--p1); }
.apph-daily-mark.is-lost { background: rgba(214, 90, 74, .16); color: #d65a4a; }

.apph-daily-text { display: flex; flex-direction: column; gap: 2px; min-width: 0; flex: 1 1 auto; }
.apph-daily-title { font-size: 15px; font-weight: 800; letter-spacing: -.015em; }
.apph-daily-sub {
  font-size: 12.5px;
  color: var(--color-text-muted);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* The numbers inside the subtitle carry the weight, not the words around
   them: a rating and a streak are what a returning player is scanning for. */
.apph-daily-sub b { color: var(--color-text-primary); font-weight: 800; }

/* A pill rather than a line of green text. With no card edge around the row,
   plain coloured words read as part of the sentence beside them; a filled
   shape reads as the thing to press. Quiet green - the docked Play now is the
   loud one, and these two must not look like the same offer. */
.apph-daily-cta {
  flex: none;
  display: inline-flex; align-items: center; gap: 1px;
  padding: 6px 8px 6px 12px;
  border-radius: 999px;
  background: color-mix(in srgb, var(--color-accent) 20%, transparent);
  font-size: 12.5px; font-weight: 800;
  color: #8fd06a;
}

/* Very narrow phones: the subtitle is the first thing that can go - the badge
   and the title still say what this is, and the row must not wrap to two. */
@media (max-width: 340px) {
  .apph-daily-sub { display: none; }
}

@media (prefers-reduced-motion: reduce) {
  .apph-daily { transition: none; }
}

/* =======================================================================
   3. The inner-page header
   =======================================================================
   Applied by js/app-header.js, which strips the redundant corner links and
   swaps the placeholder glyph AND the word beside it for one lockup. All that
   is left to do here is centre what remains and size it - the lockup is drawn
   in `em`, so the host's font-size drives the pawns and walls as well as the
   letters.

   Keyed on `.apph-topbar`, a class that file adds and only ever adds inside
   the app, so the website's header - where those links are the ONLY way off
   the page - is untouched. */
.apph-topbar {
  justify-content: center;
  /* The row was carrying two buttons; on its own the wordmark needs less
     space beneath it than they did. */
  margin-bottom: 16px;
}
/* The gap is gone with the pair it separated, and the weight and tracking come
   from `.qb` itself now (styles.css). This rule has to stay all the same: it is
   more specific than the `.auth-brand.qb-host` default in styles.css and loads
   after it, so leaving it would have put the old 9px gap back. */
.apph-topbar .auth-brand {
  gap: 0;
  font-size: 19px;
}

/* The profile page's fixed top bar, given the same brand as every other inner
   page. `.nav-toggle` is already hidden in the app, and a
   space-between row with one visible child pins that child to the left - so
   the centring has to be stated, not inherited.

   `.brand`, not `.auth-brand`: this bar predates that class and uses the
   plain one, which is also what the side rail uses. Scoped to
   .apph-mobilebar so the rail is untouched. */
.apph-mobilebar { justify-content: center; }
.apph-mobilebar .brand {
  gap: 0;
  font-size: 19px;
}

/* The profile page's fixed top bar, given the same lockup as every other
   inner page. `.nav-toggle` is already hidden in the app, and a
   space-between row with one visible child pins that child to the left - so
   the centring has to be stated, not inherited.

   `.brand`, not `.auth-brand`: this bar predates that class and uses the
   plain one, which is also what the side rail uses. Scoped to
   .apph-mobilebar so the rail is untouched. */
.apph-mobilebar { justify-content: center; }
.apph-mobilebar .brand {
  gap: 9px;
  font-size: 19px;
  font-weight: 800;
  letter-spacing: -.01em;
}
.apph-mobilebar .brand .apph-mark {
  display: inline-flex;
  align-items: center;
  /* The SVG brings its own colours; the glyph it replaced was tinted by the
     bar's own colour and must not keep tinting this. */
  color: inherit;
  filter: drop-shadow(0 2px 3px rgba(0, 0, 0, .45));
}

/* =======================================================================
   4. The leaderboard's standing explanations
   =======================================================================
   Both boards open with a line telling you what the board is: "Top players by
   ELO...", "Top players by puzzle rating...". On a desktop that sits in the
   margin of a wide page and costs nothing. On a phone it is two wrapped lines
   between the tabs and the first row, pushing the actual standings down - and
   it explains something the tab you just pressed, the column headed ELO, and
   the page titled Leaderboard have all already said.

   Hidden rather than deleted: leaderboard-page.js toggles #lb-sub's `hidden`
   class for its own reasons, and this must not turn into a fight over the
   same element. */
body.has-tabbar #lb-sub,
body.has-tabbar #lb-pz-sub { display: none !important; }

/* =======================================================================
   5. The three other doors
   =======================================================================
   Pass & play, Invite and Tournaments, as one row of three tiles under the
   daily.

   They used to be a collapsed "Play with friends" accordion with two buttons
   folded inside it and a full-width Tournaments button underneath: two rows of
   chrome for three destinations, one of them behind a tap most sessions never
   spent. The accordion existed to buy back about 50px of a phone. Three tiles
   cost less than the two rows it replaced and hide nothing.

   It is also the only thing on this screen laid out ACROSS. Everything under a
   full-bleed board is a full-width strip, and a column of nothing but
   full-width strips is most of why the screen read as one shape repeated five
   times. One row of three is the break in that rhythm.

   Built by js/app-home.js (mountQuick). Tournaments is the site's own
   #hp-tournaments button, moved in and stripped of `btn` so it stops carrying
   a button's height and padding into a tile. Native-only, so none of this can
   reach the website. */
.apph-quick { display: none; }
body.has-tabbar.signed-in:not(.in-game):not(.review-mode) .apph-quick {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 8px;
  padding: 14px 0 15px;
  border-bottom: 1px solid var(--color-border);
}

/* One tile: glyph over label, in a box raised just enough off the page to read
   as a target. The tint is the tile's own hue at a whisper - enough that three
   of them are plainly three different things, not so much that the row turns
   into a colour chart. */
body.has-tabbar .apph-quick .apph-tile {
  display: flex; flex-direction: column;
  align-items: center; justify-content: center; gap: 7px;
  min-height: 70px; height: auto;
  padding: 10px 4px;
  border: 1px solid color-mix(in srgb, var(--tint) 30%, var(--color-border));
  border-radius: 14px;
  /* Lit from below, the same way the ladder under it is: a little sky at the
     top, the tile's own hue gathering at the foot. Flat fills at this alpha
     read as three grey boxes with coloured icons in them. */
  background: linear-gradient(180deg,
    rgba(255, 255, 255, .045) 0%,
    color-mix(in srgb, var(--tint) 14%, transparent) 100%);
  color: var(--color-text-primary);
  font: inherit;
  font-size: 12px; font-weight: 700; line-height: 1.15;
  text-align: center; cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: transform .12s ease, background .12s ease;
}
body.has-tabbar .apph-quick .apph-tile:hover {
  background: linear-gradient(180deg,
    rgba(255, 255, 255, .07) 0%,
    color-mix(in srgb, var(--tint) 20%, transparent) 100%);
  border-color: color-mix(in srgb, var(--tint) 45%, var(--color-border));
  transform: none;
}
body.has-tabbar .apph-quick .apph-tile:active { transform: scale(.97); }
/* The glyph carries the colour and the label does not: three coloured words in
   a row would stop being a row of labels and start being three signs. */
body.has-tabbar .apph-quick .apph-tile svg {
  flex: none; width: 21px; height: 21px; color: var(--tint);
}
body.has-tabbar .apph-quick .apph-tile > span { display: block; max-width: 100%; }

/* The three hues, each already this thing's colour somewhere else in the app:
   the cream pawn for the phone two people share, the blue that is always
   somebody else, and the amber the Tournaments icon has always worn. */
.apph-tile[data-tint="cream"] { --tint: var(--color-cream); }
.apph-tile[data-tint="blue"]  { --tint: var(--color-blue); }
.apph-tile[data-tint="amber"] { --tint: #e0864a; }

/* Under about 340px "Tournaments" is wider than a third of the row. It is one
   word and it cannot be shortened, so the type gives instead - and the glyphs
   shrink with it rather than sitting over a smaller label at full size. */
@media (max-width: 340px) {
  body.has-tabbar .apph-quick { gap: 6px; }
  body.has-tabbar .apph-quick .apph-tile { font-size: 11px; min-height: 70px; gap: 6px; }
  body.has-tabbar .apph-quick .apph-tile svg { width: 19px; height: 19px; }
}

@media (prefers-reduced-motion: reduce) {
  body.has-tabbar .apph-quick .apph-tile { transition: none; }
  body.has-tabbar .apph-quick .apph-tile:active { transform: none; }
}

/* =======================================================================
   5b. Section headings under the board
   =======================================================================
   Recent games is the one section with a heading of its own, and with the
   panel's card gone that heading is also what separates the list from the
   ladder above it. It wears the same eyebrow the ladder does, so the two read
   as the same kind of thing, and it carries the way through to the rest of the
   history: five rows is the right number for a home screen and the wrong
   number for anyone looking for a game from last week. */
body.has-tabbar .home-panel .hp-recent-head {
  display: flex; align-items: center; justify-content: space-between;
  gap: 10px;
  margin: 17px 0 3px;
  font-size: 11px; font-weight: 700; letter-spacing: .1em;
}
.apph-more {
  display: inline-flex; align-items: center; gap: 1px;
  font-size: 12.5px; font-weight: 700; letter-spacing: .01em;
  text-transform: none;
  color: var(--color-text-muted);
  -webkit-tap-highlight-color: transparent;
}
.apph-more svg { opacity: .7; }
.apph-more:active { color: var(--color-text-primary); }

/* No games yet. On the site this claims the height the list would have had, so
   the stretched panel does not open a void under it; here the page is only as
   tall as what is on it, so the placeholder only has to say the list is empty
   and get out of the way. */
body.has-tabbar .home-panel .hp-recent-empty {
  margin: 8px 0 0;
  padding: 20px 16px;
  border-radius: 12px;
}

/* The same two modes on the SIGNED-OUT home, where the dock does not exist:
   the guest pitch is a different screen with its own shape, and a visitor
   there was just as cut off from them. In the markup unconditionally and
   hidden here, because the website's pitch is deliberately one CTA and a
   tutorial link - body.has-tabbar is the app, and only the app. */
.pitch-mode { display: none; }
body.has-tabbar .pitch-mode { display: inline-block; }
/* Three links where the site has one. The row is nowrap by default, which on
   a 390px phone would push the last one off the edge rather than under it. */
body.has-tabbar .pitch-links { flex-wrap: wrap; row-gap: 6px; }

/* =======================================================================
   The guided tutorial's coach bar
   =======================================================================
   The bar is pinned below the site's fixed topbar:

       top: calc(var(--topbar-h) + env(safe-area-inset-top) + 12px)

   The app has no topbar - body.has-tabbar hides it outright - but --topbar-h
   is still 52px, so the bar hung 52px lower than it should and landed across
   the opponent's seat card instead of above the board. Reclaim exactly that,
   leaving the safe-area inset and the 12px gap doing the same job they do on
   the site. Matters now that How to play in the More sheet opens the tutorial
   rather than the rules text, which is how most people will meet it. */
body.has-tabbar .coach {
  top: calc(env(safe-area-inset-top) + 12px);
}

/* =======================================================================
   The document pages: about, blog, privacy, terms
   =======================================================================
   These wear .profile-topbar like every other inner page, so app-header.js
   already centres the wordmark and drops the redundant "Back to game". What
   it cannot do is the page's own heading, which stayed hard left under a
   centred mark and read as though it belonged to a different layout.

   The heading and its standout line only. NOT the body copy: centred prose is
   unreadable at any length, and these pages carry the rules and two thousand
   word articles. */
body.has-tabbar .doc-page > h1,
body.has-tabbar .doc-page > .doc-meta,
body.has-tabbar .doc-page > article > h1,
body.has-tabbar .doc-page > article > .doc-meta {
  text-align: center;
}

/* The article pages put their "back" link above the title, where a centred
   heading makes a left-hugging link look like a stray. */
body.has-tabbar .doc-page .blog-back {
  display: block;
  text-align: center;
}

/* =======================================================================
   Tournaments: the app has none
   =======================================================================
   The website carries a live event on /tournaments - a dated bracket with a
   cash pool and a Register button. The app carries the same page, minus the
   event: the Tournaments entry points stay exactly where they are, and what
   they open says there is nothing on yet.

   Done here rather than by stripping the card out of the page, because it is
   the same file the website serves and the event is real there. Done in CSS
   rather than in script for the timing: the markup is already in the document
   when the stylesheet applies, so the app never paints an event card and then
   takes it away. js/tournaments-page.js has the matching Net.isNative() guard,
   which is what stops the app asking the server about a sign-up it is not
   offering. */
.tourney-none { display: none; }
body.has-tabbar .tourney-list { display: none; }
body.has-tabbar .tourney-none {
  display: block;
  padding: 30px 20px;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  background: var(--color-surface);
  text-align: center;
}
.tourney-none-title { margin: 0; font-size: 17px; font-weight: 800; }
/* Held to a short measure so the two lines centre as a block rather than
   spanning the card and leaving a ragged last line under the heading. */
.tourney-none-copy {
  margin: 8px auto 0;
  max-width: 34ch;
  color: var(--color-text-muted);
  font-size: 13.5px;
  line-height: 1.5;
}

/* =======================================================================
   Settings > Account, in the app
   =======================================================================
   Four app-only departures from the website's account page. Every one is
   gated on body.has-tabbar, which tabbar.js sets and only the app has.

   1. NO SIGN OUT ROW. The tab bar's More sheet already carries Sign out, and
      two of them one tap apart is a question ("do these do the same thing?")
      rather than a convenience. The website has no More sheet, so it keeps
      its row. Specificity beats the base rule's body.signed-in without
      needing !important - two body classes to its one. */
body.has-tabbar.signed-in .settings-row-signout { display: none; }

/* 2. NO DATA EXPORT. exportData() in js/settings-account.js builds a blob URL
      and clicks an <a download>. WKWebView does not honour the download
      attribute, and there is no @capacitor/filesystem in the bundle to write
      the file with instead, so in the app the button does nothing at all. A
      control that visibly does nothing is worse than an absent one, and worst
      of all in front of App Review. The web path works and is untouched; the
      export lives at quoridors.com for anyone who wants it. To bring it back
      here, add @capacitor/filesystem, write the JSON to Directory.Cache and
      hand the resulting URI to @capacitor/share (already a dependency). */
body.has-tabbar .account-sub-data { display: none; }

/* 3. ONE LINE PER ROW. The hint under each label is what makes these rows two
      lines tall, and on a 390px phone the label then wraps as well - so "Sign
      out everywhere else" and its button end up stacked with the text sitting
      above itself. The hints are desktop affordances; the row labels already
      say what the button does. Dropped here, kept on the web.

      The Password section is exempt: acct-password-google is a hint with no
      button, and losing it would leave a Google-only account looking at an
      empty Password heading. */
body.has-tabbar #account-settings-screen .settings-row .settings-hint-text { display: none; }
body.has-tabbar #account-settings-screen #acct-password-google .settings-hint-text { display: block; }

body.has-tabbar #account-settings-screen .settings-row {
  align-items: center;
  gap: 12px;
  min-height: 44px;          /* the iOS touch target, so rows stay tappable */
}
/* The label takes the slack and truncates rather than pushing the button
   off the edge - the button is the part that has to stay whole. */
body.has-tabbar #account-settings-screen .settings-row-label {
  flex: 1 1 auto;
  min-width: 0;
  font-size: 14.5px;
  line-height: 1.3;
  /* The sheet centres its text, which is invisible on a label the flex row has
     already squeezed to its content - and very visible on the one row that
     stretches its label full width (Display name, a settings-row-col). */
  text-align: left;
}

/* 4. ONE BUTTON SIZE. Save / Change password / Sign out others / Delete
      account are four different string lengths, so shrink-to-fit gave four
      different widths down the right-hand edge. Pinned to a common width and
      allowed to grow only for a label that genuinely will not fit. */
body.has-tabbar #account-settings-screen .account-sub .btn,
body.has-tabbar #account-settings-screen .account-form .btn {
  flex: 0 0 auto;
  min-width: 132px;
  min-height: 40px;
  padding: 9px 14px;
  font-size: 14px;
  white-space: nowrap;
  text-align: center;
}
/* The password form stacks its inputs, so its button is full width there and
   the shared min-width would fight the column. */
body.has-tabbar #account-settings-screen .account-form .btn { width: 100%; }

/* =======================================================================
   Delete account: the app's confirmation
   =======================================================================
   The web asks you to type your email address. That is the right gate for a
   desktop keyboard and the wrong one for a phone: it is slow, it is easy to
   get wrong, and a deletion flow that is hard to complete is the shape of a
   dark pattern - which is exactly what guideline 5.1.1(v) exists to stop.
   The app shows what will be destroyed and asks once. */
.delete-app-only { display: none; }
body.has-tabbar .delete-app-only { display: block; }
body.has-tabbar .delete-web-only { display: none; }

.delete-are-you-sure { font-weight: 700; color: var(--color-text-primary); }
.delete-list-head {
  margin: 14px 0 6px;
  font-size: 13.5px;
  font-weight: 600;
  color: var(--color-text-primary);
  text-align: left;      /* the card centres; the list under it does not */
}
.delete-list {
  margin: 0;
  padding-left: 20px;
  text-align: left;
  font-size: 13.5px;
  line-height: 1.55;
  color: var(--color-text-primary);
}
.delete-list li { margin: 3px 0; }
.delete-list li::marker { color: var(--color-danger, #d8564a); }
/* The one thing on the list that is NOT destroyed. Muted and set apart so it
   reads as the caveat it is rather than a seventh bullet. */
.delete-list-foot {
  margin: 12px 0 0;
  font-size: 12.5px;
  line-height: 1.5;
  color: var(--color-text-muted);
  text-align: left;      /* centred, it read as a ragged third of the list */
}
