:root{
  --paper:#F5EBD8; --espresso:#4A342A; --curtain:#B8302F; --gold:#D4A437;
  --blue:#2E5E9E; --green:#2E7D4F; --shadow:0 6px 0 rgba(74,52,42,.18);
  --profit:#1f7a45;
  /* Content width that takes BOTH axes into account: on wide, flat screens
     it grows with the height — otherwise the stage stands as a narrow column in nothing. */
  --wide:min(94vw, 165dvh);
}
*{box-sizing:border-box}
html,body{margin:0;height:100%}
/* Type scales with the smaller of the two axes — never larger than the room allows */
html{font-size:clamp(16px, min(.62vw + 9px, 1.35dvh + 8px), 19px)}
body{
  font-family:Nunito,system-ui,sans-serif;color:var(--espresso);
  background:var(--paper);
  background-image:radial-gradient(rgba(74,52,42,.05) 1px,transparent 1px);
  background-size:22px 22px;
  /* The page itself NEVER scrolls: every screen is 100dvh tall and handles
     its scrolling on the inside (.screen or .rail-list, .auction-main …). Without this
     line a single crumb of an effect sticking a few pixels past the edge would be
     enough — a shake, a checkmark popping up — and a scrollbar appeared at the
     window edge, only to vanish again straight away. */
  overflow:hidden;
  /* No double-tap zoom (the canvas takes everything anyway with
     touch-action:none), no pull-to-reload: a swipe at the top edge would otherwise
     have reloaded the page in the middle of painting. */
  touch-action:manipulation;
  overscroll-behavior:none;
  /* Android otherwise lays a grey rectangle over every tapped button — the
     :active states in the game say the same thing, only in their own handwriting. */
  -webkit-tap-highlight-color:transparent;
}
h1,h2,h3{font-family:Fraunces,serif}
.handwriting{font-family:Caveat,cursive;font-size:1.5em}
.hidden{display:none!important}
.muted{opacity:.65;font-size:.9rem}
.italic{font-style:italic}

/* ---------- Scrollbars ----------
   The operating system's grey bar was the only piece of foreign design that ran
   right through this game. It turns up in enough places to be noticed:
   start page, legal texts, the introduction, gallery, leaderboard.

   The thumb gets a transparent border instead of a paper-coloured one —
   `background-clip:padding-box` turns that into a gap that works on light
   paper AND on the dark stage. With a fixed colour a cream-coloured frame
   would otherwise sit there in the middle of the dark. */
*{scrollbar-width:thin;scrollbar-color:var(--gold) rgba(74,52,42,.14)}
::-webkit-scrollbar{width:12px;height:12px}
::-webkit-scrollbar-track{background:rgba(74,52,42,.10);border-radius:12px}
::-webkit-scrollbar-thumb{background:var(--gold);border:3px solid transparent;
  background-clip:padding-box;border-radius:12px}
@media (hover:hover){.scroll-host::-webkit-scrollbar-thumb:hover,::-webkit-scrollbar-thumb:hover{background:#c08f2b;
  border:3px solid transparent;background-clip:padding-box}}
::-webkit-scrollbar-corner{background:transparent}

/* ---------- And the narrow version, for everything that scrolls inside a card ----------
   Twelve pixels of gold are right where a whole page travels — legal texts,
   start page, gallery. In a small box they are an impertinence: the commission
   note in the atelier is 200 pixels wide, and a gold bar of 12 pixels takes a
   sixteenth of that and draws more attention to itself than the commission
   next to it. The same in the rail, in the strip with the faces and in the bid
   card.

   The list is expressly enumerated rather than governed by a class: some of
   these boxes only come into being at runtime (the rail, the guild), and a
   class somebody forgets at the next rebuild would quietly bring the thick bar
   back. */
.hud-inner,.rail-list,.portrait-presets,.players,#host-settings,.auction-main,
.reveal-grid,.final-list,.dossier-critique,.critic-row,.tools,.browse-list,
.gallery,.lot-critique,.legal-body{scrollbar-width:thin;scrollbar-color:rgba(212,164,55,.75) transparent}
.hud-inner::-webkit-scrollbar,.rail-list::-webkit-scrollbar,
.portrait-presets::-webkit-scrollbar,.players::-webkit-scrollbar,
#host-settings::-webkit-scrollbar,.auction-main::-webkit-scrollbar,
.reveal-grid::-webkit-scrollbar,.final-list::-webkit-scrollbar,
.dossier-critique::-webkit-scrollbar,.critic-row::-webkit-scrollbar,
.tools::-webkit-scrollbar,.browse-list::-webkit-scrollbar,
.gallery::-webkit-scrollbar,.lot-critique::-webkit-scrollbar,.legal-body::-webkit-scrollbar{width:6px;height:6px}
.hud-inner::-webkit-scrollbar-track,.rail-list::-webkit-scrollbar-track,
.portrait-presets::-webkit-scrollbar-track,.players::-webkit-scrollbar-track,
#host-settings::-webkit-scrollbar-track,.auction-main::-webkit-scrollbar-track,
.reveal-grid::-webkit-scrollbar-track,.final-list::-webkit-scrollbar-track,
.dossier-critique::-webkit-scrollbar-track,.critic-row::-webkit-scrollbar-track,
.tools::-webkit-scrollbar-track,.browse-list::-webkit-scrollbar-track,
.gallery::-webkit-scrollbar-track,.lot-critique::-webkit-scrollbar-track,.legal-body::-webkit-scrollbar-track{background:transparent}
.hud-inner::-webkit-scrollbar-thumb,.rail-list::-webkit-scrollbar-thumb,
.portrait-presets::-webkit-scrollbar-thumb,.players::-webkit-scrollbar-thumb,
#host-settings::-webkit-scrollbar-thumb,.auction-main::-webkit-scrollbar-thumb,
.reveal-grid::-webkit-scrollbar-thumb,.final-list::-webkit-scrollbar-thumb,
.dossier-critique::-webkit-scrollbar-thumb,.critic-row::-webkit-scrollbar-thumb,
.tools::-webkit-scrollbar-thumb,.browse-list::-webkit-scrollbar-thumb,
.gallery::-webkit-scrollbar-thumb,.lot-critique::-webkit-scrollbar-thumb,.legal-body::-webkit-scrollbar-thumb{
  background:rgba(212,164,55,.75);border:0;border-radius:6px}

/* The drawn cursor stands at the END of this file — see there for why. */

/* Blobs of colour in the background — they breathe slowly so the page is never completely still */
#splats{position:fixed;inset:0;pointer-events:none;z-index:0}
#splats::before,#splats::after{content:"";position:absolute;border-radius:60% 40% 55% 45%/50% 60% 40% 50%;opacity:.12;filter:blur(1px)}
#splats::before{width:340px;height:300px;background:var(--curtain);top:-90px;left:-110px;transform:rotate(18deg);
  animation:splat-drift 26s ease-in-out infinite}
#splats::after{width:300px;height:280px;background:var(--blue);bottom:-100px;right:-90px;transform:rotate(-24deg);
  animation:splat-drift 34s ease-in-out infinite reverse}
/* Only animate translate/scale: a transform in the keyframe would replace the
   declared value, and the blue blob (rotate(-24deg)) would jump to +18deg. */
@keyframes splat-drift{
  0%,100%{translate:0 0;scale:1}
  50%{translate:26px 18px;scale:1.08}}

.screen{display:none;height:100dvh;position:relative;z-index:1;padding:10px 14px;overflow:hidden}
.screen.active{display:flex;flex-direction:column;animation:screen-fade .3s ease}
@keyframes screen-fade{from{opacity:0}to{opacity:1}}
/* The content comes in a moment later and from below. Deliberately NOT on
   .screen itself: a transform there would tie position:fixed on the inside (knock-down
   banner, panic border) to the screen instead of to the window. */
.screen.active>.home-card,.screen.active>.lobby-grid,.screen.active>.draw-wrap,
.screen.active>.center-card,.screen.active>.stage,.screen.active>.final-wrap{
  animation:screen-in .42s cubic-bezier(.2,.9,.3,1.06)}
/* translate/scale instead of transform: that way the tilt of the cards (rotate)
   survives instead of being overwritten for the duration of the animation. */
@keyframes screen-in{from{opacity:0;translate:0 18px;scale:.985}to{opacity:1;translate:none;scale:none}}
/* NO screen swipes. `display:block;overflow-y:auto` once stood here for the
   lobby, the interim standing and the vernissage — the three pages whose
   content grows with the number of players. They were the only ones allowed to
   scroll, and that was exactly the mistake: on a phone with eight players the
   start button lay 314 pixels below the edge, on an iPhone SE 730.

   A page that swipes hides its most important button. So none of them swipes
   any more — they stay flex columns like every other screen, and whatever gets
   too long scrolls on the INSIDE: the guild in the lobby, the leaderboard and
   the collection after the game. In both cases the button stands fixed in the
   picture. */
#screen-lobby.active>.lobby-grid,#screen-final.active>.final-wrap,
#screen-standings.active>.final-wrap{flex:1 1 auto;min-height:0}
/* And a safety valve that normally does nothing: measured, none of these pages
   scrolls any more (see the test across eight players and nine sizes). Should
   it ever come to that after all — a translation longer than all four here, a
   browser with a larger base font — then the page should rather swipe than
   hide "open the vernissage". An `overflow:hidden` would be the worse answer
   at this spot. */
#screen-lobby.active,#screen-final.active,#screen-standings.active{overflow-y:auto}
/* Stage on the left, leaderboard on the right — the table runs along in every phase. */
#screen-critique.active,#screen-auction.active,#screen-reveal.active,
#screen-title.active,#screen-judging.active{flex-direction:row;gap:12px;align-items:stretch}

/* ---------- Buttons & inputs ---------- */
/* flex-shrink:0 — a button NEVER gets smaller than its label.
   Almost every button in the game sits in a flex box (.center-card,
   .stage-foot, .bar, .brief-foot), and there a child may shrink of its own
   accord. Together with the `overflow:hidden` that .btn.gold needs for its
   wipe of light, that makes not a tight button but a CLIPPED one: measured,
   "hand in" stood 31 pixels tall on the title screen instead of 49 — the
   bottom half of the type was gone. The same hit "to the auction ▶" and
   "next ▶" on narrow screens.
   A button is the smallest area you have to hit; it is the last thing that may
   give way. */
.btn{
  font-family:Nunito;font-weight:900;font-size:1rem;color:var(--espresso);
  background:#fff;border:3px solid var(--espresso);border-radius:14px;
  padding:12px 20px;cursor:pointer;box-shadow:var(--shadow);flex-shrink:0;
  transform:rotate(-.6deg);transition:transform .08s
}
/* Every :hover rule in the game sits inside this wrapper. A finger knows no
   hovering: after a tap the button would stay raised until you tapped somewhere
   else — a playing field full of half-pressed buttons. */
@media (hover:hover){
  .btn:hover{transform:rotate(.4deg) translateY(-2px)}
}
.btn:active{transform:translateY(2px);box-shadow:0 2px 0 rgba(74,52,42,.18)}
.btn:disabled{opacity:.45;cursor:not-allowed;transform:none}
.btn.gold{background:var(--gold);color:#3a2a10}
.btn.big{font-size:1.25rem;padding:16px 30px}
.btn.small{font-size:.85rem;padding:8px 12px}
/* A button that has to be there without inviting: "leave salon" stands next to
   the way in and must not outshine it. Pale, not hidden — whoever wants out
   should find it at first glance. */
.btn.quiet{background:transparent;box-shadow:none;opacity:.72;border-style:dashed}
@media (hover:hover){ .btn.quiet:hover{opacity:1;background:#fff} }
/* The way out after the finale stands on its own — .final-wrap is centred,
   the button only needs air above and below. */
#btn-leave-final{margin:10px 0 4px}
/* min-width:0 is not a finishing touch here. An <input> brings its OWN
   minimum width along (about 20 characters, measured 252 px) — and that still
   applies when width:100% stands next to it, because width sets the desired
   width and not the lower bound. In a flex box that becomes the minimum width
   of the whole box: on a 320-wide screen the sign-in card therefore stood
   416 pixels wide in a 292 pixel wide window and stuck out on BOTH sides. */
input{
  font-family:Nunito;font-size:1.05rem;padding:12px 14px;border:3px solid var(--espresso);
  border-radius:12px;background:#fffdf7;width:100%;min-width:0;color:var(--espresso)
}
input:focus{outline:3px solid var(--gold)}

/* ---------- Home ---------- */
/* The zigzag hem is a background image, not a clip-path.
   It used to hang on a clip-path with percentage points, and that was only
   partly applied on the FIRST paint: Chromium rasterised the left tile column
   (up to ~512 px) without the clip, the hem was smooth on the left and only
   jagged on the right. Every repaint — a click into the input field, an opened
   select — rasterised anew and the shape jumped. A background image comes into
   being while the element itself is painted; there is no tile boundary there
   at which it could get lost.
   Fixed along the way: the percentage points always produced exactly ten
   spikes, so 256 px wide ones on a 2560 screen and 38 px wide ones on the
   phone. The tile is now 46 px wide — as wide as one stripe — and therefore
   looks the same everywhere. The gold stands in the image as a number, because
   a CSS variable does not reach into a data URI; it is the same --gold. */
.curtain-top{position:fixed;top:0;left:0;right:0;height:70px;z-index:0;
  background:
    linear-gradient(var(--gold) 0 0) bottom/100% 8px no-repeat,
    repeating-linear-gradient(90deg,var(--curtain) 0 46px,#9c2726 46px 92px)}
.curtain-top::after{content:"";position:absolute;top:100%;left:0;right:0;height:11px;
  background:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='46' height='11' viewBox='0 0 46 11'%3E%3Cpath d='M0 0h46L23 11z' fill='%23D4A437'/%3E%3C/svg%3E") repeat-x}
/* The gap is smaller than it used to be (14px), and that is not saving air but
   a statement: what belongs together now stands in groups
   (.home-act, .join-row, .home-foot) and brings its own, tighter
   spacing along. The value here is only the gap BETWEEN the groups —
   and it has to look bigger than the one inside, otherwise the card reads
   as a list of equally ranked rows again. */
/* min-width:0 as a bolt: the card is a flex child of .home-wrap and without
   this line could never get narrower than its widest content —
   no matter how narrow the window is. What cannot shrink along on the inside
   scrolls sideways in its own box (the strip with the
   faces); the card itself always keeps to the margins. */
.home-card{max-width:430px;min-width:0;margin:auto;background:#fffdf7;border:3px solid var(--espresso);
  border-radius:20px;padding:28px 30px;box-shadow:var(--shadow);display:flex;flex-direction:column;gap:13px;transform:rotate(.5deg)}
/* The logo is an image: public/logo.webp, embedded in index.html.
   All three bounds are needed, and the third is the most important:
     100%  — never wider than the card
     21rem — hangs on the same type scale as everything else
     37dvh — ties the HEIGHT to the screen. The image is 800:721 wide to
             tall, so 37dvh of width is ~33dvh of height. Without this bound
             the logo is in the way on a phone held sideways (812×375) and pushes
             "open a new salon" below the edge of a screen that deliberately
             does not scroll (see body{overflow}). The button would not merely
             be placed badly there but be out of reach: the game could no
             longer be started. Whoever swaps the image has to recompute this
             value — it hangs on the aspect ratio.
   Taken down from 21rem/37dvh to 19rem/33dvh: below the logo the card carries
   a field, two ways in, a third and a foot — on a
   1440×900 screen it previously reached to within eleven pixels of the bottom edge.
   The logo stays the biggest thing on the page, it just does not need half
   the card for that. */
.logo{margin:0 auto;width:min(100%,19rem,33dvh);line-height:0}
.logo img{display:block;width:100%;height:auto}
/* ---------- The self-portrait on the start page ----------
   It stood in the lobby and moved here, because a lobby is the place where
   people wait for each other — not the one where somebody paints while the
   others watch. Here you are alone anyway.

   The order in the box is the order of the decision: first your own choice
   (large, with a pencil — that is at the same time the way to the paintbox), then six
   finished faces to tap, then the die for the next six. Whoever wants to get
   in quickly taps once; whoever wants to paint taps on the left. */
/* Label NEXT TO the row, not above it: stacked, the block costs 76
   pixels, side by side 56 — and the 20 pixels of difference decide on a
   1280 × 800 laptop whether the card still fits into the window.
   It stands narrow and on two lines so it takes no width from the row. */
.portrait-row{display:flex;align-items:center;gap:10px}
/* ONE word, ONE line, no wrapping — and both are a correction from live use.
   The measuring was done in English ("Your self-portrait"), the display is in
   German: "Dein Selbstporträt". At max-width:5.2em it read "DEIN
   SELBSTPO", cut off in the middle of the word. The first attempt at a fix
   (wider + overflow-wrap) turned that into "DEIN SELBSTPORT / RÄT" — a break
   in the middle of a syllable is no improvement, only a different kind of
   damage.
   So shorter rather than wider: next to your own face, the possessive pronoun
   says nothing the picture does not already show. "Self-portrait" on its own
   fits on one line in all four languages. */
.portrait-label{flex:0 0 auto;white-space:nowrap;font-size:.6rem;letter-spacing:.06em;
  text-transform:uppercase;font-weight:900;color:var(--curtain);opacity:.75;line-height:1.2}
.portrait-pick{flex:1 1 auto;min-width:0;display:flex;align-items:center;gap:9px}
/* NO overflow:hidden on the button — that was the mistake. What gets clipped
   round is the PICTURE, not the button: the pencil sits in the bottom right
   corner and therefore lies outside the circle. If the button clipped, the
   pencil became half a gold spot at the edge of the face — it did not look
   like "this can be changed" but like a blob that does not belong there. */
.portrait-preview{position:relative;flex:0 0 auto;width:56px;height:56px;padding:0;
  border:0;background:none;cursor:pointer;line-height:0}
.portrait-preview canvas{width:100%;height:100%;display:block;border-radius:50%;
  border:3px solid var(--espresso);background:#fdfaf2;box-shadow:0 3px 0 rgba(74,52,42,.18)}
/* NOT GOLD — and that is the real point, not the size. In this row gold means
   "this is your choice": it is the ring around the chosen face. A gold spot on
   the picture next to it therefore says the same thing again instead of
   something new; it read as a badge or a coin, not as a tool. On paper with a
   dark border it is a button like every other in the house — and the pencil on
   it says what it does.
   An emoji instead of ✎: the house speaks in emoji anyway (🎲 right next to it,
   🖌️ in the atelier, 🔨 in the hall), and nobody recognises a text character at
   10 pixels. */
.portrait-pen{position:absolute;right:-5px;bottom:-5px;width:26px;height:26px;
  display:grid;place-items:center;font-size:.82rem;line-height:1;border-radius:50%;
  background:#fffdf7;border:2px solid var(--espresso);
  box-shadow:0 2px 0 rgba(74,52,42,.3)}
@media (hover:hover){.portrait-preview:hover .portrait-pen{background:var(--gold)}}
.portrait-preview:focus-visible{outline:3px solid var(--gold);outline-offset:2px}
/* ONE strip that swipes sideways if it has to — not a wrapping grid.
   As a grid (auto-fit) the six faces broke into two rows on an iPhone SE,
   and the row was suddenly 122 pixels tall instead of 56: more
   than "open a new salon" and the box below it together. A strip
   is always exactly one row tall, no matter how narrow the screen gets — what
   no longer fits is pushed into view. The hit area stays
   34 pixels in the process; a shrinking grid would have squeezed it to 24. */
.portrait-presets{flex:1 1 auto;min-width:0;display:flex;gap:5px;
  overflow-x:auto;overflow-y:hidden;scrollbar-width:thin;padding:2px 0}
.portrait-preset{flex:0 0 auto;padding:0;width:34px;height:34px;border-radius:50%;overflow:hidden;
  border:2px solid rgba(74,52,42,.35);background:#fdfaf2;cursor:pointer;line-height:0}
.portrait-preset canvas{width:100%;height:100%;display:block}
.portrait-preset.on{border-color:var(--gold);border-width:3px;box-shadow:0 0 0 2px rgba(212,164,55,.4)}
@media (hover:hover){.portrait-preset:hover{border-color:var(--espresso);transform:translateY(-2px)}}
.portrait-preset:focus-visible{outline:3px solid var(--gold);outline-offset:2px}
.portrait-dice{flex:0 0 auto;width:36px;height:36px;padding:0;font-size:1.05rem;
  border:2px solid var(--espresso);border-radius:12px;background:#fffdf7;cursor:pointer;
  box-shadow:0 3px 0 rgba(74,52,42,.18)}
.portrait-dice:active{transform:translateY(2px);box-shadow:0 1px 0 rgba(74,52,42,.18)}
@media (pointer:coarse){
  .portrait-preset{width:38px;height:38px}
  .portrait-dice{width:40px;height:40px}
}
/* At 320 pixels the label takes three lines and pushes the strip
   against the wall. It stays for screen readers (aria-label on the button and on
   the group), from the picture it disappears: a round face with a
   pencil on it explains itself without a heading too. */
@media (max-width:420px){
  .portrait-label{position:absolute;width:1px;height:1px;overflow:hidden;clip-path:inset(50%)}
}

/* ---------- The paintbox behind it ---------- */
.portrait-card{width:min(460px,100%);text-align:center}
/* The canvas measures itself against BOTH axes — on a phone held sideways one
   measured only against the width would be taller than the window. */
.portrait-stage{position:relative;width:min(100%,46dvh);aspect-ratio:1;margin:12px auto 0;line-height:0}
#avatar-canvas{width:100%;height:100%;border:3px dashed var(--espresso);border-radius:14px;
  background:#fff;cursor:none;touch-action:none}
.portrait-tools{display:flex;gap:10px;align-items:center;justify-content:center;
  flex-wrap:wrap;margin-top:12px}
.portrait-card .brief-foot{justify-content:center}

/* The tab bar is a stopgap for too little room and therefore is NOT there
   by default: where all three ways fit side by side, a toggle is an
   extra click for nothing. It is switched on
   in the wrapper "the three ways as a toggle" further down. */
.home-tabs{display:none}

/* Opening and listing are ONE move: close together, so the box
   visibly belongs to the button above it and not to the code field below. */
.home-act{display:flex;flex-direction:column;gap:8px}
.home-act .check-row{align-self:center}
.home-act .fineprint{text-align:center;margin:0}
/* "or" — the place where one way in ends and the next
   begins. Dashed like the quiet button (.btn.quiet): in this house nothing
   is drawn with a ruler. */
.home-or{display:flex;align-items:center;gap:12px;margin:1px 0;
  font-family:Fraunces,serif;font-size:.78rem;font-weight:600;
  letter-spacing:.18em;text-transform:uppercase;opacity:.42}
.home-or::before,.home-or::after{content:"";flex:1;border-top:2px dashed rgba(74,52,42,.35)}
.join-row{display:flex;gap:10px}
.join-row input{width:110px;flex:0 0 auto;text-transform:uppercase;letter-spacing:.2em;text-align:center}
/* "Join" takes the rest of the row. Previously the button ended in the middle of
   the card and nothing stood to the right of it — a row that looked as though
   something were missing. */
#btn-join{flex:1}
.fineprint{font-size:.72rem;opacity:.5;margin:4px 0 0}
/* Small print, publisher, privacy: the foot of the card. The dotted
   line matters more than it looks — without it the small print stood at the
   same distance below "play alone" as "play alone" below the
   code field, and the eye looked for the way into the game all the way down to
   the privacy notice. */
.home-foot{margin-top:3px;padding-top:12px;border-top:2px dotted rgba(74,52,42,.22);
  display:flex;flex-direction:column;align-items:center;gap:0}
.home-foot .fineprint{margin:0;text-align:center}
.home-foot .credit{margin:8px 0 0}
/* Locked name field: the name comes from the CrazyGames account. Not greyed out
   — it should stay easy to read, because that is exactly how friends recognise each other.
   The lock sits on the right inside the field and takes no line away. */
#name-input.locked{
  background:
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%234A342A' stroke-width='2.2' stroke-linecap='round'%3E%3Crect x='4.5' y='10.5' width='15' height='10' rx='2.2'/%3E%3Cpath d='M8 10.5V7.5a4 4 0 0 1 8 0v3'/%3E%3C/svg%3E")
    no-repeat right 12px center / 18px 18px,
    #fffdf7;   /* the same surface as every other field, see input{} above */
  padding-right:38px;cursor:default}
#name-input.locked:focus{outline-offset:2px}
/* A button that looks like a link: it opens a box but does not leave
   the page — an <a> would be a lie for screen readers here. The
   hit area stays finger-friendly despite the small type (44 px tall). */
.linklike{background:none;border:0;padding:8px 4px;min-height:44px;font:inherit;font-size:.72rem;
  color:inherit;opacity:.6;text-decoration:underline;text-underline-offset:3px;cursor:pointer}
.linklike:hover,.linklike:focus-visible{opacity:1}
.privacy-card{width:min(560px,100%)}
.privacy-list{margin:14px 0 4px;padding-left:1.1em;display:flex;flex-direction:column;gap:9px;
  font-size:.92rem;line-height:1.45}
.privacy-list li::marker{color:var(--gold)}

/* ---------- Legal texts ----------
   Imprint, privacy policy, terms of use. They are long — and are allowed to
   be: the card scrolls on the inside (.brief-card has max-height + overflow-y), the
   screen behind it stays put. A little wider than the short
   privacy box, so a paragraph does not turn into a column. */
.legal-row{display:flex;flex-wrap:wrap;align-items:center;justify-content:center;
  gap:8px;margin:8px 0 0}
.legal-row span{opacity:.4}
.legal-card{width:min(680px,100%);text-align:left}
.legal-body{margin:12px 0 4px;font-size:.88rem;line-height:1.55}
.legal-body h3{font-size:1rem;margin:18px 0 6px}
.legal-body h3:first-child{margin-top:4px}
.legal-body p{margin:0 0 9px}
.legal-body ul{margin:0 0 10px;padding-left:1.15em;display:flex;flex-direction:column;gap:7px}
.legal-body li::marker{color:var(--gold)}
/* Address and contact: the line break is the form here, not the sentence. */
.legal-body .legal-pre{white-space:pre-line;background:rgba(212,164,55,.12);
  border-left:3px solid var(--gold);border-radius:0 8px 8px 0;padding:9px 12px;margin-bottom:10px}
.legal-body .fineprint{margin-top:16px;opacity:.6}

/* ---------- Publisher ---------- */
/* The wordmark is delivered in white and therefore belongs on a dark surface —
   recolouring would alter somebody else's logo. Small and with no way out: CrazyGames
   forbids cross-references to other platforms, a credit is allowed. */
.credit{display:flex;align-items:center;justify-content:center;gap:7px;
  margin:10px 0 0;font-size:.72rem;opacity:.55}
.credit-mark{display:inline-flex;background:var(--espresso);border-radius:7px;padding:4px 8px}
.credit-mark img{display:block;width:66px;height:auto}

/* ---------- Reporting & throwing out ---------- */
/* Two small buttons on the player card. They lie over the portrait, so they
   take no line away.

   LEFT, not right: the host's crown sits at the top right
   (.player-card.host::after, a bit past the edge of the card). On the right
   the buttons would lie exactly underneath it — and because a pseudo-element reports
   its origin during hit testing, a tap would hit the card instead of the button.

   Visible instead of only on hover: a transparent button can still be
   hit — on a phone that would mean pressing something you cannot
   see. For a tool against pictures somebody does not want to see,
   findability matters more than restraint anyway. */
.pcard-tools{position:absolute;top:6px;left:6px;display:flex;gap:4px;
  z-index:2;opacity:.4;transition:opacity .15s ease}
.player-card:hover .pcard-tools,.player-card:focus-within .pcard-tools,
.pcard-tools:focus-within{opacity:1}
.pcard-btn{width:28px;height:28px;padding:0;border-radius:50%;cursor:pointer;
  border:2px solid var(--espresso);background:#fffdf7;color:var(--espresso);
  font-size:.85rem;line-height:1;display:inline-flex;align-items:center;justify-content:center}
.pcard-btn:hover,.pcard-btn:focus-visible{background:var(--gold)}
.pcard-btn.danger:hover,.pcard-btn.danger:focus-visible{background:var(--curtain);color:#fff}
/* The same button, but free-standing under the easel instead of on a card. */
.flag-inline{position:static;opacity:.5}
.flag-inline:hover,.flag-inline:focus-visible{opacity:1}
.lot-actions{display:flex;gap:8px;align-items:center;flex-wrap:wrap}
/* A removed picture leaves an empty frame behind, not a broken link. */
img.art-gone{background:repeating-linear-gradient(45deg,#e8ddc8,#e8ddc8 8px,#ddd0b6 8px,#ddd0b6 16px);
  min-height:120px;border-radius:6px}

/* ---------- Introduction ---------- */
/* The question-mark button at the top right: round, so that next to the square
   language picker it does not look like a second select.

   Only on the start page and in the lobby. The top corner stands fixed above everything
   (#top-corner is position:fixed), and in the atelier on an iPhone SE
   the header reaches that far — a third button there would lie over "hand in".
   The introduction is read before the game anyway, not in the middle of a stroke. */
.btn.round{width:38px;height:38px;padding:0;border-radius:50%;font-weight:900;font-size:1.05rem;
  align-items:center;justify-content:center;line-height:1;display:none}
body:has(#screen-home.active) #btn-howto,
body:has(#screen-lobby.active) #btn-howto{display:inline-flex}
.howto-card{width:min(620px,100%)}
/* ---------- The introduction: four steps, one after the other ----------
   Previously all four stood below one another and explained the game in sentences.
   But sentences are exactly what somebody skips who has just pressed
   "play" for the first time. Now a built scene runs
   over each step, and the sentence only says what you are looking at.

   --sc-h IS THE ENTIRE STATICS OF THIS BOX. The scene is the only
   piece in it that can grow to any size — heading, sentence,
   controls hint and footer are text and stand fixed. Tie the
   scene to the WIDTH alone (previously: `width:100%` plus aspect ratio), and
   it grows in height on a wide, flat window until the card is
   longer than the screen — and `next` lies below the edge. That
   is exactly what happened on a phone held sideways: the card scrolled
   on the inside, and the button EVERYBODY has to press was only
   reachable with a swipe.

   So the scene measures itself against the height of the window and computes its
   width back from that (× 1.6 = the aspect ratio 16/10). It is thereby never
   taller than --sc-h, no matter how wide the box gets. */
.howto-steps{--sc-h:34dvh;list-style:none;margin:14px 0 4px;padding:0;display:grid}
/* All four lie ON TOP OF one another in the same grid cell, not below one another: that way
   the box does not jump in height while paging, because it is always as
   tall as its longest step. */
.howto-steps li{grid-area:1/1;display:grid;grid-template-columns:minmax(0,1fr);gap:11px;
  align-content:center;font-size:.95rem;line-height:1.42;visibility:hidden;opacity:0;
  transition:opacity .22s ease}
.howto-steps li.on{visibility:visible;opacity:1}
.howto-steps li p{margin:0}
.howto-icon{font-size:1.15rem;margin-right:.4em}
.howto-steps b{font-family:Fraunces,serif}

/* ================================================================
   THE FOUR SCENES
   ================================================================
   Built, not filmed (why: see the long paragraph in index.html).

   TWO RULES on which everything here hangs:

   1. MEASUREMENT IS IN cqw, NOT IN rem. Every scene is a
      `container-type:inline-size`, and every font, every gap and every
      border in it stands in percent of its WIDTH. The scene is thereby a picture
      that scales as a whole: the same drawing at 240 px on the
      phone held sideways as at 560 px at the desk, only smaller. Were
      rem to stand here, the type would grow out of the box while shrinking — and
      that is exactly the disease the old strips suffered from.

   2. ONE BEAT OF 6 s PER SCENE, and every movement is a percentage window
      within it. No animation-delay: with `infinite` a delay only applies to
      the FIRST run, after that five strokes drifted apart. So every
      movement carries its timing in its own keyframe. The old strips ran
      through ten frames in 2.1 s — 210 ms per frame, too fast to read along.

   The movement only runs in the VISIBLE step (`li.on`): animating four scenes
   at once would mean a phone computing three pictures
   nobody sees. */
/* TWO boxes, and the outer one is not decoration: `container-type` makes an
   element a container for ITS DESCENDANTS — it cannot query
   itself. Were `font-size:3.9cqw` to stand on the same element that opens the
   container, the unit would find no responsible container and fall back to the
   VIEWPORT: 3.9 % of 1440 px is 56 px of font size, and the
   scene would burst its own frame. (That is exactly how it looked on the first
   attempt too.) So .sc-box measures the width, and .sc inside it computes with that. */
.sc-box{container-type:inline-size;display:block;
  width:min(100%,calc(var(--sc-h,34dvh) * 1.6));margin-inline:auto}
.sc{position:relative;width:100%;aspect-ratio:16/10;
  overflow:hidden;border-radius:12px;border:1px solid rgba(60,36,20,.18);
  background:#efe7d8;box-shadow:0 6px 18px rgba(60,36,20,.14);
  font-size:3.9cqw;line-height:1.25}
.sc-label{display:block;font-size:.62em;letter-spacing:.14em;text-transform:uppercase;
  font-weight:900;color:var(--curtain);opacity:.8}

/* ---------- 1. Painting ----------
   The column widths are COMPUTED, not `auto`. The box is 100 cqw
   wide and 62.5 cqw tall (16/10), and the canvas in it has to be square
   — otherwise the introduction shows a canvas that does not exist in the
   atelier. With `auto` columns the CONTENT determines the width, the canvas got
   the rest, and with one line of wrapping in the note it stood past the
   edge. Now the arithmetic is written out:
     3.5 (margin) + 22 (note) + 2.5 + 54 (canvas) + 2.5 + 12.2 (box)
       + 3.5 (margin) = 100.2 cqw
   and in the height 62.5 − 7 = 55.5 cqw remain for a canvas of 54. */
.sc-paint{display:grid;grid-template-columns:22cqw minmax(0,1fr) 12.2cqw;gap:2.5cqw;
  align-items:center;padding:3.5cqw}
.sc-note{min-width:0;background:#fffdf7;border:.5cqw solid var(--espresso);border-radius:2cqw;
  padding:2.2cqw 1.8cqw;box-shadow:0 1cqw 0 rgba(74,52,42,.16);rotate:-2.4deg}
.sc-note-epoch{display:block;font-family:Fraunces,serif;font-size:.82em;line-height:1.1;
  margin-bottom:.45em;overflow-wrap:anywhere}
.sc-note-motif{display:block;font-family:Caveat,cursive;font-size:1em;line-height:1.05;
  color:var(--curtain);font-style:normal;overflow-wrap:anywhere}
/* The canvas: square as in the atelier, so the scene does not show something
   that looks different in the game. Steered via the WIDTH (the column above
   provides it), not via the height — otherwise it would hang on a line that
   nobody has set yet. */
.sc-easel{position:relative;width:100%;aspect-ratio:1;justify-self:center;
  background:#fff;border:1.4cqw solid #8a6b3f;border-radius:1cqw;
  box-shadow:0 1.2cqw 0 rgba(74,52,42,.2)}
.sc-ink{display:block;width:100%;height:100%}
.sc-stroke{fill:none;stroke:#1c1c1c;stroke-width:3.4;stroke-linecap:round;stroke-linejoin:round;
  stroke-dasharray:100;stroke-dashoffset:100}
.sc-stroke.s5{stroke:var(--gold);stroke-width:4}
.howto-step.on .sc-stroke.s1{animation:sc-d1 6s linear infinite}
.howto-step.on .sc-stroke.s2{animation:sc-d2 6s linear infinite}
.howto-step.on .sc-stroke.s3{animation:sc-d3 6s linear infinite}
.howto-step.on .sc-stroke.s4{animation:sc-d4 6s linear infinite}
.howto-step.on .sc-stroke.s5{animation:sc-d5 6s linear infinite}
/* Drawing runs from 3 % to 58 %, then the picture stands still and is wiped at
   93 % — the pause is the part in which you read the note. */
@keyframes sc-d1{0%,3%{stroke-dashoffset:100}15%,92%{stroke-dashoffset:0}95%,100%{stroke-dashoffset:100}}
@keyframes sc-d2{0%,15%{stroke-dashoffset:100}26%,92%{stroke-dashoffset:0}95%,100%{stroke-dashoffset:100}}
@keyframes sc-d3{0%,26%{stroke-dashoffset:100}36%,92%{stroke-dashoffset:0}95%,100%{stroke-dashoffset:100}}
@keyframes sc-d4{0%,36%{stroke-dashoffset:100}48%,92%{stroke-dashoffset:0}95%,100%{stroke-dashoffset:100}}
@keyframes sc-d5{0%,48%{stroke-dashoffset:100}58%,92%{stroke-dashoffset:0}95%,100%{stroke-dashoffset:100}}
/* The brush ring runs along the strokes — the same ring as at the real
   canvas (.brush-cursor), only small. */
.sc-brush{position:absolute;left:0;top:0;width:5cqw;height:5cqw;border-radius:50%;
  border:.5cqw solid var(--espresso);background:rgba(255,255,255,.5);
  margin:-2.5cqw 0 0 -2.5cqw;opacity:0}
.howto-step.on .sc-brush{animation:sc-brush 6s linear infinite}
@keyframes sc-brush{
  0%,2%{left:20%;top:77%;opacity:0}
  4%{left:20%;top:77%;opacity:1}
  9%{left:50%;top:31%}
  15%{left:80%;top:77%}
  18%{left:27%;top:77%}   21%{left:27%;top:42%}
  23%{left:73%;top:77%}   26%{left:73%;top:42%}
  29%{left:15%;top:77%}   36%{left:85%;top:77%}
  39%{left:45%;top:77%}   42%{left:45%;top:58%}
  45%{left:57%;top:58%}   48%{left:57%;top:77%}
  52%{left:70%;top:23%}   58%{left:86%;top:23%;opacity:1}
  62%,100%{left:86%;top:23%;opacity:0}}
.sc-palette{display:grid;grid-template-columns:repeat(2,5.4cqw);gap:1.4cqw}
.sc-palette i{display:block;width:5.4cqw;height:5.4cqw;border-radius:50%;background:var(--c);
  border:.44cqw solid var(--espresso)}
.howto-step.on .sc-palette i:nth-child(1){animation:sc-pick 6s linear infinite}
.howto-step.on .sc-palette i:nth-child(6){animation:sc-pick2 6s linear infinite}
@keyframes sc-pick{0%,47%{box-shadow:0 0 0 .7cqw var(--gold)}50%,100%{box-shadow:none}}
@keyframes sc-pick2{0%,47%{box-shadow:none}50%,100%{box-shadow:0 0 0 .7cqw var(--gold)}}

/* ---------- 2. Roasting ---------- */
.sc-roast{display:grid;grid-template-rows:minmax(0,1fr) auto;gap:2cqw;
  padding:4cqw 8cqw;background:#3d2420;color:var(--paper);justify-items:center}
.sc-curtain{position:absolute;top:0;bottom:0;width:7cqw;z-index:2;
  background:repeating-linear-gradient(90deg,var(--curtain) 0 2cqw,#9c2726 2cqw 4cqw)}
.sc-curtain.left{left:0;border-right:.7cqw solid var(--gold)}
.sc-curtain.right{right:0;border-left:.7cqw solid var(--gold)}
.howto-step.on .sc-curtain{animation:sc-open 6s cubic-bezier(.55,.06,.25,1) infinite}
@keyframes sc-open{0%,4%{width:50%}22%,92%{width:7cqw}99%,100%{width:50%}}
.sc-frame{height:100%;aspect-ratio:1;background:#fff;border:1.6cqw solid var(--gold);
  border-radius:.6cqw;box-shadow:0 0 6cqw rgba(212,164,55,.4);opacity:0}
.howto-step.on .sc-frame{animation:sc-hang 6s ease infinite}
@keyframes sc-hang{0%,14%{opacity:0;scale:.72;rotate:-3deg}26%,92%{opacity:1;scale:1;rotate:0deg}97%,100%{opacity:0;scale:.72;rotate:-3deg}}
.sc-art{display:block;width:100%;height:100%;fill:none;stroke:#1c1c1c;stroke-width:3.4;
  stroke-linecap:round;stroke-linejoin:round}
.sc-art circle{stroke:var(--gold);stroke-width:4}
.sc-critic{display:flex;align-items:flex-start;gap:2cqw;width:100%;z-index:3}
.sc-face{flex:0 0 auto;width:11cqw;height:11cqw;display:grid;place-items:center;font-size:6cqw;
  background:var(--paper);border:.6cqw solid var(--gold);border-radius:50%}
.howto-step.on .sc-face{animation:sc-yap 6s linear infinite}
/* The head only bobs while it is talking (36–74 %) — after that it stands still. */
@keyframes sc-yap{
  0%,34%,76%,100%{translate:0 0;scale:1 1}
  36%,40%,44%,48%,52%,56%,60%,64%,68%,72%{translate:0 0;scale:1 1}
  38%,42%,46%,50%,54%,58%,62%,66%,70%,74%{translate:0 -.5cqw;scale:1.04 .96}}
.sc-bubble{flex:1;min-width:0;background:#fffdf7;color:var(--espresso);
  border:.6cqw solid var(--espresso);border-radius:2cqw;padding:2cqw 2.4cqw;opacity:0}
.howto-step.on .sc-bubble{animation:sc-pop 6s ease infinite}
@keyframes sc-pop{0%,28%{opacity:0;scale:.86}36%,92%{opacity:1;scale:1}96%,100%{opacity:0;scale:.86}}
.sc-guess{display:block;font-size:.78em;color:var(--blue);line-height:1.15}
.sc-quote{display:block;font-size:.72em;font-style:italic;line-height:1.3;margin-top:.35em;opacity:0}
.howto-step.on .sc-quote{animation:sc-say 6s ease infinite}
@keyframes sc-say{0%,44%{opacity:0;translate:0 .6cqw}54%,92%{opacity:1;translate:none}96%,100%{opacity:0}}

/* ---------- 3. Bidding ----------
   Arithmetic as in scene 1: 4 + 30 (lot) + 4 + 58 (bid card) + 4 = 100 cqw. */
.sc-bid{display:grid;grid-template-columns:30cqw minmax(0,1fr);gap:4cqw;
  align-items:center;padding:4cqw;text-align:center}
.sc-panel{display:flex;flex-direction:column;gap:1.6cqw;min-width:0;
  background:#fffdf7;border:.6cqw solid var(--espresso);border-radius:3cqw;
  padding:2.6cqw 2.4cqw;box-shadow:0 1.2cqw 0 rgba(74,52,42,.18)}
.sc-clock{width:100%;height:2.6cqw;background:#e7dcc3;border:.44cqw solid var(--espresso);
  border-radius:1.6cqw;overflow:hidden}
.sc-clockbar{display:block;height:100%;width:100%;background:var(--blue)}
.howto-step.on .sc-clockbar{animation:sc-tick 6s linear infinite}
@keyframes sc-tick{0%{width:100%;background:var(--blue)}
  55%{background:var(--gold)}
  70%{width:0;background:var(--curtain)}100%{width:0;background:var(--curtain)}}
/* The counting number: four amounts above one another in a window exactly
   one line tall, pushed through in jumps. No script counts along — and
   the amounts themselves are set by client.js in the player's language. */
.sc-price,.sc-value{--rh:1.5em;margin:0;height:var(--rh);overflow:hidden;
  font-family:Fraunces,serif;font-weight:900;font-size:1.5em;line-height:var(--rh);
  color:var(--green);font-variant-numeric:tabular-nums}
.sc-roll{display:block}
.sc-roll b{display:block;height:var(--rh);line-height:var(--rh)}
.howto-step.on .sc-price .sc-roll{animation:sc-count 6s steps(1,end) infinite}
@keyframes sc-count{
  0%,14%{translate:0 0}
  16%,32%{translate:0 calc(var(--rh)*-1)}
  34%,50%{translate:0 calc(var(--rh)*-2)}
  52%,100%{translate:0 calc(var(--rh)*-3)}}
.sc-bidrow{display:flex;gap:1.4cqw;justify-content:center}
.sc-bidrow span{flex:1 1 0;min-width:0;display:grid;place-items:center;height:6cqw;
  border-radius:1.4cqw;font-weight:900;font-size:.66em;white-space:nowrap;
  background:#fff;border:.5cqw solid var(--espresso);box-shadow:0 .7cqw 0 rgba(74,52,42,.18)}
.howto-step.on .sc-bidrow span[data-step-bid="1"]{animation:sc-press1 6s ease infinite}
.howto-step.on .sc-bidrow span[data-step-bid="2"]{animation:sc-press2 6s ease infinite}
.howto-step.on .sc-bidrow span[data-step-bid="3"]{animation:sc-press3 6s ease infinite}
@keyframes sc-press1{0%,12%{background:#fffdf7;scale:1}16%{background:var(--gold);scale:.92}22%,100%{background:#fffdf7;scale:1}}
@keyframes sc-press2{0%,30%{background:#fffdf7;scale:1}34%{background:var(--gold);scale:.92}40%,100%{background:#fffdf7;scale:1}}
@keyframes sc-press3{0%,48%{background:#fffdf7;scale:1}52%{background:var(--gold);scale:.92}58%,100%{background:#fffdf7;scale:1}}
/* The knock-down: a sign right across the scene, as in the hall too (.sold-card).
   left/top + translate instead of inset:0, so the card grows around its own
   centre and does not travel past the edges. */
.sc-sold{position:absolute;left:50%;top:50%;margin:0;z-index:4;
  display:flex;align-items:center;gap:1.4cqw;
  font-family:Fraunces,serif;font-weight:900;font-size:1.25em;letter-spacing:.04em;
  color:var(--espresso);background:var(--paper);border:.6cqw solid var(--espresso);
  border-radius:2cqw;padding:1.6cqw 3.4cqw;box-shadow:0 1.2cqw 0 rgba(74,52,42,.32);opacity:0}
.howto-step.on .sc-sold{animation:sc-stamp 6s cubic-bezier(.2,1.35,.45,1) infinite}
@keyframes sc-stamp{
  0%,70%{opacity:0;translate:-50% -50%;scale:.5;rotate:-8deg}
  76%{opacity:1;translate:-50% -50%;scale:1.06;rotate:2deg}
  80%,92%{opacity:1;translate:-50% -50%;scale:1;rotate:-1.5deg}
  97%,100%{opacity:0;translate:-50% -50%;scale:.5;rotate:-8deg}}
.sc-gavel{flex:0 0 auto;font-size:1.1em;line-height:1}
.howto-step.on .sc-gavel{animation:sc-drop 6s cubic-bezier(.5,0,.75,1) infinite}
@keyframes sc-drop{
  0%,70%{rotate:-72deg}
  77%{rotate:12deg}
  82%{rotate:-6deg}
  87%,100%{rotate:0deg}}

/* ---------- 4. Cashing in ---------- */
.sc-cash{display:grid;grid-template-columns:34cqw minmax(0,1fr);gap:4cqw;align-items:center;
  padding:5cqw;background:#3d2420;color:var(--paper)}
/* The small frame stands in scene 3 AND 4 and does not fade in there — it is
   there from the start. The column provides its width, it fills it. */
.sc-frame.small{width:100%;height:auto;aspect-ratio:1;opacity:1;animation:none;
  border-width:1.2cqw;position:relative}
.sc-frame.lit{box-shadow:0 0 4cqw rgba(212,164,55,.5)}
/* The cloth lies over the piece and is pulled away to the bottom left as in the hall. */
.sc-veil{position:absolute;inset:0;z-index:2;
  background:repeating-linear-gradient(112deg,#efe3cb 0 2cqw,#e2d3b6 2cqw 4cqw);
  box-shadow:inset 0 0 3cqw rgba(74,52,42,.35)}
.howto-step.on .sc-veil{animation:sc-unveil 6s cubic-bezier(.6,0,.3,1) infinite}
@keyframes sc-unveil{
  0%,12%{translate:0 0;rotate:0deg;opacity:1}
  28%,92%{translate:-18% 118%;rotate:-13deg;opacity:0}
  98%,100%{translate:0 0;rotate:0deg;opacity:1}}
.sc-cashfacts{min-width:0}
.sc-cashfacts .sc-label{color:var(--gold);opacity:.85}
.sc-value{color:var(--gold);font-size:1.7em}
.howto-step.on .sc-value .sc-roll{animation:sc-count2 6s steps(1,end) infinite}
@keyframes sc-count2{
  0%,26%{translate:0 0}
  30%,40%{translate:0 calc(var(--rh)*-1)}
  44%,54%{translate:0 calc(var(--rh)*-2)}
  58%,100%{translate:0 calc(var(--rh)*-3)}}
.sc-profit{display:inline-block;margin-top:1.6cqw;font-weight:900;font-size:.8em;
  background:var(--green);color:#fff;border-radius:1.4cqw;padding:.8cqw 2.2cqw;opacity:0}
.howto-step.on .sc-profit{animation:sc-bonus 6s cubic-bezier(.3,1.6,.4,1) infinite}
@keyframes sc-bonus{
  0%,62%{opacity:0;scale:.5;rotate:-8deg}
  70%{opacity:1;scale:1.1}
  74%,92%{opacity:1;scale:1;rotate:0deg}
  97%,100%{opacity:0;scale:.5;rotate:-8deg}}

/* ---------- Without motion ----------
   Whoever has opted out of it gets no empty cell but the FINAL STATE
   of every scene: the finished picture, the open stage, the knock-down, the
   valuation. A still that tells the same story — only without the way there.
   That is why a value stands here for every animated piece; the catch-all rule right
   at the bottom of the stylesheet switches the animations off anyway. */
@media (prefers-reduced-motion:reduce){
  .howto-steps li{transition:none}
  .sc-stroke{stroke-dashoffset:0}
  .sc-brush{opacity:0}
  .sc-curtain{width:7cqw}
  .sc-frame,.sc-bubble,.sc-quote{opacity:1;scale:1}
  .sc-clockbar{width:26%;background:var(--curtain)}
  .sc-price .sc-roll,.sc-value .sc-roll{translate:0 calc(var(--rh)*-3)}
  .sc-sold{opacity:1;rotate:-1.5deg;scale:1}
  .sc-gavel{opacity:1;rotate:0deg}
  .sc-veil{opacity:0}
  .sc-profit{opacity:1;scale:1}
}

.howto-foot{display:flex;align-items:center;gap:12px;justify-content:space-between}
.howto-foot .btn{flex:0 0 auto}
/* "Back" does not disappear in the first step, it merely becomes unusable —
   otherwise the dots would slide sideways with every page turn.

   WITHOUT pointer-events:none. A `disabled` already takes the click away from the
   button itself; the line would additionally take its hit area away, and then
   elementFromPoint reports the footer at this spot instead of the button. That is exactly
   what mobile.mjs checks on eight screen sizes — and it is not a formality: whoever
   taps slightly off with their thumb should hit the button and nothing behind it. */
.howto-foot .btn[disabled]{opacity:.32;cursor:default}
.howto-dots{display:flex;gap:7px;justify-content:center;flex:1 1 auto}
.howto-dots button{width:9px;height:9px;padding:0;border:0;border-radius:50%;
  background:rgba(60,36,20,.24);cursor:pointer;transition:background .18s,transform .18s}
.howto-dots button:hover{background:rgba(60,36,20,.42)}
.howto-dots button[aria-selected="true"]{background:var(--gold);transform:scale(1.32)}
/* "Show controls visibly" — for a painting game that is exactly one sentence. */
.howto-controls{margin:16px 0 0;padding:10px 12px;border:2px dashed var(--espresso);border-radius:12px;
  display:flex;align-items:center;gap:9px;font-size:.9rem;background:rgba(212,164,55,.12)}
.howto-key{font-size:1.2rem}

/* ---------- A flat window: scene and sentence SIDE BY SIDE ----------
   Phone held sideways, short browser window, split screen — here
   the height is tight and the width is in abundance. Stacked, the card no longer
   fitted into the screen: it scrolled on the inside, and `next` lay below
   its edge. Side by side it fits, and the scene even gets
   BIGGER than when stacked — it no longer shares the height with anything.

   min-width:600px, so that a narrow AND short window (320 × 480) does not
   get two columns of 130 pixels each; there stacked stays right. */
/* First: short, no matter how wide. The gaps between the five blocks of the
   card are set for a tall screen; on a short one they add up to
   more than a line of text. They move together before anything
   else gives way.

   The double class `.howto-card .howto-foot` is no accident: `.brief-foot`
   sets margin-top:16px and stands FURTHER DOWN in the stylesheet than this
   section. At equal weight the later rule wins — a plain
   `.howto-foot` here would have no effect, and the card would go on scrolling. */
@media (max-height:620px){
  .howto-steps{--sc-h:32dvh;margin:9px 0 2px}
  .howto-card .brief-sub{margin-bottom:8px}
  .howto-card .howto-controls{margin-top:9px;padding:8px 11px}
  .howto-card .howto-foot{margin-top:9px}
}
/* And then: short AND wide — scene and sentence side by side. */
@media (max-height:620px) and (min-width:600px){
  .howto-card{width:min(880px,100%)}
  .howto-steps{--sc-h:50dvh;margin:10px 0 2px}
  .howto-steps li{grid-template-columns:minmax(0,1.08fr) minmax(0,.92fr);gap:18px;align-items:center}
  .howto-card .howto-controls{margin-top:10px;padding:7px 10px;font-size:.82rem}
}
/* Really flat (a phone held sideways is 390 tall): now the curtain at the top
   costs height too, and there is nowhere left to take it from. The controls hint
   stays — CrazyGames checks it — it only gets narrower. */
@media (max-height:470px){
  #howto{padding:8px}
  .howto-steps{--sc-h:44dvh;margin:7px 0 2px}
  .brief-card.howto-card{padding:12px 16px 10px}
  .brief-card.howto-card::before{display:none}
  .howto-card .brief-head{font-size:1.35rem}
  .howto-card .brief-sub{margin-bottom:5px;font-size:1rem}
  .howto-card .howto-controls{margin-top:7px;padding:5px 9px;font-size:.76rem;gap:6px}
  .howto-card .howto-key{font-size:1rem}
  .howto-card .howto-foot{margin-top:8px}
}
/* Rush notice: visible, but not an alarm — nothing is broken, after all.
   Gold instead of curtain red, so it looks like "well attended" and not like
   a fault. Stands right under the logo, before anybody opens a salon. */
.busy-note{
  font-size:.8rem;line-height:1.35;margin:0 0 10px;padding:8px 12px;
  background:rgba(212,164,55,.16);border:2px solid var(--gold);border-radius:12px;
  color:var(--espresso);text-align:left
}

/* ---------- Lobby ---------- */
.bar{display:flex;align-items:center;gap:14px;width:100%;max-width:min(1120px,var(--wide));margin:0 auto 10px;flex:0 0 auto}
/* The lobby bar carries three things: the code, the invitation and the way
   out. On a narrow screen they do not fit side by side — here
   it may wrap. In the atelier NOT: there the candle hangs in with them, and
   a second row would push the canvas out of the picture.
   The way out moves to the other end: it does not belong next to the button you
   use to bring people in. */
#screen-lobby .bar{flex-wrap:wrap}
#btn-leave{margin-left:auto}
/* On wide screens the word stands on the button, on narrow ones its
   symbol — see the rule for 430 pixels further down. */
.btn-icon{display:none}
/* ---------- The lobby bar on a narrow screen ----------
   The fixed corner at the top right (introduction, language) reserves room in
   every bar — a measured 100 of 292 pixels on an iPhone SE. That left 192 for
   "salon XFLY", "copy link" and "leave salon", and the bar went to THREE
   ROWS: 156 pixels, a quarter of the screen, for four words.

   The word "salon" drops out and the two buttons become their symbols. A gold
   sign with four capitals, a link and a door — that is one row of 46 pixels,
   and the 110 saved go to the guild, which thereby gets from two to four
   visible heads. The names for screen readers and mouse pointers hang on the
   button and do not change with it. */
@media (max-width:430px){
  #screen-lobby .bar h2 .salon-word{display:none}
  #screen-lobby .bar .btn-word{display:none}
  #screen-lobby .bar .btn-icon{display:inline;font-size:1rem;line-height:1.15}
  #screen-lobby .bar .btn{padding:8px 11px}
}
.code-chip{background:var(--gold);padding:4px 12px;border-radius:10px;border:2px solid var(--espresso);letter-spacing:.15em}
/* ONE column, because the lobby only carries one card any more. It stood here
   in two columns — the self-portrait on the left (260 px), the guild on the right. Since the
   portrait comes into being on the start page, the left column is empty, and the
   guild sat as a 260 pixel narrow column at the left edge of a 1440 screen,
   while two thirds of the page next to it showed nothing.
   760 px, not the full 1120: a single card across the whole width
   dragged the six settings rows right across the table. */
.lobby-grid{display:grid;grid-template-columns:minmax(0,1fr);
  grid-template-rows:minmax(0,1fr);gap:18px;
  max-width:min(760px,var(--wide));margin:0 auto;width:100%}
.panel{background:#fffdf7;border:3px solid var(--espresso);border-radius:18px;padding:18px;box-shadow:var(--shadow)}
/* ---------- The card gives up only the guild ----------
   The lobby card is a column of nothing but fixed parts — heading, settings,
   start button — and ONE that grows with the number of players. So only that
   one shrinks when there is not enough room: `flex:0 1 auto` on the guild,
   `0 0 auto` on everything else. With two people the card is short and stands
   centred; with eight the guild scrolls inside itself, and the start button
   stays where it was.

   `flex:0 1`, not `1 1`: a guild that also GROWS would push the settings to
   the bottom edge of the card with two players and leave a hand's-breadth hole
   between the two portraits and "rounds". */
/* `align-items:center`, not `stretch`: the card is as tall as its content and
   stands in the middle. Stretched, a hand's breadth of empty paper hung below
   "open the vernissage" on a 1440 screen — the card was as tall as the screen,
   its content was not. The row still stays `1fr`: only that way does
   `max-height:100%` on the card have anything to refer to at all, should the
   guild get too long after all. */
#screen-lobby .lobby-grid{align-items:center}
#screen-lobby .panel{display:flex;flex-direction:column;min-height:0;max-height:100%;overflow:hidden}
#screen-lobby .panel>*{flex:0 0 auto}
#screen-lobby .panel>h3{margin:0 0 10px}
#screen-lobby #players{flex:0 1 auto;min-height:4.4rem;overflow-y:auto;
  align-content:start;padding-right:2px}
/* The foot of the card is ONE box, not five siblings — otherwise each of them
   would have to be lifted into the second column individually when the phone
   lies sideways (see below). Stacked it behaves like what it replaces. */
.lobby-foot{display:flex;flex-direction:column}
/* 132 instead of 120: at 120 so little was left for the name that "Hieronymus
   Bot" ended as "Hieronymus …" — in a guild where people are meant to be
   recognisable. */
.players{display:grid;grid-template-columns:repeat(auto-fill,minmax(132px,1fr));gap:12px;margin-bottom:14px}
.player-card{border:2px solid var(--espresso);border-radius:14px;padding:8px;text-align:center;background:#fff;position:relative;transform:rotate(-1deg)}
.player-card:nth-child(even){transform:rotate(1.2deg)}
.player-card canvas,.player-card img{width:100%;aspect-ratio:1;border-radius:10px;background:#fdfaf2}
.player-card .pname{font-weight:900;font-size:.9rem;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.player-card .pmoney{font-size:.75rem;color:var(--green);font-weight:700}
.player-card.host::after{content:"👑";position:absolute;top:-12px;right:-6px;font-size:1.2rem}
/* ---------- Ready, and visibly so ----------
   The lobby is where this game loses its players: one does not press, four
   others wait, and nobody sees who for. The card says it itself now — a green
   frame and a tick for whoever is set, an hourglass for whoever is being waited
   for. The difference has to be recognisable on a phone screen in the sun, so
   frame AND sign: colour alone does not carry there, and without the frame the
   small sign is only seen once you look for it. */
.player-card.is-ready{border-color:var(--green);box-shadow:0 0 0 3px rgba(46,125,79,.22)}
.player-card.not-ready{border-style:dashed;opacity:.92}
.player-card .pready{position:absolute;bottom:-9px;left:-7px;width:24px;height:24px;border-radius:50%;
  display:grid;place-items:center;font-size:.72rem;font-weight:900;z-index:3;
  border:2px solid var(--espresso);background:#fff}
.player-card.is-ready .pready{background:var(--green);color:#fff;animation:tick-punch .3s cubic-bezier(.3,1.7,.4,1)}
.player-card.not-ready .pready{background:var(--paper);opacity:.85}
/* ---------- Whoever is gone ----------
   Before, a disconnected player merely stood there paler (opacity:.4) — that
   reads like a rendering fault and on a bright screen outdoors cannot be seen at
   all. Now it stands there: one word, and the card is struck through. */
.player-card.offline{opacity:.6;border-style:dotted}
.player-card.offline .pname{text-decoration:line-through;text-decoration-thickness:2px}
.player-card .poff,.off-chip{
  font-size:.55rem;font-weight:900;letter-spacing:.08em;text-transform:uppercase;line-height:1;
  padding:3px 6px;border-radius:7px;border:2px solid var(--curtain);
  background:var(--curtain);color:#fff;white-space:nowrap}
.player-card .poff{position:absolute;bottom:-8px;left:50%;transform:translateX(-50%);z-index:3}
.off-chip{display:inline-block;margin-left:5px;vertical-align:middle;
  font-size:.5rem;padding:2px 4px;border-width:1.5px;border-radius:5px}
.rail-val .off-chip{flex:0 0 auto;margin-left:0;font-size:.46rem;padding:2px 3px;letter-spacing:.04em}

/* ---------- The ready bar ----------
   The one number the whole lobby hangs on — and the mark from which it starts by
   itself. Without the mark the countdown would be a surprise; with it, it is a
   target you press towards. */
.ready-meter{margin:2px 0 8px}
.ready-bar{position:relative;height:14px;border:3px solid var(--espresso);border-radius:10px;
  background:#fff;overflow:hidden}
.ready-fill{position:absolute;inset:0 auto 0 0;width:0;background:var(--green);
  transition:width .35s cubic-bezier(.2,1.2,.4,1)}
/* The mark sits ON the bar and has to lie above the fill — otherwise it
   disappears at exactly the moment it says something. */
.ready-mark{position:absolute;top:-3px;bottom:-3px;width:3px;background:var(--espresso);
  transform:translateX(-1px);z-index:2}
.ready-meter.go .ready-fill{background:var(--gold)}
.ready-meter.go .ready-count{color:var(--green)}
.ready-count{margin:6px 0 0;font-size:.82rem;font-weight:900;text-align:center}
/* "Ready" is the button most players look for first. It therefore takes the full
   width and turns green as soon as it has been pressed — a button that looks
   after pressing the way it did before gets pressed twice. No tilt
   (transform:none): a button turned by 0.6° across the full width sticks out
   over the card with its corners.
   The start button below it takes the same width — the two belong together. */
.btn.ready{display:block;width:100%;margin:0 0 8px;transform:none}
.btn.ready.on{background:var(--green);color:#fff;border-color:var(--espresso)}
#screen-lobby #btn-start{display:block;width:100%;transform:none}
/* The mark of the summoned guests. On the card at the top RIGHT on the
   portrait: reporting and throwing out sit on the left, and the crown cannot
   get in the way here — a guest never becomes host (see disconnect in
   game.js). In the leaderboards it stands after the name and runs along the whole
   game. */
.player-card .pnpc,.npc-chip{
  font-size:.58rem;font-weight:900;letter-spacing:.1em;line-height:1;
  padding:4px 6px;border-radius:7px;border:2px solid var(--espresso);
  background:var(--espresso);color:var(--paper);opacity:.9}
.player-card .pnpc{position:absolute;top:6px;right:6px;z-index:2}
/* In the row: smaller, with a gap to the name. */
.npc-chip{display:inline-block;margin-left:5px;vertical-align:middle;
  font-size:.5rem;padding:2px 4px;border-width:1.5px;border-radius:5px}
/* In the rail a shade smaller still, and it does not give way: it should fit next
   to the money line instead of opening a third one — with eight players
   the rail otherwise grows out of the picture. */
.rail-val .npc-chip{flex:0 0 auto;margin-left:0;font-size:.46rem;padding:2px 3px;letter-spacing:.06em}
/* Game settings: pick instead of type */
.settings{display:flex;flex-direction:column;gap:9px;margin:14px 0}
.preset-row{display:flex;align-items:center;gap:12px;flex-wrap:wrap}
.preset-label{min-width:8.5em;font-size:.68rem;letter-spacing:.16em;text-transform:uppercase;
  font-weight:900;color:var(--curtain);opacity:.75}
.presets{display:flex;gap:6px;flex-wrap:wrap}
.preset{font-family:Nunito;font-weight:900;font-size:.85rem;color:var(--espresso);background:#fff;
  border:2px solid var(--espresso);border-radius:11px;padding:6px 13px;cursor:pointer;
  box-shadow:0 3px 0 rgba(74,52,42,.18);transition:transform .08s}
@media (hover:hover){.preset:hover{transform:translateY(-2px)}}
.preset:active{transform:translateY(1px);box-shadow:0 1px 0 rgba(74,52,42,.18)}
.preset.on{background:var(--gold);color:#3a2a10;box-shadow:0 3px 0 rgba(74,52,42,.35)}
@media (max-width:760px){
  /* The label stays on the row AS LONG AS the four buttons fit beside it — and
     moves above them by itself when they do not. That decision is not made by
     a pixel threshold in the stylesheet but by the row itself: `min-width` on
     the button group is the threshold below which it would rather wrap than
     let itself be squeezed together.

     Previously the label ALWAYS took the whole row (`flex:1 0 100%`), and that
     cost half a row six times over: a measured 337 pixels for six settings on
     a 390 phone, a third of the picture for text you read once. Inline it is
     205 — and the 132 pixels saved are exactly what the guild above it needs
     to show more than one head. */
  .preset-label{min-width:0;flex:0 0 auto;font-size:.6rem;line-height:1.15}
  .presets{flex:1 1 auto;min-width:min(100%,13.5rem)}
  .settings{gap:5px;margin:10px 0}
  .preset-row{gap:2px 9px}
  .preset{padding:5px 11px}
  .guest-hint{flex-basis:100%}
}
/* Guests of the house: −, number, +. A counter instead of four presets, because
   the number can also grow on its own (a public salon that is too empty
   fills itself up) — four fixed buttons could show a state that
   nobody picked. */
.guest-step{align-items:center;gap:4px}
.guest-step .preset{min-width:38px;text-align:center;padding:6px 10px;font-size:1rem;line-height:1}
.guest-count{min-width:1.4em;text-align:center;font-weight:900;font-size:1rem;font-variant-numeric:tabular-nums}
.guest-hint{font-size:.72rem;opacity:.6;flex:1 1 12em;min-width:0}
/* "Play now" is the FIRST way in, not the last: whoever lands on a
   games platform has nobody with them to invite. So it is
   the biggest button on the card, at the top of the group — and "open a new salon"
   directly below it as the quiet second way.
   No gold of its own here: it carries .btn.gold.big like every other big button
   in the game. Only the width is added, so the group has an edge. */
.btn.solo{align-self:stretch}
/* Without guests of the house there is no "play now" — then opening is
   the first way again and gets the gold back. The class is set by
   applyGuestAvailability() in client.js. */
.home-act.no-solo #btn-create{background:var(--gold);color:#3a2a10;font-size:1.25rem;padding:16px 30px}

/* ---------- Paintbox including free colour choice ---------- */
.swatches{display:flex;gap:6px;flex-wrap:wrap}
.swatches button,.swatch-picker{width:26px;height:26px;padding:0;border-radius:50%;border:2px solid var(--espresso);cursor:pointer}
.swatches .sw-active{outline:3px solid var(--gold)}
/* The last "tube" in the box mixes any colour — afterwards it shows the chosen one. */
.swatch-picker{position:relative;overflow:hidden;display:inline-block;
  background:conic-gradient(from .25turn,#B8302F,#e8c22e,#2E7D4F,#2E5E9E,#6b3fa0,#B8302F)}
.swatch-picker input[type=color]{position:absolute;inset:-25%;width:150%;height:150%;padding:0;border:0;opacity:0;cursor:pointer}
.swatch-picker::after{content:"✎";position:absolute;inset:0;display:grid;place-items:center;
  font-size:.78rem;font-weight:900;color:#fff;text-shadow:0 1px 2px rgba(0,0,0,.7);pointer-events:none}

/* ---------- Brush cursor ----------
   No browser crosshair: a ring the size of the brush with a cross exactly in the
   middle — there and only there is where the paint lands. */
.brush-cursor{position:absolute;pointer-events:none;z-index:6;border:2px solid var(--espresso);
  border-radius:50%;transform:translate(-50%,-50%);
  box-shadow:inset 0 0 0 1px rgba(255,255,255,.85),0 0 0 1px rgba(255,255,255,.7)}
.brush-cursor::before,.brush-cursor::after{content:"";position:absolute;left:50%;top:50%;
  background:#1c1c1c;box-shadow:0 0 0 1px rgba(255,255,255,.9)}
.brush-cursor::before{width:13px;height:1px;transform:translate(-50%,-50%)}
.brush-cursor::after{width:1px;height:13px;transform:translate(-50%,-50%)}
.brush-cursor.eraser{border-style:dashed}
.brush-cursor.fill{border-radius:5px}

/* ---------- Commission popup ---------- */
.brief{position:fixed;inset:0;z-index:60;display:grid;place-items:center;padding:16px;
  background:rgba(46,26,22,.62);backdrop-filter:blur(5px);animation:brief-fade .3s ease}
.brief.closing{animation:brief-out .28s ease forwards}
@keyframes brief-fade{from{opacity:0}to{opacity:1}}
@keyframes brief-out{to{opacity:0;visibility:hidden}}
/* Same language as every other card in the game: paper, thick border, hard
   offset shadow, slightly askew. The curtain from the start screen at the top. */
.brief-card{position:relative;width:min(660px,100%);max-height:92dvh;overflow-y:auto;
  background:#fffdf7;border:3px solid var(--espresso);border-radius:20px;
  padding:68px 26px 20px;box-shadow:0 10px 0 rgba(74,52,42,.3);
  transform:rotate(-.5deg);animation:brief-in .45s cubic-bezier(.2,.9,.3,1.2)}
.brief-card::before{content:"";position:absolute;top:0;left:0;right:0;height:52px;
  background:repeating-linear-gradient(90deg,var(--curtain) 0 34px,#9c2726 34px 68px);
  border-bottom:6px solid var(--gold);
  clip-path:polygon(0 0,100% 0,100% 72%,94% 100%,88% 72%,82% 100%,76% 72%,70% 100%,64% 72%,58% 100%,52% 72%,46% 100%,40% 72%,34% 100%,28% 72%,22% 100%,16% 72%,10% 100%,4% 72%,0 100%)}
.brief.closing .brief-card{animation:brief-card-out .28s ease forwards}
@keyframes brief-in{from{transform:translateY(30px) rotate(-3deg) scale(.92);opacity:0}to{transform:rotate(-.5deg);opacity:1}}
@keyframes brief-card-out{to{transform:translateY(-14px) rotate(-.5deg) scale(.96);opacity:0}}
.brief-chips{display:flex;align-items:center;gap:10px;flex-wrap:wrap}
.brief-round{background:var(--blue);color:#fff;padding:4px 12px;border-radius:10px;
  border:2px solid var(--espresso);font-weight:900;font-size:.78rem}
.brief-secret{background:var(--gold);color:#3a2a10;padding:4px 12px;border-radius:10px;
  border:2px solid var(--espresso);font-weight:900;font-size:.78rem;transform:rotate(2.5deg)}
.brief-head{font-size:2.1rem;margin:.2em 0 0;font-weight:900;line-height:1}
.brief-sub{margin:.1em 0 14px;font-family:Caveat,cursive;font-size:1.25rem;color:var(--blue)}
.brief-body{display:grid;grid-template-columns:1fr 1fr;gap:20px;background:#faf3e2;
  border:2px dashed var(--curtain);border-radius:14px;padding:16px}
.brief-field{min-width:0}
.brief-label,.hud-label{display:block;font-size:.65rem;letter-spacing:.2em;text-transform:uppercase;font-weight:900;color:var(--curtain);opacity:.75}
.brief-big{font-family:Fraunces,serif;font-size:1.5rem;font-weight:900;margin:.1em 0 0;line-height:1.12}
.brief-big.handwriting{font-family:Caveat,cursive;font-size:2.1rem;color:var(--curtain)}
.brief-tips{margin:.5em 0 0;padding-left:18px;font-size:.85rem;opacity:.8}
.brief-tips li{margin:.15em 0}
.brief-ref{margin-top:10px;width:100%;border:3px solid var(--espresso);border-radius:10px}
.brief-public{font-size:.85rem;margin-top:14px;opacity:.85}
.brief-public h4{font-family:Fraunces,serif;margin:0 0 4px;font-size:.92rem}
.brief-public p{margin:.15em 0}
.brief-foot{display:flex;align-items:center;gap:14px;margin-top:16px;flex-wrap:wrap}
.brief-count{margin-left:auto;font-weight:900;font-variant-numeric:tabular-nums;opacity:.6;font-size:.85rem}
/* Where a ✕ sits in the corner, the heading must not run underneath it. On
   a wide screen you never notice — at 320 px "here is how this
   works" reaches exactly to below the button. Better one line of wrapping than two
   words lying on top of each other. */
.brief-card:has(.modal-x) .brief-head{padding-right:46px}
@media (pointer:coarse){.brief-card:has(.modal-x) .brief-head{padding-right:52px}}
.modal-x{position:absolute;top:9px;right:12px;z-index:3;width:34px;height:34px;border-radius:50%;
  background:var(--paper);border:2px solid var(--espresso);font-weight:900;cursor:pointer;box-shadow:var(--shadow)}

/* ---------- The house rules: one line in the card, a sheet for changing them ----
   In the lobby the result of the six settings stands as one dashed line — the
   name small and in small caps, the value in bold beside it. Everybody reads
   it; only the host opens it, and the button for that sits at the end of the
   same line so it is clear what it changes. */
.rules-row{display:flex;align-items:center;gap:10px 12px;flex-wrap:wrap;
  margin:0 0 12px;padding:8px 12px;border-radius:13px;
  background:#f8f1e3;border:2px dashed rgba(74,52,42,.3)}
.rules-summary{display:flex;flex-wrap:wrap;gap:3px 15px;flex:1 1 11rem;min-width:0}
.rule-chip{display:inline-flex;align-items:baseline;gap:5px;white-space:nowrap}
.rule-chip i{font-style:normal;font-size:.56rem;letter-spacing:.13em;text-transform:uppercase;
  font-weight:900;color:var(--curtain);opacity:.7}
.rule-chip b{font-size:.86rem;font-weight:900;color:var(--espresso);font-variant-numeric:tabular-nums}
.rules-edit{flex:0 0 auto}
.rules-edit-icon{display:none}
/* Narrow: the pencil instead of the word. Measured on an iPhone SE, the row
   with "change" took 130 pixels — five values, each on its own line, because
   only 150 pixels were left for the text. With the pencil it is 204, and two
   fit side by side. */
@media (max-width:430px){
  .rules-edit-word{display:none}
  .rules-edit-icon{display:inline;font-size:1rem;line-height:1}
  .rules-edit{padding:7px 10px}
  .rules-summary{gap:2px 11px}
  .rule-chip i{font-size:.5rem;letter-spacing:.1em}
  .rule-chip b{font-size:.78rem}
}
/* The sheet itself: narrower than the commission, because at 660 pixels a
   settings row dragged right across the table. The label ALWAYS stays on the
   left here — on the sheet there is room the lobby did not have. */
.rules-card{width:min(540px,100%)}
.rules-card .settings{margin:0}
.rules-card .brief-foot{justify-content:flex-end}
@media (max-width:760px){
  .rules-card .preset-label{flex:1 0 100%;font-size:.64rem}
  .rules-card .preset{padding:6px 12px;font-size:.85rem}
}

/* Confirmation before the final hand-in */
.confirm-card{width:min(470px,100%);text-align:center}
.confirm-card .brief-foot{justify-content:center}
.confirm-body{margin:0;font-size:.95rem;background:#faf3e2;border:2px dashed var(--curtain);
  border-radius:12px;padding:12px 14px}

/* ---------- Drawing ---------- */
/* ---------- Clock & escalation ---------- */
.candle-wrap{flex:1;height:18px;background:#e7dcc3;border:2px solid var(--espresso);border-radius:10px;position:relative}
.candle{height:100%;width:100%;border-radius:8px 0 0 8px;position:relative;
  background:linear-gradient(90deg,var(--gold),var(--curtain));transition:width .2s linear}
/* Flame at the burning end — flickers, and increasingly nervously at that */
.candle::after{content:"";position:absolute;right:-7px;top:50%;width:14px;height:19px;
  border-radius:50% 50% 45% 45%/62% 62% 38% 38%;
  background:radial-gradient(circle at 50% 70%,#fff6cf 0%,var(--gold) 44%,var(--curtain) 80%);
  box-shadow:0 0 14px rgba(212,164,55,.85);
  transform-origin:50% 80%;animation:flame 1.1s ease-in-out infinite}
@keyframes flame{
  0%,100%{transform:translateY(-50%) scale(1) rotate(-3deg)}
  50%{transform:translateY(-50%) scale(1.16,.88) rotate(4deg)}}
.warn .candle::after{animation-duration:.55s}
.panic .candle::after{animation-duration:.25s;box-shadow:0 0 22px rgba(184,48,47,.95)}
.panic .candle{background:linear-gradient(90deg,var(--curtain),#8d1f1e)}

.timer{display:inline-block;font-weight:900;font-variant-numeric:tabular-nums;transition:color .2s}
.timer.warn{color:#b8620f}
.timer.panic{color:var(--curtain);font-size:1.4em}
/* A beat every second — that is the real stress-maker */
.timer.punch{animation:tick-punch .3s cubic-bezier(.3,1.7,.4,1)}
@keyframes tick-punch{from{transform:scale(1.55)}to{transform:scale(1)}}

/* A red cast at the screen edge in the last seconds */
.screen.panic::after{content:"";position:fixed;inset:0;pointer-events:none;z-index:40;
  box-shadow:inset 0 0 clamp(50px,9vw,150px) rgba(184,48,47,.5);
  animation:edge-throb 1s ease-in-out infinite}
@keyframes edge-throb{0%,100%{opacity:.35}50%{opacity:1}}
#btn-finish.done{background:var(--green);color:#fff;opacity:1}
.draw-wrap{display:flex;gap:14px;width:100%;max-width:var(--wide);margin:0 auto;justify-content:center;align-items:stretch;flex:1;min-height:0}
/* The canvas measures itself against the SMALLER axis of its box — otherwise it becomes
   rectangular on flat or narrow screens and all the strokes are distorted. */
.canvas-stage{flex:1 1 auto;min-width:0;min-height:0;position:relative;display:flex;align-items:center;justify-content:center;container-type:size}
/* The doubled width/height is intentional: a browser without container-query
   units discards the second line and keeps width/height:auto — together
   with max-width, max-height and aspect-ratio the canvas stays square. */
/* stylelint-disable-next-line declaration-block-no-duplicate-properties */
#draw-canvas{width:auto;height:auto;max-width:100%;max-height:100%;aspect-ratio:1;
  width:min(100cqw,100cqh);height:min(100cqw,100cqh);
  background:#fff;border:6px solid #8a6b3f;outline:3px solid var(--espresso);border-radius:6px;
  box-shadow:0 10px 0 rgba(74,52,42,.2);cursor:none;touch-action:none}
/* Two-column bar: costs a bit of width (we have plenty of that) and saves
   height (flat screens have too little of that) — in one column it overflows below ~700px. */
.tools{display:grid;grid-template-columns:repeat(2,46px);gap:8px;justify-content:center;justify-items:center;
  align-content:safe center;flex:0 0 auto;overflow-y:auto;overflow-x:hidden;scrollbar-width:thin}
.tool{font-size:1.3rem;background:#fffdf7;border:2px solid var(--espresso);border-radius:12px;width:46px;height:46px;cursor:pointer}
.tool.active{background:var(--gold)}
.swatches.vertical{grid-column:1/-1;display:grid;grid-template-columns:repeat(3,26px);gap:6px}
.sizes{grid-column:1/-1;display:grid;grid-template-columns:repeat(2,40px);gap:6px;justify-content:center}
.sizes button{width:40px;height:40px;background:#fffdf7;border:2px solid var(--espresso);border-radius:50%;cursor:pointer;display:grid;place-items:center}
.sizes button.active{background:var(--gold)}
.sizes i{display:block;border-radius:50%;background:var(--espresso)}

/* The commission as a note stuck up next to the easel — not as a panel over the
   full height: stretched empty that looked like a forgotten container. */
.brief-hud{flex:0 0 auto;align-self:flex-start;width:clamp(180px,16vw,240px);
  max-height:100%;margin-top:12px;display:flex;
  position:relative;background:#fffdf7;border:3px solid var(--espresso);border-radius:14px;
  padding:16px 14px 14px;box-shadow:var(--shadow);transform:rotate(-1.3deg)}
/* Scrolling is handled by the inner box — otherwise the note cuts off its own
   sticky tape (which sticks out at the top). */
.hud-inner{display:flex;flex-direction:column;gap:12px;width:100%;min-height:0;overflow-y:auto}
/* Sticky tape */
.brief-hud::before{content:"";position:absolute;top:-10px;left:50%;width:62px;height:19px;
  transform:translateX(-50%) rotate(-3deg);background:rgba(212,164,55,.8);
  border:2px solid rgba(74,52,42,.4);border-radius:2px}
.hud-block{min-width:0}
.hud-value{font-family:Fraunces,serif;font-weight:900;font-size:1.1rem;margin:.12em 0 0;line-height:1.15}
.hud-value.handwriting{font-family:Caveat,cursive;font-size:1.55rem;color:var(--curtain);line-height:1.05}
.hud-tips{margin:.45em 0 0;padding-left:16px;font-size:.78rem;opacity:.75}
.hud-tips li{margin:.15em 0}
.hud-ref{width:100%;border:2px solid var(--espresso);border-radius:8px}
.hud-secret{font-size:.66rem;opacity:.45;margin:0;font-style:italic}

/* ---------- Leaderboard as a rail (runs along in every phase) ---------- */
/* Hangs at the top right like a second note — grows with the number of players, never past
   the height of the screen. */
.rail{flex:0 0 auto;width:clamp(148px,14.5vw,208px);align-self:flex-start;max-height:100%;min-height:0;
  display:flex;flex-direction:column;background:#fffdf7;border:3px solid var(--espresso);
  border-radius:16px;padding:10px 9px 8px;box-shadow:var(--shadow);transform:rotate(.5deg)}
.rail-head{font-family:Fraunces,serif;font-size:.78rem;margin:0 0 8px;text-align:center;
  text-transform:uppercase;letter-spacing:.12em}
/* The ✓ marker deliberately sits over the corner of the entry (top:-8px, right:-7px).
   The list therefore needs exactly enough margin for it to fit: with the
   old 2px it stuck out to the right, the list became scrollable
   horizontally, the crossbar ate height — and then a vertical
   scrollbar stood there too, as soon as even one person had handed in. overflow-x:hidden
   is the bolt behind it, in case anything ever sticks past the edge again. */
.rail-list{list-style:none;margin:0;padding:9px 9px 3px;display:flex;flex-direction:column;gap:7px;
  overflow-y:auto;overflow-x:hidden;min-height:0;flex:0 1 auto;scrollbar-width:thin}
.rail-item{position:relative;display:flex;align-items:center;gap:6px;background:#fff;
  border:2px solid var(--espresso);border-radius:11px;padding:4px 6px}
.rail-item.me{background:#fdf3d8;border-color:var(--gold)}
.rail-item.offline{opacity:.45}
.rail-rank{font-weight:900;font-size:.76rem;min-width:1.1em;text-align:center;flex:0 0 auto}
.rail-av{width:26px;height:26px;border-radius:50%;border:2px solid var(--espresso);background:#fdfaf2;flex:0 0 auto}
.rail-mid{display:flex;flex-direction:column;min-width:0;flex:1}
.rail-name{font-weight:900;font-size:.73rem;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.rail-val{display:flex;align-items:baseline;gap:5px;min-width:0;flex-wrap:wrap}
.rail-total{display:inline-block;font-size:.72rem;font-weight:900;color:var(--green);
  font-variant-numeric:tabular-nums;white-space:nowrap}
.rail-total.num-up{color:var(--profit);animation:num-pop .5s ease}
.rail-total.num-down{color:var(--curtain);animation:num-pop .5s ease}
@keyframes num-pop{0%{transform:scale(1)}40%{transform:scale(1.2)}100%{transform:scale(1)}}
.rail-delta{font-size:.6rem;font-weight:900;white-space:nowrap}
.rail-delta.up{color:var(--profit)}
.rail-delta.down{color:var(--curtain)}
.rail-done{position:absolute;top:-8px;right:-7px;width:20px;height:20px;border-radius:50%;
  background:var(--green);color:#fff;border:2px solid var(--espresso);display:grid;place-items:center;
  font-size:.62rem;font-weight:900;animation:tick-punch .3s cubic-bezier(.3,1.7,.4,1)}
.rail-foot{font-size:.62rem;opacity:.55;text-align:center;margin:8px 0 0;font-weight:700}

/* ---------- Titles / centred cards ---------- */
.center-card{max-width:520px;max-height:100%;overflow-y:auto;margin:auto;text-align:center;background:#fffdf7;border:3px solid var(--espresso);border-radius:20px;padding:26px;box-shadow:var(--shadow);display:flex;flex-direction:column;gap:12px;align-items:center}
.painting-preview{width:min(80%,32dvh);height:auto;border:8px solid #8a6b3f;border-radius:4px}

/* ---------- The stage and its curtains ----------
   --curtain-w is the width of ONE curtain, and it stands here as a variable
   because two things need it: the curtain itself, and the padding the stage
   has to keep free on the inside so that nothing comes to lie on it.

   Previously it was a fixed 90 pixels — on a phone almost a quarter of the
   stage, and the padding was 26. The result: piece, critic and speech bubble
   lay VISIBLY ON the red curtain. On a 390 screen that is not a subtlety but
   the first thing you notice. The only place where it was right was the
   desktop layout — that kept its own 108 pixels free, a second number for the
   same thing, and exactly that fell away as soon as a flat window triggered
   the sideways wrapper.

   Now both hang on one number: the curtain grows with the stage (7 % of the
   window width, capped at 90), and the padding is always itself plus a hand's
   breadth. Only the critique stage keeps it free — the unveiling carries no
   curtains and would otherwise get margin for no reason. */
.stage{--curtain-w:clamp(16px,7vw,90px);
  position:relative;width:100%;max-width:min(900px,var(--wide));margin:0 auto;background:#3d2420;border-radius:22px;padding:22px 26px 18px;flex:1;min-height:0;overflow:hidden;color:var(--paper);display:flex;flex-direction:column}
#screen-critique .stage{padding-inline:calc(var(--curtain-w) + 14px)}
.stage .curtain{position:absolute;top:0;bottom:0;width:var(--curtain-w);background:repeating-linear-gradient(90deg,var(--curtain) 0 22px,#9c2726 22px 44px)}
.curtain.left{left:0;border-right:6px solid var(--gold)}
.curtain.right{right:0;border-left:6px solid var(--gold)}
.lot-chip{position:relative;z-index:2;display:inline-block;align-self:flex-start;background:var(--gold);color:#3a2a10;font-weight:900;padding:4px 14px;border-radius:10px;margin:0 0 12px}
/* The picture measures itself against the width of its column AND against --easel-h — whichever
   is smaller. Steered via the width, because a 512 PNG would otherwise never grow past its
   natural size and would look lost on big screens.
   width:100% is compulsory in the process: with container-type AND margin:0 auto the
   easel would collapse to width 0 as a grid child (shrink-to-fit). */
/* `min-height:0` is no trimming here: the easel is a flex child of the stage, and
   a flex child does not by itself give way below its content size. On an iPhone SE
   sideways (568 × 320) the picture was 129 pixels tall, the stage 189, and with the
   lot chip and the foot that came to 245 — the 56 too many were cut off at the
   bottom by `overflow:hidden`, "next ▶" included. Now the picture gives way; the
   foot stays. It is the way onward, and the picture one has just seen. */
.easel{--easel-h:38dvh;position:relative;z-index:2;width:100%;max-width:min(460px,74vw);margin:0 auto;text-align:center;container-type:inline-size;min-height:0}
.easel .art{min-height:0}
.easel img{width:min(100cqw,var(--easel-h));height:auto;max-width:100%;max-height:100%;object-fit:contain;
  border:12px solid var(--gold);border-radius:4px;background:#fff;box-shadow:0 0 60px rgba(212,164,55,.35)}
/* The spotlight lies on the WRAPPER, not on the picture: otherwise the piece would
   travel in and the watermark would already stand there finished for the whole 0.8 s. */
.easel .art{animation:spotlight .8s ease}
.easel.small img{border-width:8px}

/* ---------- Watermark ----------
   On every piece anybody gets to see — critique, auction, unveiling,
   gallery, detail and the downloaded file. NOT on the picture that goes to
   the critic: that is the server's version (submit_painting sends the
   bare canvas from P.png()), and the stamp only comes into being here in the
   browser. A critic who found writing in the picture would appraise it too.

   --frame is the frame width of the piece in question. The frame sits on the img,
   the wrapper around it is exactly its border box — without the offset the
   stamp would lie on the gold frame instead of on the canvas, and a crop to
   the edge of the picture would cut it off cleanly. Which is exactly what it is supposed to prevent. */
.wm{position:absolute;z-index:3;left:var(--frame,0);right:var(--frame,0);bottom:var(--frame,0);
  display:flex;align-items:center;gap:.42em;overflow:hidden;
  padding:.9em var(--wm-gap,.5em) .42em .5em;pointer-events:none;user-select:none;
  font-size:var(--wm,.62rem);line-height:1;
  background:linear-gradient(to top,rgba(24,15,11,.6),rgba(24,15,11,0))}
/* Bottom left, because the buyer's portrait sits at the bottom right and the
   round stamp at the top left. --wm-gap keeps free the room the portrait takes up.
   But that only reserves it — text that gets longer anyway would run
   on underneath. That is why the font size in the gallery hangs on the
   TILE WIDTH (which ranges from 168 px to half a screen width):
   that way "Bad Art Auction" fits next to the portrait instead of running into it. */
.gal-frame{container-type:inline-size}
.gal-frame .wm{--wm-gap:46px;--wm:clamp(.44rem,4.4cqw,.7rem)}
.lot-frame .wm{--wm-gap:56px}
/* Both parts come from logo.webp — the name too. A rebuilt typeface
   (previously Fraunces) is precisely NOT the typeface of the brand: the lettering in the
   logo is drawn, with an outline, a gradient and a drop shadow, and no
   typeset variant matches that.

   The crops are measured against the file (800×721, tools/test scanned it
   row by row): drawing 80.0 682×597 — lettering 0.605 800×116,
   eight empty rows in between. If logo.webp is ever swapped out, these
   six numbers and the ones in watermarked() need re-measuring.

   The cropping is done via background-size/-position in em rather than via %:
   percentage values in background-position compute against (tile − image) and here
   would not be the offset you write down. */
.wm-mark{flex:0 0 auto;--mw:1.62em;width:var(--mw);height:calc(var(--mw)*597/682);
  background:url(logo.webp) no-repeat calc(var(--mw)*-80/682) 0/calc(var(--mw)*800/682) auto;
  filter:drop-shadow(0 1px 2px rgba(20,12,8,.55))}
.wm-name{flex:0 0 auto;--nh:1.25em;height:var(--nh);width:calc(var(--nh)*800/116);
  background:url(logo.webp) no-repeat 0 calc(var(--nh)*-605/116)/auto calc(var(--nh)*721/116);
  filter:drop-shadow(0 1px 2px rgba(20,12,8,.55))}
.art{position:relative;display:inline-block;max-width:100%;line-height:0;--frame:12px;--wm:.76rem}
.easel.small .art{--frame:8px;--wm:.68rem}
@keyframes spotlight{from{transform:scale(.7) rotate(-3deg);opacity:0}to{transform:none;opacity:1}}
/* Dark on light paper, light on the stage — otherwise the title disappears. */
.painting-title{color:var(--espresso);font-size:1.4rem;margin:6px 0 0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.stage .painting-title{color:var(--paper)}
/* flex:1 1 auto — and that is the difference between "fits" and "does not
   fit". The stage is a column of three parts: lot row, piece, critique,
   the foot below them. Without this line `flex:0 1 auto` stood here: the
   critique box was allowed to SHRINK but not to GROW. On a phone and
   on a tablet in portrait that meant both at once — the roast was cut off
   mid-sentence ("I see a…"), and below it stood 200 pixels of
   empty stage that it would have fitted into. Now it takes what is left, and
   only scrolls when that is not enough either. */
.critic-row{position:relative;z-index:2;display:flex;gap:14px;align-items:flex-start;max-width:640px;
  margin:14px auto 0;width:100%;flex:1 1 auto;overflow-y:auto;min-height:0}
.critic-figure{font-size:3.4rem;background:var(--paper);border:3px solid var(--gold);border-radius:50%;width:84px;height:84px;display:grid;place-items:center;flex-shrink:0}
.critic-figure.thinking{animation:sway 2.2s ease-in-out infinite}
@keyframes sway{0%,100%{transform:rotate(-4deg)}50%{transform:rotate(4deg)}}
/* While he gibbers away, the head bobs along in time with the syllables */
.critic-figure.talking{animation:yap .17s ease-in-out infinite}
@keyframes yap{0%,100%{transform:translateY(0) scale(1)}50%{transform:translateY(-3px) scale(1.05,.95)}}
.bubble{background:#fffdf7;color:var(--espresso);border:3px solid var(--espresso);border-radius:16px;padding:14px 16px;position:relative;flex:1}
.bubble::before{content:"";position:absolute;left:-14px;top:26px;border:8px solid transparent;border-right-color:var(--espresso)}
.epoch-guess{font-weight:900;color:var(--blue);margin:0 0 6px}
.label-badge{display:inline-block;margin-top:8px;background:var(--curtain);color:#fff;font-weight:900;padding:3px 10px;border-radius:8px;font-size:.85rem}
/* Foot of the stage: clock on the right, "next" for the host beside it */
.stage-foot{position:relative;z-index:2;flex:0 0 auto;display:flex;align-items:center;gap:12px;
  justify-content:flex-end;margin-top:10px}
.stage-foot.center{justify-content:center;margin:18px 0}
.stage-count{font-size:.85rem;opacity:.7;font-weight:700}
.stage .stage-count{color:var(--paper)}

/* ---------- Appraisal (auction & detail view) ---------- */
.dossier{position:relative;z-index:2;margin-top:12px;text-align:left;background:#fffdf7;
  border:3px solid var(--espresso);border-radius:14px;padding:11px 13px;box-shadow:var(--shadow)}
.dossier-grid{display:grid;grid-template-columns:1fr 1fr;gap:12px}
.dossier-cell{min-width:0}
.dossier-label{display:block;font-size:.6rem;letter-spacing:.2em;text-transform:uppercase;
  font-weight:900;color:var(--curtain);opacity:.75}
.dossier-value{font-family:Fraunces,serif;font-weight:900;font-size:1rem;margin:.1em 0 0;line-height:1.15}
.dossier-value.handwriting{font-family:Caveat,cursive;font-size:1.35rem;color:var(--curtain);line-height:1.05}
.dossier-critique{font-style:italic;font-size:.86rem;margin:.6em 0 0;max-height:6.5em;overflow-y:auto;opacity:.9}
.verdict{display:inline-block;font-weight:900;font-size:.8rem;margin:.6em 0 0;padding:3px 10px;
  border:2px solid var(--espresso);border-radius:9px}
.verdict.hit{background:var(--green);color:#fff}
.verdict.miss{background:#f6ded9;color:#8d1f1e}
/* The room's murmur — a hint of how the sub-scores lean, never the value
   itself. Small and italic on purpose: a rumour overheard, not a number
   read off a ledger. */
.buzz-line{font-size:.75rem;letter-spacing:.02em;font-style:italic;color:var(--gold);
  opacity:.85;margin:.5em 0 0;font-weight:700}

/* ---------- Auction ---------- */
.auction-wrap{width:100%;max-width:min(980px,var(--wide));margin:0 auto;position:relative;flex:1;min-height:0;display:flex;flex-direction:column}
.auction-left{display:flex;flex-direction:column;min-width:0}
#screen-auction .easel.small{--easel-h:34dvh}
/* overflow-y: otherwise the bid buttons slide out of reach on narrow screens.
   overflow-x + bottom margin: the bid card shakes on every bid (fx-shake). A
   shifted element counts towards the scrollable area of its scroll container —
   without these two lines a bar therefore flashed up briefly on EVERY bid.
   The bottom margin catches the vertical swing, hidden the horizontal one. */
.auction-main{flex:1;min-height:0;overflow-y:auto;overflow-x:hidden;padding-bottom:8px;
  display:grid;grid-template-columns:1fr 1fr;gap:20px;align-items:start}
/* min-width:0 as with .auction-left: without it the column sets its width by
   what the bid card needs at minimum — and the field "your own bid"
   brings a good 200 pixels of its own demand along as an input field. On a narrow
   screen the column thereby grew past the edge, and because .auction-main
   clips horizontally, the "bid" button lay behind the edge. */
.bid-panel{min-width:0;background:#fffdf7;border:3px solid var(--espresso);border-radius:18px;padding:18px;box-shadow:var(--shadow);text-align:center}
.auction-clock{display:flex;align-items:center;gap:10px;margin-bottom:12px}
.timer-bar-wrap{flex:1;height:14px;background:#e7dcc3;border:2px solid var(--espresso);border-radius:8px;overflow:hidden}
.timer-bar{height:100%;background:var(--blue);width:100%;transition:width .2s linear,background-color .3s}
#auction-count{min-width:1.6em;text-align:right;font-size:1.15rem}
#screen-auction.warn .timer-bar{background:var(--gold)}
#screen-auction.panic .timer-bar{background:var(--curtain);animation:bar-throb .5s ease-in-out infinite}
@keyframes bar-throb{0%,100%{opacity:1}50%{opacity:.45}}
/* The hammer is already lying ready */
#screen-auction.panic .bid-panel{border-color:var(--curtain);box-shadow:0 6px 0 rgba(184,48,47,.3)}
.current-bid-label{margin:0;font-weight:700;opacity:.6;text-transform:uppercase;font-size:.75rem;letter-spacing:.1em}
.current-bid{font-family:Fraunces,serif;font-size:2.6rem;font-weight:900;margin:.05em 0;color:var(--green);font-variant-numeric:tabular-nums}
.leader{display:flex;gap:8px;justify-content:center;align-items:center;min-height:40px;font-weight:900}
.leader img{width:36px;height:36px;border-radius:50%;border:2px solid var(--espresso);animation:wiggle .5s ease}
@keyframes wiggle{0%,100%{transform:rotate(0)}25%{transform:rotate(-9deg)}75%{transform:rotate(9deg)}}
.bid-buttons{display:flex;gap:8px;flex-wrap:wrap;justify-content:center;margin:12px 0}
.bid-buttons .btn{flex:0 0 auto}
/* ---------- How much does this bid hurt? ----------
   Money here is not a score but ammunition: whoever empties their coffers on the
   second lot watches the rest of the game go past. That is written nowhere, and
   you notice it exactly once — too late. So the button takes on the colour of
   what would be left AFTER the bid; the step above that also gets a thicker
   border, so that it does not hang on colour alone (one man in twelve does not
   tell red and green apart). */
.bid-buttons .btn.risk-mid{background:#fdf3d8}
.bid-buttons .btn.risk-high{background:#f7dfc4;border-color:#a8552a}
.bid-buttons .btn.risk-all{background:#f3cfc6;border-color:var(--curtain);border-width:4px;color:#7d1f1e}
/* And all-or-nothing carries a pulse of its own: it is the only button in the
   room with a question behind it. */
.bid-buttons .btn.allin{border-color:var(--curtain);animation:allin-throb 2.2s ease-in-out infinite}
@keyframes allin-throb{0%,100%{box-shadow:var(--shadow)}50%{box-shadow:0 6px 0 rgba(184,48,47,.35),0 0 0 3px rgba(184,48,47,.25)}}
/* ---------- Why the clock is running ----------
   An accelerated clock without an explanation is a fault, not a game move:
   whoever sees two seconds disappear per second takes it for a stuttering
   phone. The line says it in words — and it sits ABOVE the bid, because that is
   where the eye is anyway. */
.auction-note{margin:0 0 8px;padding:6px 10px;border-radius:10px;font-weight:900;
  font-size:.82rem;line-height:1.25;text-wrap:balance;border:2px solid var(--espresso)}
.auction-note.rush{background:var(--curtain);color:#fff;border-color:#7d1f1e;
  animation:note-throb .7s ease-in-out infinite}
.auction-note.sealed{background:var(--gold);color:#3a2a10}
/* And the clock itself twitches once when the run begins — the same flash as on
   being outbid, it is the same kind of fright. */
.auction-clock.outbid{animation:outbid-flash .7s ease}
@keyframes note-throb{0%,100%{opacity:1}50%{opacity:.62}}
/* The label steps back while the line above it is shouting. */
#screen-auction .auction-note.rush~.current-bid-label{opacity:.45}
.custom-bid{display:flex;gap:8px;justify-content:center}
.custom-bid input{width:170px}
/* Hammer above the writing instead of beside it: display:flex, so that both lines
   stand below one another. No !important — otherwise the rule would beat .hidden. */
/* The knock-down: a sign, not a curtain.
   ---------------------------------------
   Two things were wrong here. First, the movement lay on the WRAPPER: a
   `position:fixed; inset:0` is exactly window-sized, `scale(2)` turns that into
   double the window size — the box grows past all four edges,
   writing and hammer travel right across the screen in the process and the browser gets to
   think about scrollbars along the way. Now the wrapper stands still and only
   the card inside it moves; that scales around its own centre and stays
   where it is.

   Second, an almost opaque brown (rgba(61,36,32,.85)) covered the whole
   hall — in exactly the moment in which you want to see WHAT has just
   been knocked down. The veil is now thin and blurred instead of dense:
   piece, bid and leaderboard stay readable, the card carries the message.

   pointer-events:none, because the card stays put for 2.2 s and in that time should
   not intercept anything — the auction is over anyway. */
.sold-banner{position:fixed;inset:0;z-index:50;display:grid;place-items:center;padding:0 6vw;
  pointer-events:none;background:rgba(74,52,42,.22);backdrop-filter:blur(2px);-webkit-backdrop-filter:blur(2px);
  animation:sold-veil .22s ease both}
/* The card measures itself against BOTH axes: measured only against the width the
   knock-down would stand there on a phone held sideways in letters taller
   than half the screen. */
.sold-card{display:flex;align-items:center;justify-content:center;gap:.45em;margin:0;
  max-width:min(720px,100%);padding:.5em .85em;
  font-family:Fraunces,serif;font-weight:900;font-size:clamp(1.05rem,min(4.4vw,7dvh),2.1rem);
  line-height:1.15;text-align:center;text-wrap:balance;
  color:var(--espresso);background:var(--paper);
  border:3px solid var(--espresso);border-radius:16px;box-shadow:0 10px 0 rgba(74,52,42,.32);
  animation:sold-stamp .42s cubic-bezier(.2,1.35,.45,1) both}
/* No knock-down, no gold: muted paper, dashed border — the same
   mark the unsold lot carries in the gallery too. */
.sold-banner.no-sale .sold-card{background:#efe4d2;border-style:dashed;color:#6b5344;box-shadow:0 8px 0 rgba(74,52,42,.22)}
@keyframes sold-veil{from{opacity:0}to{opacity:1}}
@keyframes sold-stamp{
  0%{transform:scale(.62) rotate(-7deg);opacity:0}
  55%{transform:scale(1.05) rotate(1.6deg);opacity:1}
  100%{transform:scale(1) rotate(-1deg)}}

/* ---------- Unveiling ---------- */
.gold-stage.rich{box-shadow:inset 0 0 140px rgba(212,164,55,.5)}
/* The same arithmetic as with .critic-row, and here it was a real
   game-stopper: the grid stood on `margin:auto` and took its
   natural height. On a phone held sideways (844 × 390) that was
   bigger than the stage — and because .stage clips at overflow:hidden,
   "next ▶" and the clock in the foot lay BELOW the edge. Not small, not
   shifted: gone. The host could not continue the game and
   had to wait until the 30 seconds had run out by themselves.
   Now the stage shares out the height: the foot keeps its own, the grid
   gets the rest and scrolls on the inside. */
.reveal-grid{position:relative;z-index:2;display:grid;grid-template-columns:1fr 1fr;gap:22px;
  align-items:center;max-width:min(760px,100%);margin:0 auto;width:100%;
  flex:1 1 auto;min-height:0;overflow-y:auto}
#screen-reveal .easel{--easel-h:46dvh}
.reveal-facts{min-width:0}
.reveal-facts p{margin:.35em 0}
.counter{color:var(--gold)}
.bonus{background:var(--green);color:#fff;display:inline-block;padding:4px 12px;border-radius:10px;font-weight:900}
.profit-pos{color:#7fd49a;font-weight:900}
.profit-neg{color:#ff9b8f;font-weight:900}

/* ---------- Interim standings & finale ----------
   Two lists that both grow with the game: the leaderboard (one row per head)
   and the collection (one picture per head and round). With eight players over
   three rounds that is eight rows and twenty-four pictures — not finishable on
   any screen in the world.

   So it is not the page that scrolls but the two lists for themselves. The
   difference is the button BETWEEN them: "next ▶" or "another round" stands
   between leaderboard and collection, and when the page was swiped the
   collection pushed it below the edge — on a phone you had to swipe past
   twenty-four pictures to get on. This way it stands fixed. */
.final-wrap{max-width:min(1120px,var(--wide));margin:14px auto;text-align:center;
  display:flex;flex-direction:column;min-height:0}
.final-wrap>*{flex:0 0 auto}
/* The leaderboard first, with a cap: it is the answer to "who won", and you
   want to see that whole before the collection gets any room. */
.final-list{list-style:none;padding:0;display:flex;flex-direction:column;gap:10px;
  max-width:560px;margin:0 auto 18px;width:100%;
  flex:0 0 auto;min-height:4.6rem;max-height:min(38dvh,430px);overflow-y:auto;
  padding:4px 2px 0 0}
/* `flex:0 0 auto` above, not `0 1`: the leaderboard and the collection are both
   flex children, and the initial size counts when shrinking. The collection
   brings 2400 pixels along, the list 430 — and the shortfall was still divided
   between the two, leaving the leaderboard 78 pixels of 634 on a tablet. A
   vernissage at which you cannot see the winner.
   Now only the collection gives way. The list stands there up to its cap, and
   whatever does not fit scrolls inside it. */
@media (max-height:620px){
  .final-list{max-height:min(32dvh,300px);margin-bottom:10px}
  .final-wrap>h2{margin:.2em 0 .4em}
  .final-foot{margin-bottom:8px}
  /* On a short screen "the collection" and its hint are two lines that cost a
     row of pictures — and a wall of picture frames explains itself. */
  .final-gal>h3,.final-gal>.gallery-hint{display:none}
}
/* ---------- Wide enough: leaderboard on the left, collection on the right ----------
   Stacked, the two share everything the height provides, and on no screen is
   that enough for both: measured, the collection got 68 pixels of 2518 on a
   1440 desktop and 50 of 1091 sideways on the phone — a strip with half a
   picture frame on it. That does not look "scrollable", it looks broken. And
   half the page lies idle beside it: the card is 1120 pixels wide, and both
   lists are narrow.

   Side by side each gets the full height. The way onwards stays in the left
   column under the leaderboard — where you are standing anyway after looking
   at the winner.

   Two wrappers, one rule set: wide (from 900) OR short and wide enough (from
   440, when the screen lies flat). In between — the tall, narrow phone — it
   stays stacked, and there that is right too.

   440 and not 640: a window of 460 × 400 left the collection 15 pixels when
   stacked — less than a fifth of a tile. Side by side it is 200, and the left
   column still carries the leaderboard legibly. */
@media (min-width:900px),(max-height:620px) and (min-width:440px){
  #screen-standings .final-wrap,#screen-final .final-wrap{
    display:grid;column-gap:22px;
    grid-template-columns:minmax(0,1.05fr) minmax(0,1fr);
    grid-template-rows:auto minmax(0,1fr) auto;
    grid-template-areas:"kopf kopf" "liste galerie" "fuss galerie";
    align-content:stretch}
  .final-wrap>h2{grid-area:kopf}
  .final-wrap>.final-list{grid-area:liste;max-height:none;margin-bottom:0}
  .final-wrap>.final-foot{grid-area:fuss;margin:12px 0 0}
  .final-wrap>.final-gal{grid-area:galerie}
}
/* Sideways on the phone the right column is only 325 pixels wide: at a
   minimum width of 168 pixels exactly ONE tile fitted there, and the
   collection stood as one room-high picture instead of a wall. */
@media (max-height:620px) and (min-width:440px){
  .final-gal>h3,.final-gal>.gallery-hint{display:none}
  .final-wrap>.final-gal .gallery{gap:10px;padding-bottom:0;
    grid-template-columns:repeat(auto-fill,minmax(118px,1fr))}
}
/* ---------- On a phone the collection is a wall of pictures ----------
   Up to here a tile carried a frame, title, valuation, knock-down and a PNG
   button — 200 pixels tall together. 158 fit into the collection of an iPhone
   SE, and so NO tile was ever fully visible: whoever swiped always had half a
   picture in front of them. The test on the phone reported exactly that.

   On a narrow screen the frame therefore stays and nothing else — three small
   pictures per row, as on a wall. Title, valuation, knock-down and the PNG all
   stand on the sheet a tap on the frame opens anyway (#lot-modal, with a
   "download" of its own). Nothing is lost that is not there again one finger
   tap further on.
   Short screens too, not only narrow ones: in a 460 × 400 window the collection
   is a strip, and a 200 pixel tile is never whole in it either. */
@media (max-width:430px),(max-height:500px){
  .final-gal .gallery{grid-template-columns:repeat(auto-fill,minmax(76px,1fr));gap:8px}
  .final-gal .gallery figure{padding:5px;gap:0}
  .final-gal .gallery figcaption,.final-gal .gallery .dl-btn{display:none}
}
/* `flex:0 0 auto` on every row, and that is no formality: the list is a flex
   box with a limited height, and each row further down carries an
   `overflow:hidden` (for the winner's gold shimmer). Exactly that sets a flex
   child's automatic minimum height to ZERO — the rows were squashed together
   and cut off their own second line: "Leonardo da VinAI / 6 pieces · 146,676 €
   brought i…". Eight ranks on 262 instead of 528 pixels, and not one of them
   fully readable. They no longer give way; what gets too long is the LIST, and
   that scrolls. */
.final-list li{flex:0 0 auto;display:flex;align-items:center;gap:12px;background:#fffdf7;border:3px solid var(--espresso);border-radius:14px;padding:10px 16px;box-shadow:var(--shadow);text-align:left}
.final-list li:first-child{background:var(--gold);transform:rotate(-.6deg)}
.final-list li.winner{transform:scale(1.06) rotate(-.6deg);font-size:1.1rem}
.final-list canvas{width:44px;height:44px;border-radius:50%;border:2px solid var(--espresso);background:#fdfaf2;flex:0 0 auto}
.fblock{display:flex;flex-direction:column;min-width:0}
.fsub{font-size:.7rem;opacity:.6;font-weight:700}
.final-list .ftotal{margin-left:auto;font-weight:900;color:var(--green);font-variant-numeric:tabular-nums;white-space:nowrap}
.gallery-hint{font-size:.8rem;opacity:.55;margin:.2em 0 14px;font-weight:700}

/* ---------- Gallery ---------- */
/* The foot of the page: the way onwards. It stands BETWEEN leaderboard and
   collection and not below it — after twenty-four pictures nobody looks for it
   any more. */
.final-foot{display:flex;flex-direction:column;align-items:center;gap:8px;margin-bottom:14px}
/* The collection with its heading as one box: it gets whatever is left and
   scrolls inside that. The only part of the page that MAY grow — if the game
   was short and the collection small, it fills the rest instead of leaving a
   hole. */
.final-gal{flex:1 1 auto;min-height:0;display:flex;flex-direction:column;text-align:left}
.final-gal>h3,.final-gal>.gallery-hint{flex:0 0 auto;text-align:center}
.final-gal>h3{margin:0 0 .2em}
.gallery{display:grid;grid-template-columns:repeat(auto-fill,minmax(168px,1fr));gap:16px;
  padding-bottom:12px;flex:1 1 auto;min-height:0;overflow-y:auto;align-content:start}
.gallery figure{margin:0;background:#fffdf7;border:3px solid var(--espresso);border-radius:12px;
  padding:8px;transform:rotate(-1.2deg);display:flex;flex-direction:column;gap:6px}
.gallery figure:nth-child(even){transform:rotate(1.4deg)}
.gal-frame{position:relative;display:block;width:100%;padding:0;border:0;background:none;
  cursor:pointer;line-height:0;border-radius:4px;--frame:6px;--wm:.55rem}
.gal-frame:focus-visible{outline:3px solid var(--gold);outline-offset:3px}
.gallery img{width:100%;border:6px solid #8a6b3f;border-radius:3px;display:block;transition:filter .15s}
@media (hover:hover){.gal-frame:hover img{filter:brightness(1.05) saturate(1.05)}}
.gallery figure.expensive img{border-color:var(--gold)}
/* Round stamp at the top left, buyer's portrait at the bottom right on the picture */
.round-stamp{position:absolute;top:7px;left:7px;background:var(--blue);color:#fff;
  border:2px solid var(--espresso);border-radius:8px;font-size:.6rem;font-weight:900;
  padding:2px 7px;transform:rotate(-4deg);line-height:1.35;letter-spacing:.04em}
.owner-badge{position:absolute;right:0;bottom:0;width:42px;height:42px;border-radius:50%;
  border:3px solid var(--gold);background:#fdfaf2;overflow:hidden;line-height:0;
  box-shadow:0 3px 0 rgba(74,52,42,.35)}
.owner-badge canvas{width:100%;height:100%;display:block}
.owner-badge.unsold{border-color:var(--espresso);border-style:dashed}
.gallery figcaption{font-size:.8rem;font-weight:700;text-align:left;line-height:1.3}
.gal-title{display:block;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.gal-value{display:block;font-family:Fraunces,serif;font-weight:900;color:var(--green);font-variant-numeric:tabular-nums}
.gal-sub{display:block;font-size:.72rem;opacity:.6;font-weight:700}
.dl-btn{align-self:flex-start;transform:none;font-size:.72rem;padding:5px 11px;box-shadow:0 3px 0 rgba(74,52,42,.18)}
@media (hover:hover){.dl-btn:hover{transform:translateY(-2px)}}

/* ---------- A piece in detail ---------- */
.lot-card{width:min(950px,100%)}
.lot-grid{display:grid;grid-template-columns:minmax(0,.95fr) minmax(0,1.05fr);gap:22px;align-items:start}
.lot-frame{position:relative;line-height:0;--frame:10px;--wm:.8rem}
.lot-frame img{width:100%;border:10px solid #8a6b3f;border-radius:4px;background:#fff;display:block;
  box-shadow:0 8px 0 rgba(74,52,42,.22)}
.lot-frame .owner-badge{width:54px;height:54px;right:-8px;bottom:-8px}
.lot-facts{min-width:0;text-align:left}
.lot-facts .brief-head{font-size:1.7rem}
.lot-facts .brief-sub{margin-bottom:12px}
.lot-facts .dossier-grid{background:#faf3e2;border:2px dashed var(--curtain);border-radius:12px;padding:12px}
.lot-critique{margin:.7em 0;padding:10px 14px;border-left:6px solid var(--curtain);background:#faf3e2;
  border-radius:0 12px 12px 0;font-style:italic;font-size:.95rem}
.price-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:10px;margin:.7em 0}
.price-cell{background:#fff;border:2px solid var(--espresso);border-radius:12px;padding:8px 10px;min-width:0}
.price-value{font-family:Fraunces,serif;font-weight:900;font-size:1.05rem;margin:.1em 0 0;
  font-variant-numeric:tabular-nums;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.price-value.gold-text{color:#a97c12}
.price-value.profit-pos{color:var(--profit)}
.price-value.profit-neg{color:var(--curtain)}
.lot-owner{font-size:.9rem;font-weight:700;margin:.2em 0 .9em}

/* ---------- Toast ---------- */
.toast{position:fixed;bottom:24px;left:50%;transform:translateX(-50%);background:var(--espresso);color:var(--paper);padding:12px 22px;border-radius:14px;font-weight:900;z-index:99;box-shadow:var(--shadow);
  animation:toast-in .32s cubic-bezier(.2,1.3,.4,1)}
@keyframes toast-in{from{opacity:0;translate:0 22px;scale:.9}to{opacity:1;translate:none;scale:none}}

/* ---------- 3 · 2 · 1 ----------
   Lies over everything (over the modal cards too, z-index 60) and belongs to no
   screen: the countdown begins in the lobby and ends in the studio, and in
   between the screen changes underneath it. It takes no clicks — whoever presses
   "Ready" in the last second should hit the button and not the curtain.

   The digit is deliberately enormous: it is the one sign in this game that pulls
   somebody out of their self-portrait before the canvas arrives. clamp() works it
   out against BOTH axes — on a phone held sideways the height is the scarce
   space, not the width. */
.countdown{position:fixed;inset:0;z-index:70;display:grid;place-items:center;
  pointer-events:none;background:radial-gradient(circle at 50% 42%,rgba(40,26,20,.72),rgba(40,26,20,.9));
  animation:cd-in .2s ease both}
.countdown-card{text-align:center;padding:18px 30px;max-width:min(92vw,520px)}
.countdown-num{margin:0;font-family:Fraunces,serif;font-weight:900;line-height:.9;
  font-size:clamp(4rem,min(30vw,34dvh),13rem);color:var(--paper);
  text-shadow:0 8px 0 rgba(74,52,42,.55),0 0 42px rgba(212,164,55,.55)}
.countdown-num.pop{animation:cd-pop .42s cubic-bezier(.2,1.5,.4,1)}
/* The starting shot is a word, not a digit: "C’est parti !" at digit height
   would be three times as wide as a narrow phone screen. */
.countdown-num.word{font-size:clamp(1.8rem,min(11vw,13dvh),4.6rem);line-height:1.05;text-wrap:balance}
.countdown-why{margin:.9em 0 0;font-weight:900;font-size:clamp(.85rem,min(3.6vw,2.4dvh),1.15rem);
  color:var(--gold);text-transform:uppercase;letter-spacing:.1em;text-wrap:balance;
  text-shadow:0 2px 0 rgba(24,14,10,.6)}
@keyframes cd-in{from{opacity:0}to{opacity:1}}
@keyframes cd-pop{0%{transform:scale(1.6);opacity:.15}60%{transform:scale(.94);opacity:1}100%{transform:scale(1)}}

/* ---------- Sound control ----------
   Bottom left, small and semi-transparent: in the game it should not stand out,
   but be there at once if somebody is sitting in the library. */
#audio-corner{position:fixed;z-index:95;display:flex;align-items:flex-end;gap:8px;
  left:max(14px,env(safe-area-inset-left));bottom:max(14px,env(safe-area-inset-bottom))}
.audio-btn{width:42px;height:42px;border-radius:50%;font-size:1.15rem;cursor:pointer;
  background:#fffdf7;border:3px solid var(--espresso);box-shadow:var(--shadow);opacity:.55;
  transition:opacity .15s,transform .1s}
.audio-btn:focus-visible{opacity:1}
@media (hover:hover){.audio-btn:hover,#audio-corner:hover .audio-btn{opacity:1}}
#audio-corner:has(.audio-panel.open) .audio-btn{opacity:1}
.audio-btn:active{transform:translateY(2px)}
.audio-btn.muted{background:#f0e2d6}
.audio-panel{display:none;flex-direction:column;gap:7px;background:#fffdf7;border:3px solid var(--espresso);
  border-radius:16px;padding:12px;box-shadow:var(--shadow);transform:rotate(-.8deg);min-width:172px;
  animation:brief-in .3s cubic-bezier(.2,.9,.3,1.2)}
.audio-panel.open{display:flex}
.audio-head{font-family:Fraunces,serif;font-size:.7rem;text-transform:uppercase;letter-spacing:.14em;opacity:.6}
.audio-toggle{font-family:Nunito;font-weight:900;font-size:.82rem;color:var(--espresso);background:#fff;
  border:2px solid var(--espresso);border-radius:11px;padding:6px 11px;cursor:pointer;text-align:left;
  box-shadow:0 3px 0 rgba(74,52,42,.18);opacity:.5}
.audio-toggle.on{background:var(--gold);color:#3a2a10;opacity:1}
.audio-toggle:active{transform:translateY(1px);box-shadow:0 1px 0 rgba(74,52,42,.18)}
/* The card contains the only sound controls — with the keyboard it has to be
   visible where you currently stand. */
.audio-toggle:focus-visible,.audio-vol input:focus-visible{outline:3px solid var(--gold);outline-offset:2px;opacity:1}
.audio-vol{display:flex;align-items:center;gap:7px;font-size:.85rem}
.audio-vol input{width:100%;padding:0;border:0;accent-color:var(--gold);cursor:pointer}
@media (max-width:760px){
  #audio-corner{left:max(8px,env(safe-area-inset-left));bottom:max(8px,env(safe-area-inset-bottom))}
  .audio-btn{width:36px;height:36px;font-size:1rem}
}

/* ---------- Particles & one-off effects ----------
   A single canvas over everything; the loop in fx.js sleeps as soon as nothing
   is flying any more. Modal dialogs (z-index 60) deliberately lie above it — confetti
   must not cover a confirmation. */
#fx-canvas{position:fixed;inset:0;pointer-events:none;z-index:55}
.fx-float{position:fixed;transform:translate(-50%,-50%);z-index:96;pointer-events:none;
  font-family:Fraunces,serif;font-weight:900;font-size:1.35rem;white-space:nowrap;
  text-shadow:0 2px 0 rgba(255,253,247,.9),0 0 12px rgba(255,253,247,.7);
  animation:fx-float 1.4s cubic-bezier(.2,.8,.3,1) forwards}
.fx-float.up{color:var(--profit)}
.fx-float.down{color:var(--curtain)}
.fx-float.gold{color:#a97c12}
@keyframes fx-float{
  0%{opacity:0;translate:0 0;scale:.6}
  18%{opacity:1;scale:1.12}
  30%{scale:1}
  100%{opacity:0;translate:0 -70px}}
.fx-flash{position:fixed;inset:0;z-index:54;pointer-events:none;animation:fx-flash ease-out forwards}
@keyframes fx-flash{from{opacity:.85}to{opacity:0}}
/* Ink wipe: a dark curtain travels right across the picture and out again */
.fx-wipe{position:fixed;inset:0;z-index:58;pointer-events:none;
  background:linear-gradient(100deg,transparent 0 12%,#3d2420 26% 74%,transparent 88% 100%);
  animation:fx-wipe .68s cubic-bezier(.7,0,.3,1) forwards}
@keyframes fx-wipe{from{transform:translateX(-115%)}to{transform:translateX(115%)}}
.fx-shake{animation:fx-shake .5s cubic-bezier(.36,.07,.19,.97)}
@keyframes fx-shake{
  0%,100%{translate:0 0}
  15%{translate:-8px 3px}35%{translate:7px -4px}
  55%{translate:-5px 2px}75%{translate:4px -2px}90%{translate:-2px 1px}}
.fx-rise{animation:fx-rise .5s cubic-bezier(.2,.9,.3,1.15) backwards;animation-delay:var(--fx-delay,0ms)}
@keyframes fx-rise{from{opacity:0;translate:0 26px;scale:.9}to{opacity:1;translate:none;scale:none}}
.fx-pop{animation:fx-pop .5s cubic-bezier(.3,1.6,.4,1)}
@keyframes fx-pop{0%{scale:1}35%{scale:1.18}100%{scale:1}}
.fx-glow{animation:fx-glow .9s ease}
@keyframes fx-glow{0%,100%{filter:none}40%{filter:drop-shadow(0 0 16px rgba(212,164,55,.95)) brightness(1.15)}}

/* ---------- Curtain: the critique stage opens ---------- */
.stage.opening .curtain{animation:curtain-open 1s cubic-bezier(.55,.06,.25,1) backwards}
/* Ends on --curtain-w, not on 90px: otherwise the curtain jerked at the end of
   the animation to a width that is not its own on any narrow screen. */
@keyframes curtain-open{from{width:53%}to{width:var(--curtain-w)}}
/* As long as the curtain is running, the piece waits behind it */
.stage.opening .easel img{animation:spotlight .8s ease .55s backwards}

/* ---------- The cloth over the piece (unveiling) ---------- */
.veil-wrap{position:relative;display:inline-block;max-width:100%;line-height:0}
/* Above the watermark (z-index:3): as long as the cloth lies there, nothing of the
   piece is to be seen — not even the stamp on it. */
.veil{position:absolute;inset:0;z-index:4;border-radius:4px;pointer-events:none;
  background:repeating-linear-gradient(112deg,#efe3cb 0 14px,#e2d3b6 14px 28px);
  box-shadow:inset 0 0 30px rgba(74,52,42,.35)}
.veil.off{animation:veil-off .75s cubic-bezier(.6,0,.3,1) forwards}
/* Right out after the animation — see the paragraph at veil.addEventListener
   in client.js: a cloth that stays lying invisibly 118 % below the frame makes
   the grid above it scrollable. */
.veil.gone{display:none}
@keyframes veil-off{
  0%{transform:translate(0,0) rotate(0);opacity:1}
  100%{transform:translate(-18%,118%) rotate(-13deg);opacity:0}}

/* ---------- The hammer falls ---------- */
/* The hammer now stands NEXT TO the text, no longer above it: in the card
   both sit on one line, and a display:block would tear it out of there.
   It still falls — only around its own baseline, no longer across
   half the screen. */
.sold-banner .gavel{flex:0 0 auto;font-size:1.25em;line-height:1;animation:gavel-drop .55s cubic-bezier(.5,0,.75,1)}
@keyframes gavel-drop{
  0%{transform:translateY(-45%) rotate(-72deg);opacity:0}
  55%{transform:translateY(0) rotate(12deg);opacity:1}
  70%{transform:rotate(-6deg)}
  85%{transform:rotate(3deg)}
  100%{transform:none}}

/* ---------- Auction: making bids palpable ---------- */
.current-bid{transition:color .2s}
.current-bid.bumped{animation:bid-bump .45s cubic-bezier(.3,1.7,.4,1)}
@keyframes bid-bump{0%{scale:1}30%{scale:1.22;color:#a97c12}100%{scale:1}}
.bid-panel.outbid{animation:outbid-flash .7s ease}
@keyframes outbid-flash{0%,100%{background:#fffdf7}30%{background:#fbe3de;border-color:var(--curtain)}}
.bid-panel.leading{box-shadow:0 6px 0 rgba(46,125,79,.35),0 0 0 3px rgba(46,125,79,.35)}
.bid-buttons .btn{transition:transform .08s,box-shadow .08s}
@media (hover:hover){.bid-buttons .btn:not(:disabled):hover{box-shadow:0 8px 0 rgba(74,52,42,.22)}}
/* The gold button gets a wipe of light — it is the most expensive click in the game */
.btn.gold{position:relative;overflow:hidden}
.btn.gold::after{content:"";position:absolute;top:-60%;bottom:-60%;width:38%;left:-60%;
  background:linear-gradient(100deg,transparent,rgba(255,255,255,.75),transparent);
  transform:skewX(-18deg);animation:shine 4.5s ease-in-out infinite}
/* translate instead of left: the wipe runs endlessly, and `left` triggered
   a new layout in every frame. 500 % of its own width (38 %) is the 190 %
   of button width from -60 % to 130 %. */
@keyframes shine{0%,72%{translate:0}86%,100%{translate:500% 0}}

/* ---------- Unveiling: the valuation ---------- */
.current-bid.counting{animation:count-throb .4s ease-in-out infinite}
@keyframes count-throb{0%,100%{text-shadow:0 0 0 rgba(212,164,55,0)}50%{text-shadow:0 0 22px rgba(212,164,55,.85)}}
.current-bid.jackpot{animation:jackpot 1.1s cubic-bezier(.3,1.5,.4,1)}
@keyframes jackpot{
  0%{scale:1}25%{scale:1.35;text-shadow:0 0 40px rgba(212,164,55,1)}
  60%{scale:.97}100%{scale:1}}
.gold-stage.rich{animation:rich-glow 2.4s ease-in-out infinite}
@keyframes rich-glow{
  0%,100%{box-shadow:inset 0 0 140px rgba(212,164,55,.5)}
  50%{box-shadow:inset 0 0 190px rgba(212,164,55,.78)}}
.bonus{animation:bonus-in .6s cubic-bezier(.3,1.6,.4,1)}
@keyframes bonus-in{0%{opacity:0;scale:.5;rotate:-8deg}70%{scale:1.1}100%{opacity:1;scale:1;rotate:0deg}}
.label-badge{animation:stamp-in .45s cubic-bezier(.3,1.5,.4,1)}
@keyframes stamp-in{0%{opacity:0;scale:2.2;rotate:-14deg}60%{opacity:1;scale:.94}100%{scale:1;rotate:0deg}}

/* ---------- Lobby: whoever joins gets seen ---------- */
.player-card.joined{animation:card-in .6s cubic-bezier(.2,1.4,.4,1)}
@keyframes card-in{0%{opacity:0;scale:.4;rotate:-14deg}65%{scale:1.08}100%{opacity:1;scale:1;rotate:0deg}}
.player-card.host::after{animation:crown-bob 3s ease-in-out infinite}
@keyframes crown-bob{0%,100%{transform:translateY(0) rotate(-6deg)}50%{transform:translateY(-4px) rotate(8deg)}}
/* The ✓ marker pops up when somebody hands in (the rule above sets the animation) */
.rail-item.just-done{animation:fx-pop .5s cubic-bezier(.3,1.6,.4,1)}

/* ---------- Appraisal: the critic is at work ---------- */
#judging-quip{animation:quip-in .5s ease}
@keyframes quip-in{from{opacity:0;translate:0 8px}to{opacity:1;translate:none}}
.critic-figure{position:relative}
.critic-figure.thinking::after{content:"💭";position:absolute;left:58px;top:-10px;font-size:1.1rem;
  animation:think-float 2.6s ease-in-out infinite}
@keyframes think-float{
  0%{opacity:0;transform:translate(0,10px) scale(.6)}
  35%{opacity:.95;transform:translate(6px,-6px) scale(1)}
  100%{opacity:0;transform:translate(16px,-26px) scale(1.25)}}

/* ---------- Finale: podium, crown, shine ---------- */
/* Ends neutral, not at 1.06: the base rule above already sets
   transform:scale(1.06) rotate(-.6deg), and scale/rotate in the keyframe come
   ON TOP. An ending at 1.06 (or a forwards) would mean 1.06 × 1.06. */
.final-list li.winner{animation:winner-in .8s cubic-bezier(.2,1.35,.4,1)}
@keyframes winner-in{0%{opacity:0;scale:.66;rotate:-3.4deg}60%{scale:1.07}100%{opacity:1;scale:1;rotate:0deg}}
/* The crown falls into the frame — the wipe of light underneath needs
   overflow:hidden, so we let it sail in from the top edge instead of over it. */
.final-list li{position:relative;overflow:hidden}
/* Onto the corner of the portrait, not next to the total — there it would be in the way of the numbers. */
.final-list li.winner::after{content:"👑";position:absolute;left:40px;top:-1px;font-size:1.35rem;
  rotate:14deg;animation:crown-drop .7s cubic-bezier(.3,1.5,.4,1) .45s backwards}
@keyframes crown-drop{0%{opacity:0;translate:0 -46px;rotate:-30deg}100%{opacity:1;translate:none;rotate:14deg}}
.final-list li.winner::before{content:"";position:absolute;inset:0;pointer-events:none;
  background:linear-gradient(100deg,transparent 35%,rgba(255,255,255,.6) 50%,transparent 65%);
  animation:winner-shine 3.2s ease-in-out infinite}
@keyframes winner-shine{0%{transform:translateX(-120%)}55%,100%{transform:translateX(120%)}}

/* ---------- Gallery: pieces arrive on the wall in sequence ---------- */
.gallery figure{transition:transform .16s,box-shadow .16s}
@media (hover:hover){.gallery figure:hover{box-shadow:0 8px 0 rgba(74,52,42,.22)}}
/* Keyframes of our own instead of rich-glow: its box-shadow is an INSET (meant for
   the stage) and would have replaced the declared outer glow here completely. */
.gallery figure.expensive .gal-frame::after{content:"";position:absolute;inset:-4px;border-radius:6px;
  pointer-events:none;box-shadow:0 0 22px rgba(212,164,55,.75);animation:frame-glow 3s ease-in-out infinite}
@keyframes frame-glow{
  0%,100%{box-shadow:0 0 16px rgba(212,164,55,.6)}
  50%{box-shadow:0 0 28px rgba(212,164,55,.9)}}

/* ---------- Tools & buttons: more tactile ---------- */
.tool,.sizes button,.swatches button,.preset{transition:transform .09s,background-color .15s}
.tool:active,.sizes button:active,.swatches button:active{transform:scale(.9)}
.tool.active{animation:fx-pop .3s ease}

/* ---------- Wide, flat screens: side by side instead of below one another ---------- */
@media (min-width:940px) and (min-height:400px) and (min-aspect-ratio:6/5){
  /* No pixel cap any more: the stage grows with the height (see --wide) */
  .stage,.auction-wrap{max-width:var(--wide)}

  #screen-critique .stage{display:grid;grid-template-columns:minmax(0,1.05fr) minmax(0,.95fr);
    /* The side padding comes from --curtain-w (see .stage) — a second, hand-typed
       108 once stood here, and it fell away as soon as a flat window triggered
       the sideways wrapper. One number, one place. */
    grid-template-rows:auto minmax(0,1fr) auto;column-gap:30px;padding-block:20px 18px}
  #screen-critique .lot-chip,#screen-critique .stage-foot{grid-column:1/-1}
  #screen-critique .easel{grid-row:2;align-self:center;max-width:100%;margin:0;--easel-h:min(58dvh,38vw)}
  #screen-critique .critic-row{grid-row:2;align-self:center;margin:0;max-width:100%}

  #screen-auction .auction-main{grid-template-columns:minmax(0,1.12fr) minmax(0,.88fr);gap:28px;align-items:center}
  #screen-auction .easel.small{max-width:100%;--easel-h:min(45dvh,30vw)}

  #screen-reveal .reveal-grid{max-width:100%;gap:30px}
  /* 68dvh instead of 56: on a tall screen (a measured 1503 × 880) the piece
     stood at 490 pixels in a stage of 840 — and because both columns sit
     centred, the remaining 350 spread themselves as holes above and below the
     numbers. The unveiling is the moment in which the piece stands large for
     the last time; it is the wrong place to economise. The 40vw cap stops it
     from crushing the numbers on a very wide window. */
  /* 64dvh, not 68: --easel-h caps the PICTURE, and below it the easel still
     carries the title (~40 px). At 68 the column overflowed on a flat window
     by exactly that line and made the grid scrollable. */
  #screen-reveal .easel{max-width:100%;--easel-h:min(64dvh,40vw)}
}

/* Portrait or narrow: the commission as a bar ABOVE the canvas, tools below it.
   A side panel would eat exactly the width here that the canvas needs. */
@media (max-width:760px),(max-aspect-ratio:6/5){
  .draw-wrap{flex-direction:column;align-items:stretch}
  .tools{display:flex;flex-direction:row;flex-wrap:wrap;justify-content:center;align-items:center;overflow:visible}
  .swatches.vertical{display:flex;flex-direction:row;flex-wrap:wrap}
  .sizes{display:flex;flex-direction:row}
  /* Right across the canvas: a straight strip of paper, not a slanted note */
  .brief-hud{width:auto;align-self:auto;margin-top:0;transform:none;padding:8px 12px;
    border-left:8px solid var(--curtain)}
  .brief-hud::before{display:none}
  .hud-inner{flex-direction:row;align-items:baseline;gap:14px;overflow:visible}
  .brief-hud .hud-block{display:flex;align-items:baseline;gap:8px;min-width:0}
  .hud-tips,.hud-ref,.hud-secret{display:none}
  .hud-value{font-size:1rem;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
  .hud-value.handwriting{font-size:1.3rem}

  /* ---------- Portrait means: everything below one another ----------
     Until recently these four rules stood in the wrapper below, which only
     checks `max-width:760px`. That let a whole class of device slip through the net:
     between 761 and 939 pixels of width NEITHER of the two layouts took hold —
     for the desktop version the screen is too narrow (that one demands
     min-width:940px), for the phone version too wide. An iPad in portrait
     (768 × 1024) therefore got the two-column grid with
     `align-items:start`: piece and bid card stuck in the upper half,
     the text in the appraisal broke off mid-sentence, and below it stood
     four hundred pixels of empty paper. On the world's best-selling tablet
     the game thereby looked like a half-loaded screen.

     That is decided not by the width but by the ORIENTATION: if a
     screen is taller than it is wide, then piece over appraisal over bid is right — whether
     it is 390 or 820 pixels wide. That is why they now stand here, where
     everything portrait-shaped stands anyway. */
  .auction-main,.reveal-grid{grid-template-columns:1fr}
  /* The bid card stays put at the bottom edge while piece and appraisal
     run away above it. The auction lasts 15 seconds — in which
     nobody should first have to scroll to the buttons. */
  .auction-main{padding-bottom:0;gap:12px}
  .bid-panel{position:sticky;bottom:0;z-index:3}

  /* On the critique stage it is the other way round: there ONLY the piece stands and a
     two-liner from the critic, and in portrait the stage has height in abundance.
     With the 460 pixels from the desktop a third of the stage on a tablet
     stayed empty brown below the speech bubble. The piece is the reason
     you are looking — it gets the space. */
  #screen-critique .easel{max-width:min(560px,86vw);--easel-h:min(46dvh,86vw)}
  /* And whatever is left after that spreads around the speech bubble
     instead of collecting below it. */
  .critic-row{align-items:center}

  /* In the auction, by contrast, every pixel counts: a smaller lot, so that appraisal
     AND bid buttons stay in the picture without scrolling. */
  #screen-auction .easel.small{--easel-h:24dvh}
  .dossier{padding:9px 11px}
  .dossier-critique{max-height:4.6em;font-size:.8rem}
  /* The leaderboard lies as a band under the stage instead of beside it */
  #screen-critique.active,#screen-auction.active,#screen-reveal.active,
  #screen-title.active,#screen-judging.active{flex-direction:column}
  .rail{width:auto;align-self:stretch;flex:0 0 auto;transform:none;flex-direction:row;
    align-items:center;padding:6px 8px;gap:8px}
  .rail-head,.rail-foot{display:none}
  /* Laid sideways the rail scrolls horizontally — the ✓ marker then needs its
     margin at the top and on the right, otherwise overflow-y:hidden cuts it off. */
  .rail-list{flex-direction:row;gap:7px;overflow-x:auto;overflow-y:hidden;padding:9px 9px 3px}
  .rail-item{flex:0 0 auto;padding:3px 7px}
  .rail-name{max-width:74px}
}

@media (max-width:760px){
  .lobby-grid,.brief-body,.lot-grid{grid-template-columns:1fr}
  .brief-card{padding:20px 18px 16px}
  .brief-card::before{display:none}
  .modal-x{top:6px;right:8px}
  .brief-head{font-size:1.7rem}
  .price-grid{grid-template-columns:1fr 1fr}
}
@media (prefers-reduced-motion:reduce){
  *,*::before,*::after{animation:none!important;transition:none!important}
  /* Without animation the cloth would never be pulled away — then the piece would stay
     veiled forever. Here it disappears abruptly instead of gliding. */
  .veil.off{display:none}
  /* The wipe of light on gold buttons and the winner's row is pure decoration and
     would otherwise stand still in the picture as a bright stripe. */
  .btn.gold::after,.final-list li.winner::before{display:none}
}

/* ================================================================
   LANGUAGE, ACCOUNT, SALON SEARCH, AD SLOTS
   ================================================================ */

/* On tablets a long press otherwise selects text and shows the magnifier —
   in the middle of painting. Input fields expressly stay selectable. */
body{-webkit-user-select:none;user-select:none;-webkit-touch-callout:none}
input,textarea,select{-webkit-user-select:text;user-select:text}
/* In the CrazyGames app's fullscreen the notch and home indicator lie over the picture. */
.screen{padding-left:max(14px,env(safe-area-inset-left));padding-right:max(14px,env(safe-area-inset-right));
  padding-top:max(10px,env(safe-area-inset-top));padding-bottom:max(10px,env(safe-area-inset-bottom))}

.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;
  clip-path:inset(50%);white-space:nowrap;border:0}

/* ---------- Language & account (top right) ---------- */
/* ---------- The corner belongs to the foyer, not to the round ----------
   Language and account are settings, and a setting is made before playing or
   afterwards — never in the middle of a brush stroke. Standing there all the
   time they cost the header of the studio 145 pixels on a phone, and "hand in"
   slid underneath them: visible, and dead, because the tap hit the language
   picker above it.

   The same reasoning already applied to the "?" beside them (see .btn.round
   further up) — it was only ever drawn on the start page and in the lobby. Now
   the whole corner follows that rule, plus the finale: after the game somebody
   may well want to switch the language or sign in, and there is nothing in the
   top right of that screen to collide with. */
#top-corner{position:fixed;z-index:95;display:none;align-items:center;gap:8px;
  top:max(14px,env(safe-area-inset-top));right:max(14px,env(safe-area-inset-right))}
#lang-select,.room-lang,.browse-lang{
  font-family:Nunito;font-weight:700;font-size:.9rem;color:var(--espresso);
  background:#fffdf7;border:3px solid var(--espresso);border-radius:12px;
  padding:6px 10px;cursor:pointer;box-shadow:0 3px 0 rgba(74,52,42,.18)}
#lang-select:focus-visible,.room-lang:focus-visible,.browse-lang:focus-visible{outline:3px solid var(--gold)}
#cg-account{display:flex;align-items:center;gap:8px;padding:6px 12px}
#cg-account[title]{cursor:default}
.cg-av{width:24px;height:24px;border-radius:50%;border:2px solid var(--espresso);object-fit:cover}

/* ---------- Start page: card + salon search side by side ---------- */
/* The start page is the ONLY page of the game allowed to swipe. It is the only one that
   cannot move together on a short window: logo, name field, two
   ways in, the salon list and the foot with the legal texts all stand there
   at the same time. Without this line .screen (overflow:hidden) simply
   clipped at the bottom — on a flat window "play alone" and the three
   buttons in the foot lay out of reach below the edge.
   margin:auto on the child stays right nonetheless: if there is room, it centres;
   if there is none, auto margins resolve to zero and it scrolls
   instead of clipping at the top (which justify-content:center would do). */
/* `safe center` instead of `margin:auto` — and that is not taste but a
   bug that only the test across eight screen sizes made visible.

   An auto margin centres as long as there is room. If there is NONE,
   it centres anyway: the overflow spreads to both sides, and the
   upper half of it lies BEFORE the start of the scrollable area — it is
   unreachable with any swipe. On an iPhone SE in portrait the
   name field, portrait, tabs and both buttons therefore lay outside the picture, and
   swiping did not help: there was nothing there to swipe.

   `safe` means exactly that: centre as long as it works — and as soon as it gets
   tight, align at the start so nothing slides past the top edge. */
#screen-home.active{overflow-y:auto;justify-content:safe center}
/* max-width:960px, NOT min(96vw,960px). 96vw measures against the window and knows
   nothing of the margins .screen already keeps itself (14 px per side, more
   at a notch). At 320 pixels that was 307 pixels of content in a 292
   pixel wide box: name field, portrait, tabs and both buttons stood
   15 pixels past the right edge — visible, yes, but no longer cleanly
   hittable with a thumb, and the test across eight screen sizes
   rightly reported them as "outside the picture". `width:100%`, by contrast,
   measures against the PARENT, and that has already subtracted the margins. */
.home-wrap{margin:0 auto;display:flex;flex-wrap:wrap;gap:22px;align-items:flex-start;justify-content:center;
  max-width:960px;width:100%}
.screen.active>.home-wrap{animation:screen-in .42s cubic-bezier(.2,.9,.3,1.06)}
.home-wrap>.home-card{margin:0}
.home-card.browse{max-width:400px;flex:1 1 320px;transform:rotate(-.4deg);gap:10px;padding:24px}
/* ---------- Laid sideways the two cards stand side by side ----------
   On the "salons" tab the start page carries two cards: your own (name, face,
   tabs) and the list. Stacked they are 462 pixels tall on a phone held
   sideways, and the page is 390 — a measured 72 pixels of overhang, and the
   page was the only one in the whole game that still swiped.

   Side by side they fit: 844 pixels of width is plenty for two cards, they
   just must not each want to be 430 wide. `flex:1 1 0` divides the row into
   two equal halves, `nowrap` forbids the wrap, and the list in the right-hand
   card scrolls inside itself instead of lengthening the page. */
@media (max-height:620px) and (min-width:640px){
  body[data-home-tab="browse"] .home-wrap{flex-wrap:nowrap;align-items:stretch;max-width:100%}
  body[data-home-tab="browse"] .home-wrap>.home-card{flex:1 1 0;max-width:none;min-width:0}
  body[data-home-tab="browse"] .home-card.browse{display:flex;flex-direction:column;min-height:0}
  body[data-home-tab="browse"] .browse-list{flex:1 1 auto;min-height:0;max-height:none}
  /* The sign-in card only has half the width here — and laid sideways the tabs
     sit in its right column, of which 141 pixels are left after the corner.
     Measured, that came to 10 pixels per tab: three vertical letters. So the
     same answer as for a narrow window — a row of its own across the whole
     card, below the portrait strip and far away from the corner. */
  body[data-home-tab="browse"] #home-tabs{grid-area:5/1/6/3;margin:6px 0 0}
  body[data-home-tab="browse"] .home-tab{font-size:.8rem;padding:8px 6px;white-space:nowrap}
}
.browse-head{display:flex;align-items:center;justify-content:space-between;gap:10px}
.browse-head h3{margin:0;font-size:1.25rem}
.browse-list{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:8px;
  max-height:min(46dvh,340px);overflow-y:auto}
/* If no salon is open, the list is not merely empty but gone: as an
   empty box it would go on taking a gap out of the card's spacing,
   and a hole would yawn above the notice for no reason. */
.browse-list:empty{display:none}
/* A grid of two rows instead of a row of three columns:

     [CODE]  painter23        [Join]
     4/8 seats · 1 round · German

   Code and button stand at the top and give up no width; the details run
   below them across the whole card. Previously name AND details shared a
   middle column of barely 180 pixels — "4/8 seats · 1 round · German"
   wrapped onto three lines there, the rows ended up different heights and the
   list looked like a staircase. It is pulled together via a fixed
   row height: every salon is the same height, no matter how long its name is. */
.browse-item{display:grid;grid-template-columns:auto minmax(0,1fr) auto;
  grid-template-areas:"code name join" "sub sub sub";
  align-items:center;column-gap:10px;row-gap:2px;background:var(--paper);
  border:2px solid rgba(74,52,42,.3);border-radius:12px;padding:8px 10px}
.browse-item>.code-chip{grid-area:code}
.browse-item>.btn{grid-area:join}
/* A long artist name must not push the button out of the card. */
.browse-host{grid-area:name;min-width:0;line-height:1.25;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.browse-sub{grid-area:sub;font-size:.72rem;opacity:.65;line-height:1.3;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.code-chip.small{font-size:.85rem;padding:2px 8px}
.check-row{display:flex;align-items:center;gap:8px;font-size:.82rem;opacity:.8;cursor:pointer}
.check-row input{width:18px;height:18px;accent-color:var(--gold);cursor:pointer}

/* ---------- Side by side: the list stands at half height ----------
   The same 772 px as further down — from here on sign-in card and
   salon list stand side by side (430 + 320 + gap), below that the list lies
   in its own row anyway.

   Previously both were flush at the top, and because the sign-in card is almost twice
   as tall, a hole of half a screen height yawned at the bottom right.
   STRETCHING the list to the same height does not fix that, it only moves it
   inside: four salons in an 800 pixel tall box are the same
   emptiness, only framed. So the card goes on growing with its content and
   stands centred beside it — short with four salons, long with twenty, in both
   cases without a hole. */
@media (min-width:772px){
  .home-card.browse{align-self:center}
}

/* ---------- The three ways as a toggle ----------
   NARROW OR SHORT: a tablet in portrait (768) and a phone sideways (390
   tall) both have too little room for all three ways at once, but
   for different reasons — one lacks the width for two cards
   side by side, the other the height for nine rows below one another.
   The same answer helps both.

   660 as the height limit instead of 620, and not one pixel more: a window of
   1180 × 640 — an ordinary laptop with the dev console open — got no tabs,
   therefore showed all the ways below one another, and overflowed. The first
   attempt set the limit at 740 and was too generous: that gave tabs to a
   1280 × 720 laptop window as well, which is the normal case at a desk. The
   tests reported it, because the salon list suddenly lay behind a tab there.
   660 catches the short windows and leaves the ordinary ones alone. */
@media (max-width:900px),(max-height:660px){
  /* Measured, the start page was 1.3 screens long on a phone, and
     most of it was a way the player is not taking right now: whoever
     wants to open swipes past the code field and the salon list; whoever wants to join,
     past "open a new salon". Only ONE of them ever has to be visible.

     What stays at the top is the person — logo, name, portrait. What stands
     below that is decided by the tab. Each of the three views thereby fits entirely
     into the picture; there is no swiping at all any more.

     Steered via an attribute on the <body>, not via classes on each
     individual box: the salon list is a card of its own BESIDE the
     sign-in card, not a child of it — from the inside it could not be
     reached. */
  .home-tabs{display:grid;grid-template-columns:repeat(var(--tabs,3),minmax(0,1fr));
    gap:6px;margin:2px 0 2px}
  /* ON ONE LINE, and that is a correction to a correction: `white-space:normal`
     briefly stood here so that "with code" would not become "with co…" in the
     halved card of the "salons" tab. It made the tabs a shade taller
     everywhere, the card grew upwards — and laid sideways the first tab slid
     under the fixed "?" in the corner. The test on the phone reported it:
     "home-tab — covered by #btn-howto".
     So it stays at one line, and the special case is solved where it arises
     (see .home-tab in the salons wrapper further up, and the narrow-and-tall
     rule below for the languages whose tab names are simply longer). */
  .home-tab{font-family:Nunito;font-weight:900;font-size:.82rem;color:var(--espresso);
    background:#fff;border:2px solid var(--espresso);border-radius:12px;padding:9px 4px;
    cursor:pointer;box-shadow:0 3px 0 rgba(74,52,42,.18);white-space:nowrap;
    overflow:hidden;text-overflow:ellipsis;min-height:44px}
  .home-tab[aria-selected="true"]{background:var(--gold);color:#3a2a10}
  /* NARROW AND TALL — the third place a tab name does not fit, and the only one
     that depends on the language. On an iPhone SE three tabs share 73 pixels
     each; "with code" is "Avec un code" in French, "Con il codice" in Italian,
     "Com código" in Portuguese, and all of them were cut off. Nobody had
     reported it, because a truncated tab is exactly as wide, as tall and as
     tappable as an intact one — it is merely unreadable.

     Wrapping is safe here and nowhere else: the rule needs BOTH a narrow screen
     and a tall one, so it can never reach the case above (laid sideways a phone
     is 390 tall and the tab would slide under the "?"). i18n-layout.mjs sweeps
     all ten languages over all eight sizes and would say so either way. */
  @media (max-width:420px) and (min-height:500px){
    .home-tab{white-space:normal;line-height:1.1;text-wrap:balance;padding:6px 3px}
  }

  .home-tab:focus-visible{outline:3px solid var(--gold);outline-offset:2px}

  /* The separator "OR" explained that two ways lie side by side here.
     Side by side they now lie in the tabs — it has nothing left to
     say. */
  .home-or{display:none}
  body[data-home-tab="join"] .home-act,
  body[data-home-tab="join"] #btn-solo,
  body[data-home-tab="browse"] .home-act,
  body[data-home-tab="browse"] #btn-solo,
  body[data-home-tab="create"] .join-row,
  body[data-home-tab="browse"] .join-row{display:none}
  /* The list of open salons is the third tab — and when it is up,
     the foot with the legal texts steps aside: it belongs to signing in,
     not to browsing, and the list needs the height. */
  body[data-home-tab="browse"] .home-foot{display:none}
  body:not([data-home-tab="browse"]) .home-card.browse{display:none}
  .home-card.browse{margin:0}
  body[data-home-tab="browse"] .browse-list{max-height:min(46dvh,420px)}

  /* ---------- "With code" gets the whole tab ----------
   Side by side, the code field and "join" are one row made of a 110 pixel
   wide box and a wide button next to it — a layout that makes sense as long
   as two other ways still stand above and below it. In a tab of its own it
   no longer does: there the code is the only thing to do, and it sat small
   and on the left in an otherwise empty card.

   So stacked and large. Four capitals with wide letter-spacing are what the
   player is having read out to them by a friend right now — they may look
   like the field on a cinema ticket. */
  body[data-home-tab="join"] .join-row{flex-direction:column;gap:10px}
  body[data-home-tab="join"] .join-row input{width:100%;flex:0 0 auto;
    font-size:1.6rem;letter-spacing:.42em;text-indent:.42em;padding:14px 10px;text-align:center}
  body[data-home-tab="join"] #btn-join{width:100%;font-size:1.1rem;padding:14px 20px}
}

/* ---------- Short windows: the sign-in card gives way ----------
   Measured, the start page did not start scrolling on the phone but already
   on an ordinary laptop: 1280 × 800 overflowed by 18 pixels, a tablet
   sideways by 36. A game whose start page swipes on a laptop looks broken
   before it has even begun.

   Only what costs nothing may give way in the process: the logo (it stays the biggest thing
   on the page, it just does not need 33 % of the height for that) and the gaps.
   Not the buttons, not the name field, not the hit areas in the foot —
   those are the way into the game. */
@media (max-height:940px){
  .logo{width:min(100%,17rem,28dvh)}
  .home-card{gap:10px;padding:22px 26px}
  /* The same move as on the phone: publisher and legal texts share
     a row instead of standing two above one another. The hit areas
     of the three links stay 44 pixels tall. */
  .home-foot{flex-direction:row;flex-wrap:wrap;justify-content:center;align-items:center;
    gap:0 12px;padding-top:8px;margin-top:0}
  .home-foot .fineprint{flex:1 0 100%;font-size:.68rem;line-height:1.3}
  .home-foot .credit{margin:2px 0 0}
  .home-foot .legal-row{margin:0}
}
/* Shorter still (laptop at 800, tablet sideways at 768): the logo goes on
   giving way, the gaps too. It stays the biggest thing on the page. */
@media (max-height:820px){
  .logo{width:min(100%,16rem,24dvh)}
  .home-card{gap:9px;padding:20px 24px}
  .portrait-preview{width:50px;height:50px}
}
/* A rung that was missing. The ladder jumped from 820 to 620, and in between
   lies a whole range of ordinary windows: a laptop at 1180 × 700, a browser
   window with the dev console open, a phone inside another program at
   360 × 640. Measured, they all overflowed — by between 22 and 101 pixels
   depending on the width — and none of the eight test sizes touched the range.
   A dense grid of twenty widths and thirteen heights found it. */
@media (max-height:740px){
  .logo{width:min(100%,15rem,20dvh)}
  .home-card{gap:7px;padding:15px 20px}
  .portrait-preview{width:48px;height:48px}
}
/* And on a really short screen the house motto drops out. It is
   atmosphere, not a way into the game — and "play alone" stands directly above it. */
@media (max-height:620px){
  .home-foot .fineprint{display:none}
  .logo{width:min(100%,15rem,15dvh)}
  /* The big button stays the biggest but gets flatter: it stands out
     here through gold and full width anyway — the extra
     padding costs height that there is nowhere to find at 390 pixels. */
  .btn.solo,.home-act.no-solo #btn-create{font-size:1.08rem;padding:11px 18px}
  /* Publisher and legal texts on ONE row instead of two — and the three
     links no longer wrap below one another, otherwise it would be two again
     after all. The hit areas stay finger-sized (38 px tall).

     "Do not wrap" was taken too literally, though: with flex-wrap:nowrap AND
     justify-content:center the row grew past BOTH screen edges on long words,
     and the first link slid out of the picture on the left. In German it never
     showed ("Datenschutz · Nutzungsbedingungen · Impressum" fits); in Russian
     the same link is called "Конфиденциальность", and the three together are
     wider than an iPhone SE. The row may wrap now — it only does so when it
     must, which is exactly where one line no longer reaches. It wraps BETWEEN
     the links, never inside one: white-space sits on the link, not on the row. */
  .home-foot{gap:0 10px;padding-top:6px}
  .home-foot .legal-row{flex-wrap:wrap;white-space:normal}
  .home-foot .legal-row .linklike{white-space:nowrap}
  .home-foot .credit{margin:0;font-size:.66rem}
  .home-foot .credit-mark img{width:54px}
  .home-foot .legal-row{gap:5px}
  .home-foot .linklike{font-size:.66rem;padding:6px 2px;min-height:38px}
}

/* ---------- The guild as a list ----------
   NARROW OR SHORT, and the comma is the point: the block first stood only
   in the width wrapper, and a phone held sideways (844 wide, 390 tall)
   therefore got the tiled guild — four portraits over half the picture height,
   clipped at 390 pixels. A gallery needs height, not width; where one
   of the two is missing, the list is right. */
@media (max-width:760px),(max-height:620px){
  /*
     One card per player with the portrait at full tile width is the right form on a
     desktop — there it stands next to the painting area and has
     room. On a phone four players are two rows of 150
     pixels each with that, and the 300 pixels decide whether "open the vernissage"
     is still in the picture or not. Laid sideways the same guild costs 110.

     Nothing is lost in the process: portrait, name, capital, crown, guest badge
     and the two buttons all still stand there — only side by side instead of
     on top of one another. The places are expressly assigned (grid-area), because
     badge and buttons previously lay OVER the portrait: in one row there
     is no portrait left with room above it, and without fixed places the
     "NPC" would lie on the name. */
  /* 210 px, not 160: portrait, name, capital, two
     buttons and the guest badge fit on one row. At 160 the name was left with 43 pixels, and
     "Käthe Kollbitz" became "C…" — a guild in which nobody is recognisable
     any more. On a phone that means one player per row; that is still
     a third of the height of the old tiles. */
  /* WITHOUT a cap. A max-height once stood here so that the guild would not
     push everything below it away — and it produced exactly what it was meant
     to prevent: on a 390 phone the list scrolled on the inside AND the page on
     the outside, two scrollbars on top of each other for a card that fits
     entirely into the picture uncapped anyway (a measured 812 of 824 pixels).
     The guild may grow; the start button stands at the end of the card, where
     you look for it. */
  .players{grid-template-columns:repeat(auto-fill,minmax(210px,1fr));gap:8px;margin-bottom:12px}

  /* ---------- The lobby's header bar on ONE row ----------
     "Salon" + code + "copy link" + "leave salon" are together wider than the
     screen at 390 pixels, so the bar wrapped and was 115
     pixels tall — a fifth of the visible height for four words. Measured,
     the start button was then exactly 21 pixels short of the edge. Smaller
     type and tighter buttons win back 59. */
  #screen-lobby .bar{gap:8px;margin-bottom:8px}
  #screen-lobby .bar h2{font-size:1.15rem;display:flex;align-items:center;gap:7px}
  #screen-lobby .bar .btn{font-size:.8rem;padding:7px 11px;white-space:nowrap}
  #screen-lobby .code-chip{padding:3px 9px}
  #screen-lobby #btn-leave{margin-left:0}
  .player-card,.player-card:nth-child(even){
    display:grid;grid-template-columns:auto minmax(0,1fr) auto auto auto;
    align-items:center;column-gap:8px;padding:7px 9px;text-align:left;transform:none}
  .player-card canvas,.player-card img{grid-area:1/1/3/2;width:38px;height:38px;border-radius:50%}
  .player-card .pname{grid-area:1/2/2/3}
  /* A total that wraps is two lines of nonsense: "25,000" above "€". */
  .player-card .pmoney{grid-area:2/2/3/3;white-space:nowrap}
  .player-card .pcard-tools{grid-area:1/3/3/4;position:static;opacity:.75}
  .player-card .pnpc,.player-card .pwatch{grid-area:1/4/3/5;position:static}
  /* The ready sign and "gone" move out of the corners into the row: on a card
     edge 7 pixels high they would otherwise overlap the neighbouring card, and
     the sign at the bottom centre would lie half under the next row. Both share
     the same column — they never appear together (in the lobby nobody is
     disconnected, and mid-game nobody reports ready). */
  .player-card .pready,.player-card .poff{grid-area:1/5/3/6;position:static;transform:none}
  .player-card .pready{width:22px;height:22px}
  .pcard-btn{width:26px;height:26px;font-size:.76rem}
  /* The crown sat above the top right corner of the portrait. The portrait is
     now on the left and round — it moves along. */
  .player-card.host::after{top:-9px;right:auto;left:22px}
}

/* ---------- A short screen: the card gives up only the guild ----------
   Two attempts to fit six settings rows onto a 390 pixel tall screen stood
   here one after the other. The first gave the card a fixed height and let the
   guild and the settings each scroll for themselves: measured, the guild got
   45 pixels for 120 pixels of content, the settings 57 for 234 — two peepholes
   with a line and a half each. The second put them side by side, guild on the
   left, settings on the right; that was more readable, but the settings got
   120 of 258 pixels and went on scrolling in their column.

   Both times the answer to the wrong question was right. Six settings rows do
   not BELONG on a 390 pixel tall screen — they belong on a sheet of their own
   (see .rules-card further up), and what belongs in the card is their result
   as one line. With that the lobby carries the same thing everywhere: heading,
   guild, house rules, start button. Only the guild grows, so only it scrolls —
   the same on every device, with no special rule for short windows. The whole
   block that stood here is gone without replacement. */
@media (max-height:620px){
  /* What is left on a short screen is moving together: the guild's heading and
     the house-rules row each give up a few pixels so that more than one row of
     heads stays visible. */
  #screen-lobby .panel{padding:12px 14px}
  #screen-lobby .panel>h3{margin:0 0 6px;font-size:1.05rem}
  .rules-row{margin-bottom:8px;padding:6px 10px}
  /* The ready bar moves together too — the mark stays, it is the whole point. */
  .ready-meter{margin:0 0 6px}
  .ready-bar{height:10px}
  .ready-count{margin:.3em 0 0;font-size:.7rem}
  .btn.ready{margin-bottom:6px;padding:10px 16px}
  #screen-lobby #players{margin-bottom:8px}
}
/* ---------- Laid sideways: the foot NEXT TO the guild ----------
   A short screen is rarely also narrow — sideways a phone has 844 pixels of
   width and 390 of height. Stacked, 72 of those were left for the guild: less
   than one row of heads, while two thirds of the card stood empty to the right
   of the house rules. Side by side it gets 228 and shows six of eight.

   Only the arrangement turns, not the content: the same heading, the same
   guild, the same foot. And because the house rules would otherwise wrap onto
   four lines in this narrow column, their values stand below one another there
   — a list is more right in a column than a band.

   520 pixels of width, not 640: an iPhone SE sideways is 568 × 320, and
   stacked the card had no room there for guild, house rules AND the start
   button — the button was cut off by the card's `overflow:hidden`. Side by
   side it fits. Below 520 it stays stacked; there is no room for two columns
   there either. */
@media (max-height:620px) and (min-width:520px){
  #screen-lobby .panel{display:grid;
    grid-template-columns:minmax(0,1.45fr) minmax(0,1fr);
    grid-template-rows:auto minmax(0,1fr);
    grid-template-areas:"kopf fuss" "gilde fuss";
    column-gap:16px;align-content:stretch}
  #screen-lobby .panel>h3{grid-area:kopf}
  #screen-lobby #players{grid-area:gilde;margin:0;min-height:0}
  /* `safe center`, for the reason already written down at #screen-home.active
     further up: a container that centres AND scrolls spreads its overflow to
     both ends, and the half above the start is unreachable — scrollTop stops at
     0. The rule was known; this box was made a scroller later, when the lobby
     was laid out in two columns for a phone on its side, and the lesson did not
     come along.

     It cost a finding that only ever appeared on the build server: "#rules-open
     — still covered after swiping". Measured here afterwards, at 568×260 the ✎
     sat at y=61 with its box starting at 83 — twenty-two pixels above the top
     edge, and no swipe reaches them. On this machine that happens from about
     260 pixels of height, over there already at 320: the same fault, one screen
     size earlier, because the type is measured slightly differently. */
  #screen-lobby .lobby-foot{grid-area:fuss;justify-content:safe center;
    min-height:0;overflow-y:auto}
  #screen-lobby .rules-summary{flex-direction:column;flex-wrap:nowrap;gap:2px}
  #screen-lobby .rules-row{flex-wrap:nowrap;align-items:flex-start}
  /* Der Fußraum für die Klangkugel darf hier weg: Sie hängt unten LINKS, und
     links steht in dieser Aufteilung die Gilde — ein Kasten, der ohnehin
     scrollt und unter dem nichts endet. Der Startknopf sitzt rechts. Die 44
     Pixel gehen an die rechte Spalte, der sie auf einem 320 Pixel hohen
     Schirm sonst fehlen: Dort war die Hausordnung oben und „Vernissage
     eröffnen" unten angeschnitten. */
  #screen-lobby{padding-bottom:max(8px,env(safe-area-inset-bottom))}
  #screen-lobby #players{padding-bottom:38px}
}
/* Und auf dem flachsten Schirm wird auch der Startknopf flacher — zweizeilig
   („Vernissage / eröffnen") ist er 90 Pixel hoch, und die hat die Spalte
   nicht. */
@media (max-height:420px){
  #btn-start{font-size:1rem;padding:10px 16px}
}
/* ---------- Why no sticky start button ----------
   A `position:sticky` stood on the start button twice, so that it would stay
   put while swiping, and was discarded twice: the button then floated in the
   middle of the card over a player card or over the "visibility" row — with a
   paper ring around it through which content still peeked out above and below.
   It looked like a fault, not like a footer.

   The question no longer arises: the lobby does not swipe, the button stands
   fixed at the foot of its card, and only the guild above it scrolls. The note
   stays all the same, because the temptation comes back — and with it the
   answer that came before it, which was worse still: forcing the card to a
   fixed height and locking its content into two 50-pixel peepholes. Not
   scrolling is not the same as being readable. */

/* ---------- Ad slots ----------
   Only on screens with no game going on, always below the content and
   never over a button. With no ad delivered the slot stays 0 tall. */
/* The slot always stands in the flow but is zero tall without an ad — room
   is only reserved by crazygames.js, and only if something really arrives. */
.ad-slot{flex-shrink:0;margin:12px auto 0;display:flex;justify-content:center;
  align-items:center;max-width:100%;overflow:hidden}
/* During a video ad the game lies still — for the mouse too. */
body.ad-break .screen{pointer-events:none;filter:saturate(.4) brightness(.85)}

/* On the game screens the leaderboard runs along on the right — exactly where
   the language picker hangs fixed in the picture. The rail therefore moves below the corner
   instead of letting its heading disappear behind it.

   PADDING, NOT MARGIN — and that is not a question of taste. The rail is limited to
   `max-height:100%` so that it never grows past the screen.
   A margin lies OUTSIDE that bound: 46 pixels of margin plus 100 % height is
   together 46 pixels more than the screen is tall. On a phone held
   sideways the rail therefore stuck out at the bottom — the last
   player and the footer were cut off, and the stage next to it was
   computed shorter for it as well. Padding counts towards the height, so
   the bound is right again. */
#screen-critique .rail, #screen-auction .rail, #screen-reveal .rail,
#screen-title .rail, #screen-judging .rail, #screen-draw .rail{
  padding-top:calc(56px + env(safe-area-inset-top))}

@media (max-width:760px){
  #top-corner{top:max(8px,env(safe-area-inset-top));right:max(8px,env(safe-area-inset-right));gap:6px}
  #lang-select{font-size:.8rem;padding:5px 8px}
  #cg-account span{display:none}
  .home-wrap{gap:14px}
  .home-card.browse{padding:18px}

  /* ---------- The foot of the sign-in card ----------
     Small print, publisher and the three legal texts are compulsory, but
     no way into the game. Stacked below one another they cost around 115 pixels
     on a phone — more than "join" and "play alone" together, and
     exactly those pixels are missing further down at the list of open salons. Publisher
     and legal texts therefore share a row. The hit areas of the
     three links stay untouched (44 px, see .linklike). */
  .home-foot{flex-direction:row;flex-wrap:wrap;justify-content:center;
    align-items:center;gap:0 12px;padding-top:8px;margin-top:0}
  .home-foot .fineprint{flex:1 0 100%;font-size:.68rem;line-height:1.3}
  .home-foot .credit{margin:2px 0 0}
  .home-foot .legal-row{margin:0}
}
/* A locked choice stays visible — it merely explains itself instead of taking effect. */
.check-row.off{opacity:.45;cursor:not-allowed}
.check-row.off input{cursor:not-allowed}
.preset:disabled{opacity:.4;cursor:not-allowed;box-shadow:none}

/* ================================================================
   ON THE PHONE
   Everything from here on applies to narrow, short or finger-operated
   screens. The layout for mouse and big screen stays as it
   was — every rule sits in a wrapper that a desktop does not
   enter.
   ================================================================ */

/* ---------- 1. The fixed corner at the top right ----------
   Language and account hang above everything (z-index 95). Where the content reaches to the
   right edge, the button standing there disappears underneath it — in the
   atelier that is "hand in", of all things. The click would then hit the language picker.
   client.js measures the corner and stores its width as --corner-w; the bar
   keeps free exactly as much as the corner really reaches into it. On a
   wide screen that comes out as zero — there nothing changes. */
.bar{padding-right:max(0px,calc(var(--corner-w,0px) + 8px - (100% - min(1120px,var(--wide)))/2))}
/* The same for the lot row: it starts on the left and in the auction runs over
   half the width. It now wraps instead of ending under the corner. */
.lot-chip{max-width:calc(100% - var(--corner-w,0px) - 6px)}
/* If a dialog is open, the corner is only in the way: it lies over the appraisal's
   close cross, and you do not change the language through a window. */
body:has(#screen-home.active) #top-corner,
body:has(#screen-lobby.active) #top-corner,
body:has(#screen-final.active) #top-corner{display:flex}
body:has(.brief:not(.hidden)) #top-corner{visibility:hidden}

/* The start page cannot get out of the corner's way: "refresh" sits at the top
   right in the salon list, and as soon as the list stands BESIDE the sign-in card,
   that is exactly the spot the language picker hangs at. Both only apply in
   a narrow window of screen widths:
     from 772 px  the two cards stand side by side at all
                  (430 + 320 + gap) — below that the list lies far down
     up to 1150 px the list reaches to under the corner; after that the margin is
                  wide enough and nothing changes here
   The list has to give way, not the whole page: making room at the side
   pushed the two cards below one another, and setting the whole page lower
   would push "join" right under the edge. The list, by contrast, has air — it
   ducks under the corner. */
@media (min-width:772px) and (max-width:1150px){
  .home-card.browse{padding-top:calc(var(--corner-h,42px) + 14px + env(safe-area-inset-top))}
}

/* Keeping room free alone is not enough on a phone: "German" plus the arrow
   is 110 of 390 pixels, and the header bar in the atelier already carries a candle,
   a clock, "commission" and "hand in" — the candle shrank to a stub.
   The picker therefore becomes a button: the globe stands there visibly, the
   select lies invisibly over it and opens the system's list with
   all the language names written out. The paint tube in the paintbox already
   uses the same trick. */
@media (max-width:560px){
  .lang-pick{position:relative;display:grid;place-items:center;width:44px;height:40px;
    background:#fffdf7;border:3px solid var(--espresso);border-radius:12px;
    box-shadow:0 3px 0 rgba(74,52,42,.18)}
  .lang-pick::after{content:"🌐";font-size:1.05rem;pointer-events:none}
  .lang-pick:focus-within{outline:3px solid var(--gold)}
  #lang-select{position:absolute;inset:0;width:100%;height:100%;
    padding:0;border:0;opacity:0;box-shadow:none;background:none}
  /* The buttons of the header bar keep their width — what should shrink is the
     candle, not the labelling. */
  .bar .btn{flex:0 0 auto;white-space:nowrap}
  .candle-wrap{min-width:52px}
}

/* ---------- 2. Finger-sized targets ----------
   An index finger hits about 9 mm — a mouse hits a point. Where the game is played
   with a finger, the smallest targets grow: the paintbox (in the atelier the
   most-tapped button of all), the tools, the cross on a dialog. */
@media (pointer:coarse){
  .swatches button,.swatch-picker{width:32px;height:32px}
  .swatches.vertical{grid-template-columns:repeat(3,32px)}
  .tools{grid-template-columns:repeat(2,50px)}
  .tool{width:50px;height:50px}
  .modal-x{width:40px;height:40px;top:7px;right:8px}
  .check-row input{width:22px;height:22px}
  .browse-list{max-height:min(40dvh,340px)}
  /* iOS zooms into every field whose type is smaller than 16px when tapped
     — and does not zoom back out again by itself afterwards. The page would stay
     shifted, in the middle of the auction. Sideways the base type shrinks
     to 13px; the fields expressly do not take that step along. */
  input,select,textarea{font-size:max(16px,1rem)}
  /* The sound button hangs fixed at the bottom left of the picture — 36 pixels
     tall, 8 from the edge. 58 pixels of footroom once stood here, because
     these three pages scrolled and nothing was allowed to END underneath the
     button. They do not scroll any more; the only thing left is that the start
     button must not peek out from under the sound bubble. For that 44 is
     enough — and the 14 pixels saved are half a player card on a phone held
     sideways. */
  #screen-lobby,#screen-final,#screen-standings{
    padding-bottom:calc(44px + env(safe-area-inset-bottom))}
}

/* ---------- 3. Portrait or narrow ----------
   The same wrapper as further up in the stylesheet: where the leaderboard slides as a band under the
   stage and the commission goes as a strip over the canvas. */
@media (max-width:760px),(max-aspect-ratio:6/5){
  /* The sound button sits fixed at the bottom left — exactly where the leaderboard lies
     as a band. The band moves past it instead of beginning underneath it. */
  .rail{margin-left:calc(44px + env(safe-area-inset-left))}
  /* Laid sideways the rail lies at the bottom, not at the top right — the padding that
     let it duck under the language corner on the desktop would only be a
     46 pixel tall hole in the middle of the picture here. The canvas gets it back. */
  #screen-critique .rail, #screen-auction .rail, #screen-reveal .rail,
  #screen-title .rail, #screen-judging .rail, #screen-draw .rail{padding-top:6px}
  /* The commission strip: epoch and motif share one row as long as
     both get 15rem each — otherwise each stands on its own. Previously
     a single row forced truncations down to "I…". */
  .hud-inner{flex-wrap:wrap;gap:3px 14px}
  .brief-hud .hud-block{flex:1 1 auto;min-width:min(100%,15rem)}
  .brief-hud .hud-value{flex:1;min-width:0}

  /* The start page carries two cards — its own and the list of open salons.
     Stacked below one another they no longer fit on a small phone, and
     .screen clips instead of scrolling: on an iPhone SE
     "refresh" and the language filter lay out of reach below the edge. The
     start page is the only page of the game allowed to swipe — "open a new salon"
     and "join" still stand in the picture without swiping. */
  #screen-home.active{overflow-y:auto}
}

/* ---------- 3b. Only really narrow ----------
   From here on everything stands below one another (see the one-column rule further up).
   Deliberately without the aspect-ratio branch: a flat window on the desktop
   is "landscape", true, but has room enough — there nothing should budge. */
@media (max-width:760px){
  /* The one-column grid and the sticky bid card stand further up in the
     orientation wrapper — here only what REALLY hangs on the width remains:
     that everything is set more tightly. */
  .bid-panel{padding:11px 13px}
  .auction-note{font-size:.76rem;padding:5px 8px;margin-bottom:6px}
  .auction-clock{margin-bottom:7px}
  .current-bid{font-size:1.9rem}
  .leader{min-height:30px;font-size:.9rem}
  .leader img{width:30px;height:30px}
  .bid-buttons{gap:7px;margin:9px 0 7px}
  .bid-buttons .btn{padding:10px 14px;font-size:.92rem}
  .custom-bid input{width:auto;flex:1;min-width:0}
  .bid-panel .muted{font-size:.78rem;margin:.4em 0 0}

  /* The unveiling: piece and numbers run through underneath the foot instead of pushing it out
     of the picture. The running-through itself now stands as a base rule
     at .reveal-grid — here only the tight setting remains. */
  #screen-reveal .easel{--easel-h:23dvh}
  .reveal-grid{align-items:start;gap:12px}

  /* ---------- The lobby on a phone ---------- */
  .lobby-grid{gap:12px}
  .panel{padding:14px}
  /* The start button is the only button everybody is waiting for. */
  #btn-start{width:100%;transform:none}
}

/* ---------- 4. Sideways and flat ----------
   Between 760 and 940 pixels of width neither of the two layouts takes hold:
   a phone held sideways gets the desktop view at 390 pixels of
   height. On top of that --wide (min(94vw,165dvh)) chokes the stage at the height — on
   844 × 390, 643 of 844 pixels of width were left and 174 pixels for
   the canvas. Here the width gives back what the height does not provide.

   WITHOUT `pointer:coarse`, and that is a correction: the wrapper was once called
   "the phone is lying sideways" and therefore asked for a finger. A flat
   window, though, is not a device but a measurement — a halved screen,
   a browser window with the developer console open, a television in a
   16:9 crop. All three needed the same tighter spacing and did not get
   it, because a mouse hung on it. Along the way that also makes the branch
   testable in the first place: a test browser reports `pointer:fine`, so
   not one line of this ever ran through the tests. */
@media (orientation:landscape) and (max-height:560px){
  :root{--wide:96vw}
  /* The floor of 16px stems from the time when every screen was tall enough.
     Sideways the height is tight — the type may shrink along. */
  html{font-size:clamp(13px, min(.62vw + 9px, 1.35dvh + 8px), 19px)}
  .screen{padding-top:max(6px,env(safe-area-inset-top));padding-bottom:max(6px,env(safe-area-inset-bottom))}
  .bar{margin-bottom:6px}

  /* Atelier: note and tools make themselves narrow, the canvas takes the
     room. The toolbar stands in three columns — in one column it ran out of
     the picture at the bottom, and "undo" was no longer reachable. */
  .brief-hud{width:clamp(126px,17vw,190px);margin-top:6px;padding:11px 10px 9px}
  .hud-tips{display:none}
  .tools{grid-template-columns:repeat(3,44px);gap:6px}
  .tool{width:44px;height:44px;font-size:1.15rem}
  .swatches.vertical{grid-template-columns:repeat(5,24px);gap:5px}
  .swatches button,.swatch-picker{width:24px;height:24px}
  .sizes{grid-template-columns:repeat(4,32px)}
  .sizes button{width:32px;height:32px}
  /* The rail gets narrower but not tighter: a stump of a name ("A…") and
     a cut-off total ("2…") are worse than no rail at all.
     The portrait gives up the pixels the number needs. */
  .rail{width:clamp(136px,17vw,166px)}
  .rail-list{padding:8px 5px 3px;gap:6px}
  .rail-item{padding:3px 4px;gap:4px}
  .rail-av{width:22px;height:22px}
  .rail-head{margin-bottom:5px}
  /* The rail stood 46px lower in order to get through under the corner — in the
     atelier the header bar already pushes it almost underneath anyway. */
  #screen-draw .rail{padding-top:8px}
  /* Sideways the corner at the top right is flatter (see .lang-pick further up), and
     the rail needs every pixel for the names below it. */
  #screen-critique .rail, #screen-auction .rail, #screen-reveal .rail,
  #screen-title .rail, #screen-judging .rail{padding-top:calc(48px + env(safe-area-inset-top))}

  /* Stage, auction, unveiling: set more densely, so that buttons and clock stay in
     the picture without scrolling. */
  /* Tighter at the top and bottom only. The SIDE padding belongs to the
     curtains (see --curtain-w at .stage) — flattening it here would mean
     laying the piece and the speech bubble on the red stripes. That is exactly
     what this line did while it still read `padding:12px 16px 10px`: at
     1151 × 560 this wrapper takes hold, overrode the desktop layout's side
     padding, and the speech bubble ran into the right-hand curtain. */
  .stage{padding-block:12px 10px}
  .lot-chip{margin-bottom:7px}
  .easel{--easel-h:30dvh}
  #screen-auction .easel.small{--easel-h:26dvh}
  #screen-reveal .easel{--easel-h:34dvh}
  .critic-figure{width:64px;height:64px;font-size:2.4rem}
  .bubble{padding:10px 12px}
  .bid-panel{padding:10px 12px}
  .auction-note{font-size:.72rem;padding:4px 7px;margin-bottom:5px}
  .auction-clock{margin-bottom:6px}
  .current-bid{font-size:1.8rem;margin:0}
  .leader{min-height:26px}
  .leader img{width:26px;height:26px}
  .bid-buttons{gap:6px;margin:7px 0 6px}
  .bid-buttons .btn{padding:8px 12px;font-size:.9rem}
  .bid-panel .muted{font-size:.75rem;margin:.3em 0 0}
  .dossier{margin-top:8px;padding:8px 10px}
  .dossier-critique{max-height:4.4em}
  .reveal-facts p{margin:.2em 0}

  /* The commission card: the curtain at the top costs 68px out of 390. */
  .brief-card{padding:16px 18px 14px;max-height:96dvh}
  .brief-card::before{display:none}
  .brief-head{font-size:1.6rem}
  .brief-sub{margin-bottom:10px}
  .brief-big{font-size:1.25rem}
  .brief-big.handwriting{font-size:1.7rem}
  .brief-body{padding:12px;gap:14px}
  .brief-public{margin-top:10px;font-size:.8rem}
  .brief-foot{margin-top:12px}

  /* ---------- Sideways: the sign-in card becomes two-column ----------
     Below one another this card is around 540 pixels tall. A phone held
     sideways has 390, and swiping only helped so far: the third way into the game —
     "play alone", the fastest of them all — lay below the edge, and
     whoever did not know it did not find it.

     Side by side the same card fits. On the left stands who you are (logo,
     name), on the right where you want to go (open, join, play alone). The
     places are assigned individually instead of filled in order: two of the nine
     children are hidden most of the time (the rush notice and the notice
     about the locked name field), and an automatically filled grid
     would shift the whole right column with each of them. */
  #screen-home.active{overflow-y:auto}
  .home-card{display:grid;grid-template-columns:minmax(0,.92fr) minmax(0,1.12fr);
    column-gap:20px;row-gap:6px;align-items:center;
    max-width:700px;padding:14px 18px}
  /* On the left who you are — on the right where you want to go. The two ways (open,
     join) share THE SAME cell: only one is visible at a time
     anyway, and the tab above decides that. That way the card stays the same
     height, whichever way is currently open. */
  /* The portrait field stands ACROSS THE WHOLE WIDTH, not in the left column.
     There it was 95 pixels wide and showed 2.4 of six faces — the third one
     cut through in the middle. An offer you cannot see is no offer; and a
     halved circle looks like a fault, not like a strip. Across the full card
     it is 640 pixels and all six stand there, at finger size.
     That is paid for with the logo: it gives up 21 pixels of height here
     (16dvh instead of 27). At 390 pixels of height it is only a mark anyway,
     not an eye-catcher — and a face you can tap is the more useful of the
     two. */
  .logo{grid-area:1/1;width:min(100%,16dvh)}
  #home-busy{grid-area:2/1;margin:0}
  #name-input{grid-area:3/1}
  #name-locked-note{grid-area:4/1}
  /* Kept free is what the corner really covers of the card, not how wide the
     corner is: it hangs at the right edge of the SCREEN and the card ends well
     before that. --corner-over is measured by client.js on both boxes; with the
     full width the three tabs were left 157 pixels instead of 234, and at 48
     each even "Mit Code" was cut off.
     From 700 pixels of card width that is affordable — below it is not, see
     the row-of-its-own further down. */
  #home-tabs{grid-area:1/2;margin:0 var(--corner-over,0px) 0 0}
  /* What the corner takes away, the type wins back: three tabs then share 234
     instead of 356 pixels, and "with code" would need 70 of 74 at full size.
     Set smaller it is 62 — tight, but whole. Tighter rather than on two lines,
     because the card has only 18 pixels of air below it here (and laid sideways
     a wrapped tab slides under the "?" — see the note on white-space above). */
  .home-tab{font-size:.74rem;padding:9px 3px}
  /* And NOT in three equal parts. Thirds give every tab the same width, so they
     are cut to fit the AVERAGE word — whichever language is above it loses its
     ending. Here that was Portuguese: "Com código" wants 69 pixels and gets 67,
     while "Criar" beside it leaves 30 unused. At 13-pixel root type there is
     nothing left to shrink; the answer is not smaller type but a fairer share.
     Divided by content each tab takes what its word needs, the short ones give
     up what they do not, and the rule holds in all ten languages instead of
     being tuned to one. */
  #home-tabs{display:flex;gap:5px}
  #home-tabs .home-tab{flex:1 1 auto;min-width:0}
  .home-act,.join-row{grid-area:2/2/4/3;align-self:center}
  .portrait-row{grid-area:4/1/5/3;gap:14px}
  .home-foot{grid-area:5/1/6/3;margin:0;padding-top:6px}
  /* At full width the faces may give something up too. */
  .portrait-preview{width:52px;height:52px}
  .portrait-preset{width:40px;height:40px}
  .final-wrap{margin:8px auto}
}

/* ---------- 5. Very narrow ----------
   From here on every millimetre counts: iPhone SE (320) and everything below. */
@media (max-width:400px){
  .home-card{padding:22px;gap:12px}
  .join-row input{width:96px}
  .btn{padding:11px 16px}
  .btn.big{font-size:1.1rem;padding:14px 22px}
  /* The guild already stands here as a list (see above) — at 320 pixels exactly
     one player fits per row, and that is the right number. A second one
     beside it would leave four letters of each of the two names. */
  .players{grid-template-columns:1fr;gap:7px}
  /* At 320 pixels "15 s", "20 s", "30 s", "45 s" only fit on one row if the
     buttons sit tighter — otherwise four buttons wrap onto two rows, and six
     settings rows become ten. */
  .preset{padding:4px 8px;font-size:.76rem}
  .guest-step .preset{padding:4px 7px;min-width:32px}
  .price-grid{grid-template-columns:1fr}
  .final-list li{padding:9px 12px;gap:9px}
  /* The lot row of the auction is a whole sentence — in large type that would be
     three lines, and those are missing from the piece below. */
  .lot-chip{font-size:.85rem;padding:3px 10px;margin-bottom:8px}
  /* A name must not push the total out of the row. */
  .rail-name{max-width:66px}

  /* The header bar in the atelier no longer carries everything at 320 pixels: candle,
     clock, "commission" and "hand in" together are wider than the screen —
     and whatever sticks out ends up under the corner at the top right. The digital clock
     goes first: the candle shows the same time, only more insistently. */
  .bar{gap:8px}
  .bar .btn{padding:7px 10px;font-size:.8rem}
  #draw-timer{display:none}
  .candle-wrap{min-width:40px}

  /* The commission strip and the rail give height up to the canvas —
     on such a short screen it is otherwise barely bigger than a postage stamp. */
  .brief-hud{padding:6px 10px}
  .hud-value{font-size:.92rem}
  .hud-value.handwriting{font-size:1.15rem}
  .brief-label{font-size:.58rem;letter-spacing:.14em}
  .swatches button,.swatch-picker{width:28px;height:28px}
  .sizes button{width:34px;height:34px}
  .tool{width:42px;height:42px;font-size:1.15rem}
  .draw-wrap{gap:9px}
  .rail-av{width:22px;height:22px}
  .rail-list{padding:8px 7px 3px}

  /* The bid card has to fit entirely into the picture — it sticks to the bottom edge, and
     whatever sticks out past its edge is unreachable with any swipe. */
  .bid-panel{padding:9px 10px}
  .auction-note{font-size:.7rem;padding:4px 6px;margin-bottom:5px}
  .current-bid{font-size:1.6rem}
  .current-bid-label{font-size:.66rem}
  .leader{min-height:26px;font-size:.82rem}
  .leader img{width:26px;height:26px}
  .bid-buttons{gap:6px;margin:7px 0 6px}
  .bid-buttons .btn{padding:9px 11px;font-size:.86rem}
  /* No font-size here: the 16px rule for input fields further up stops
     iOS from zooming into the field when it is tapped. */
  .custom-bid input{padding:9px 10px}
  .bid-panel .muted{font-size:.72rem}
}

/* The leaderboard is always under time pressure — cut-off numbers are
   worse there than cut-off names. Both now get an ellipsis
   instead of running past the edge of their card. */
.rail-val{min-width:0}
.rail-total{min-width:0;overflow:hidden;text-overflow:ellipsis}

/* The statistics switch in the privacy box. A consent, not a button:
   hence a row with a checkbox and not the gold button beside it. */
.privacy-toggle{margin:12px 0 2px;font-size:.86rem;line-height:1.4}
.privacy-toggle label{display:flex;align-items:flex-start;gap:9px;cursor:pointer}
.privacy-toggle input{margin-top:.2em;width:17px;height:17px;accent-color:var(--gold);flex:0 0 auto}

/* ---------- Almost square and short ----------
   A window like 500 × 500 or 460 × 540 is neither phone nor desk: it gets the
   stacked sign-in card (the width for the two-column arrangement is missing)
   and still has only half a screen of height. Measured, the card was 516
   pixels tall there in a 500 pixel window.

   Again only padding and gaps may give way — the buttons keep finger size, the
   name field its 16 pixel type (otherwise iOS zooms in on a tap and does not
   come back by itself). */
@media (max-height:560px){
  .home-card{gap:6px;padding:13px 18px}
  .home-act{gap:6px}
  .home-act .btn{font-size:1rem;padding:9px 16px}
  .portrait-preview{width:44px;height:44px}
  .portrait-preset{width:36px;height:36px}
  .check-row{font-size:.78rem}
  .check-row input{width:19px;height:19px}
}

/* ---------- Sideways and NARROW: the tabs get a row of their own ----------
   A window like 460 × 360 — a game somebody opened inside another program — is
   sideways and cramped all the same. The sign-in card stands two-column there,
   and 210 pixels fit into the right column. Of those the tab strip keeps the
   fixed corner free (about 85), leaving 125 for three tabs: 36 pixels each.
   "Spielen", "Mit Code" and "Salons" shrank to three vertical letters — S, M,
   S — and a finger no longer hit them either.

   Measured across the widths: 844 gives every tab 67 pixels, 700 only 55, 600
   49, 460 then 36 — and 55 is already one pixel too few for "Mit Code". Below
   760 the row simply does not have it any more, and no type size rescues that,
   because the finger width is missing too.

   So there the strip takes a row for itself, across the WHOLE card: 382 pixels
   at 460, so 121 per tab. It then sits below the portrait strip, far away from
   the corner — and within thumb reach, which is no disadvantage on a device
   held sideways.

   The new row (52 pixels) is paid for in five places that take it more easily:
   crest, faces, button padding, line spacing, foot. The card was 357 pixels
   tall before at 360 pixels of window height — it overflowed even then, and
   afterwards no longer. */
@media (orientation:landscape) and (max-height:560px) and (max-width:759px){
  #home-tabs{grid-area:5/1/6/3;margin:6px 0 0}
  .home-foot{grid-area:6/1/7/3}
  .home-tab{font-size:.8rem;padding:8px 6px;min-height:40px}
  /* The five places that give way for it. */
  .logo{width:min(100%,11dvh)}
  .home-card{row-gap:4px;padding:10px 14px}
  .portrait-preview{width:42px;height:42px}
  .portrait-preset{width:34px;height:34px}
  .portrait-row{gap:9px}
  /* Both ways, not only the big one: "open a new salon" carries no .big and
     would otherwise have been the only one left standing at full height. */
  .home-act .btn{font-size:1rem;padding:9px 16px}
  .home-act{gap:6px}
  #name-input{padding:9px 12px;font-size:1rem}
  .check-row{font-size:.78rem}
  .check-row input{width:19px;height:19px}
  .home-foot{padding-top:4px}
  .home-foot .credit{font-size:.62rem}
  .home-foot .linklike{font-size:.62rem;padding:4px 2px;min-height:32px}
  /* On the "Salons" tab the list lies below the sign-in card — a 460 pixel
     wide window is too narrow for two cards side by side. So that the page
     still does not swipe, the stack itself becomes a column in window height:
     the sign-in card keeps its height, the list gets the rest and scrolls
     inside it. */
  body[data-home-tab="browse"] .home-wrap{flex-direction:column;flex-wrap:nowrap;
    height:100%;gap:10px}
  body[data-home-tab="browse"] .home-wrap>.home-card{flex:0 0 auto;width:100%;max-width:none}
  body[data-home-tab="browse"] .home-card.browse{flex:1 1 auto;min-height:0;
    display:flex;flex-direction:column;padding:12px 16px;gap:7px}
  body[data-home-tab="browse"] .browse-list{flex:1 1 auto;min-height:0;max-height:none}
}

/* ---------- Narrow AND short at the same time ----------
   A window of 412 × 460 is narrower than any phone and shorter than any — that
   is what happens when a game opens inside another program in a cut-out.
   Stacked, 22 pixels were missing there. */
@media (max-height:500px) and (max-width:460px){
  .logo{width:min(100%,10dvh)}
  .home-card{gap:5px;padding:11px 14px}
  .portrait-preview{width:40px;height:40px}
  .portrait-preset{width:33px;height:33px}
  .home-act .btn{padding:8px 14px;font-size:.96rem}
  .home-foot .credit,.home-foot .linklike{font-size:.6rem}
  .home-foot .linklike{min-height:30px;padding:3px 2px}
}

/* ---------- Quite flat: the stage cuts off its own foot ----------
   At 568 × 320 and 460 × 400 the stage was 189 and 269 pixels tall, its content
   296 and 333 — the easel alone took 180 to 217. What lay below that was cut
   off by `overflow:hidden`: "next ▶" and "report this work" stood in the window
   but no longer on the stage, and a finger tap hit nothing. The same trap as
   once in the reveal, only one step further down the size table.
   The picture gives way; the foot stays. It is the way onward, and the picture
   one has just seen. */
@media (max-height:420px){
  #screen-critique .easel{--easel-h:min(30dvh,34vw)}
  #screen-auction .easel.small{--easel-h:min(26dvh,30vw)}
  #screen-reveal .easel{--easel-h:min(34dvh,34vw)}
}

/* ---------- Quite flat: iPhone SE sideways (568 × 320) ----------
   The flattest devices there still are. Every row counts double here: measured,
   25 pixels were missing, and they sit in the foot and in the portrait strip.
   The three legal links stay — they have to stand there — but as finger targets
   of 30 instead of 38 pixels in height. */
@media (orientation:landscape) and (max-height:400px){
  .logo{width:min(100%,9dvh)}
  .home-card{row-gap:2px;padding:7px 12px}
  .home-foot .linklike{min-height:28px}
  .portrait-preview{width:38px;height:38px}
  .portrait-preset{width:32px;height:32px}
  .portrait-row{gap:7px}
  .home-act .btn{padding:6px 14px}
  .home-tab{min-height:36px;padding:6px 6px}
  .home-foot{padding-top:1px}
  .home-foot .linklike{min-height:30px;padding:3px 2px}
}

/* ---------- The smallest screen there still is ----------
   iPhone SE in portrait: 320 × 568. The start page was the last page of the
   game that still swiped — a measured 83 pixels past the edge, and at the
   bottom the publisher credit hung half in nothing.

   Only what costs nothing may give way: the logo (it stays the biggest thing
   on the page) and the gaps. The buttons, the name field, the faces and the
   tabs keep every pixel — that is the way into the game, and a cramped way
   into the game is worse than a smaller crest.

   Height AND width in the wrapper: a 320 pixel wide but tall window does not
   have the problem, and a 900 pixel wide, short one is a desktop at half
   window height — a postage-stamp logo would only be ugly there. */
@media (max-height:740px) and (max-width:430px){
  .logo{width:min(100%,11rem,10dvh)}
  .home-card{gap:5px;padding:12px 16px}
  .home-act{gap:6px}
  .home-foot{padding-top:4px}
  .home-foot .credit-mark img{width:46px}
  /* The three legal links wrap onto two lines here — they have to, because
     "Конфиденциальность · Условия · Выходные данные" is wider than an iPhone
     SE. Two lines at 38 pixels each are 76 of 568; at 32 they are 64, and the
     finger still finds them. */
  .home-foot .linklike{min-height:32px;padding:4px 2px}
}

/* ---------- The cursor ----------
   Two drawn arrows instead of the system cursor: espresso as long as there is nothing
   to get, and gold over everything that can be pressed. Both carry a
   light outline so they do not disappear on the dark stage either.

   RIGHT AT THE END, and the classes stand individually instead of just `button`. Both
   for the same reason: spread across the file, `.btn`, `.tool`,
   `.preset`, `.linklike` and a dozen others set their own `cursor:pointer`.
   A selector `button` (0-0-1) loses against each of these classes (0-1-0),
   however far down it stands — on the first attempt "open a new salon"
   therefore went on carrying the system cursor. The same weight class plus
   the last line wins.

   Only on devices with a real pointer. A finger has none, and a phone
   would otherwise compute two images nobody ever gets to see.

   NOT touched: the two canvases. There `cursor:none` stands, and the
   brush circle (.brush-cursor) takes over — it shows the stroke width, and
   an arrow next to it would be a second cursor in the picture. */
@media (hover:hover) and (pointer:fine){
  :root{
    --cur-arrow:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24'%3E%3Cpath d='M3 2 L3 17.6 L7.3 13.7 L9.9 19.7 L12.7 18.4 L10.1 12.6 L15.8 12.3 Z' fill='%234A342A' stroke='%23F5EBD8' stroke-width='1.7' stroke-linejoin='round'/%3E%3C/svg%3E") 3 2;
    --cur-hand:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='26' height='26'%3E%3Cpath d='M3 2 L3 17.6 L7.3 13.7 L9.9 19.7 L12.7 18.4 L10.1 12.6 L15.8 12.3 Z' fill='%23D4A437' stroke='%234A342A' stroke-width='1.7' stroke-linejoin='round'/%3E%3C/svg%3E") 3 2;
  }
  body{cursor:var(--cur-arrow),auto}
  button,select,summary,[role="button"],
  .btn,.linklike,.check-row,.preset,.tool,.pcard-btn,.audio-toggle,.audio-btn,
  .swatches button,.swatch-picker,.sizes button,.gal-frame,.dl-btn,.modal-x,
  input[type=checkbox],input[type=range],
  /* The three language pickers carry an ID or classes of their own and would
     otherwise be the only ones still standing there with the system cursor. */
  #lang-select,.room-lang,.browse-lang{cursor:var(--cur-hand),pointer}
  /* What does not work does not look like it either. */
  .btn:disabled,button:disabled,input:disabled,select:disabled,
  .check-row:has(input:disabled){cursor:var(--cur-arrow),not-allowed}
  /* Text stays text: a drawn arrow over an input field
     would keep quiet about the fact that you can type there. */
  input[type=text],input:not([type]),textarea{cursor:text}
}

/* Spectators: they see everything but do not intervene. The notice stands in the
   way of the bid field so that nobody types in vain. */
body.spectator .bid-buttons,body.spectator .bid-custom{opacity:.45;pointer-events:none}

/* The spectator's waiting card lies in the same section as the
   critic's and swaps with it while the others are painting. Afterwards — when the
   critic really is looking — his stands there again: the spectator then waits
   for the same thing as everybody else. */
/* The eye on a spectator's card — on the left, because the guest badge sits on the
   right. */
.player-card .pwatch{position:absolute;top:6px;left:6px;z-index:2;
  font-size:.72rem;line-height:1;padding:3px 5px;border-radius:7px;
  background:var(--espresso);opacity:.9}

#watch-card{display:none}
body.watching-draw #judging-card{display:none}
/* flex, not block: .center-card centres via flex-direction/align-items —
   switched to display:block the eye slid to the left and the card out
   of the middle. */
body.watching-draw #watch-card{display:flex}
#watch-card .critic-figure{animation:none}

/* "Running" in the salon list: the dot pulses so the row can be found
   without reading — next to it stand lobbies in which nothing is happening yet.
   The row itself gets a red edge: it does not truncate with an
   ellipsis and therefore carries on narrow screens too. */
.browse-item.running{border-left-width:6px;border-left-color:var(--curtain,#B8302F)}
.browse-live{display:inline-flex;align-items:center;gap:.34em;margin-right:.5em;
  font:600 .68rem/1 var(--ui,inherit);letter-spacing:.06em;text-transform:uppercase;
  color:#fff;background:var(--curtain,#B8302F);border-radius:999px;padding:.28em .6em;
  vertical-align:middle}
.browse-live::before{content:"";width:.44em;height:.44em;border-radius:50%;background:#fff;
  animation:live-blink 1.6s ease-in-out infinite}
@keyframes live-blink{0%,100%{opacity:1}50%{opacity:.25}}
@media (prefers-reduced-motion:reduce){.browse-live::before{animation:none}}
