/* =============================================================================
   «ובניו» UI tokens + component recipes            src/ui/tokens.css
   The spec that explains every value here: docs/STYLE_SPEC.md
   The page that renders every recipe:      docs/style_samples.html

   Decisions (2026-11-09, run 5, work item 7; the owner's three answers applied):
   - Everything is prefixed: variables --ub-*, classes .ub-*. index.html keeps
     its own --ink/--paper/.tag/.logo until each screen is rebuilt on these, so
     linking this file changes nothing that already exists.
   - ONE scale knob: --ub-u. Every size is calc(N * var(--ub-u)), N in phone
     CSS px (844 x 390 is the design frame). Desktop scales the UI instead of
     shrinking it: x1.2 from 1000 x 600, x1.4 from 1200 x 700 (principle 9),
     x1.8 from 1800 x 1000.
   - Two faces. "UB Rubik" (variable, 500-900) for every Hebrew word: body,
     labels, headings, buttons. "UB Karantina" (the logo's blocky face) for the
     logo and for numbers of 22u and up, nothing else. Both SIL OFL 1.1, subset
     to Hebrew + Latin + digits + punctuation; Karantina was given tabular-figure
     alternates (tnum) so both faces line digits up.
   - Four surfaces, one paper system: paper (cream panel), receipt (thermal
     paper, torn foot), board (chalkboard; the HUD is the same board), sticker.
     One outline (2u warm ink), one radius (12u; 6u inside; pills for tags),
     one shadow (a 3u hard ink ledge + one soft drop).
   - Role colours, one meaning each: green = go (the one primary action, healthy
     states); gold = reward (points, coins, stars, crown, bonus, NEW); blue =
     system and selection (hints, links, network, focus, the chosen tile);
     red = danger only (inspector, fire, burnt, late order, fines). The logo's
     red is brand, not UI. Player apron colours live on the chefs, never on UI.
   Revised 2026-11-10 (same item, second pass):
   - Fonts rebuilt with pyftsubset; the Latin halves now carry « » ° ‹ › „ (the
     brand is written «ובניו»; they fell back to a system face before). Each
     unicode-range below is the file's real cmap, so no character is promised
     by a file that does not draw it.
   - Values vs words: a VALUE (score, clock, day number, total, column value,
     counter) is Karantina at 22u+, or Rubik 800 below 22u; a number inside a
     phrase is word text. All values on one surface share one face and one
     baseline (.ub-stat--text aligns a label to a value's baseline).
   - Added: the four apron colours as tokens (--ub-player-*), the 60u avatar
     bubble (.ub-avatar: principle 7's read test), the hero's minimum height
     (--ub-hero-min-h, principle 6), the day-end beat timings (--ub-t-hold,
     --ub-t-stagger, principle 12), danger and mute inks for dark surfaces.
   ========================================================================== */

/* ---------------------------------------------------------------- fonts ---- */
/* Hebrew and Latin halves of each face (SIL OFL 1.1), subset with pyftsubset; the
   exact commands are in docs/STYLE_SPEC.md. A page fetches only the halves it draws.
   Bytes: rubik-hebrew 5,324 · rubik-latin 20,808 · karantina-hebrew 1,712 ·
   karantina-latin 5,412 = 33,256. Preload rubik-hebrew, rubik-latin, karantina-latin. */
@font-face{font-family:"UB Rubik";font-style:normal;font-weight:500 900;font-display:swap;
  src:url("fonts/rubik-hebrew.woff2") format("woff2");
  unicode-range:U+0020,U+00A0,U+05BE,U+05D0-05EA,U+05F3-05F4,U+20AA}
@font-face{font-family:"UB Rubik";font-style:normal;font-weight:500 900;font-display:swap;
  src:url("fonts/rubik-latin.woff2") format("woff2");
  unicode-range:U+0020-007E,U+00A0,U+00A9,U+00AB,U+00B0,U+00B7,U+00BB,U+00D7,U+2013-2014,U+2018-2019,U+201C-201E,U+2022,U+2026,U+2039-203A,U+2212}
/* block, not swap: the logo and the score never flash in a fallback face */
@font-face{font-family:"UB Karantina";font-style:normal;font-weight:400 900;font-display:block;
  src:url("fonts/karantina-hebrew.woff2") format("woff2");
  unicode-range:U+0020,U+00A0,U+05BE,U+05D0-05EA,U+05F3-05F4,U+20AA}
@font-face{font-family:"UB Karantina";font-style:normal;font-weight:400 900;font-display:block;
  src:url("fonts/karantina-latin.woff2") format("woff2");
  unicode-range:U+0020-007E,U+00A0,U+00A9,U+00AB,U+00B0,U+00B7,U+00BB,U+00D7,U+2013-2014,U+2018-2019,U+201C-201E,U+2022,U+2026,U+2039-203A,U+2191,U+2193,U+2212}

/* --------------------------------------------------------------- tokens ---- */
:root{
  --ub-u:1px;

  /* ink and surfaces */
  --ub-ink:#3A2317;            /* every outline, every word on paper */
  --ub-ink-2:#6B5443;          /* secondary words on paper (6.6:1) */
  --ub-paper:#FFF6E3;          /* cream panel */
  --ub-paper-2:#F3E3C2;        /* inset rows, empty slots, secondary button on paper */
  --ub-receipt:#FFFDF6;        /* thermal paper: receipts, tickets (baked into the torn edge below) */
  --ub-rule:#D9C6A5;           /* dotted leaders and dashed rules on paper */
  --ub-board:#2B342E;          /* chalkboard and HUD board (chalk on it 11.3:1) */
  --ub-board-a:rgba(43,52,46,.9);
  --ub-board-2:#36413A;        /* a row inset into the board */
  --ub-chalk:#F6F0DE;          /* words on the board */
  --ub-chalk-2:rgba(246,240,222,.72);
  --ub-wood:#8A5A3A;           /* the chalkboard frame, the ticket rail */
  --ub-wood-d:#5C3A22;
  --ub-mute:#B6A188;           /* locked silhouettes, empty-slot icons */
  --ub-mute-ink:#8C7A66;       /* the outline of a locked / empty icon */
  --ub-scrim:rgba(20,13,24,.55); /* over the 3D room behind a menu: the room stays visible */

  /* the four aprons (= render3d.js APRON). ONLY on the chef, the floor ring, the
     name-plate dot and the avatar ring. Never a button, a panel or a tag. */
  --ub-player-red:#E04A3F; --ub-player-gold:#F7BB2A; --ub-player-green:#55C078; --ub-player-blue:#52A0E4;

  /* roles: one meaning each */
  --ub-go:#2F9A57;   --ub-go-d:#1F6B3C;   --ub-on-go:#FFFDF6;     /* go: paper on green 3.5:1, 22u bold + ink ledge */
  --ub-gold:#F7BB2A; --ub-gold-d:#B97A06; --ub-on-gold:#3A2317;   /* reward: ink on gold 8.4:1 */
  --ub-info:#2F7FC8; --ub-info-ink:#1E6FB8; --ub-on-info:#FFFDF6; /* system + selection */
  --ub-danger:#D63D31; --ub-danger-ink:#B92F25; --ub-on-danger:#FFFDF6; /* danger: paper on red 4.5:1 */
  --ub-danger-on-dark:#FF8A7E;        /* a fine / burnt value on the board or over the room */
  --ub-secondary:rgba(58,35,23,.8);   /* the secondary button: transparent brown */
  --ub-brand:#F0584E;                 /* the logo, only */

  /* type: two faces, five sizes (48/32/22/16/13), logo outside the scale */
  --ub-font-ui:"UB Rubik","Rubik","Arial Hebrew","Segoe UI","Noto Sans Hebrew",system-ui,sans-serif;
  --ub-font-num:"UB Karantina","Karantina","UB Rubik",sans-serif;
  --ub-fs-1:calc(48 * var(--ub-u));   /* display: screen title, hero number */
  --ub-fs-2:calc(32 * var(--ub-u));   /* heading; HUD score and clock */
  --ub-fs-3:calc(22 * var(--ub-u));   /* subhead, primary button, receipt values */
  --ub-fs-4:calc(16 * var(--ub-u));   /* body, labels, secondary buttons */
  --ub-fs-5:calc(13 * var(--ub-u));   /* small: captions, tags, dock labels (the floor) */
  --ub-fs-logo:calc(96 * var(--ub-u));
  --ub-fs-logo-s:calc(44 * var(--ub-u));
  --ub-w-body:500; --ub-w-label:700; --ub-w-head:800; --ub-w-display:900;
  --ub-lh-num:1; --ub-lh-head:1.1; --ub-lh-body:1.35;

  /* space: 4-based */
  --ub-sp-1:calc(4 * var(--ub-u));  --ub-sp-2:calc(8 * var(--ub-u));
  --ub-sp-3:calc(12 * var(--ub-u)); --ub-sp-4:calc(16 * var(--ub-u));
  --ub-sp-5:calc(24 * var(--ub-u)); --ub-sp-6:calc(32 * var(--ub-u));
  --ub-sp-7:calc(48 * var(--ub-u));

  /* the paper system: one outline, one radius, one shadow */
  --ub-bw:calc(2 * var(--ub-u));
  --ub-bw-2:calc(3 * var(--ub-u));     /* selection ring, total rule, stamp frame */
  --ub-r:calc(12 * var(--ub-u));       /* every container and every button */
  --ub-r-sm:calc(6 * var(--ub-u));     /* inside a container: rows, stamps, stickers, tickets */
  --ub-r-pill:999px;                   /* tags and counters only */
  --ub-ledge:0 calc(3 * var(--ub-u)) 0 var(--ub-ink);
  --ub-drop:0 calc(8 * var(--ub-u)) calc(14 * var(--ub-u)) rgba(20,10,4,.35);
  --ub-shadow:var(--ub-ledge),var(--ub-drop);
  --ub-shadow-s:0 calc(2 * var(--ub-u)) 0 var(--ub-ink);    /* stickers, tickets, tiles */
  --ub-shadow-press:0 0 0 var(--ub-ink),0 calc(2 * var(--ub-u)) calc(4 * var(--ub-u)) rgba(20,10,4,.3);
  --ub-tilt:-3deg;                     /* every sticker */
  --ub-stamp-tilt:-8deg;               /* every stamp */

  /* touch and sizes */
  --ub-hit:max(44px,calc(44 * var(--ub-u)));       /* nothing tappable is smaller, ever */
  --ub-btn-h:calc(56 * var(--ub-u));               /* the primary button */
  --ub-dock-w:max(60px,calc(72 * var(--ub-u)));    /* a HUD dock button: 72 x 64 */
  --ub-dock-h:max(56px,calc(64 * var(--ub-u)));
  --ub-icon-s:calc(24 * var(--ub-u));              /* inline with 16u text */
  --ub-icon-m:calc(32 * var(--ub-u));              /* buttons, dock, tickets */
  --ub-icon-l:calc(48 * var(--ub-u));              /* empty states, unlock card */
  --ub-avatar:calc(60 * var(--ub-u));              /* a friend's bubble; every hat must read at this size */
  --ub-hero-min-h:calc(var(--ub-vh) / 3);          /* the hero chef on title / lobby: at least a third of the height */

  /* safe areas: 24u everywhere; 44 px on both sides of a touch phone held sideways
     (the notch can be on either side; iOS reports equal side insets anyway) */
  --ub-safe-x:max(calc(24 * var(--ub-u)),env(safe-area-inset-left,0px),env(safe-area-inset-right,0px));
  --ub-safe-top:max(calc(24 * var(--ub-u)),env(safe-area-inset-top,0px));
  --ub-safe-bottom:max(calc(24 * var(--ub-u)),env(safe-area-inset-bottom,0px));
  --ub-vh:100vh;
  --ub-panel-max-h:calc(var(--ub-vh) - var(--ub-safe-top) - var(--ub-safe-bottom));

  /* layers */
  --ub-z-hud:10; --ub-z-panel:20; --ub-z-toast:30; --ub-z-modal:40;

  /* motion */
  --ub-ease-out:cubic-bezier(.2,.8,.25,1);     /* everything that arrives */
  --ub-ease-pop:cubic-bezier(.3,1.45,.5,1);    /* things that land: toasts, numbers, tiles */
  --ub-ease-in:cubic-bezier(.55,0,.8,.2);      /* everything that leaves */
  --ub-t-press:90ms;     /* button down/up */
  --ub-t-fast:160ms;     /* exits, number landing pop */
  --ub-t-mid:240ms;      /* toast in, panel in */
  --ub-t-stamp:380ms;    /* the stamp slam */
  --ub-t-count:900ms;    /* count-up default: 500 (<=50) / 900 (<=500) / 1200 (>500) */
  --ub-t-toast:2400ms;   /* time a toast stays (unlock: 3200) */
  --ub-t-hold:900ms;     /* day end beat 1: the room freezes under «נסגר!» this long */
  --ub-t-stagger:120ms;  /* rows of a receipt / tiles of a grid arrive this far apart */
}
@supports (height:100dvh){:root{--ub-vh:100dvh}}
@media (min-width:1000px) and (min-height:600px){:root{--ub-u:1.2px}}
@media (min-width:1200px) and (min-height:700px){:root{--ub-u:1.4px}}
@media (min-width:1800px) and (min-height:1000px){:root{--ub-u:1.8px}}
@media (pointer:coarse) and (orientation:landscape){
  :root{--ub-safe-x:max(44px,env(safe-area-inset-left,0px),env(safe-area-inset-right,0px))}}

/* ------------------------------------------------------------ type ---- */
[class^="ub-"],[class*=" ub-"],[class^="ub-"]::before,[class^="ub-"]::after{box-sizing:border-box}
.ub{font-family:var(--ub-font-ui);font-weight:var(--ub-w-body);font-size:var(--ub-fs-4);
  line-height:var(--ub-lh-body);color:var(--ub-ink);-webkit-font-smoothing:antialiased;
  font-synthesis:none;text-rendering:optimizeLegibility}
.ub-display{font:var(--ub-w-display) var(--ub-fs-1)/var(--ub-lh-head) var(--ub-font-ui);letter-spacing:0}
.ub-heading{font:var(--ub-w-display) var(--ub-fs-2)/var(--ub-lh-head) var(--ub-font-ui)}
.ub-subhead{font:var(--ub-w-head) var(--ub-fs-3)/var(--ub-lh-head) var(--ub-font-ui)}
.ub-body{font:var(--ub-w-body) var(--ub-fs-4)/var(--ub-lh-body) var(--ub-font-ui)}
.ub-label{font:var(--ub-w-label) var(--ub-fs-4)/1.2 var(--ub-font-ui)}
.ub-small{font:var(--ub-w-body) var(--ub-fs-5)/1.3 var(--ub-font-ui)}
.ub-small-b{font:var(--ub-w-head) var(--ub-fs-5)/1.2 var(--ub-font-ui)}
.ub-muted{color:var(--ub-ink-2)}
.ub-logo{font:700 var(--ub-fs-logo)/.72 var(--ub-font-num);color:var(--ub-brand);letter-spacing:0;
  -webkit-text-stroke:calc(3 * var(--ub-u)) var(--ub-ink);paint-order:stroke fill;
  text-shadow:0 calc(5 * var(--ub-u)) 0 var(--ub-ink)}
.ub-logo--s{font-size:var(--ub-fs-logo-s);-webkit-text-stroke-width:calc(2 * var(--ub-u));
  text-shadow:0 calc(3 * var(--ub-u)) 0 var(--ub-ink)}

/* numbers: LTR island inside RTL, tabular, one face per size band */
.ub-num{font-family:var(--ub-font-num);font-weight:700;line-height:var(--ub-lh-num);
  font-variant-numeric:tabular-nums lining-nums;font-feature-settings:"tnum" 1,"lnum" 1;
  direction:ltr;unicode-bidi:isolate;white-space:nowrap;letter-spacing:.02em;display:inline-block}
.ub-num--xl{font-size:var(--ub-fs-1)}
.ub-num--l{font-size:var(--ub-fs-2)}
.ub-num--m{font-size:var(--ub-fs-3)}
.ub-num--s{font-family:var(--ub-font-ui);font-weight:var(--ub-w-head);font-size:var(--ub-fs-4);letter-spacing:0}
.ub-num--xs{font-family:var(--ub-font-ui);font-weight:var(--ub-w-head);font-size:var(--ub-fs-5);letter-spacing:0}
.ub-num--col{min-width:3.4ch;text-align:right}           /* a value column: units line up */
.ub-num--reward{color:var(--ub-gold)}                     /* on the board only; on paper use ink + a gold icon */
.ub-num--fine{color:var(--ub-danger-ink)}
.ub-board .ub-num--fine,.ub-num--fine.on-board{color:var(--ub-danger-on-dark)}
.ub-stat{display:inline-flex;align-items:center;gap:var(--ub-sp-2)}   /* icon first in DOM = on the right */
.ub-stat--text{align-items:baseline;gap:var(--ub-sp-1)}              /* a word label first: label and value on one baseline */
/* push an item to the far (left) end of an RTL row. PHYSICAL on purpose: .ub-num is
   an LTR island, so margin-inline-start on a number means its LEFT margin and pulls
   it back against the label. Never position a .ub-num with logical margins. */
.ub-end{margin-right:auto}
/* feedback that floats up where it happened (+15 at the pass): gold, inked, over the room */
.ub-float-num{font:700 var(--ub-fs-2)/1 var(--ub-font-num);color:var(--ub-gold);direction:ltr;unicode-bidi:isolate;
  font-variant-numeric:tabular-nums;-webkit-text-stroke:calc(4 * var(--ub-u)) var(--ub-ink);paint-order:stroke fill;
  text-shadow:0 calc(3 * var(--ub-u)) 0 var(--ub-ink);white-space:nowrap}
.ub-float-num--fine{color:var(--ub-danger-on-dark)}

/* ------------------------------------------------------------ icons ---- */
.ub-icon{width:var(--ub-icon-m);height:var(--ub-icon-m);flex:none;display:inline-block;
  vertical-align:middle;overflow:visible;color:currentColor}
.ub-icon--s{width:var(--ub-icon-s);height:var(--ub-icon-s)}
.ub-icon--l{width:var(--ub-icon-l);height:var(--ub-icon-l)}
.ub-icon--locked{--ub-ic-m:var(--ub-mute);--ub-ic-hl:transparent;--ub-ic-ink:var(--ub-mute-ink);color:var(--ub-mute-ink)}

/* ---------------------------------------------------------- surfaces ---- */
/* 1. paper: the cream panel. Cards, ledgers, the blame card, the unlock card. */
.ub-paper{background:var(--ub-paper);color:var(--ub-ink);border:var(--ub-bw) solid var(--ub-ink);
  border-radius:var(--ub-r);box-shadow:var(--ub-shadow);padding:var(--ub-sp-4)}
.ub-paper__head{display:flex;align-items:baseline;gap:var(--ub-sp-2);
  padding-bottom:var(--ub-sp-2);margin-bottom:var(--ub-sp-3);border-bottom:var(--ub-bw) solid var(--ub-ink)}
.ub-paper__head>:first-child{font:var(--ub-w-head) var(--ub-fs-3)/var(--ub-lh-head) var(--ub-font-ui)}
.ub-paper__head>.ub-muted{margin-inline-start:auto;font-size:var(--ub-fs-5)}
.ub-inset{background:var(--ub-paper-2);border-radius:var(--ub-r-sm);padding:var(--ub-sp-2) var(--ub-sp-3)}

/* 2. receipt: thermal paper with a torn foot. Day end, the bank, the till. */
.ub-receipt{position:relative;display:flex;flex-direction:column;
  background:var(--ub-receipt);color:var(--ub-ink);
  border:var(--ub-bw) solid var(--ub-ink);border-bottom:0;
  border-radius:var(--ub-r-sm) var(--ub-r-sm) 0 0;
  padding:var(--ub-sp-3) var(--ub-sp-4) var(--ub-sp-1);
  margin-bottom:calc(9 * var(--ub-u));
  max-height:calc(var(--ub-panel-max-h) - 9 * var(--ub-u));
  filter:drop-shadow(0 calc(6 * var(--ub-u)) calc(8 * var(--ub-u)) rgba(20,10,4,.42))}
/* the torn edge: ink zigzag over receipt paper; colours baked = --ub-ink, --ub-receipt */
.ub-receipt::after{content:"";position:absolute;top:100%;left:calc(-1 * var(--ub-bw));right:calc(-1 * var(--ub-bw));
  height:calc(9 * var(--ub-u));
  background:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 9'%3E%3Cpath d='M0 0H12V1.2L6 7.2 0 1.2Z' fill='%23FFFDF6'/%3E%3Cpath d='M-6 7.2L0 1.2 6 7.2 12 1.2 18 7.2' fill='none' stroke='%233A2317' stroke-width='2' stroke-linejoin='round'/%3E%3C/svg%3E") repeat-x 0 0/calc(12 * var(--ub-u)) 100%}
.ub-receipt__head{display:flex;align-items:center;gap:var(--ub-sp-2);padding-bottom:var(--ub-sp-2);
  border-bottom:var(--ub-bw) dashed var(--ub-rule)}
.ub-receipt__head .ub-label{margin-inline-start:auto}
.ub-receipt__body{overflow-y:auto;overscroll-behavior:contain;min-height:0;padding:var(--ub-sp-1) 0}
.ub-receipt__row{display:flex;align-items:baseline;gap:var(--ub-sp-2);
  padding:calc(3 * var(--ub-u)) 0;font:var(--ub-w-label) var(--ub-fs-4)/1.2 var(--ub-font-ui)}
.ub-receipt__row::after{content:"";order:1;flex:1;min-width:var(--ub-sp-3);
  border-bottom:var(--ub-bw) dotted var(--ub-rule);transform:translateY(-.25em)}
.ub-receipt__row>.ub-num{order:2;font-size:var(--ub-fs-3);min-width:3.4ch;text-align:right}
.ub-receipt__total{display:flex;align-items:baseline;gap:var(--ub-sp-2);margin-top:var(--ub-sp-1);
  padding-top:var(--ub-sp-2);border-top:var(--ub-bw-2) solid var(--ub-ink);
  font:var(--ub-w-display) var(--ub-fs-4)/1 var(--ub-font-ui)}
.ub-receipt__total>.ub-num{margin-right:auto;font-size:var(--ub-fs-2)}
.ub-receipt__stamp{display:grid;place-items:center;min-height:calc(52 * var(--ub-u));
  border-top:var(--ub-bw) dashed var(--ub-rule);margin-top:var(--ub-sp-2)}

/* 3. board: the chalkboard. HUD panels are the same board, plain. */
.ub-board{background:var(--ub-board);color:var(--ub-chalk);border:var(--ub-bw) solid var(--ub-ink);
  border-radius:var(--ub-r);box-shadow:var(--ub-shadow);padding:var(--ub-sp-3) var(--ub-sp-4)}
.ub-board--hud{background:var(--ub-board-a);box-shadow:var(--ub-ledge);padding:var(--ub-sp-2) var(--ub-sp-3)}
.ub-board--framed{border:calc(6 * var(--ub-u)) solid var(--ub-wood);
  box-shadow:0 0 0 var(--ub-bw) var(--ub-ink),0 calc(3 * var(--ub-u)) 0 var(--ub-bw) var(--ub-ink),
    var(--ub-drop),inset 0 0 0 var(--ub-bw) rgba(0,0,0,.35);
  background-image:radial-gradient(ellipse 60% 50% at 30% 25%,rgba(255,255,255,.07),transparent 70%),
    radial-gradient(ellipse 50% 40% at 75% 85%,rgba(255,255,255,.05),transparent 70%)}
.ub-board .ub-muted,.ub-board--framed .ub-muted{color:var(--ub-chalk-2)}
.ub-board__row{display:flex;align-items:center;gap:var(--ub-sp-2);background:var(--ub-board-2);
  border-radius:var(--ub-r-sm);padding:var(--ub-sp-1) var(--ub-sp-2)}
.ub-qr{flex:none;width:calc(96 * var(--ub-u));height:calc(96 * var(--ub-u));padding:calc(6 * var(--ub-u));
  background:var(--ub-receipt);border-radius:var(--ub-r-sm)}   /* the QR tile, on the chalkboard */
.ub-qr>*{display:block;width:100%;height:100%}
.ub-chalk-code{font:var(--ub-w-display) var(--ub-fs-1)/1 var(--ub-font-ui);letter-spacing:.14em;
  direction:ltr;unicode-bidi:isolate;color:var(--ub-chalk)}

/* 4. sticker: emphasis. One per card, tilted -3deg, never over a value. */
.ub-sticker{display:inline-flex;align-items:center;gap:var(--ub-sp-1);
  padding:calc(4 * var(--ub-u)) calc(10 * var(--ub-u));
  background:var(--ub-gold);color:var(--ub-on-gold);border:var(--ub-bw) solid var(--ub-ink);
  border-radius:var(--ub-r-sm);box-shadow:var(--ub-shadow-s);transform:rotate(var(--ub-tilt));
  font:var(--ub-w-display) var(--ub-fs-5)/1 var(--ub-font-ui);white-space:nowrap}
.ub-sticker--l{font-size:var(--ub-fs-4);padding:calc(6 * var(--ub-u)) calc(14 * var(--ub-u))}
.ub-sticker--go{background:var(--ub-go);color:var(--ub-on-go)}
.ub-sticker--info{background:var(--ub-info);color:var(--ub-on-info)}
.ub-sticker--danger{background:var(--ub-danger);color:var(--ub-on-danger)}
.ub-sticker--paper{background:var(--ub-receipt);color:var(--ub-ink)}

/* ----------------------------------------------------------- buttons ---- */
.ub-btn{appearance:none;-webkit-appearance:none;display:inline-flex;align-items:center;justify-content:center;
  gap:var(--ub-sp-2);min-height:var(--ub-hit);min-width:var(--ub-hit);padding:0 var(--ub-sp-5);
  border:var(--ub-bw) solid var(--ub-ink);border-radius:var(--ub-r);
  background:var(--ub-paper);color:var(--ub-ink);box-shadow:var(--ub-ledge);
  font:var(--ub-w-head) var(--ub-fs-4)/1 var(--ub-font-ui);white-space:nowrap;cursor:pointer;
  touch-action:manipulation;-webkit-tap-highlight-color:transparent;user-select:none;-webkit-user-select:none;
  transition:transform var(--ub-t-press) var(--ub-ease-out),box-shadow var(--ub-t-press) var(--ub-ease-out)}
.ub-btn:active,.ub-btn.is-pressed{transform:translateY(calc(3 * var(--ub-u)));box-shadow:var(--ub-shadow-press)}
.ub-btn:focus-visible{outline:var(--ub-bw-2) solid var(--ub-info);outline-offset:var(--ub-bw-2)}
.ub-btn[disabled],.ub-btn.is-disabled{opacity:.45;box-shadow:none;cursor:default;transform:none}
/* the ONE primary action on a screen */
.ub-btn--primary{min-height:var(--ub-btn-h);min-width:calc(200 * var(--ub-u));padding:0 var(--ub-sp-6);
  background:var(--ub-go);color:var(--ub-on-go);
  font:var(--ub-w-display) var(--ub-fs-3)/1 var(--ub-font-ui);
  text-shadow:0 calc(2 * var(--ub-u)) 0 var(--ub-ink);
  box-shadow:inset 0 calc(3 * var(--ub-u)) 0 rgba(255,255,255,.25),var(--ub-shadow)}
.ub-btn--primary:active,.ub-btn--primary.is-pressed{box-shadow:inset 0 calc(3 * var(--ub-u)) 0 rgba(0,0,0,.12),var(--ub-shadow-press)}
.ub-btn--primary .ub-icon{filter:drop-shadow(0 calc(2 * var(--ub-u)) 0 var(--ub-ink))}
/* a primary that waits (the draft before a card is picked): opaque paper-2, ink-2 words, never see-through */
.ub-btn--primary[disabled],.ub-btn--primary.is-disabled{opacity:1;background:var(--ub-paper-2);color:var(--ub-ink-2);
  text-shadow:none;box-shadow:var(--ub-ledge)}
.ub-btn--primary[disabled] .ub-icon,.ub-btn--primary.is-disabled .ub-icon{filter:none;opacity:.7}
/* everything else: transparent brown over the room, paper-2 on paper */
.ub-btn--secondary{background:var(--ub-secondary);color:var(--ub-chalk)}
.ub-paper .ub-btn--secondary,.ub-receipt .ub-btn--secondary{background:var(--ub-paper-2);color:var(--ub-ink)}
.ub-btn--text{background:none;border-color:transparent;box-shadow:none;color:inherit;padding:0 var(--ub-sp-2);
  text-decoration:underline var(--ub-bw);text-underline-offset:calc(5 * var(--ub-u))}
.ub-btn--text:active{transform:none;opacity:.7}
.ub-btn--icon{padding:0;width:var(--ub-hit);background:var(--ub-secondary);color:var(--ub-chalk)}

/* the HUD dock button: paper, icon over a word (<= 5 letters); the counter sits in the word's row, inside the box */
.ub-dock{position:relative;display:grid;grid-template-rows:1fr auto;justify-items:center;align-items:center;
  width:var(--ub-dock-w);height:var(--ub-dock-h);padding:calc(5 * var(--ub-u)) calc(3 * var(--ub-u)) calc(5 * var(--ub-u));
  background:var(--ub-paper);color:var(--ub-ink);border:var(--ub-bw) solid var(--ub-ink);border-radius:var(--ub-r);
  box-shadow:var(--ub-ledge);font:var(--ub-w-head) var(--ub-fs-5)/1 var(--ub-font-ui);
  cursor:pointer;touch-action:manipulation;-webkit-tap-highlight-color:transparent;user-select:none;
  transition:transform var(--ub-t-press) var(--ub-ease-out),box-shadow var(--ub-t-press) var(--ub-ease-out)}
.ub-dock:active,.ub-dock.is-pressed{transform:translateY(calc(3 * var(--ub-u)));box-shadow:var(--ub-shadow-press)}
.ub-dock__label{display:inline-flex;align-items:center;gap:calc(3 * var(--ub-u));white-space:nowrap}
.ub-dock__count{box-sizing:border-box;min-width:calc(18 * var(--ub-u));height:calc(18 * var(--ub-u));padding:0 calc(4 * var(--ub-u));
  display:grid;place-items:center;border-radius:var(--ub-r-pill);background:var(--ub-gold);color:var(--ub-on-gold);
  border:var(--ub-bw) solid var(--ub-ink);font:var(--ub-w-display) var(--ub-fs-5)/1 var(--ub-font-ui);
  font-variant-numeric:tabular-nums;direction:ltr}
.ub-dock__key{position:absolute;top:calc(4 * var(--ub-u));inset-inline-start:calc(5 * var(--ub-u));
  font:var(--ub-w-label) var(--ub-fs-5)/1 var(--ub-font-ui);color:var(--ub-ink-2);display:none}
@media (pointer:fine){.ub-dock__key{display:block}}
.ub-dock.is-danger{border-color:var(--ub-danger);box-shadow:0 0 0 var(--ub-bw) var(--ub-danger),var(--ub-ledge);
  animation:ub-pulse 500ms var(--ub-ease-out) infinite}

/* ------------------------------------------------------------ tickets ---- */
.ub-rail{position:relative;height:calc(8 * var(--ub-u));background:var(--ub-wood);
  border:var(--ub-bw) solid var(--ub-ink);border-radius:var(--ub-r-pill);box-shadow:var(--ub-shadow-s)}
.ub-tickets{display:flex;gap:var(--ub-sp-2);align-items:flex-start;padding-inline:var(--ub-sp-3);margin-top:calc(-2 * var(--ub-u))}
.ub-ticket{position:relative;display:flex;flex-direction:column;align-items:center;gap:calc(6 * var(--ub-u));
  width:calc(84 * var(--ub-u));padding:calc(17 * var(--ub-u)) calc(6 * var(--ub-u)) calc(8 * var(--ub-u));
  background:var(--ub-receipt);color:var(--ub-ink);border:var(--ub-bw) solid var(--ub-ink);
  border-radius:0 0 var(--ub-r-sm) var(--ub-r-sm);box-shadow:var(--ub-shadow-s);transform-origin:50% 0}
.ub-ticket::before{content:"";position:absolute;top:calc(-6 * var(--ub-u));left:50%;
  width:calc(14 * var(--ub-u));height:calc(10 * var(--ub-u));margin-left:calc(-7 * var(--ub-u));
  background:var(--ub-wood-d);border:var(--ub-bw) solid var(--ub-ink);border-radius:calc(3 * var(--ub-u))}
.ub-ticket__no{position:absolute;top:calc(3 * var(--ub-u));inset-inline-end:calc(6 * var(--ub-u));
  font:var(--ub-w-head) var(--ub-fs-5)/1 var(--ub-font-ui);color:var(--ub-ink-2);
  font-variant-numeric:tabular-nums;direction:ltr;unicode-bidi:isolate}
.ub-ticket__items{display:flex;align-items:center;justify-content:center;gap:calc(2 * var(--ub-u));min-height:var(--ub-icon-m)}
.ub-ticket__qty{font:700 var(--ub-fs-3)/1 var(--ub-font-num);font-variant-numeric:tabular-nums;direction:ltr;unicode-bidi:isolate}
.ub-ticket__bar{align-self:stretch;height:calc(8 * var(--ub-u));border-radius:var(--ub-r-pill);
  background:var(--ub-paper-2);border:var(--ub-bw) solid var(--ub-ink);overflow:hidden;direction:rtl}
.ub-ticket__bar>i{display:block;height:100%;width:var(--p,100%);background:var(--ub-go);border-radius:inherit}
.ub-ticket.is-late .ub-ticket__bar>i{background:var(--ub-danger)}
.ub-ticket.is-late{animation:ub-swing 1s var(--ub-ease-out) infinite}

/* --------------------------------------------------------------- tags ---- */
.ub-tag{display:inline-flex;align-items:center;gap:calc(4 * var(--ub-u));height:calc(22 * var(--ub-u));
  padding:0 calc(10 * var(--ub-u));border-radius:var(--ub-r-pill);background:var(--ub-paper-2);color:var(--ub-ink);
  font:var(--ub-w-head) var(--ub-fs-5)/1 var(--ub-font-ui);white-space:nowrap}
.ub-tag .ub-icon{width:calc(16 * var(--ub-u));height:calc(16 * var(--ub-u))}
.ub-tag--go{background:var(--ub-go);color:var(--ub-on-go)}
.ub-tag--gold{background:var(--ub-gold);color:var(--ub-on-gold)}
.ub-tag--info{background:var(--ub-info);color:var(--ub-on-info)}
.ub-tag--danger{background:var(--ub-danger);color:var(--ub-on-danger)}
.ub-tag--ink{background:var(--ub-ink);color:var(--ub-gold)}

/* -------------------------------------------------------------- toast ---- */
.ub-toast-host{position:fixed;inset-inline:0;bottom:calc(var(--ub-safe-bottom) + var(--ub-sp-2));
  display:flex;justify-content:center;pointer-events:none;z-index:var(--ub-z-toast)}
.ub-toast{display:inline-flex;align-items:center;gap:var(--ub-sp-2);max-width:min(50vw,calc(440 * var(--ub-u)));
  padding:calc(8 * var(--ub-u)) var(--ub-sp-4) calc(8 * var(--ub-u)) var(--ub-sp-4);
  background:var(--ub-paper);color:var(--ub-ink);border:var(--ub-bw) solid var(--ub-ink);
  border-inline-start:calc(8 * var(--ub-u)) solid var(--ub-toast-role,var(--ub-info));
  border-radius:var(--ub-r);box-shadow:var(--ub-shadow);font:var(--ub-w-label) var(--ub-fs-4)/1.25 var(--ub-font-ui)}
.ub-toast--gold{--ub-toast-role:var(--ub-gold)}
.ub-toast--go{--ub-toast-role:var(--ub-go)}
.ub-toast--danger{--ub-toast-role:var(--ub-danger)}
.ub-toast.is-in{animation:ub-toast-in var(--ub-t-mid) var(--ub-ease-pop) both}
.ub-toast.is-out{animation:ub-toast-out var(--ub-t-fast) var(--ub-ease-in) both}

/* -------------------------------------------------------------- stamp ---- */
.ub-stamp{display:inline-block;padding:calc(6 * var(--ub-u)) calc(14 * var(--ub-u));
  color:var(--ub-danger);border:var(--ub-bw-2) solid currentColor;border-radius:var(--ub-r-sm);
  box-shadow:inset 0 0 0 var(--ub-bw) var(--ub-receipt),inset 0 0 0 calc(4 * var(--ub-u)) currentColor;
  font:var(--ub-w-display) var(--ub-fs-3)/1 var(--ub-font-ui);white-space:nowrap;
  transform:rotate(var(--ub-stamp-tilt));opacity:.95;mix-blend-mode:multiply;
  -webkit-mask-image:url("../../art/ui/grain.svg");mask-image:url("../../art/ui/grain.svg");
  -webkit-mask-size:calc(160 * var(--ub-u));mask-size:calc(160 * var(--ub-u))}
.ub-stamp--go{color:var(--ub-go)}
.ub-stamp--danger{color:var(--ub-danger)}
.ub-stamp.is-in{animation:ub-stamp-in var(--ub-t-stamp) var(--ub-ease-out) both}

/* ------------------------------------------------- lobby, pickers, empties ---- */
.ub-plate{display:inline-flex;align-items:center;gap:calc(6 * var(--ub-u));
  padding:calc(4 * var(--ub-u)) calc(12 * var(--ub-u));background:var(--ub-paper);color:var(--ub-ink);
  border:var(--ub-bw) solid var(--ub-ink);border-radius:var(--ub-r-sm);box-shadow:var(--ub-shadow-s);
  font:var(--ub-w-head) var(--ub-fs-4)/1.1 var(--ub-font-ui);white-space:nowrap}
.ub-plate__dot{width:calc(12 * var(--ub-u));height:calc(12 * var(--ub-u));border-radius:50%;
  background:var(--ub-player,var(--ub-player-red));border:var(--ub-bw) solid var(--ub-ink);flex:none}
.ub-plate.is-me{background:var(--ub-ink);color:var(--ub-paper);font-size:var(--ub-fs-3);
  box-shadow:0 0 0 var(--ub-bw-2) var(--ub-player,var(--ub-player-red)),var(--ub-shadow-s)}
.ub-plate.is-empty{background:var(--ub-paper-2);color:var(--ub-ink-2);box-shadow:none}
/* the avatar bubble: a friend's face + hat (the hero render's PNG goes inside). 60u is the
   read test for every hat (principle 7). Ring = that player's apron; mine adds the ink ledge. */
.ub-avatar{position:relative;display:grid;place-items:center;flex:none;overflow:hidden;
  width:var(--ub-avatar);height:var(--ub-avatar);border-radius:50%;background:var(--ub-paper);
  border:var(--ub-bw) solid var(--ub-ink);box-shadow:0 0 0 var(--ub-bw-2) var(--ub-player,var(--ub-player-red))}
.ub-avatar>img,.ub-avatar>canvas{width:100%;height:100%;object-fit:cover;object-position:50% 20%}
.ub-avatar.is-me{box-shadow:0 0 0 var(--ub-bw-2) var(--ub-player,var(--ub-player-red)),
  0 calc(3 * var(--ub-u)) 0 var(--ub-bw-2) var(--ub-ink)}
.ub-avatar.is-empty{background:var(--ub-paper-2);box-shadow:none}
.ub-tile{position:relative;display:grid;place-items:center;width:calc(72 * var(--ub-u));height:calc(72 * var(--ub-u));
  background:var(--ub-paper);border:var(--ub-bw) solid var(--ub-ink);border-radius:var(--ub-r);box-shadow:var(--ub-shadow-s);cursor:pointer}
.ub-tile .ub-icon{width:var(--ub-icon-l);height:var(--ub-icon-l)}
.ub-tile.is-selected{box-shadow:0 0 0 var(--ub-bw-2) var(--ub-info),var(--ub-shadow-s)}
.ub-tile.is-locked{background:var(--ub-paper-2);cursor:default}
.ub-tile__corner{position:absolute;top:calc(-8 * var(--ub-u));inset-inline-end:calc(-6 * var(--ub-u))}
.ub-tile__check{position:absolute;bottom:calc(-8 * var(--ub-u));inset-inline-end:calc(-8 * var(--ub-u));
  width:calc(24 * var(--ub-u));height:calc(24 * var(--ub-u));border-radius:50%;display:grid;place-items:center;
  background:var(--ub-info);color:var(--ub-on-info);border:var(--ub-bw) solid var(--ub-ink)}
.ub-tile__check .ub-icon{width:calc(16 * var(--ub-u));height:calc(16 * var(--ub-u))}
.ub-tile__q{position:absolute;bottom:calc(4 * var(--ub-u));font:var(--ub-w-display) var(--ub-fs-5)/1 var(--ub-font-ui);
  color:var(--ub-ink-2);letter-spacing:.1em;direction:ltr}
.ub-empty{display:flex;align-items:center;gap:var(--ub-sp-2);background:var(--ub-paper-2);color:var(--ub-ink-2);
  border-radius:var(--ub-r);padding:var(--ub-sp-2) var(--ub-sp-3);font:var(--ub-w-label) var(--ub-fs-5)/1.2 var(--ub-font-ui)}
.ub-empty .ub-icon{--ub-ic-m:var(--ub-mute);--ub-ic-hl:transparent;--ub-ic-ink:var(--ub-mute-ink);color:var(--ub-mute-ink)}
.ub-scrim{position:fixed;inset:0;background:var(--ub-scrim);z-index:var(--ub-z-panel)}
.ub-screen{position:absolute;inset:0;box-sizing:border-box;
  padding:var(--ub-safe-top) var(--ub-safe-x) var(--ub-safe-bottom)}

/* ------------------------------------------------------------- motion ---- */
@keyframes ub-pop{0%{transform:scale(1)}40%{transform:scale(1.14)}100%{transform:scale(1)}}
@keyframes ub-pulse{0%,100%{transform:scale(1)}50%{transform:scale(1.06)}}
@keyframes ub-swing{0%,100%{transform:rotate(0)}25%{transform:rotate(2deg)}75%{transform:rotate(-2deg)}}
@keyframes ub-shake{0%,100%{transform:translateX(0)}25%{transform:translateX(calc(2 * var(--ub-u)))}75%{transform:translateX(calc(-2 * var(--ub-u)))}}
@keyframes ub-enter{from{opacity:0;transform:translateY(calc(16 * var(--ub-u))) scale(.98)}to{opacity:1;transform:none}}
@keyframes ub-toast-in{from{opacity:0;transform:translateY(calc(12 * var(--ub-u))) scale(.96)}to{opacity:1;transform:none}}
@keyframes ub-toast-out{to{opacity:0;transform:translateY(calc(8 * var(--ub-u)))}}
@keyframes ub-stamp-in{0%{opacity:0;transform:rotate(var(--ub-stamp-tilt)) scale(1.8)}
  55%{opacity:.95;transform:rotate(var(--ub-stamp-tilt)) scale(.94)}
  100%{opacity:.95;transform:rotate(var(--ub-stamp-tilt)) scale(1)}}
@keyframes ub-float{0%{opacity:0;transform:translateY(0) scale(.8)}
  15%{opacity:1;transform:translateY(calc(-6 * var(--ub-u))) scale(1.12)}
  75%{opacity:1}100%{opacity:0;transform:translateY(calc(-36 * var(--ub-u))) scale(1)}}
.ub-anim-enter{animation:ub-enter var(--ub-t-mid) var(--ub-ease-pop) both}
.ub-anim-land{animation:ub-pop var(--ub-t-fast) var(--ub-ease-pop)}
.ub-anim-shake{animation:ub-shake 120ms linear}            /* the card, as the stamp hits */
.ub-anim-float{animation:ub-float 800ms var(--ub-ease-out) both;pointer-events:none}
@media (prefers-reduced-motion:reduce){
  [class*="ub-"]{animation-duration:1ms!important;animation-iteration-count:1!important;
    transition-duration:1ms!important}}
