/* ==========================================================================
   OVERTAKE — READABLE CARDS ON A PHONE · three trials
   site/overtake/bigcards.css  (pairs with bigcards.js)

   WHY THIS EXISTS
   The felt table computes ONE scale factor, R = min(W/1600, H/900), and
   multiplies the whole composition by it. At 844x390 — the owner's phone —
   R is 0.43, which gives a 37px card, a 16px letter and an EIGHT PIXEL
   value. The layout is perfectly proportioned at every size and legible at
   exactly one. That is a zoom, not a responsive layout.

   Measured at 844x390 with the fit log the table already keeps:
       wTerm  0.591   the room beside the rail
       hTerm  0.490   <-- BINDING: five projected rows + the fan, vertically
       capTerm 0.811  the size a held card would be on its own
       feltTerm 1.298 staying on the felt

   So the card is small because of HEIGHT, not width. Widening it alone
   changes nothing — min() still returns hTerm. Each trial below buys
   vertical room a different way, and says what it costs:

     A  fewer places on the table   — a RULE change (35 -> 21)
     B  the hand rides the felt     — no rule change, the fan stops
                                      taking a band of its own
     C  hard legibility floors      — the field grows past the felt and
                                      crops, the way the ellipse already does

   All three also slim the rail (28% of the width to show 9px names) and put
   a real floor under the value. Nothing here is loaded unless ?cards= asks
   for it — live play is untouched.
   ========================================================================== */

/* ---------------------------------------------------------------- the rail
   224px of an 844px screen, carrying 19px rows and 9px names. In every trial
   it keeps its job — who is at the table and where you stand — at a size
   that can actually be read, by dropping to the avatar and the score and
   letting the names go. */
/* The row the painter actually builds — read off the DOM, not guessed:
       .ofelt-row > .ofelt-fr > .ofelt-in > .ofelt-face  (full-bleed portrait)
                                          > .ofelt-av    (the avatar disc)
                                          > .ofelt-id    > .ofelt-nm  the name
                                                         > .ofelt-st  the STATUS
                                          > .ofelt-pts   > b  the score
                                                         > s  the word "points"
                  > .ofelt-rk   the rank
   Nothing is removed that carries meaning. What goes is the decoration —
   the full-bleed portrait behind the text, and the word "points" stacked
   under a number that is itself only 11px. The rest gets a size floor. */
body.otbc-rail .ofelt-lb .ofelt-face{ opacity:.28 }
body.otbc-rail .ofelt-lb .ofelt-pts s{ display:none }
body.otbc-rail .ofelt-lb .ofelt-pts{ display:flex;align-items:center }
body.otbc-rail .ofelt-lb .ofelt-pts b{
  font:900 var(--bcRailPt,14px)/1 Cairo,sans-serif;color:#eafcff;
  font-variant-numeric:tabular-nums;text-shadow:0 1px 3px rgba(0,0,0,.8) }
body.otbc-rail .ofelt-lb .ofelt-nm{
  /* 1.7, not 1.2 — Arabic ink measures ~1.7x the font size and `overflow:hidden`
     below turns a short line box into a clip, not a tight rhythm. Measured: a 23px
     <bdi> inside a 14.4px box, 5.0px off the bottom of every name in the rail. */
  font:800 var(--bcRailNm,12px)/1.7 Cairo,sans-serif;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
  text-shadow:0 1px 3px rgba(0,0,0,.85) }
body.otbc-rail .ofelt-lb .ofelt-st{
  font:700 var(--bcRailSt,10px)/1.2 Cairo,sans-serif;
  text-shadow:0 1px 3px rgba(0,0,0,.85) }
body.otbc-rail .ofelt-lb .ofelt-rk{
  font:800 var(--bcRailRk,12px)/1 Cairo,sans-serif;
  font-variant-numeric:tabular-nums }
body.otbc-rail .ofelt-lb .ofelt-av{
  width:var(--bcAv,26px);height:var(--bcAv,26px) }

/* ------------------------------------------------------------- B: the hand
   rides the felt's near rim instead of taking a band under it. The fan is
   absolutely placed over the table rather than stacked below, which hands
   the whole 0.896*SH term of the vertical budget back to the card. The near
   rows of the field are empty far more often than not, so it lands on felt,
   not on cards — and it is the thing your thumb is on anyway. */
body.otbc-overlap .handwrap{
  bottom:var(--bcHandDrop,-6px)!important;
  height:var(--fhandH,150px)!important;
  z-index:14;pointer-events:none }
body.otbc-overlap .handwrap .hand{ pointer-events:auto }
/* a wash under the fan so a light card never sits on a light patch of felt */
body.otbc-overlap .handwrap::before{
  content:"";position:absolute;left:0;right:0;bottom:0;height:130%;
  background:linear-gradient(180deg,rgba(6,12,16,0),rgba(6,12,16,.55) 45%,rgba(6,12,16,.82));
  pointer-events:none;z-index:-1 }

/* ------------------------------------------------------------- C: the floors
   The card stops shrinking. The field then no longer fits inside the felt,
   so it runs past it and crops at the screen edge — which is what the
   ellipse itself already does deliberately (the design overscans it ~2.4x).
   The table becomes a window onto the pool rather than the whole pool. */
body.otbc-crop .ofelt-slots{ overflow:visible }
body.otbc-crop .ofelt-felt{ overflow:visible }
/* the near and far edges get a fade so a cropped row reads as "there is more"
   rather than as a bug */
body.otbc-crop .ofelt-table::after{
  content:"";position:absolute;inset:0;z-index:12;pointer-events:none;
  background:linear-gradient(180deg,rgba(8,14,19,.85),rgba(8,14,19,0) 14%,
                             rgba(8,14,19,0) 86%,rgba(8,14,19,.85)) }

/* ============================================================== D: STACKED
   THE OWNER'S IDEA, and it is the right one: there are only 28 letters in
   Arabic and 26 in English, so a 35-card pool can never need more than 28
   places and early in a round needs a handful. Duplicates pile up on ONE
   place and the table gives most of itself back to the cards.

   USING THE SAME LETTER TWICE still works, which was his first question about
   it: every copy stays in the DOM and stays clickable. The pile is ordered
   unselected-first, so the card under your thumb is always the next one you
   have not spent; tap it three times and you take three. The chip counts what
   is still AVAILABLE, not how many were thrown, so it answers the only
   question you actually have while spelling.
   ---------------------------------------------------------------------- */
/* EVERY COPY IS STILL A DIRECT GRID CHILD of .pool — felt.js places, sizes and
   re-skins those, so wrapping them in a pile div stripped the metal face and
   the 3D placement off every card on the table. A pile is made by sharing a
   grid CELL, not by sharing a parent. */
/* THE PILE LOOKS LIKE A PILE — the owner's reference image: two cards read as
   two cards, three as three, no ×N chip. Each copy under the top one peeks
   out low and slightly turned, a loose deck on the felt. */
/* RAISED, like the owner's reference: each copy stands a step ABOVE the one
   before it, peeking over the top edge — «مرتفعين فوق بعض» — so a pile reads
   as a pile at a glance, before anyone writes a word. */
/* BOTH DECLARATIONS MUST BE !important, and neither was — which is why the pile
   stayed perfectly flat even once stackPool() started running again:
   - felt.css has `body.ot-felt .pool .pcard{animation:none!important;transform:none!important}`
     because an element that ANIMATES inside the table's preserve-3d parent is promoted
     to its own compositing layer and paints outside the projection. That reason is about
     ANIMATION, so `animation:none` is left exactly as it is; a STATIC transform composes
     inside the 3D context instead of escaping it, which is precisely what a peeking card
     wants. This selector already outranks felt's, so !important settles it.
   - z-index was being beaten by an INLINE `el.style.zIndex='1'` that the game's
     syncPoolSel() writes onto every unselected pool card after each tap, which flattened
     the pile's depth order to plain DOM order. A stylesheet !important outranks a
     non-important inline style, so the pile keeps its own stacking. */
body.otbc-stack .pool .pcard.bcdeep{
  pointer-events:auto;
  transform:translate(calc(var(--bci,1) * 5%),calc(var(--bci,1) * -16%)) rotate(var(--bcr,0deg))!important;
  z-index:calc(40 - var(--bci,0))!important }
/* the pile's front card sits above the copies peeking out behind it (see bcdeep above:
   the game writes an inline z-index:1 onto it, which the deep copies' 39/38 would beat) */
body.otbc-stack .pool .pcard.bctop{ z-index:41!important }
/* a spent copy stays in the pile — readable, not ghosted, still tappable */
body.otbc-stack .pool .pcard.bcspent{ opacity:.55 }
/* the buried copies' order numbers, surfaced on the pile's top card so a fast
   speller sees every selection the word already holds */
body.otbc-stack .pool .bcords{ position:absolute;z-index:62;top:-12%;left:50%;
  transform:translateX(-50%);display:flex;gap:2px;pointer-events:none }
body.otbc-stack .pool .bcords b{ min-width:calc(var(--cc,10px) * 1.75);
  height:calc(var(--cc,10px) * 1.75);padding:0 2px;border-radius:999px;
  box-sizing:border-box;display:flex;align-items:center;justify-content:center;
  background:linear-gradient(180deg,#8ff6f6,#0f8fa0);color:#04222a;
  border:1px solid rgba(4,26,32,.55);
  font:900 calc(var(--cc,10px) * 1.02)/1 Cairo,sans-serif;
  font-variant-numeric:tabular-nums;
  box-shadow:0 0 10px rgba(69,237,237,.85),0 2px 4px rgba(0,0,0,.5) }

/* ---- the word box stays on screen for the whole round ----
   It used to arrive only for the spelling phase, which is both a layout jump
   and a surprise. Reserved and visible throughout, it is furniture, not an
   event. */
/* The word box only exists once the spelling phase starts, so the round markup
   now also carries a DISABLED twin for the throwing phase. It is hidden for
   everyone by default — live play is exactly as it was — and only this trial
   shows it, which is what makes the box "always visible" without giving anyone
   a field they could type into before the buzzer. */
.racebar.prebar{ display:none }
body.otbc-keepbar .racebar.prebar{ display:flex;opacity:.55 }
body.otbc-keepbar .racebar.prebar input{ cursor:default }

/* ---- the hand, spread so every letter is readable ----
   The fan overlapped by 11-13px a card, which on a phone buried the letters
   behind each other. The owner asked to keep the fan and open it out. */
/* the overlap itself now comes from the painter (--hfan in felt.js/felt.css),
   which sizes the held card and spreads the fan against THAT rather than
   against a place on the table — in live play too, not only under a trial */
body.otbc-spread .handwrap{ padding-bottom:calc(2px + env(safe-area-inset-bottom)) }

/* ---- E: THE WORD PLATE ----
   The typing box is gone; the word the player is building is READ on a plate
   standing over the felt's left margin — the strip the ellipse spills into and
   nothing else uses — with erase and lock-in on the plate itself. The table
   gets the input's whole band back (felt.js skips the bar reserve under
   .otbc-sideword). Glass over artwork, per the house style; the lock button
   stays solid because it is the primary act of the round. */
body.otbc-sideword .racebar{ display:none!important }
/* NOTHING between the hand and the table — the cue line moves onto the plate,
   and felt.js stops reserving its band (the owner: "I don't want anything
   between my cards on hand and the cards on table") */
body.otbc-sideword .arena-cen > .instr{ display:none!important }
/* BACK IN THE LEFT COLUMN. The round-2 bake carried a -248px drag that was
   made BLIND (the bench panel stood on the plate) and it stranded the word
   entry above the screen on phones — the owner: "the word entry must exist
   on mobile." The designed centring returns, and the bench vars now COMPOSE
   with it (the -50% lives inside the same translate), so whatever is tuned
   next is exactly what ships — the replace-the-centring trap is closed. */
.bcword{ position:fixed;z-index:15;left:calc(6px + env(safe-area-inset-left));
  top:var(--bcwTop,50%);
  transform:translate(var(--twWordX,0px),calc(var(--twWordY,0px) - 50%));
  width:clamp(96px,14vw,150px);box-sizing:border-box;
  display:flex;flex-direction:column;gap:7px;align-items:stretch;
  padding:10px 10px 9px;border-radius:14px;
  background:rgba(13,20,27,.55);border:1px solid rgba(255,255,255,.09);
  backdrop-filter:blur(9px);-webkit-backdrop-filter:blur(9px);
  box-shadow:0 10px 28px rgba(0,0,0,.5);
  font-family:Cairo,sans-serif;text-align:center }
.bcword .bcwlbl{ font-size:9px;font-weight:900;letter-spacing:1.2px;
  color:rgba(140,235,247,.75);text-transform:uppercase }
/* the word itself — the thing the plate exists to show. Wraps and breaks
   because a 15-letter word must still be read on a 96px plate. */
.bcword .bcwrd{ min-height:34px;display:flex;align-items:center;justify-content:center;
  font-size:clamp(17px,4.6vh,24px);font-weight:900;line-height:1.15;color:#eafcff;
  letter-spacing:.5px;word-break:break-all;overflow-wrap:anywhere;
  text-shadow:0 1px 4px rgba(0,0,0,.7) }
/* break-all is for a 15-letter WORD on a narrow plate — on the HINT it cut
   «الطاولة» mid-word and left a lone ة on its own line */
.bcword .bcwrd i{ font-style:normal;font-size:12px;line-height:1.5;font-weight:800;
  color:rgba(210,240,246,.8);letter-spacing:0;
  word-break:normal;overflow-wrap:normal;white-space:normal }
.bcword.ok .bcwrd{ color:#8DEBF7;text-shadow:0 0 14px rgba(69,237,237,.45) }
.bcword .bcwsc{ min-height:14px;font-size:13px;font-weight:900;
  font-variant-numeric:tabular-nums;color:#f2b84b }
.bcword.locked{ border-color:rgba(242,184,75,.4) }
.bcword.locked .bcwrd{ color:#f2d98b }
.bcword.locked .bcwbtns{ display:none }
/* THE TWO ACTS OF THE ROUND, unmissable — the owner: "make lock-in and erase
   more obvious." Full-height buttons in the plate, the lock glowing when the
   word is real. */
.bcword .bcwbtns{ display:flex;flex-direction:column;gap:6px }
.bcword .bcwbtns button{ all:unset;cursor:pointer;box-sizing:border-box;width:100%;
  min-height:40px;display:flex;align-items:center;justify-content:center;
  border-radius:11px;font:900 15px/1 Cairo,sans-serif;
  transition:transform .1s ease,box-shadow .15s ease }
.bcword .bcwbtns button:active{ transform:scale(.96) }
.bcword .bcwclear{ color:#dff2f6;border:1px solid rgba(150,220,230,.4);
  background:rgba(6,12,16,.5) }
.bcword .bcwclear:hover{ color:#fff;border-color:rgba(150,220,230,.7) }
.bcword .bcwlock{ background:linear-gradient(135deg,#0f7f92,#45eded);color:#04252b;
  box-shadow:0 6px 18px -6px rgba(69,237,237,.7) }
.bcword.ok .bcwlock{ box-shadow:0 0 0 2px rgba(69,237,237,.5),0 0 22px rgba(69,237,237,.65);
  animation:bcwReady 1.4s ease-in-out infinite }
@keyframes bcwReady{0%,100%{filter:brightness(1)}50%{filter:brightness(1.22)}}
.bcword .bcwlock:disabled{ opacity:.35;cursor:default;box-shadow:none;animation:none }

/* the tapped letter lifts off its card and lands on the plate */
.bcwfly{ position:fixed;z-index:100002;pointer-events:none;
  transform:translate(-50%,-50%);opacity:1;
  font:900 min(6vh,34px)/1 Cairo,sans-serif;color:#eafcff;
  text-shadow:0 0 14px rgba(69,237,237,.9),0 2px 6px rgba(0,0,0,.8);
  transition:transform .42s cubic-bezier(.25,.9,.35,1),opacity .42s ease }
.bcword.bcwtake{ animation:bcwTake .4s ease }
@keyframes bcwTake{0%{box-shadow:0 10px 28px rgba(0,0,0,.5)}
  45%{box-shadow:0 0 0 3px rgba(69,237,237,.55),0 0 30px rgba(69,237,237,.5)}
  100%{box-shadow:0 10px 28px rgba(0,0,0,.5)}}
@media(prefers-reduced-motion:reduce){ .bcwfly{display:none} .bcword.bcwtake{animation:none} .bcword.ok .bcwlock{animation:none} }
/* waiting (throw phase): furniture, present but quiet — the mechanism is
   announced before it is needed, which is what makes it a mechanism and not
   a surprise */
.bcword.wait{ opacity:.55 }
/* …AND THE BUTTONS ARE PART OF THE FURNITURE. Owner, 2026-08-15: «تكون الأزرار
   موجودة ولكنها مطفئة حتى يقوم اللاعب برمي الورقة». Hiding them contradicted
   the line directly above — a mechanism cannot be announced before it is needed
   while it is off the screen — and it cost «كلمتك» its shape: the plate stood
   two rows shorter through the whole throw phase and grew the instant the race
   opened, so the console jumped under the thumb at the one moment nobody can
   afford to look away. They stand where they will stand, switched off (all
   three are disabled in the wait state — bigcards.js), and nothing moves when
   the round begins. */
.bcword.wait .bcwbtns{ display:flex }
/* AND THEY ARE DIMMED ONCE, NOT TWICE. The plate above already sits at .55, so
   a button carrying its own .45 off-state landed at .25 — present in the DOM and
   very nearly absent to the eye, which is not what «مطفئة» asks for. .82 of .55
   is .45: the identical off-state the same button wears in the race with an
   empty word, so "switched off" looks like one thing in this console and not
   two. Scoped to `.wait`; the race keeps its own value untouched.
   ⚠️ THE `body ` PREFIX IS LOAD-BEARING. console-skin.css paints the same
   buttons with `body.otcs .bcword .otcs-act[disabled]{opacity:.45}` — the same
   specificity as this rule without it, and it is linked AFTER this file, so the
   plain selector would lose every time on the only pages that exist. Measured,
   not counted. */
body .bcword.wait .bcwbtns button[disabled],
body .bcword.wait > button.bcwlock:disabled{ opacity:.82 }
@media (max-height:420px){
  .bcword{ padding:7px 8px 6px;gap:5px }
  .bcword .bcwrd{ min-height:26px }
  /* still a thumb-sized target — the owner asked for OBVIOUS, and a short
     screen is exactly where his thumb is doing the work */
  .bcword .bcwbtns button{ min-height:36px;font-size:14px } }

/* ---- FULL BLEED ----
   The game sits in a 1080px frame with an 18px radius, a border and 12px of
   padding. On a desktop that is the design; on a phone it is a dark margin
   around all four sides of a screen we are fighting for every pixel of. The
   owner: "this is not acceptable for the mobile since we want to get use of
   every empty space." */
@media (max-width:1024px){
  body.otbc-bleed .frame{ max-width:none!important;margin:0!important;width:100%!important }
  body.otbc-bleed .stage{
    border:0!important;border-radius:0!important;
    padding:calc(2px + env(safe-area-inset-top)) calc(2px + env(safe-area-inset-right))
            calc(2px + env(safe-area-inset-bottom)) calc(2px + env(safe-area-inset-left))!important }
  body.otbc-bleed .app,body.otbc-bleed .wrap{ padding:0!important;margin:0!important }
}

/* --------------------------------------------------------------- the switch
   A small strip so the owner can flip between the three on the device he is
   holding, without editing a URL by hand. Trials only — it is never on
   without ?cards=. */
/* IT COLLAPSES, because a control for judging the table must not cover the
   table. Top-centre put it straight over the clock — the owner's own screenshot
   shows «الوقت المتبقي» gone behind it. Collapsed it is a chip in the corner
   the game leaves empty; tapped, it opens the full row, and tapping a trial
   closes it again by navigating. */
.bcbar{position:fixed;z-index:100001;display:flex;align-items:center;gap:4px;
  inset-inline-end:calc(6px + env(safe-area-inset-right));
  bottom:calc(46px + env(safe-area-inset-bottom));
  padding:3px 5px;border-radius:999px;font-family:Cairo,sans-serif;
  background:rgba(6,12,16,.88);border:1px solid rgba(120,214,226,.35);
  backdrop-filter:blur(6px);-webkit-backdrop-filter:blur(6px);
  box-shadow:0 6px 20px rgba(0,0,0,.6);max-width:calc(100vw - 16px)}
.bcbar b{font-size:9px;font-weight:800;letter-spacing:.6px;color:#45eded;padding:0 4px}
.bcbar button{all:unset;cursor:pointer;padding:5px 10px;border-radius:999px;
  font:800 11px/1 Cairo,sans-serif;color:#bfe6ee;white-space:nowrap}
.bcbar button:hover{color:#eafcff}
.bcbar button.on{background:linear-gradient(135deg,#0f7f92,#45eded);color:#04252b}
/* the live sizes stay on ONE line — stacked in a 40px column they were unreadable */
.bcbar .bcnum{font:700 9.5px/1 Cairo,sans-serif;color:rgba(190,232,240,.7);
  padding-inline:6px;border-inline-start:1px solid rgba(255,255,255,.14);
  font-variant-numeric:tabular-nums;white-space:nowrap;direction:ltr}

/* the handle: always visible, always tiny */
.bctog{all:unset;cursor:pointer;flex:none;display:flex;align-items:center;justify-content:center;
  gap:4px;padding:5px 10px;border-radius:999px;
  font:800 11px/1 Cairo,sans-serif;color:#04252b;
  background:linear-gradient(135deg,#0f7f92,#45eded)}
.bctog i{font-style:normal;font-weight:900}
/* collapsed: everything but the handle stands down */
.bcbar.shut > :not(.bctog){display:none}
@media (max-width:520px){ .bcbar b{display:none} .bcbar button{padding:5px 8px;font-size:10.5px} }

/* phones do not pay for glass (see felt.css) — tint without blur */
@media (max-width:1024px){
  .bcword,.bcbar{backdrop-filter:none!important;-webkit-backdrop-filter:none!important}
  .bcword{background:rgba(11,18,24,.82)}
}

/* ---- the word, read BIG + the undo-letter key (owner asks, 2026-07-31) --- */
.bcword .bcwrd .bcww{ font-size:clamp(19px,3.4vh,26px);font-weight:900;letter-spacing:1.5px;
  line-height:1.25;display:inline-block;animation:bcwpop .16s ease-out }
@keyframes bcwpop{ from{transform:scale(1.22)} to{transform:scale(1)} }
/* THE BUTTONS DECIDE FOR THEMSELVES WHETHER THEY FIT. They share one row, and
   the question "is there room for two Arabic labels?" was being answered by a
   VIEWPORT test — `@media (min-width:1200px)` — for buttons that live in
   --hudCol: clamp(92px, 12.5vw, 210px). Those are different measurements. At
   1257px (the owner's laptop, 2026-08-05) the media query says yes and the
   column is 12.5vw ≈ 157px, so each button gets ~75px with nowrap — and
   «إزالة الكلمة» cannot be drawn in 75px any more than in the 42px that caused
   the first report. So they ran into each other again, and «ثبّت» under them:
   «كل شيء فوق بعض». The earlier note assumed ~150px was enough for two Arabic
   labels. It is not, and no fixed breakpoint can know that — the answer depends
   on the label, the font and the language, none of which a px threshold sees.
   min-width:max-content makes each button refuse to be drawn narrower than its
   own text, and wrap lets the second one drop to its own line the moment both
   will not fit. Side by side when there is truly room, stacked when there is
   not, at every width and in both languages, with nothing to keep in sync. */
.bcword .bcwbtns .bcwrow{ display:flex;flex-wrap:wrap;gap:5px }
.bcword .bcwbtns .bcwrow button{ flex:1 1 auto;min-width:max-content;white-space:nowrap }
/* every button in the group, not only the undo. The skin has its own disabled
   face (console-skin.css `.otcs-act[disabled]`) and both live pages load it —
   but «إزالة الكلمة» had no unskinned off-state at all, so if the skin ever
   failed to dress it the button would read fully lit while refusing the press. */
.bcword .bcwback[disabled],.bcword .bcwclear[disabled]{ opacity:.45;cursor:default }
/* ===== FROZEN: THE WHOLE CONSOLE GOES OUT ==================================
   A frozen player could still press Erase, Undo letter and Lock in. Nothing
   happened when he did — both tables refuse the tap and say why — but the
   buttons stayed lit and took the press, which reads as a game that swallowed
   the tap rather than a rule that stopped it. Owner: «إما بإخفاء الأزرار أو
   جعلها رمادية اللون وغير قابلة للضغط».
   GREY, NOT HIDDEN, and only the buttons: hiding them collapses the column and
   moves the clock and the word plate mid-round, and those two are exactly what a
   frozen player is still reading — he is counting the seconds he is losing.
   The `disabled` ATTRIBUTE is deliberately NOT used. bigcards.js owns it, sets
   all three every tick, and would overwrite anything written from outside on its
   next pass. Frozen is a state that logic does not know about, so it is said
   where that logic does not compete — a body class and pointer-events.
   ⚠️ EVERY DECLARATION CARRIES !important, and that is not belt-and-braces:
   console-skin.css paints `.otcs-act` with its own !important filter and
   opacity, so the first version of this rule greyed Lock in and left ERASE at
   full strength — dead to the pointer but still lit, which is the same
   half-truth in a quieter voice. Measured, not assumed.
   The class is set by each table from its own single source of ice:
   overtake.html syncPoolIce(), overtake-online.html syncFrozenClass(). */
body.otw-frozen .bcword button{ filter:grayscale(1) brightness(.55) !important;
  opacity:.42 !important;pointer-events:none !important;cursor:not-allowed;
  box-shadow:none !important;transition:filter .28s ease,opacity .28s ease }
@media(prefers-reduced-motion:reduce){ body.otw-frozen .bcword button{ transition:none } }

/* ===== SELF-CONTAINED SKINS STAND ALONE (owner, 2026-08-01: «صايرين فوق بعض») =====
   A purchased skin like Arcane is a complete SVG card — frame, face, glow and values
   all inside it. The steel dress and the reflection gloss must stand down entirely,
   or the two designs render stacked on one card. */
.face.arcane,.face.arcane.hcard,.face.arcane.pcard{background:none!important;box-shadow:none!important;border:none!important}
.face.arcane::before,.face.arcane::after{display:none!important;content:none!important}
.face.arcane .acard-svg{position:relative;z-index:1}


/* ==== short viewports (owner's phone, ~400px tall), 2026-08-01 ====
   the vertically-centred word plate swallowed the felt clock (the timer
   ghosted THROUGH the plate) — below the clock instead; and the two small
   buttons breathe and wrap so «Undo letter» never runs into «Erase» */
@media (max-height:460px){
  body.ot-felt .bcword{ top:calc(128px + var(--twWordY,0px)); transform:translate(var(--twWordX,0px),0) }
  .bcword .bcwbtns .bcwrow{ gap:5px }
  /* ONE BUTTON PER LINE, FULL WIDTH — and it is min-width:max-content that
     guarantees it, not a flex-direction. Releasing min-width here (which the
     first version of this did, to let long labels wrap inside a narrow button)
     let «إزالة الكلمة» and «مسح حرف» squeeze side by side at ~40px each on the
     87px HUD column of a landscape phone; each then wrapped to three lines and
     the plate grew to 206px inside a 127px max-height, so `overflow:hidden` ate
     the bottom of it — including «ثبّت», the button that commits your word.
     Measured at 844x390. Kept at max-content, neither label fits beside the
     other at this width, so they wrap onto their own full-width lines by
     themselves — the old stacked layout, arrived at by measurement instead of
     by a breakpoint. Only the type gets smaller here. */
  .bcword .bcwbtns .bcwrow button{ line-height:1.15;font-size:10px;padding:5px 4px }
  /* THE PLATE MUST FIT THE ROOM IT IS GIVEN, AND «ثبّت» MUST ALWAYS BE REACHABLE.
     leftcol.js sizes this plate with an inline `max-height … !important` from
     whatever the column has left, and on a landscape phone that came to 127px
     around 205px of content — with overflow:hidden, so «ثبّت», the button that
     COMMITS YOUR WORD, sat at 163px and could be neither seen nor pressed.
     Measured at 844x390 AR. Two answers, together:
     · spend less height — the caption is redundant when the word is right under
       it, and the buttons do not need 36px to hold 10px type;
     · and if a column is ever tighter still, the plate scrolls rather than
       swallowing a control. A scrollbar is a poor HUD; an unreachable Lock-in
       button is a broken game. */
  .bcword .bcwlbl{ display:none }
  /* AND IT MUST NOT SCROLL AT ALL. The owner, on the phone: «النص كبير مما يؤدي
     إلى جعلي أنزل للأسفل لإكمال القراءة في كلمتك». overflow:auto stopped the
     Lock-in button being swallowed, but a HUD you have to scroll during a
     15-second race is still a HUD you cannot use. Measured after the first pass:
     129px of content in a 127px box — two pixels. The empty score line and the
     plate's own padding are where they come from; the scroll stays behind it
     only as the guarantee it was added to be, never as the normal state. */
  .bcword{ padding-block:6px }
  .bcword .bcwsc:empty{ display:none }
  .bcword .bcwbtns .bcwrow{ gap:4px }
  .bcword .bcwbtns .bcwrow button{ padding:3px 4px;min-height:0 }
  /* ⚠️ SPLIT OFF FROM THE ROW BUTTONS, DELIBERATELY. The two shared one selector,
     so the zero that the secondary buttons need was also being applied to the one
     control that COMMITS THE WORD — measured 72.4x20 on overtake.html at 880x400,
     64x20 at 740x360, 96.5x21 at 932x430, at a computed min-height of 0.
     Growing `.bcwrow button` too was measured and rejected: it takes the plate to
     152.5px against leftcol.js's 150px cap. This one does not — measured .bcword
     is 122px inside that 150px cap, so +16px lands at 138px with 95px of empty
     column still below it.
     This selector matches only the UNSKINNED page: console-skin.js lifts «ثبّت»
     out of `.bcwbtns` on overtake-online.html, where console-skin.css owns it. */
  .bcword .bcwbtns .bcwlock{ padding:3px 4px;min-height:36px }
  .bcword .bcwrd .bcww{ font-size:clamp(15px,2.6vh,19px) }
  /* `body.otw-on .bcword` in overtake-online.html carries the overflow:hidden and
     outranks a bare .bcword, so the guarantee has to be stated at least as loudly
     as the thing that swallows the button. */
  body.otw-on .bcword,
  body.ot-felt .bcword{ overflow-y:auto!important;overscroll-behavior:contain }
}
/* ===== A LETTER GLOWS IN ITS OWN METAL =====
   The owner asked for the wildcard's hover light to be the card's own colour
   rather than one borrowed cyan, and then for the same on the letters. They
   already ship in two metals — steel, and gold once a letter is worth 6 or
   more — so the light is simply the metal it is made of. The purchased skins
   keep their own. Pool cards get it too: in this mode you build the word by
   tapping the TABLE, so those are the ones under the finger.
   No layout is touched — transform and filter only, so nothing reflows. */
.hand .hcard,.pool .pcard{ --cardGlow:rgba(186,214,226,.8);
  transition:transform .14s ease,filter .16s ease }
.hand .hcard.hi,.pool .pcard.hi{ --cardGlow:rgba(240,196,90,.95) }
.hand .hcard.arcane,.pool .pcard.arcane{ --cardGlow:rgba(154,95,208,.9) }
@media (hover:hover){
  .hand .hcard:hover,.pool .pcard:hover{ transform:translateY(-3px);
    filter:drop-shadow(0 0 4px var(--cardGlow)) drop-shadow(0 0 12px var(--cardGlow)) }
}
/* SELECTING A CARD LIGHTS IT IN ITS OWN METAL TOO.
   The selected ring was a flat `box-shadow: 0 0 0 2px var(--cyan)` on every
   card — so picking a gold letter lit it cyan, which is the same complaint as
   the hover glow one level down: «كل بطاقة نفس اللون». The ring, the spread and
   the halo now all read --cardGlow, so a gold letter selects gold and a steel
   one selects steel. Higher specificity than the .pcard.sel rule it replaces
   (0,3,0 against 0,2,0), so it wins without !important. */
.pool .pcard.sel,.hand .hcard.sel{
  outline-color:var(--cardGlow);
  box-shadow:0 0 0 2px var(--cardGlow),0 10px 22px -6px var(--cardGlow);
  filter:drop-shadow(0 0 5px var(--cardGlow)) drop-shadow(0 0 14px var(--cardGlow)) }

/* ===== YOU STILL OWE A CARD — the table says so =====
   Driven by body.ot-needthrow (bigcards.js). The felt goes quiet and the four
   things that matter stay lit: the hand you throw FROM, the clock you are
   racing, the wildcard you may still hold, and the rail that says who else is
   still deciding. Nothing moves and nothing is disabled — this is a change of
   emphasis, not of layout, so it cannot push anything off a small screen.
   The hand keeps full pointer events throughout; dimming must never make the
   thing you are being asked to press harder to press. */
/* ONE dim, two states. body.ot-locked (below) wants exactly this quieting and
   nothing else, so it shares the declaration rather than picking its own
   brightness — two "off" tables that were off by different amounts would read
   as two different things happening. They can never collide: ot-needthrow is
   the discard phase, ot-locked is the race. */
body.ot-needthrow .ofelt-table,
body.ot-needthrow .pool,
body.ot-needthrow .board,
body.ot-locked .ofelt-table,
body.ot-locked .pool,
body.ot-locked .board{ filter:brightness(.5) saturate(.7);
  transition:filter .3s ease }
/* Z-INDEX ONLY — the position:relative that used to sit here WAS the owner's
   «when I go fullscreen the cards go off to the right and are not where they
   were». The felt lays the hand out as position:absolute, left:0, with a width
   that ENCODES ITS CENTRE: felt.js writes --fhandW as centre*2, so a centred
   flex row inside it lands exactly on the centre it picked. Forcing the element
   back to relative drops the left:0 and turns it into an in-flow block narrower
   than its wrap — and where the spare width goes is then decided by the page
   direction. In English it falls to the right and the hand looks correct by
   accident; in ARABIC the page is RTL, the spare falls to the LEFT, and the hand
   is pushed that far right, under the players panel. It scales with the rail, so
   it is invisible on a phone and glaring at fullscreen: measured at 1902x1057 in
   Arabic, centre 1036 where felt.js asked for 866 — off by exactly the 171px of
   spare width.
   Nothing is lost. z-index needs a positioned element, not specifically a
   relative one: the base .hand rule is already relative for the other two table
   designs, and the felt's own rule is absolute. Both take a z-index. */
body.ot-needthrow .hand{ z-index:16 }
/* THE HAND RISES. The owner: "the cards should just float up and dim the table
   so we can only see the cards ... right now the cards are moving towards the
   right, I would like them just to go up a bit, indicating that we need to
   throw them."
   Measured before touching it: every card's travel was 0px on BOTH axes while
   the prompt was up — the state only pulsed a glow and never moved anything.
   What reads as drifting right is the fan itself, which is static: each slot is
   rotated 7deg or 14deg and pushed down at the edges, so the outer cards sit
   lower and lean. That is the hand's normal shape and it stays.
   What was missing is the lift, and it goes on `translate`, NOT on `transform`
   — the fan lives in a transform on the slot and a second transform here would
   fight it. `translate` composes with it instead, so the whole fan keeps its
   arc and simply floats, straight up, no sideways component at all. */
body.ot-needthrow .hand .hcard{
  animation:otNeed 1.6s ease-in-out infinite, otNeedLift 2.1s ease-in-out infinite }
@keyframes otNeed{ 0%,100%{ filter:drop-shadow(0 0 3px var(--cardGlow)) }
  50%{ filter:drop-shadow(0 0 9px var(--cardGlow)) drop-shadow(0 0 18px var(--cardGlow)) } }
@keyframes otNeedLift{ 0%,100%{ translate:0 -7px } 50%{ translate:0 -18px } }
/* the clock, the card and the rail stay at full strength and pick up a ring */
body.ot-needthrow .ofelt-clock{ animation:otNeedRing 1.6s ease-in-out infinite }
body.ot-needthrow .otw-slot .gw-wrap{ animation:otNeedRing 1.6s ease-in-out infinite }
body.ot-needthrow .ofelt-lb{ animation:otNeedRing 1.6s ease-in-out infinite }
@keyframes otNeedRing{ 0%,100%{ filter:none }
  50%{ filter:drop-shadow(0 0 8px rgba(240,192,79,.55)) } }
/* CALMER, NOT DEAD. This branch used to stop the hand outright, and the owner —
   whose desktop has Windows' animation effects switched off, so his browser asks
   for reduced motion while his tablet does not — reported the difference as a
   bug: «حركة الطيران موجودة في التابلت ولكنها ليست موجودة في المتصفح». It was
   the preference being honoured, and honouring it is right; stopping dead was
   the part that was wrong. «اجعل الحركة أهدأ».

   So the float stays and is turned down instead: 4px of travel where the full
   version has 11, over 6.4s rather than 2.1, and no glow pulse at all — the
   drop-shadow is held at a constant strength. What reduced-motion exists to
   prevent is large, fast, vestibular movement; a slow 4px drift is none of
   those, and it keeps the one thing the state has to say, which is that the
   table is waiting for a card. The clock, the wildcard and the rail keep their
   pulse suppressed outright — those are FILTER flashes, which is exactly the
   kind of motion this preference is asking us not to do. */
@media (prefers-reduced-motion:reduce){
  body.ot-needthrow .ofelt-clock,
  body.ot-needthrow .otw-slot .gw-wrap,
  body.ot-needthrow .ofelt-lb{ animation:none }
  body.ot-needthrow .hand .hcard{
    filter:drop-shadow(0 0 7px var(--cardGlow));
    animation:otNeedLiftCalm 6.4s ease-in-out infinite }
  @keyframes otNeedLiftCalm{ 0%,100%{ translate:0 -11px } 50%{ translate:0 -15px } }
}

/* ===== THE EMOJI TRAY — under the players panel, in squares, on a lock =====
   Driven by overtake/reacttray.js, which measures the rail and publishes
   --otrtR / --otrtW / --otrtB. Nothing here is a fixed column: the rail is
   0.175 of the width on a phone and 0.265 on a desktop, so the tray is given
   the rail's own measured box and simply sits at its foot.

   SQUARES, as asked — aspect-ratio 1 on an auto-fill grid, so the cells stay
   square while the count per row follows the width the rail can spare. The tray
   opens UPWARD, because it stands at the bottom of the panel and there is
   nothing below it to open into.

   THE LOCK IS VISIBLE. While the five seconds run the button turns to the
   number of seconds left and the cells go flat and unclickable — a lock the
   player cannot see reads as a broken button. */
/* AN ICON, THE SAME SIZE AND DRESS AS THE PANEL'S OWN ARROW (.ofelt-lbtog, 34px
   glass square) — the owner asked for the two to behave as a pair, so they should
   read as a pair. It was a labelled bar as wide as the rail (--otrtW), which
   announced itself far more loudly than the control beside it and covered a strip
   of felt the whole match. --otrtW still sizes the TRAY; only the button shrank. */
/* IT RIDES WITH THE ARROW. --otrtR mirrors .ofelt-lbtog's own target offset and
   --otrtT parks this directly beneath it, and the right transition is copied from
   that arrow verbatim so the pair slides across on one curve when the rail opens
   or closes, instead of one control travelling and the other staying put. */
.otrt-btn{ position:fixed;z-index:58;
  right:var(--otrtR,10px);top:var(--otrtT,48px);width:34px;height:34px;
  display:none;align-items:center;justify-content:center;
  padding:0;border-radius:9px;cursor:pointer;
  font:800 13.5px/1 Cairo,sans-serif;
  color:#bfe6ec;background:rgba(13,20,27,.62);border:1px solid rgba(255,255,255,.14);
  -webkit-backdrop-filter:blur(9px);backdrop-filter:blur(9px);
  box-shadow:0 6px 18px -8px rgba(0,0,0,.85);
  font-variant-numeric:tabular-nums;
  transition:color .15s,border-color .15s,background .15s,transform .1s,
             right .38s cubic-bezier(.4,0,.2,1) }
.otrt-btn:hover{ background:rgba(14,28,36,.92);border-color:rgba(76,215,246,.7);color:#eafcff }
.otrt-btn:active{ transform:scale(.93) }
/* ===== BOTH TOGGLES FILL WITH THE LOGO COLOUR WHEN THEY ARE ON =====
   The owner: «make the background of the icon of the arrow to be the logo color and
   invert the arrow inside it, and same for the emoji icon». So ON is not a tint on
   the same glass chip — it is the inverse: the brand teal floods the button and the
   glyph goes dark against it, which is the one state you can read at a glance from
   across a phone in landscape. #1FE9DD→#0AB6D4 is the logo's own teal, not a near shade.
   Each is ON when ITS OWN panel is showing: the emoji button while the tray is open,
   the arrow while the rail is out. They are mutually exclusive, so at most one of
   the two is ever lit — which is itself the clearest statement of the pairing. */
.otrt-btn.on{ color:#04222a;border-color:transparent;
  background:linear-gradient(180deg,#1FE9DD,#0AB6D4);
  box-shadow:0 6px 18px -8px rgba(10,182,212,.75) }
.otrt-btn.on:hover{ color:#04222a;border-color:transparent;
  background:linear-gradient(180deg,#3ff2e7,#12c3e2) }
/* the rail's arrow, lit while the rail is out. felt.css owns .ofelt-lbtog; this
   file loads after it and this selector outranks it, so the base chip is untouched
   and only the lit state is added. Its svg is stroke:currentColor, so the glyph
   inverts with the colour and needs no rule of its own. */
body.ot-felt:not(.ot-lbhide) .ofelt-lbtog{ color:#04222a;border-color:transparent;
  background:linear-gradient(180deg,#1FE9DD,#0AB6D4);
  box-shadow:0 6px 18px -8px rgba(10,182,212,.75) }
.otrt-btn.locked{ cursor:default;color:#f2b84b;border-color:rgba(242,184,75,.45);
  background:rgba(24,18,8,.82) }
@media(max-width:1024px){ .otrt-btn{-webkit-backdrop-filter:none;backdrop-filter:none;
  background:rgba(11,18,24,.85)} }
/* the tray hangs BELOW the button now that the button sits at the top of the
   column — it used to open upward, which from up here would have run it off the
   ceiling. Same --otrtR and the same slide, so it travels with its own button. */
.otrt{ position:fixed;z-index:59;display:none;
  right:var(--otrtR,10px);top:calc(var(--otrtT,48px) + 40px);width:var(--otrtW,150px);
  transition:right .38s cubic-bezier(.4,0,.2,1);
  box-sizing:border-box;padding:7px;border-radius:13px;
  grid-template-columns:repeat(auto-fill,minmax(clamp(26px,4.4vh,38px),1fr));gap:5px;
  background:rgba(8,15,20,.94);border:1px solid rgba(76,215,246,.34);
  box-shadow:0 16px 38px -14px rgba(0,0,0,.95) }
.otrt.on{ display:grid;animation:otrtIn .16s ease-out both }
/* it drops OUT of the button now, so it enters from above, not from below */
@keyframes otrtIn{ from{ opacity:0;transform:translateY(-6px) } to{ opacity:1;transform:none } }
.otrt-e{ aspect-ratio:1/1;width:100%;display:flex;align-items:center;justify-content:center;
  padding:0;border-radius:8px;cursor:pointer;line-height:1;
  font-size:clamp(15px,2.6vh,21px);
  background:rgba(255,255,255,.05);border:1px solid rgba(255,255,255,.09);
  transition:transform .12s,background .12s,border-color .12s }
.otrt-e:hover:not(:disabled){ transform:translateY(-2px);background:rgba(76,215,246,.16);
  border-color:rgba(76,215,246,.5) }
.otrt-e:disabled{ cursor:default;opacity:.35;transform:none }
@media(prefers-reduced-motion:reduce){ .otrt.on{ animation:none } .otrt-e:hover{ transform:none } }

/* ===== THE TRAY TAKES THE PLAYERS PANEL'S OWN BOX =====
   The owner: «make the same height and size of the player panel for the emoji to
   display, and for the gear icon to display the button inside it». Three panels
   share ONE slot on the right and only one is ever up — so they should be one
   shape, not three sizes taking turns in the same corner.

   The box is not guessed: felt.js writes the rail's own right/top/width/height
   into .ofelt-lb's inline style and keeps them there even while it is slid off,
   so overtake/corner.js reads them and publishes --otpn*. Without that file —
   ONLINE, for now — none of this applies and the small tray is exactly as it was.

   --otrtCols/--otrtCell come from the same place: the largest square that fits
   twelve cells into this particular panel, so the grid fills it on a phone and
   does not blow up on a desktop rail twice the width. */
body.ot-corner .otrt{ right:0;top:var(--otpnT,0px);
  width:var(--otpnW,126px);height:var(--otpnH,100vh);
  padding:10px;border-radius:14px 0 0 14px;border-right:none;
  background:rgba(8,15,20,.9);box-shadow:-16px 0 38px -16px rgba(0,0,0,.95);
  grid-template-columns:repeat(var(--otrtCols,2),var(--otrtCell,52px));
  grid-auto-rows:var(--otrtCell,52px);
  align-content:center;justify-content:center;gap:6px;
  transition:none }
/* it comes in off the right edge, the way the players panel does */
body.ot-corner .otrt.on{ animation:otpnIn .26s cubic-bezier(.4,0,.2,1) both }
@keyframes otpnIn{ from{ opacity:0;transform:translateX(18%) } to{ opacity:1;transform:none } }
body.ot-corner .otrt-e{ font-size:calc(var(--otrtCell,52px) * .46);border-radius:10px }
@media(prefers-reduced-motion:reduce){ body.ot-corner .otrt.on{ animation:none } }

/* ===== A REACTION FLIES ACROSS THE TABLE =====
   The owner: "the emojis should be shown from the users into the table, not
   under — they should go from the north into the southwest, almost into the
   hand, and they should float up and down, north-west or west or south-west,
   random. And I need to see who sent it, so his name tag under it in a faded
   way, for robots and for humans."

   The taunt used to appear at the sender's rail row and sink 150% straight
   down with a ±20px wobble, so it never crossed the table and never read as
   coming FROM anyone. It now travels: the rail is pinned to the physical right
   at every size and in both languages (felt.js sets right:0 unconditionally),
   so the journey is always westward, and emitReact picks one of three headings
   — up-left, level, down-left. --tx/--ty carry that vector and the stops below
   walk it in equal fractions, which is what keeps the flight on one straight
   line rather than the zigzag the first version had.

   IT IS DECORATION. pointer-events stay off, the layer sits under the wildcard
   slot and every strike overlay, and it fades out on arrival — a taunt must
   never cost you a card you were reaching for, or a letter you were typing. */
/* LIKE A BALLOON, in the owner's words. That is a pace, not a path: a balloon
   let go drifts at an even speed and keeps drifting, it does not dart out and
   brake. So the easing is all but linear — a soft push at the release and
   nothing after it — over four and a bit seconds rather than under three, and
   it thins out over the last third instead of snapping off at the end. The line
   it drifts along is still dead straight; only the speed changed. */
body.ot-felt .rfloat{ animation:rfFly 4.3s cubic-bezier(.28,.06,.62,1) both;
  pointer-events:none;z-index:34 }
/* STRAIGHT. The owner, after seeing the first version: "I meant for the emoji to
   move in a straight way, not in a zigzag way ... either send it up in the corner
   or to the left or to the corner, like the southwest or the northwest."
   So the bob is gone. Every stop multiplies BOTH --tx and --ty by the SAME
   fraction, which is what keeps the path on one line from the rail to the
   corner — change one of those fractions without the other and the flight bends.
   The heading is picked once, in setFlight; the animation only walks it. */
@keyframes rfFly{
  0%   { opacity:0;transform:translate(-50%,-50%) scale(.55) }
  8%   { opacity:1;transform:translate(calc(-50% + var(--tx,0px) * .08),
           calc(-50% + var(--ty,0px) * .08)) scale(1.06) }
  62%  { opacity:1;transform:translate(calc(-50% + var(--tx,0px) * .62),
           calc(-50% + var(--ty,0px) * .62)) scale(1) }
  100% { opacity:0;transform:translate(calc(-50% + var(--tx,0px)),
           calc(-50% + var(--ty,0px))) scale(.92) }
}
/* faded, as asked — it says who without competing with the letters it crosses */
body.ot-felt .rfloat .rfwho{ opacity:.72;font-weight:700;
  background:rgba(8,14,20,.5);border-color:rgba(140,220,232,.22);
  color:rgba(226,244,247,.9);
  -webkit-backdrop-filter:none;backdrop-filter:none }
@media(prefers-reduced-motion:reduce){
  body.ot-felt .rfloat{ animation:rfFade 1.6s ease-out both }
  @keyframes rfFade{ 0%{opacity:0} 18%,70%{opacity:1} 100%{opacity:0} } }

/* ===== THROW A CARD — the ask stands with the cards =====
   Driven by body.ot-needthrow, placed by ntPlace() off the hand's own measured
   box. The felt going dim said something was owed; this says what, in the one
   place the owner is already looking. It breathes upward rather than blinking —
   a nudge toward the fan, not a warning — and it stands until the throw lands.

   TWO TRANSFORMS, TWO ELEMENTS, ON PURPOSE. The outer box owns the centring
   (translate -50%) and the outer box alone flips to sit above the fan when the
   glass has no room under it; the inner pill owns the motion. Put both on one
   element and the keyframe wipes the centring every frame and the tag walks off
   to the right. */
.otnt{ position:fixed;z-index:32;pointer-events:none;display:none;
  left:var(--otntX,50vw);top:var(--otntY,88%);transform:translate(-50%,0);
  max-width:min(90vw,420px);text-align:center }
.otnt.above{ transform:translate(-50%,-100%) }
body.ot-needthrow .otnt{ display:block }
.otnt-in{ display:inline-block;white-space:nowrap;
  padding:clamp(4px,1.1vh,8px) clamp(12px,2.4vw,20px);border-radius:999px;
  font:900 clamp(11px,min(3.4vh,1.6vw),18px)/1.2 Cairo,sans-serif;
  letter-spacing:.3px;color:#11202a;
  background:linear-gradient(135deg,#f2b84b,#ffdc8c);
  box-shadow:0 0 0 3px rgba(242,184,75,.16),0 8px 22px -8px rgba(242,184,75,.95);
  animation:otntRise 1.6s ease-in-out infinite }
@keyframes otntRise{ 0%,100%{ transform:translateY(0) }
  50%{ transform:translateY(-6px) } }
@media(prefers-reduced-motion:reduce){ .otnt-in{ animation:none } }

/* ===== YOUR WORD IS LOCKED IN — the table says so =====
   Driven by body.ot-locked (bigcards.js). The felt takes the SAME dim as the
   throw prompt and the word you committed stands lit in the middle of it with a
   tick and its points, because the owner could not tell that ثبّت had landed and
   could not tell what it had earned him.

   IT IS NOT A MODAL. pointer-events:none on the whole panel — a wildcard can
   still be fired at you while you wait for the buzzer, and the wildcard slot
   (z-index 60) and the strike overlays (9000+) both sit above this, so nothing
   the game needs to show or you need to press is behind it.

   IT IS NOT PINNED TO A PIXEL. --otlkX / --otlkW are measured each time the
   panel comes up, from the word plate on the left and the players rail on the
   right — both of which felt.js sizes off the viewport. So on the owner's
   844x390 phone the panel lives in the ~590px band between a ~124px left column
   and a ~126px rail, and on a 1520x840 desktop it simply grows into the wider
   band. Vertically it takes --bcwTop, the point felt.js already computed as the
   middle of the visible felt between the clock and the top of the held cards —
   the same anchor the word plate uses, so it cannot land on the hand.
   The type sizes read min(vh,vw): a landscape phone is SHORT, and a size chosen
   in vh alone shrinks to nothing there while a size in vw alone overflows. */
.otlk{ position:fixed;z-index:30;pointer-events:none;display:none;
  left:var(--otlkX,50vw);top:var(--bcwTop,46%);
  transform:translate(-50%,-50%);
  width:max-content;max-width:var(--otlkW,86vw);box-sizing:border-box;
  font-family:Cairo,sans-serif;text-align:center }
body.ot-locked .otlk{ display:block;
  animation:otlkIn .3s cubic-bezier(.2,.9,.3,1.2) both }
.otlk-in{ display:flex;flex-direction:column;align-items:center;
  gap:clamp(4px,1.1vh,9px);box-sizing:border-box;max-width:100%;
  padding:clamp(10px,2.4vh,20px) clamp(14px,3vw,30px);border-radius:18px;
  /* the owner's standing glass, and the gold edge the left plate already uses
     for its own locked state — one locked word, one colour */
  background:rgba(13,20,27,.55);border:1px solid rgba(242,184,75,.4);
  backdrop-filter:blur(9px);-webkit-backdrop-filter:blur(9px);
  box-shadow:0 14px 40px rgba(0,0,0,.55) }
.otlk-tick{ flex:none;display:flex;align-items:center;justify-content:center;
  width:clamp(24px,min(6.4vh,4.2vw),42px);height:clamp(24px,min(6.4vh,4.2vw),42px);
  border-radius:50%;color:#04252b;
  background:linear-gradient(135deg,#3ad29f,#93ecc9);
  box-shadow:0 0 0 3px rgba(58,210,159,.2),0 6px 18px -6px rgba(58,210,159,.85) }
.otlk-tick svg{ width:60%;height:60% }
body.ot-locked .otlk-tick{ animation:otlkPop .46s cubic-bezier(.2,.9,.3,1.4) both }
/* the word is the point of the panel — break-all so a 15-letter word still
   fits the band rather than pushing the panel over the rail */
.otlk-w{ display:block;max-width:100%;
  font:900 clamp(24px,min(9vh,6.2vw),58px)/1.1 Cairo,sans-serif;
  color:#f7e6b4;letter-spacing:1.5px;
  word-break:break-all;overflow-wrap:anywhere;
  text-shadow:0 2px 10px rgba(0,0,0,.75),0 0 26px rgba(242,184,75,.32) }
.otlk-sc{ display:block;font:900 clamp(19px,min(6.2vh,4.2vw),40px)/1 Cairo,sans-serif;
  font-variant-numeric:tabular-nums;color:#f2b84b;
  text-shadow:0 0 18px rgba(242,184,75,.45) }
.otlk-lbl{ display:block;font:800 clamp(11px,min(2.7vh,1.8vw),16px)/1.35 Cairo,sans-serif;
  color:rgba(210,240,246,.85);letter-spacing:.6px }
.otlk-note{ display:block;max-width:min(100%,32ch);
  font:700 clamp(10px,min(2.3vh,1.5vw),14px)/1.4 Cairo,sans-serif;
  color:rgba(242,184,75,.82) }
/* [hidden] must beat the display above it — the score and the note come and go */
.otlk-sc[hidden],.otlk-note[hidden]{ display:none }
@keyframes otlkIn{ from{ opacity:0;transform:translate(-50%,-50%) scale(.86) }
  to{ opacity:1;transform:translate(-50%,-50%) scale(1) } }
@keyframes otlkPop{ 0%{ transform:scale(.4);opacity:0 }
  62%{ transform:scale(1.14);opacity:1 } 100%{ transform:scale(1) } }
@media(prefers-reduced-motion:reduce){
  body.ot-locked .otlk,body.ot-locked .otlk-tick{ animation:none } }
/* phones do not pay for glass — same trade the word plate already makes above:
   drop the blur, keep the tint, so the panel stays readable over a lit felt */
@media (max-width:1024px){
  .otlk-in{ backdrop-filter:none!important;-webkit-backdrop-filter:none!important;
    background:rgba(11,18,24,.86) } }
/* THE SHORT SCREEN IS THE REAL ONE. 390px of height is the owner's phone, and
   --bcwTop lands the panel's middle roughly halfway between the clock and the
   top of the held cards — a band about 120px deep. Every part of the panel gives
   back a few pixels here so its full height stays inside that band and the fan
   below it is never touched. Same threshold the word plate already uses. */
@media (max-height:420px){
  .otlk-in{ padding:8px 14px 7px;gap:3px;border-radius:15px }
  .otlk-tick{ width:22px;height:22px }
  .otlk-w{ font-size:clamp(22px,7.4vh,34px);letter-spacing:1px }
  .otlk-sc{ font-size:clamp(18px,5.4vh,26px) }
  .otlk-lbl{ font-size:10.5px }
  .otlk-note{ font-size:9.5px } }
