/* ===========================================================================
   /watch/<Name> ON A TELEVISION

   The third dress for this page, after player-channel.css (a live match) and
   player-channel-scenes.css (the rest of the evening). This one is not a
   different look -- it is the same page with the website taken off it.

   WHY IT EXISTS. The place this page actually gets watched is a monitor propped
   beside a pool table, ten feet from the people reading it. In a browser window
   that screen spends a third of its height on a logo, a nav bar and a banner,
   none of which anybody standing at a table is going to click, and the picture
   and the score get what is left. Full screen gives the whole screen to the two
   things being watched.

   TWO SWITCHES, ONE CLASS. `html.is-tv` is this layout; the browser's own
   fullscreen is separate and optional. They are driven together by
   js/player-channel/tv-mode.js, but the class stands on its own -- on an iPhone,
   where a document cannot go fullscreen at all, and on ?tv=1, where a bookmarked
   screen comes up chromeless with no gesture to request fullscreen with.

   THE SIZES ARE IN vh, NOT vw. Everything else on this page scales with
   viewport WIDTH, which is the right choice in a window and the wrong one here:
   a 1080p television and a 1080p laptop are the same number of pixels wide and
   about eight feet apart. Height is what actually differs once the browser's own
   chrome is gone, and it is the axis the layout is fighting for -- a 16:9
   picture plus a panel of numbers has to fit between the top and bottom of a
   screen nobody is going to scroll.
   ========================================================================= */

/* ---------------------------------------------------------------------------
   The switch itself
   ---------------------------------------------------------------------------
   In a window: a quiet chip above the stage, right-aligned over the panel it
   belongs to. In full screen: fixed in the corner, and gone within seconds --
   see the idle rules at the bottom of this file. */

.pc-viewer-bar {
  display: flex;
  justify-content: flex-end;
  align-items: center;
  gap: 10px;
  margin: 0 0 12px;
}

/* The page renders the bar hidden and tv-mode.js unhides it, and `display:
   flex` above would otherwise beat the browser's own [hidden] rule and leave a
   dead button on the page for anybody without JavaScript. */
.pc-viewer-bar[hidden] {
  display: none;
}

.pc-tv-toggle {
  display: inline-flex;
  align-items: center;
  gap: 8px;

  margin: 0;
  padding: 7px 14px;
  border: 1px solid rgba(255, 255, 255, 0.16);
  border-radius: 999px;

  font: inherit;
  font-size: 13px;
  font-weight: 700;
  letter-spacing: 0.2px;
  line-height: 1;
  color: rgba(255, 255, 255, 0.82);
  background: rgba(8, 13, 20, 0.85);

  cursor: pointer;
  transition:
    color 160ms ease,
    border-color 160ms ease,
    background-color 160ms ease;
}

.pc-tv-toggle:hover,
.pc-tv-toggle:focus-visible {
  color: #fff;
  border-color: rgba(46, 255, 115, 0.55);
  background: rgba(46, 255, 115, 0.12);
}

.pc-tv-toggle-icon {
  display: block;
  width: 15px;
  height: 15px;
  flex: none;
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* One label per state, both in the markup, so the script only ever flips a
   class and there is no second copy of this wording in JavaScript to drift. */
html:not(.is-tv) .pc-tv-toggle-exit,
html.is-tv .pc-tv-toggle-enter {
  display: none;
}

.pc-tv-toggle kbd {
  padding: 1px 5px;
  border-radius: 4px;
  border: 1px solid rgba(255, 255, 255, 0.22);
  font: inherit;
  font-size: 11px;
  color: rgba(255, 255, 255, 0.7);
}

/* The browser cannot put this document in full screen (an iPhone), so the
   button must not promise that it can. The class is still worth having -- it
   still strips the chrome -- and the script says so by way of this attribute. */
.pc-tv-toggle[data-fullscreen="unsupported"] .pc-tv-toggle-icon {
  display: none;
}

/* ---------------------------------------------------------------------------
   Taking the website off
   ---------------------------------------------------------------------------
   Everything #wrapper-index holds except this page: the header, the nav, the
   member/apply banner, the footer, and whatever banner gets added next -- which
   is why this is a negation rather than a list of ids to keep in step. */

html.is-tv #wrapper-index > *:not(.player-channel-page) {
  display: none !important;
}

/* Dark regardless of theme, like the rest of this page: it frames video. */
html.is-tv body {
  background: #04070c;
}

/* What else is on tonight is a page of links. Nobody clicks a television. */
html.is-tv .player-channel-elsewhere {
  display: none;
}

/* ---------------------------------------------------------------------------
   Filling the screen
   ---------------------------------------------------------------------------
   Only where there is a screen to fill. Under 900px the hero is already one
   column and the page is already mostly picture, so full screen there means
   the chrome coming off and nothing else -- forcing a phone's worth of height
   to hold a feed AND a scoreboard would just crop the scoreboard. */

@media (min-width: 901px) {
  html.is-tv {
    /* The margin around the whole picture. Small, and not zero: a screen with
       a bezel wants a little air, and a 16:9 feed in a 16:9 screen with no
       margin at all leaves the panel nowhere to be. */
    --pc-tv-pad: clamp(10px, 1.6vh, 28px);
    --pc-tv-gap: clamp(10px, 1.2vw, 22px);
    /* Wide enough for a name, a rail of balls and a three-digit score at TV
       size; narrow enough to leave the feed the rest. Every pixel taken off
       this goes straight onto the picture, which on a 16:9 screen is limited by
       the width of its column and not by the height available. */
    --pc-tv-panel: clamp(320px, 24vw, 540px);
  }

  html.is-tv,
  html.is-tv body {
    height: 100%;
    /* There is no scrollbar on a television and nobody to drag one. Anything
       that does not fit has to fit some other way -- see the panel below. */
    overflow: hidden;
  }

  html.is-tv .player-channel-page {
    width: 100%;
    max-width: none;
    height: 100dvh;
    margin: 0;
    padding: var(--pc-tv-pad);
    display: flex;
    flex-direction: column;
  }

  /* The root is rewritten wholesale on every state change -- match, idle,
     searching -- so the rule that makes its contents fill the screen has to be
     about whatever is in there, not about one scene. */
  html.is-tv .player-channel-root {
    flex: 1 1 auto;
    min-height: 0;
    display: flex;
    flex-direction: column;
  }

  html.is-tv .player-channel-root > * {
    flex: 1 1 auto;
    min-height: 0;
  }

  /* --- A live match ----------------------------------------------------- */

  html.is-tv .player-channel-hero {
    grid-template-columns: minmax(0, 1fr) var(--pc-tv-panel);
    gap: var(--pc-tv-gap);
    align-items: stretch;
  }

  /* A 16:9 box that fits in the height available rather than one derived from
     the width, which on a wide screen would be taller than the screen and push
     the panel off the bottom of it. Capped at 100% so a tall, narrow window
     gets a picture as wide as the column and no wider. */
  html.is-tv .player-channel-stream {
    align-self: center;
    width: min(100%, calc((100dvh - (var(--pc-tv-pad) * 2)) * 16 / 9));
    margin: 0 auto;
    border-radius: 14px;
  }

  /* THE PANEL SCROLLS IN ONE PLACE, AND IT IS NOT THE SCORE.
     ------------------------------------------------------------------------
     Nobody drags a scrollbar on a television, so anything that has to scroll
     has to be the part nobody needs to read. Round-by-round is the only block
     here that grows without limit -- three rounds each, plus a tiebreaker, is
     eight rows under a score that is two -- so it gets the leftover height and
     scrolls inside it, and the score, the result and the names stay put however
     long the match runs.

     The panel keeps a scrollbar of its own as a backstop, for the short window
     where even the fixed part does not fit. */
  html.is-tv .player-channel-panel {
    padding: clamp(14px, 2vh, 28px);
    display: flex;
    flex-direction: column;
    overflow-y: auto;
    scrollbar-width: thin;
  }

  /* WHO WON, ABOVE THE HISTORY OF HOW.
     The result card is written last into the panel because in a window it is
     read last, after a scroll. There is no scroll here: left where it is, the
     headline and the rating change at the end of every match would sit below
     eight rows of round history, off the bottom of the screen, at the one
     moment everybody in the room is looking up. */
  html.is-tv .pc-matchup { order: 1; }
  html.is-tv .pc-coverage { order: 2; }
  html.is-tv .pc-site-viewers { order: 3; }
  html.is-tv .pc-round { order: 4; }
  html.is-tv .pc-results { order: 5; }
  html.is-tv .pc-score { order: 6; }
  html.is-tv .pc-rounds { order: 7; }
  html.is-tv .player-channel-links { order: 8; }

  /* A flex item will not shrink below its own minimum content width unless it
     is told it may, and a grid or a nowrap row inside one -- the matchup
     header, the score rows -- computes that minimum from a name nobody chose
     to be short. Without this a long name pushes the total off the right of
     the panel, and the panel is a fixed column, so there is nowhere for it to
     go. It is the one thing making the panel a flex column costs. */
  html.is-tv .player-channel-panel > * {
    min-width: 0;
  }

  /* Both are chips, and a flex item stretches to the full width of the column
     unless it is told not to. */
  html.is-tv .pc-round,
  html.is-tv .pc-site-viewers {
    align-self: flex-start;
  }

  html.is-tv .pc-rounds {
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
    scrollbar-width: thin;
  }

  /* The match is over, so the live score rows and the result card are the same
     two numbers one above the other. In a window they are a scroll apart and
     read as a running score and then a summary; side by side on a television
     they read as the page printing the score twice.

     :has() and not a class, because nothing in the match payload says "results
     are showing" -- the page simply fills in a section and unhides it. A
     browser too old for :has() drops this rule and shows both, which is the
     redundancy we started with rather than anything broken. */
  html.is-tv .player-channel-panel:has(.pc-results:not([hidden])) .pc-score {
    display: none;
  }

  /* Kick handles, for clicking. Not on a television, and the room they take is
     room the score wants. */
  html.is-tv .player-channel-links {
    display: none;
  }

  /* --- An idle scene ---------------------------------------------------- */

  /* The tall minimum exists so the page does not lurch when a match starts.
     In full screen the scene is already exactly as tall as the screen. */
  html.is-tv .pc-scene {
    min-height: 0;
    border-radius: 16px;
  }

  /* 880px of centred text is a reasonable column in a window and a postage
     stamp on a 4K television. */
  html.is-tv .pc-scene-inner {
    max-width: min(1200px, 78vw);
  }

  /* On air with no ranked match on: the scene is wrapped around a feed, so its
     width is governed by the height available, exactly as the match stage is. */
  html.is-tv .pc-scene--channel .pc-scene-inner {
    max-width: min(1600px, calc((100dvh - 14vh) * 16 / 9));
  }
}

/* ---------------------------------------------------------------------------
   Reading it from across the room
   ---------------------------------------------------------------------------
   The panel's sizes were chosen for a 400px column an arm's length away. Each
   one below keeps its original value as the clamp floor -- so a small window in
   full screen is never made worse -- and grows with the height of the screen.

   Not applied through a single scale factor or a zoom: the panel is a grid
   track with a width, and scaling the box rather than the type would push its
   contents out of the column it has to live in. */

@media (min-width: 901px) {
  html.is-tv .pc-side-name {
    font-size: clamp(19px, 2.5vh, 36px);
    /* In a window a long name is cut with an ellipsis, so that one player
       cannot reflow the header and push the score down the panel. At this size
       that costs half of what the page is about -- "Marlon Alcant..." above a
       match he is playing -- and the height it was protecting is height this
       layout has going spare. So it wraps. */
    white-space: normal;
    overflow: visible;
    text-overflow: clip;
  }

  html.is-tv .pc-side-meta {
    font-size: clamp(13px, 1.7vh, 23px);
    gap: 10px;
  }

  html.is-tv .pc-rank,
  html.is-tv .pc-versus {
    font-size: clamp(12px, 1.5vh, 20px);
  }

  html.is-tv .pc-coverage {
    font-size: clamp(14px, 1.7vh, 23px);
  }

  html.is-tv .pc-site-viewers,
  html.is-tv .pc-round {
    font-size: clamp(12px, 1.6vh, 21px);
  }

  /* The number somebody is squinting at. */
  html.is-tv .pc-score-value {
    font-size: clamp(22px, 4.4vh, 62px);
  }

  html.is-tv .pc-score-name {
    font-size: clamp(16px, 2.5vh, 34px);
  }

  /* "+5 this turn" moves under the name rather than sitting between it and the
     total. Three things on one line at this size is one thing too many -- the
     name is the one that gives way, and the name of whoever is at the table is
     not the part to lose. */
  html.is-tv .pc-turn-points {
    font-size: clamp(13px, 1.9vh, 26px);
    order: 1;
    flex: 1 0 100%;
    margin-left: 0;
  }

  html.is-tv .pc-score-head {
    flex-wrap: wrap;
    row-gap: 2px;
  }

  /* The base rule drops the total's auto margin whenever the turn chip is
     present, because on one line the chip is what pushes it right. It is no
     longer on that line. */
  html.is-tv .pc-score-head .pc-turn-points ~ .pc-score-value {
    margin-left: auto;
  }

  /* The rails, on both the live score and the round history. ball-rail.js sizes
     its SVGs in em off this, so the balls grow with the line they sit on. */
  html.is-tv .ov-balls {
    font-size: clamp(15px, 2.3vh, 32px);
  }

  html.is-tv .pc-note {
    font-size: clamp(11px, 1.4vh, 19px);
  }

  html.is-tv .pc-round-label {
    width: auto;
    min-width: 34px;
    font-size: clamp(11px, 1.4vh, 19px);
  }

  html.is-tv .pc-round-player,
  html.is-tv .pc-round-points {
    font-size: clamp(16px, 2vh, 27px);
  }

  html.is-tv .pc-result-headline {
    font-size: clamp(20px, 2.8vh, 40px);
  }

  /* The result row is a name, a rank, a rating change, sometimes a tiebreaker
     score, and the total -- five things on one line, which at this size leaves
     the name about four characters and an ellipsis. The name goes on its own
     line and everything that qualifies it follows underneath. */
  html.is-tv .pc-result-row {
    flex-wrap: wrap;
    row-gap: 4px;
  }

  html.is-tv .pc-result-row .pc-score-name {
    flex: 1 0 100%;
    white-space: normal;
    overflow: visible;
    text-overflow: clip;
  }

  html.is-tv .pc-result-reason {
    font-size: clamp(13px, 1.7vh, 22px);
  }

  html.is-tv .pc-elo,
  html.is-tv .pc-result-sd {
    font-size: clamp(13px, 1.7vh, 22px);
  }

  /* Over the picture: whose camera this is, and who is shooting. Both are read
     from the same distance as the panel. */
  html.is-tv .pc-feed-tag {
    font-size: clamp(13px, 1.9vh, 26px);
    padding: 6px 16px;
  }

  html.is-tv .pc-shooting {
    font-size: clamp(13px, 2vh, 28px);
    padding: 7px 18px;
  }

  html.is-tv .pc-dot {
    width: clamp(8px, 1.1vh, 14px);
    height: clamp(8px, 1.1vh, 14px);
  }
}

/* ---------------------------------------------------------------------------
   The control, once the screen is a television
   ---------------------------------------------------------------------------
   Out of the layout and into the corner, below both cards that can appear over
   the feed -- a message somebody has just typed and "this game cannot be won
   any more" are both more important than the way out of full screen.

   TOP LEFT, having moved across from the right where it sits in a window. The
   right is where the scoreboard is, and a button parked over it covers the
   opponent's name for as long as somebody is moving a mouse. The left is dead
   space above a letterboxed feed, and in the worst case -- a tall window where
   the picture fills the height -- it is the one corner of the stage nothing else
   claims: the shooting badge and the live-sync chip are top right, the camera
   tag is bottom left. */

html.is-tv .pc-viewer-bar {
  position: fixed;
  top: clamp(10px, 1.6vh, 28px);
  left: clamp(10px, 1.6vh, 28px);
  z-index: 58;
  margin: 0;
  transition:
    opacity 320ms ease,
    visibility 320ms ease;
}

/* Nothing has moved and no key has been pressed for a few seconds, so there is
   nobody at the keyboard and this is a screen on a wall. The button goes, and
   the mouse pointer with it -- an arrow parked in the middle of a stream is the
   single most common thing wrong with a picture on a television.

   Any movement, any key, brings both straight back: see tv-mode.js. */
html.is-tv.is-tv-idle .pc-viewer-bar {
  opacity: 0;
  visibility: hidden;
}

html.is-tv.is-tv-idle,
html.is-tv.is-tv-idle body {
  cursor: none;
}

/* Keyboard focus is somebody at the keyboard, whatever the idle timer thinks.
   On the bar and not on the button: the button cannot bring back a parent that
   has been faded out, and opacity does not inherit the way visibility does. */
html.is-tv.is-tv-idle .pc-viewer-bar:focus-within {
  opacity: 1;
  visibility: visible;
}

@media (prefers-reduced-motion: reduce) {
  html.is-tv .pc-viewer-bar {
    transition: none;
  }
}
