/* ===== TikTok in Plex Hub — the surface =====

   Chunk 1 of PLAN-T2. Phone-shaped, in the app's own theme, playing real
   TikToks through TikTok's official embed player.

   TWO FACTS, BOTH CHECKED AGAINST THE LIVE SERVICE RATHER THAN ASSUMED, that
   decide everything about this file:

     www.tiktok.com/foryou          x-frame-options: SAMEORIGIN
     www.tiktok.com/player/v1/<id>  no frame restriction at all

   So the real For You feed CANNOT be put inside our page -- not on the website,
   not on the desktop app, not anywhere an iframe is what we have. It opens in a
   browser instead, which is also the only place liking, commenting and messages
   can happen, because no API offers any of them.

   What CAN live in our page is the embed player, and it is a real player: it
   takes autoplay/controls/muted parameters and answers postMessage. That is
   what this styles -- a full-bleed vertical surface that is ours everywhere
   except the rectangle TikTok is legally entitled to own.

   Phone first, deliberately. Pierre asked for phone and said desktop can wait. */

#v-tiktok{
  /* The feed is a vertical pager: one post per screen, snapped. The height has
     to exclude the bottom bar or the last post sits under it -- the same thing
     --ph-bar-h exists for everywhere else in this app. */
  /* --sa-t as well as the bar: the shell's <main> carries the notch as 59px of
     padding-top, so a view that is 100vh minus the bar starts 59px down and
     ends 59px UNDER the bar. That was the document's 59px of scroll on this
     view, measured, and it is what pulled the header up behind the clock. */
  --tk-h: calc(100vh - var(--ph-bar-h) - var(--ph-top-h, 50px) - var(--sa-t, 0px));
  padding-bottom: 0;
  /* THE VIEW IS EXACTLY ONE SCREEN, AND THE FEED INSIDE IT IS THE ONLY SCROLLER.
     The header used to be a sticky box ON TOP of a feed that was already a full
     screen tall, so the view came to --tk-h PLUS the header and the document
     scrolled: measured on 2026-09-26 with one post saved, scrollHeight 1076
     against a 932 viewport, 144px of scroll that took the title, the count and
     Open For You off the top with no way back to them while the pager held the
     touch. Header and feed now share the one screen. */
  position:relative; height:var(--tk-h); overflow:hidden;
}
/* The column is on #tk-root, not on the view: the view's only child is that
   root (tiktok.js renders into it), so a flex column on the view would only
   ever lay out one box and the header and feed inside it would keep sizing
   themselves to their content -- measured, a 150px-tall feed inside an 834px
   view. */
#tk-root{ height:100%; display:flex; flex-direction:column; }

/* ---------- the header: ours, not theirs ---------- */
/* In flow and never scrolled, because the view around it does not scroll. */
.tk-head{
  display:flex; align-items:center; gap:10px; flex:0 0 auto;
  padding:10px 14px 8px; position:relative; z-index:6;
  background:linear-gradient(180deg, var(--bg) 62%, transparent);
}
.tk-head h2{ margin:0; font-size:var(--fs-title); font-weight:800; letter-spacing:-.01em; }
.tk-head .tk-sub{ color:var(--dim); font-size:var(--fs-meta); }

/* The button that leaves for the real thing. Deliberately prominent: it is the
   only route to the For You feed, and pretending otherwise would be the kind of
   lie this codebase keeps having to undo. */
/* The two header buttons travel together, so the group carries the auto margin
   rather than the pill -- with the auto still on .tk-open the plus would have
   been shoved to the left edge beside the title. */
.tk-headacts{ margin-left:auto; display:flex; align-items:center; gap:8px; }

/* ADD A LINK, AT ANY TIME.
   Until 2026-09-26 the only field that could save a TikTok was inside the empty
   state, so saving the FIRST post removed the only way to save a second one --
   measured in the lab: one post saved, [data-tk-add] count 0. The plus is the
   way back to it, and the row it opens is the same form. */
.tk-addbtn{
  width:38px; height:38px; border-radius:50%; display:grid; place-items:center;
  border:1px solid var(--line2); background:var(--card); color:var(--txt);
  cursor:pointer; padding:0;
}
.tk-addbtn[aria-expanded="true"]{ background:var(--accent); color:#000; border-color:transparent; }
.tk-addrow{
  position:absolute; left:0; right:0; top:100%;
  padding:6px 14px 12px; background:linear-gradient(180deg, #000000cc 0%, #00000000 100%);
}
.tk-addrow[hidden]{ display:none; }
.tk-addrow form{ display:flex; gap:8px; width:100%; }
.tk-addrow input{ flex:1; min-width:0; }

/* ---------- the account panel (PLAN-T2 layer 1) ---------- */
/* A DROP-DOWN, NOT A CARD IN THE FLOW, for exactly the reason the add row is
   one: this view is pinned to --tk-h and everything in the header's flow comes
   straight out of the feed's height. Measured while building this - a 150px
   account card turned an 834px feed into 684px, which on a one-post-per-screen
   pager is a visibly shorter video. Closed, this costs zero pixels. */
/* Lit only once something is actually linked. The circle is otherwise identical
   to the plus, because an account nobody has connected is not more important
   than the button that saves a video.

   :not([aria-expanded="true"]) IS NOT DECORATION. `.tk-addbtn[aria-expanded]`
   above fills the circle with --accent and blackens the glyph when the panel is
   open, and it has the SAME specificity as `.tk-acctbtn.tk-linked` (0,2,0) — so
   this rule, being later, would win the colour and lose the background, leaving
   an accent glyph on an accent fill: an invisible button, exactly when he has
   just tapped it. The open state wins outright instead. */
.tk-acctbtn.tk-linked:not([aria-expanded="true"]){
  border-color:var(--accent); color:var(--accent);
}
.tk-acctrow{
  position:absolute; left:0; right:0; top:100%;
  padding:6px 14px 14px;
  background:linear-gradient(180deg, #000000e0 0%, #000000b0 72%, #00000000 100%);
}
.tk-acctrow[hidden]{ display:none; }
.tk-acctbody{
  display:flex; flex-direction:column; gap:9px;
  background:var(--card); border:1px solid var(--line2); border-radius:14px;
  padding:13px 14px;
}
.tk-acctbody strong{ font-size:var(--fs-small); font-weight:800; }
/* One dim class rather than inline colours, so the sentences in this panel
   cannot drift apart from each other the way three inline styles would. */
.tk-acctbody .tk-dim{ color:var(--dim); font-size:var(--fs-meta); line-height:1.5; }
.tk-acctbody code{
  font-size:var(--fs-meta); background:#ffffff14; border-radius:5px; padding:1px 5px;
}
.tk-acctbody button{ align-self:flex-start; }
.tk-acctbody form{ display:flex; gap:8px; }
.tk-acctbody form input{ flex:1; min-width:0; }
.tk-acctwho{ display:flex; align-items:center; gap:10px; }
.tk-acctwho > div{ display:flex; flex-direction:column; }
.tk-acctav{
  width:36px; height:36px; border-radius:50%; flex:0 0 auto;
  object-fit:cover; background:#ffffff12;
}
.tk-acctav-none{ display:grid; place-items:center; color:var(--dim); }

.tk-open{
  display:inline-flex; align-items:center; gap:7px;
  padding:9px 14px; border-radius:999px; border:1px solid var(--line2);
  background:var(--card); color:var(--txt); font-weight:750;
  font-size:var(--fs-meta); cursor:pointer; position:relative;
}
.tk-open svg{ pointer-events:none; }

/* ---------- the vertical pager ---------- */
.tk-feed{
  /* Whatever is left under the header, not a second full screen. min-height:0
     is what lets a flex child actually shrink to it. */
  flex:1 1 auto; min-height:0;
  overflow-y:auto; overscroll-behavior-y:contain;
  scroll-snap-type:y mandatory;
  /* A vertical pager must own the vertical axis or the page scrolls with it. */
  touch-action:pan-y;
  -webkit-overflow-scrolling:touch;
}
.tk-post{
  height:100%; scroll-snap-align:start; scroll-snap-stop:always;
  position:relative; display:flex; align-items:center; justify-content:center;
  background:#000;
}
/* TikTok's player is 9:16. Letterbox it rather than stretch it: a distorted
   video is worse than a black margin, and the black IS the design here. */
.tk-frame{
  /* MEASURED, not assumed, and the measurement is why this rule changed:
     --tk-h is the whole VIEW (the header AND the feed), so --tk-h * 9/16 came
     out 410px against a post that is 644 tall -- 48px wider than 9:16 wants.
     The letterbox this rule promises never happened; TikTok filled the 48px
     with its own blurred pillarbox, which is exactly the padded look the note
     above set out to avoid. aspect-ratio derives the width from the height the
     post ACTUALLY has, so no variable can drift away from it again. The video
     does not change size either way -- TikTok already renders it at 362 -- so
     all this decides is whose margin you see, and black is ours.
     max-width keeps a narrow screen full width, where 9:16 does not fit and
     TikTok's pillarbox is the only thing there is. */
  height:100%; width:auto; aspect-ratio:9 / 16; max-width:100%;
  border:0; display:block; background:#000;
}

/* ---------- our chrome over their rectangle ---------- */
/* Everything in this block is OURS. The player carries TikTok's creator,
   description and sound; these are the Plex Hub abilities layered beside it. */
/* ABOVE WHATEVER IS FLOATING DOWN THERE.
   Found by driving this at 375px with music playing: the mini-player and the
   "Up next" pill span the bottom of the screen, and every one of these buttons
   failed a hit test underneath them. --ph-dock-h is the height of that floating
   stack, published by PHDock on 2026-09-10 for this exact class of problem; it
   is 0 when nothing is docked, so an ordinary screen is unchanged. */
/* AND ON THE LEFT, BECAUSE THE BOTTOM-RIGHT IS TIKTOK'S AND ALWAYS WAS.
   The embed draws its own like / comment / share rail flush to the bottom-right
   of the iframe -- measured in the lab with our chrome hidden
   (docs/lab/q4d-tk-bare.png): heart 35.2K, comment 5486, share 1491, occupying
   x 362-406 of a 430 post and the bottom 155px of the frame. These three
   buttons were stacked exactly on top of it: "Remove" was printed across the
   like count and "Sound off" across the share arrow (docs/lab/q4d-tk-before.png).
   Nothing can be done about that from here -- the rail is cross-origin and it
   is TikTok's attribution, which is the whole reason the official player is
   used at all -- so OUR rail moves. Left and right, caption between them, which
   is TikTok's own layout and reads as one screen rather than two. */
.tk-side{
  position:absolute; left:10px;
  bottom:calc(max(var(--sa-b), var(--ph-dock-h, 0px)) + 18px);
  /* 26px, not 14px. Each button carries its label 15px BELOW itself, so at a
     14px gap the word sat on top of the next button -- "Remove" was printed
     across the sound control in docs/lab/q4-tk-one.png. The gap has to clear
     the label, not just the circle. */
  display:flex; flex-direction:column; gap:26px; z-index:3;
}
.tk-act{
  width:44px; height:44px; border-radius:50%;
  display:grid; place-items:center;
  background:#0b0e13b8; border:1px solid #ffffff1f; color:#fff;
  cursor:pointer; backdrop-filter:blur(10px);
}
.tk-act:disabled{ opacity:.4; cursor:default; }
.tk-act .tk-lbl{
  position:absolute; bottom:-15px; left:50%; transform:translateX(-50%);
  font-size:10px; font-weight:700; color:#ffffffc4; white-space:nowrap;
}
.tk-act{ position:relative; }

/* The caption strip: our typography, their text. */
.tk-meta{
  /* Inset by a button's width on BOTH sides now: ours on the left, TikTok's on
     the right. 66px each side leaves 298px of a 430 post for the words, and it
     is the same number on both sides because it is the same obstacle. */
  position:absolute; left:66px; right:66px;
  bottom:calc(max(var(--sa-b), var(--ph-dock-h, 0px)) + 18px);
  z-index:3; color:#fff; text-shadow:0 1px 12px #000a;
}
.tk-meta .tk-author{ font-weight:800; font-size:var(--fs-small); }
.tk-meta .tk-title{
  font-size:var(--fs-meta); color:#ffffffd8; margin-top:3px;
  display:-webkit-box; -webkit-line-clamp:2; -webkit-box-orient:vertical; overflow:hidden;
}

/* ---------- our progress bar ---------- */
/* The player's own is switched off (progress_bar=0) because two bars over one
   video is worse than either. This one is drawn from onCurrentTime, which
   carries {currentTime, duration} on every tick, and it sits ABOVE the floating
   dock for the same reason the action buttons do. */
.tk-prog{
  position:absolute; left:0; right:0;
  bottom:calc(max(var(--sa-b), var(--ph-dock-h, 0px)));
  height:2px; background:#ffffff24; z-index:3;
}
.tk-prog i{
  display:block; height:100%; width:0;
  background:var(--accent);
  /* Not animated: onCurrentTime arrives several times a second, and a
     transition on every one of them fights the next update instead of
     smoothing it. */
}

/* The sound control lights up when it is ON, because muted is the state the
   browser forces at the start and the interesting one is the other. */
.tk-act.tk-on{ background:var(--accent); color:#000; border-color:transparent; }

/* ---------- empty and loading ---------- */
.tk-empty{
  height:100%; display:flex; flex-direction:column;
  align-items:center; justify-content:center; gap:12px; text-align:center;
  padding:0 34px; color:var(--dim);
}
.tk-empty strong{ color:var(--txt); font-size:var(--fs-small); }
.tk-empty span{ font-size:var(--fs-meta); line-height:1.5; }

/* ---------- desktop, minimally ---------- */
/* Pierre said phone first and desktop later. This is not a desktop design; it
   is only enough that a wide window does not look broken while we get there. */
@media (min-width: 901px){
  /* The desktop form's nav is a FIXED pill at the top of the window (measured:
     #ph-threshold-frame at y 14, 36px tall), not a band the layout reserves, so
     a view that starts at 0 has its own header printed underneath it -- which
     is what "TikTok / 1 saved here" was doing. The padding is inside the height,
     so the view still ends where it did. */
  #v-tiktok{ --tk-h: calc(100vh - 120px); padding-top:58px; }
  .tk-feed{ max-width:520px; margin:0 auto; }
  /* The drop-downs follow the feed's column instead of the window. Left full
     width they printed a paragraph 1512px across the top of the page -- seen in
     docs/lab/q4b-tk-desk.png -- which is both unreadable as prose and unrelated
     to the 520px strip everything else on this view lives in. */
  .tk-acctrow, .tk-addrow{ max-width:548px; margin:0 auto; }
}
