  :root{
    --wall:#8f9296; --wall-dark:#75787c; --wall-line:#7c7f83;
    --floor:#5c6570; --floor-dark:#4a525c;
    --desk:#d3c4a0; --desk-dark:#b5a67e; --desk-edge:#8c7d5c; --desk-hi:#e0d3b0;
    --monitor:#26251f; --monitor-glow:#8fe0a0; --monitor-bez:#3a3830;
    --skin:#e3b98d; --shirt:#e9edf1; --tie:#8a2b2b;
    --hair:#4a3826; --ink:#201d16;
    --danger:#c23b3b; --warn:#d9a53d; --good:#5c9a5f; --gold:#e0b23a;
    --panel:#23241d; --panel-light:#33352a; --text:#f4efe0; --text-dim:#b9b39a;
    --shade: rgba(20,17,10,0.28);
    --hi: rgba(255,255,255,0.16);
  }
  *{box-sizing:border-box;}
  /* Stops a rapid double-tap on any button from being read as the browser's
     zoom gesture on mobile. No effect on desktop -- this is purely a touch
     concern, not a layout one. */
  button, .iconbtn, .tabbtn, .supportbtn{ touch-action:manipulation; }
  html,body{height:100%;}
  body{
    margin:0; min-height:100%; background:#111008;
    background-image: radial-gradient(ellipse at 50% 0%, #1c1a12 0%, #0d0c08 70%);
    display:flex; align-items:center; justify-content:center;
    font-family:'VT323','Courier New',monospace; color:var(--text); padding:16px;
  }
  button{ font-family:inherit; }
  .cabinet{
    /* Grows to fill more of the browser viewport on large screens instead of
       sitting in a small fixed box, capped by whichever of these binds first:
       an absolute ceiling (1000px), 92% of viewport width, or a height-derived
       ceiling that keeps .cabinet's total height within 88% of viewport height.
       .cabinet's height = .stage's height (3/4 of .cabinet's inner width, via
       aspect-ratio) + ~193px of titlebar/status-row/coffee-button/padding/
       border chrome above and below the stage (measured directly, not a
       theoretical estimate) + 32px of body padding. On a short window this
       naturally settles back near the original 640px rather than overflowing.
       dev.html overrides this below to also clear its fixed dev bar. */
    width:100%; max-width:min(1000px, 92vw, calc((88vh - 225px)/0.75 + 28px)); background:var(--panel);
    border:4px solid var(--ink); box-shadow:0 0 0 2px #000, 8px 8px 0 rgba(0,0,0,0.5);
    padding:10px; position:relative;
  }
  .titlebar{ display:flex; align-items:center; justify-content:space-between; padding:2px 6px 10px 6px; }
  .titlebar h1{ font-family:'Press Start 2P',monospace; font-size:13px; margin:0; color:var(--gold); letter-spacing:1px; text-shadow:2px 2px 0 var(--ink); }
  .titlebar .btns{ display:flex; gap:6px; position:relative; }
  /* Held open from the sound button. Width is the span the panel is meant to
     cover -- the stats button's left edge to the sound button's right edge --
     which at 32px buttons and 6px gaps is three buttons plus two gaps. Right
     aligned to .btns so it stays put if buttons are ever added on the left.
     z-index because .stage is positioned and comes later in the document, so
     without it the scene paints over the panel; this is HUD chrome sitting
     above the stage, not part of the scene's own paint order. */
  /* Hidden with opacity+visibility rather than display, so it can fade rather
     than blink out when it times out or is dismissed. The delayed visibility
     transition is what keeps it hit-testable and painted for the length of the
     fade; on the way in, .show overrides that so it appears promptly. */
  .volumePanel{
    position:absolute; top:calc(100% + 5px); right:0; z-index:30;
    width:108px; display:flex; flex-direction:column; gap:5px;
    background:var(--panel-light); border:2px solid var(--ink);
    box-shadow:2px 2px 0 var(--ink); padding:6px 7px;
    opacity:0; visibility:hidden; pointer-events:none;
    transition:opacity 350ms ease, visibility 0s linear 350ms;
  }
  .volumePanel.show{
    opacity:1; visibility:visible; pointer-events:auto;
    transition:opacity 120ms ease;
  }
  .volRow{ display:flex; align-items:center; gap:5px; cursor:pointer; }
  .volIcon{ font-size:11px; line-height:1; color:var(--text); width:10px; text-align:center; flex:none; }
  .volumePanel input[type=range]{
    -webkit-appearance:none; appearance:none; flex:1; min-width:0;
    height:4px; background:var(--ink); outline:none; cursor:pointer;
  }
  .volumePanel input[type=range]::-webkit-slider-thumb{
    -webkit-appearance:none; appearance:none; width:8px; height:14px;
    background:var(--gold); border:1.5px solid var(--ink); cursor:pointer;
  }
  .volumePanel input[type=range]::-moz-range-thumb{
    width:8px; height:14px; border-radius:0;
    background:var(--gold); border:1.5px solid var(--ink); cursor:pointer;
  }
  .iconbtn{ background:var(--panel-light); border:2px solid var(--ink); color:var(--text); width:32px; height:32px; font-size:16px; cursor:pointer; display:flex; align-items:center; justify-content:center; box-shadow:2px 2px 0 var(--ink); }
  .iconbtn svg{ flex-shrink:0; }
  #terminalBtn{ font-family:'Space Mono',monospace; font-weight:700; font-size:14px; color:#8fef6a; }
  #supportBtn{ font-size:20px; }
  .iconbtn:active{ transform:translate(2px,2px); box-shadow:none; }

  .stage{ position:relative; width:100%; aspect-ratio:4/3; background:var(--wall); border:3px solid var(--ink); overflow:hidden; }
  .ceiling{ position:absolute; top:0; left:0; right:0; height:16%; background:#c2c4c1; background-image:repeating-linear-gradient(90deg, transparent 0 78px, rgba(0,0,0,0.08) 78px 80px), repeating-linear-gradient(0deg, transparent 0 28px, rgba(0,0,0,0.06) 28px 30px); border-bottom:3px solid #8c8f8c; }
  .ceilingLight{ position:absolute; top:0; width:3%; height:15%; background:#f4f3ea; border:1.5px solid #a8a89c; }
  .wallpanel{ position:absolute; top:16%; bottom:42%; left:0; right:0; background:repeating-linear-gradient(90deg, var(--wall) 0 58px, var(--wall-line) 58px 60px); }
  .wallSide{ position:absolute; top:16%; bottom:42%; width:9%; background:#65686c; }
  .wallSide.left{ left:0; }
  .wallSide.right{ right:0; }
  .neighborGlimpse{ position:absolute; top:16%; bottom:42%; width:3%; background:#54575b; opacity:0.75; }
  .neighborGlimpse.left{ left:0; }
  .neighborGlimpse.right{ right:0; }
  .neighborDesk{ position:absolute; bottom:42%; width:2.5%; height:5%; background:#7a6b4a; opacity:0.55; }
  .wallCorner{ position:absolute; top:16%; bottom:42%; width:4px; background:#45474a; }
  .wallTrim{ position:absolute; left:0; right:0; top:16%; height:2.5%; background:#b0b3b6; border-bottom:3px solid #7c7f83; }
  .wallSeam{ position:absolute; top:18.5%; bottom:42%; width:3px; background:var(--wall-line); }
  .baseboard{ position:absolute; left:0; right:0; bottom:42%; height:3%; background:var(--wall-dark); }
  .fluorflicker{ position:absolute; inset:0 0 42% 0; background:rgba(238,243,223,0.05); animation:flicker 7s infinite steps(1); pointer-events:none; }
  @keyframes flicker{ 0%,100%{opacity:1;} 92%{opacity:1;} 93%{opacity:.4;} 94%{opacity:1;} 96%{opacity:.55;} 97%{opacity:1;} }
  .floor{ position:absolute; left:0; right:0; bottom:0; height:42%; background:repeating-linear-gradient(0deg, var(--floor) 0 10px, var(--floor-dark) 10px 11px); }

  .clockwrap{ position:absolute; top:25.5%; left:50%; width:11.25%; aspect-ratio:1/1; cursor:grab; touch-action:none; transform:translate(-50%,-50%); }
  .clockwrap svg{ width:100%; height:100%; display:block; }

  /* Sized so that wall decor ends up with exactly the clock's travel area,
     which is the reference for anything hung on the cubicle wall.
     makeDraggable keeps an item wholly inside its zone, so a decor item's
     centre is clamped to the zone inset by half the item's own size -- these
     four values are the solution to that inset landing on the clock's own
     bounds (x 0.0968-0.9032, y 0.209-0.521 of the stage, see the clockEl
     makeFreeDraggable call). Every wall item is .decorItem at a uniform 11% of
     the zone width (.bigItem/33% is only the plant, which lives on the floor in
     .deskDecorZone), so one rect is exact for all of them, and .stage is locked
     to aspect-ratio 4/3, so the vertical solution holds at any viewport size.
     Changing the zone, the item width, or the stage aspect breaks the match --
     re-solve rather than nudging these by eye. */
  .decorZone{ position:absolute; top:14.26%; left:4.70%; width:90.61%; height:44.49%; pointer-events:none; }
  .decorItem{ position:absolute; width:11%; aspect-ratio:1/1; cursor:grab; touch-action:none; user-select:none; pointer-events:auto; }
  .deskDecorZone{ position:absolute; left:1%; bottom:1%; width:98%; height:40%; pointer-events:none; }
  .decorItem.bigItem{ width:33%; }
  .stringLightsFull{ position:absolute; top:0; left:0; width:100%; height:10%; pointer-events:none; }
  .stringLightsFull svg{ width:100%; height:100%; overflow:visible; }
  .decorItem:active{ cursor:grabbing; }
  .decorItem svg{ width:100%; height:100%; overflow:visible; }

  .desk{ position:absolute; left:16%; right:16%; bottom:8%; height:32.5%; background:var(--desk-dark); border-top:4px solid var(--desk-edge); }
  .deskFront{ position:absolute; left:16%; right:16%; bottom:19.2%; height:8.5%; background:var(--desk-dark); }
  .deskFront::before{ content:""; position:absolute; left:12%; width:3px; top:15%; bottom:15%; background:var(--desk-dark); opacity:.4; }
  .deskFront::after{ content:""; position:absolute; right:12%; width:3px; top:15%; bottom:15%; background:var(--desk-dark); opacity:.4; }
  /* The desk's surface band, repainted in front of Bob. .desk sits behind him
     and so cannot occlude anything; this covers the identical span (top 59.5%
     to 72.3%, matching .desk's top edge and .deskFront's top edge) but paints
     AFTER .charwrap in the scene markup, so it is what hides his lower half.
     Bob is sized and placed against these two edges -- hands on the top, feet
     on the bottom -- so his lower half is exactly this band's height and the
     surface swallows it whole when he sits down. Keep it flush with both edges.
     This is the only part of the desk in the light var(--desk); .desk itself,
     .deskFront and the legs are all var(--desk-dark), so the body reads as one
     colour and the surface is the single lighter plane sitting on top of it. */
  .deskSurface{ position:absolute; left:16%; right:16%; bottom:27.7%; height:12.8%; background:var(--desk); }

  .keyboard{ position:absolute; left:42.9%; bottom:35.5%; width:17%; height:4%; background:#d8d3c4; border:2px solid var(--ink); }
  .keyboard::after{ content:""; position:absolute; inset:15% 8%; background:repeating-linear-gradient(90deg, #b7b19c 0 3px, transparent 3px 5px); }
  /* Flipped end-for-end: the mouse is symmetric left-to-right, so swapping the
     top and bottom corner radii is the same 180-degree rotation without a
     transform (which would spawn a stacking context for no reason). Order is
     top-left, top-right, bottom-right, bottom-left. */
  .mouse{ position:absolute; left:38.9%; bottom:35.5%; width:2.6%; height:4%; background:#d8d3c4; border:2px solid var(--ink); border-radius:20% 20% 40% 40%; }
  /* This declaration IS the paper's standard spawn: resetPaperStackPosition
     clears the saved position and inline styles each new day so the stack falls
     back to exactly here, which is why the coordinates live in one place rather
     than being duplicated as a JS constant. Positioned so the stapler's own
     spawn lands on the LEFT side of the pile -- move one and the other needs
     re-measuring against it. */
  .papers{ position:absolute; left:23.18%; bottom:31.79%; width:11%; height:3%; cursor:grab; touch-action:none; }
  /* Ten stapleable sheets in the footprint the three static ones used to
     occupy. The offsets are percentages, not the concept's pixels: the whole
     stack is only ~15px tall in game, so 2.67% per sheet is what keeps the top
     sheet (24% + 72% height) inside the element. Removing sheets shortens the
     stack by ~24% overall, which reads as the pile going down even though any
     single sheet is a fraction of a pixel. */
  /* Each sheet's height on the pile, tilt and paper tone are set inline by
     renderPaperStack, derived from PAPER_SHEETS_PER_STACK. They used to be a
     hardcoded ladder of :nth-child rules, which only covered ten sheets and
     would have silently left everything above that unpositioned the moment the
     stack got deeper. The tilt arrives as a custom property rather than an
     inline transform specifically so .removing can still override the
     transform -- an inline transform would outrank the class and kill the
     stapling animation. */
  .paperSheet{
    position:absolute; left:0; right:0; height:72%; overflow:hidden;
    background:#efe9d6; border:1.5px solid var(--ink);
    transform-origin:50% 80%;
    transform:rotate(var(--tilt,0deg));
    transition:opacity 90ms ease-out, transform 110ms ease-out;
  }
  .paperSheet.removing{ opacity:0; transform:translateY(12%) scale(.97) rotate(0deg); }
  .papers.gone{ display:none; }
  /* Document artwork stretches to the sheet with preserveAspectRatio="none",
     so it is drawn in a 100x55 box with deliberately heavy strokes -- a sheet
     is about 76x11 real pixels, so anything under ~4 units of stroke weight
     disappears entirely at this scale. */
  .paperArt{ position:absolute; inset:0; width:100%; height:100%; display:block; pointer-events:none; }

  .monitor{ position:absolute; left:59%; bottom:41%; width:21.25%; height:19.55%; background:var(--monitor-bez); border:3px solid var(--ink); cursor:pointer; transform:perspective(340px) rotateY(-14deg); transform-style:preserve-3d; }
  .monitor:hover{ filter:brightness(1.08); }
  .monitor .screen{ position:absolute; inset:14%; background:var(--monitor); overflow:hidden; }
  .monitor .screen svg{ width:100%; height:100%; }
  /* The monitor's base. A child of .monitor, so it picks up the same
     perspective/rotateY skew and stays put if the monitor ever moves. Sized by
     what actually renders rather than by the raw numbers: the perspective
     transform means the layout box and the painted box differ, and most of the
     element sits hidden behind the monitor body. bottom:-14%/height:14% puts
     1.89 points of it below the monitor at 5.12 wide -- the ~2%x5% asked for --
     with its bottom edge at 61.6%, resting on the desk surface (top 59.5%).
     .monitor paints after .deskSurface in the scene markup, without which the
     surface buries the base. */
  .monitor .stand{ position:absolute; left:50%; bottom:-14%; width:18.3%; height:14%; background:var(--ink); transform:translateX(-50%); }
  /* The foot the stand rests on, twice the stand's width and ~1.5 points tall.
     Also a child of .monitor, so it inherits the same skew. Like the stand,
     these numbers are chosen by what renders, not by the arithmetic: at
     width:36.8%/height:5.7% it paints 7.25 wide by 1.53 tall, against the
     stand's 3.6. It overlaps the stand's bottom edge slightly so the two
     read as one piece, and its own bottom lands at 62.3%, on the surface. */
  .monitor .foot{ position:absolute; left:50%; bottom:-20%; width:36.8%; height:5.7%; background:var(--ink); transform:translateX(-50%); }
  .mailBadge{ position:absolute; top:-9px; right:-9px; background:var(--danger); color:#fff; border:2px solid var(--ink); border-radius:50%; width:20px; height:20px; font-size:12px; display:flex; align-items:center; justify-content:center; font-family:'Space Mono',monospace; font-weight:700; }

  /* Matches .deskSurface exactly, so a desk toy can only ever be placed on the
     desk's surface -- the same way .decorZone bounds wall decor to the cubicle
     wall. Keep these four values in sync with .deskSurface. */
  .toyZone{ position:absolute; left:16%; right:16%; bottom:27.7%; height:12.8%; pointer-events:none; }
  .toyItem{ position:absolute; width:9%; aspect-ratio:1/1; cursor:grab; touch-action:none; user-select:none; pointer-events:auto; }
  /* The Pen Holder is the one desk toy issued narrower than the standard 9%.
     It ships equipped on every new career and has to share the strip of desk
     left of the keyboard with the paper stack and the stapler, and at 9% there
     is no gap on that strip wide enough to take it (3.27% left of the papers,
     1.47% between the stapler and the mouse, against a 6.07%-of-stage box).
     4.8% fits the left gap exactly, and a narrow pen cup is the right shape for
     the object anyway -- the static pen holder element this replaced was
     hand-sized at 4.5% of the stage for the same reason. Since raised from that
     original 4.8% by a quarter, so it reads at desk scale rather than as a
     thimble; it no longer fits the gap left of the paper stack, which is fine
     now that it isn't placed on the desk by default. */
  /* aspect-ratio matches the icon's 20x28 viewBox, so the cup FILLS its box
     instead of letterboxing inside the default square one. That is what makes
     it render 20% wider and 40% taller than the old 20x24-in-a-square version
     at the same 4.8% width -- the extra width was already there as dead space. */
  .toyItem[data-item-id="penholder"]{ width:6%; aspect-ratio:20/28; }

  /* Red Stapler. The top presses in and the base lifts a fraction, so the thing
     compresses like a real stapler without its resting silhouette moving at all.
     transform-box:view-box means these px values are viewBox user units -- 24ths
     of the icon -- which is why sub-pixel numbers are the right magnitude here. */
  .staplerTop, .staplerBase{ transform-box:view-box; }
  .toyItem.clacking .staplerTop{ animation:staplerTopClack 150ms cubic-bezier(.35,0,.25,1); }
  .toyItem.clacking .staplerBase{ animation:staplerBaseClack 150ms cubic-bezier(.35,0,.25,1); }
  @keyframes staplerTopClack{
    0%{ transform:translateY(0); } 28%{ transform:translateY(.78px); }
    48%{ transform:translateY(.78px); } 75%{ transform:translateY(-.10px); }
    100%{ transform:translateY(0); }
  }
  @keyframes staplerBaseClack{
    0%{ transform:translateY(0); } 28%{ transform:translateY(-.18px); }
    48%{ transform:translateY(-.18px); } 75%{ transform:translateY(.04px); }
    100%{ transform:translateY(0); }
  }

  /* Rubber Duck. The body takes most of the squeeze; the head compresses less
     and settles toward the body, then both overshoot on release. fill-box so
     each group scales about its own centre rather than the icon's origin. */
  .duckBody, .duckHead{ transform-box:fill-box; transform-origin:center; }
  .toyItem.squeezing .duckBody{ transform:scaleX(.90) scaleY(.82); }
  .toyItem.squeezing .duckHead{ transform:translate(-.25px,1.05px) scaleX(.96) scaleY(.92); }
  .toyItem.releasing .duckBody{ animation:duckBodyRelease .34s cubic-bezier(.2,.8,.25,1); }
  .toyItem.releasing .duckHead{ animation:duckHeadRelease .34s cubic-bezier(.2,.8,.25,1); }
  @keyframes duckBodyRelease{
    0%{ transform:scaleX(.90) scaleY(.82); } 48%{ transform:scaleX(1.035) scaleY(1.055); }
    72%{ transform:scaleX(.985) scaleY(.98); } 100%{ transform:scaleX(1) scaleY(1); }
  }
  @keyframes duckHeadRelease{
    0%{ transform:translate(-.25px,1.05px) scaleX(.96) scaleY(.92); }
    48%{ transform:translate(.1px,-.25px) scaleX(1.015) scaleY(1.025); }
    72%{ transform:translate(0,.08px) scaleX(.995) scaleY(.995); }
    100%{ transform:translate(0,0) scaleX(1) scaleY(1); }
  }

  /* Mini Zen Garden. The rake sweeps left-to-right across the tray; the jostle
     is applied to the inner <svg>, NOT the .toyItem wrapper, because the
     wrapper carries the translate(-50%,-50%) centring that syncMultiSlot sets
     inline -- animating the wrapper would fight it and teleport the tray. */
  .sandLine{ fill:none; stroke:#8d7348; stroke-width:.72; stroke-linecap:round; stroke-linejoin:round; }
  .zenStone{ transition:transform .25s ease; transform-box:fill-box; transform-origin:center; }
  .zenRake{ transform-origin:8px 7px; transform-box:view-box; }
  .zenRake.raking{ animation:zenRakeSweep .52s cubic-bezier(.35,.1,.25,1); }
  @keyframes zenRakeSweep{
    0%{ transform:translateX(0) rotate(0); } 16%{ transform:translateX(-1.2px) rotate(-7deg); }
    72%{ transform:translateX(8.5px) rotate(5deg); } 100%{ transform:translateX(0) rotate(0); }
  }
  .zenJostle{ animation:zenJostle .24s ease-out; }
  @keyframes zenJostle{
    0%{ transform:rotate(0); } 22%{ transform:rotate(-1.5deg); }
    48%{ transform:rotate(1.2deg); } 75%{ transform:rotate(-.5deg); } 100%{ transform:rotate(0); }
  }

  /* Pen Holder. will-change keeps the per-frame rattle off the main raster
     path; the rest of each pen's transform is written inline by makePenHolder. */
  .pen{ transform-box:view-box; will-change:transform; }

  /* String Lights. A failing bulb is not a glow or an opacity blink -- it is the
     flat fill stepping to a darker variant and back, which is the only thing
     that reads as "broken" in this art style. steps(1,end) keeps every change
     an instant cut rather than a fade. */
  .stringLightBulb{ pointer-events:auto; cursor:pointer; }
  .bulbCore{ fill:var(--bulb-color); }
  .stringLightBulb.bad .bulbCore{ animation:badBulbFlicker 1.35s steps(1,end) infinite; }
  @keyframes badBulbFlicker{
    0%{ fill:var(--bulb-color); }  8%{ fill:var(--bulb-dark); } 15%{ fill:var(--bulb-color); }
    23%{ fill:var(--bulb-mid); }  29%{ fill:var(--bulb-color); } 51%{ fill:var(--bulb-color); }
    56%{ fill:var(--bulb-dark); } 62%{ fill:var(--bulb-color); } 68%{ fill:var(--bulb-mid); }
    74%{ fill:var(--bulb-color); } 100%{ fill:var(--bulb-color); }
  }
  /* One tiny voltage wobble when a bulb is clicked back to life, then solid. */
  .stringLightBulb.fixedFlash .bulbCore{ animation:fixedBulbSettle 280ms steps(1,end) 1; }
  @keyframes fixedBulbSettle{
    0%{ fill:var(--bulb-dark); } 28%{ fill:var(--bulb-color); } 46%{ fill:var(--bulb-mid); }
    64%{ fill:var(--bulb-color); } 100%{ fill:var(--bulb-color); }
  }
  .toyItem:active{ cursor:grabbing; }
  .toyItem svg{ width:100%; height:100%; overflow:visible; }
  /* Fidget Cube solve/scramble feedback (makeFidgetCubeGame) -- applied to
     the svg itself, not the .toyItem wrapper, since the wrapper's own
     transform:translate(-50%,-50%) is what keeps it centered on its
     left/top position and an animation here would fight that. */
  @keyframes cubeSolveKick{ 0%{ transform:rotate(0deg) scale(1); } 45%{ transform:rotate(-2deg) scale(1.03); } 100%{ transform:rotate(0deg) scale(1); } }
  @keyframes cubeScrambleKick{ 0%{ transform:rotate(0deg); } 20%{ transform:rotate(-6deg); } 45%{ transform:rotate(5deg); } 70%{ transform:rotate(-3deg); } 100%{ transform:rotate(0deg); } }
  .cubeSolveKick{ animation:cubeSolveKick .18s ease-out; }
  .cubeScrambleKick{ animation:cubeScrambleKick .34s ease-out; }

  /* Bob's mug while he is holding it but not mid-sip -- NOT a desk object.
     It is placed against the straight-arm left hand (the same hand that grips
     #pCupInHand during a sip), measured at 46.2%/57.36% with Bob at the desk,
     so it has to move whenever .charwrap does. Parked anywhere else it reads
     as a stray mug sitting on the desk. Note the mug is not centred on the
     hand: within its 20-wide viewBox the body is x2-16 and the handle x16-20,
     so `left` is offset to bring the HANDLE onto the hand and hang the body
     clear to its left, rather than covering the hand with the mug's body. */
  .cup{ position:absolute; width:4%; height:7%; transition:left .5s cubic-bezier(.4,0,.3,1), bottom .5s cubic-bezier(.4,0,.3,1), transform .5s ease; left:42.2%; bottom:39.2%; display:none; }
  .cup.show{ display:block; }
  .cup svg{ width:100%; height:100%; overflow:visible; }

  /* left matches the walk-in start in applyPose(); every seated pose overrides
     it inline, so this only shows for the frame before the first pose applies. */
  .charwrap{ position:absolute; bottom:26.92%; left:-2%; width:26%; pointer-events:none; }
  .chairEl{ position:absolute; bottom:37.92%; left:39.375%; width:11%; pointer-events:none; }
  .chairEl svg{ width:100%; display:block; overflow:visible; }
  .deskLeg{ position:absolute; bottom:0; width:2.4%; background:var(--desk-dark); border:2px solid var(--desk-edge); }
  .charwrap svg{ width:100%; overflow:visible; display:block; }
  .charwrap.hidden{ visibility:hidden; }
  /* Bob is inert except his head, which toggles the headphones. A descendant can
     opt back in even though .charwrap is pointer-events:none, so this is the only
     clickable part of him. .decorZone paints before .charwrap, so his head is
     already drawn in front of wall decor and now takes the click there too.
     visibleFill, not all: the *visible* values respect visibility, so the hit
     target goes dead with .charwrap.hidden (the 'offscreen' pose) instead of
     leaving a clickable ghost of Bob's head behind. The Fill part means the
     transparent interior is still a target, which a paint-based value would
     refuse. */
  .charwrap #pHeadHit{ pointer-events:visibleFill; cursor:pointer; }
  /* The tap lifts the arm rather than pressing it down. Bob's hands rest at
     59.35% and .deskSurface starts at 59.39% and paints in front of him, so
     there is only 0.04 of headroom below them -- pressing down 3px (0.87 stage
     points) buried 0.83 of each hand behind the desk on every keystroke. Going
     up keeps the whole hand visible and still reads as typing, since it returns
     to rest on the keys. Do not flip these back to a positive translateY
     without first giving the hands room to travel into. */
  @keyframes typeTapA{ 0%{ transform:translateY(0); } 35%{ transform:translateY(-3px); } 100%{ transform:translateY(0); } }
  @keyframes typeTapB{ 0%{ transform:translateY(0); } 35%{ transform:translateY(-3px); } 100%{ transform:translateY(0); } }
  #pArmR.typingBurstA, #pArmL.typingBurstA{ animation:typeTapA 0.22s ease-out; }
  #pArmR.typingBurstB, #pArmL.typingBurstB{ animation:typeTapB 0.22s ease-out; }
  @keyframes spin{ to{ transform:rotate(360deg); } }
  .swirl{ animation:spin 0.9s linear infinite; }

  /* Sleeping z's: each one rises off Bob's head, drifts right, grows a little
     and fades. All three share one path and one duration; the stagger below is
     what turns it into a stream instead of a pulse. transform-box:fill-box so
     the scale grows from each glyph's own centre rather than the SVG origin --
     without it they slide away toward the corner as they grow. */
  @keyframes sleepZFloat{
    0%   { opacity:0; transform:translate(0,0) scale(.55); }
    18%  { opacity:1; }
    70%  { opacity:.85; }
    100% { opacity:0; transform:translate(15px,-27px) scale(1.3); }
  }
  /* backwards fill matters: without it the two delayed z's sit fully opaque and
     motionless on top of the first one until their delay elapses, so the effect
     opens with three stacked z's that suddenly jump into motion. */
  .sleepZ{ animation:sleepZFloat 2.7s linear infinite; animation-fill-mode:backwards; transform-box:fill-box; transform-origin:50% 50%; }
  .sleepZ1{ animation-delay:0.9s; }
  .sleepZ2{ animation-delay:1.8s; }

  .bubble{ position:absolute; background:var(--panel); color:var(--text); border:2px solid var(--ink); padding:3px 7px; font-size:13px; white-space:nowrap; opacity:0; pointer-events:none; z-index:5; }
  .bubble.play{ animation:bubblefloat 3.2s ease-out forwards; }
  @keyframes bubblefloat{ 0%{opacity:0; transform:translateY(0);} 12%{opacity:1; transform:translateY(-4px);} 80%{opacity:1; transform:translateY(-14px);} 100%{opacity:0; transform:translateY(-20px);} }

  .closedOverlay{ position:absolute; inset:0; background:rgba(10,10,8,0.72); display:none; flex-direction:column; align-items:center; justify-content:center; text-align:center; padding:10%; z-index:6;}
  .closedOverlay.show{ display:flex; }
  .closedOverlay .big{ font-size:22px; color:var(--text); margin-bottom:8px; }
  .closedOverlay .small{ font-size:16px; color:var(--text-dim); }

  .hud{ padding:10px 4px 2px 4px; }
  .energyrow{ display:flex; align-items:center; gap:8px; margin-bottom:8px; }
  .barwrap{ flex:1; height:22px; background:var(--panel-light); border:2px solid var(--ink); position:relative; overflow:visible; }
  .barfill{ position:absolute; left:0; top:0; bottom:0; width:0%; background:var(--good); }
  .barfill.zone-red-low{ background:var(--danger); }
  .barfill.zone-yellow-low{ background:#d9c23a; }
  .barfill.zone-green{ background:var(--good); }
  .barfill.zone-yellow-high{ background:#d9c23a; }
  .barfill.zone-red-high{ background:var(--danger); animation:pulse 1s infinite; }
  .barfill.zone-candy{ background-image:repeating-linear-gradient(45deg, #c23b3b 0 8px, #f4f1e8 8px 16px); animation:pulse .4s infinite; }
  @keyframes pulse{ 0%,100%{filter:brightness(1);} 50%{filter:brightness(1.35);} }
  .barmark100{ position:absolute; top:-4px; bottom:-4px; width:2px; background:var(--ink); left:66.6%; }
  .barlabel{ font-size:16px; min-width:52px; text-align:right; }
  .statusrow{ font-size:16px; color:var(--text-dim); margin-bottom:10px; min-height:20px; }
  .coffeebtn{ display:block; width:100%; background:var(--panel-light); border:3px solid var(--ink); color:var(--text); font-family:'Press Start 2P',monospace; font-size:12px; padding:14px 10px; cursor:pointer; box-shadow:4px 4px 0 var(--ink); letter-spacing:1px; }
  .coffeebtn:not(:disabled):hover{ background:#3d3f31; }
  .coffeebtn:not(:disabled):active{ transform:translate(4px,4px); box-shadow:none; }
  .coffeebtn:disabled{ opacity:.5; cursor:default; }

  .startscreen{ position:absolute; inset:0; background:var(--panel); display:flex; flex-direction:column; align-items:center; gap:18px; text-align:center; padding:20px; z-index:20; overflow-y:auto; scrollbar-width:none; }
  .startscreen::-webkit-scrollbar{ display:none; }
  .startscreen .startscreenPanel{ margin:auto 0; position:relative; z-index:10; }
  .startBg{ position:absolute; inset:0; overflow:hidden; z-index:0; }
  .startBgTrack{ position:absolute; inset:0; display:flex; will-change:transform; }
  .startBgTile{ position:relative; width:800px; height:100%; flex:none; }
  .startBgTile svg{ width:100%; height:100%; display:block; }
  #startBgClouds{ animation:startBgScroll 200s linear infinite; z-index:0; }
  #startBgSkyline{ animation:startBgScroll 130s linear infinite; z-index:1; }
  #startBgFg{ animation:startBgScroll 60s linear infinite; z-index:2; }
  @keyframes startBgScroll{ from{ transform:translateX(0); } to{ transform:translateX(-800px); } }
  .startBgDark{ position:absolute; inset:0; background:rgba(10,10,8,0.62); z-index:3; pointer-events:none; }
  .soundStartBtn{ position:absolute; right:14px; bottom:14px; z-index:11; }
  .startscreen h1{ font-family:'Press Start 2P',monospace; font-size:22px; color:var(--gold); text-shadow:3px 3px 0 var(--ink); margin:0; }
  .betaTag{ font-size:11px; color:var(--text-dim); text-shadow:none; vertical-align:middle; }
  .startscreen p{ color:var(--text-dim); font-size:17px; max-width:460px; margin:0 0 16px; }
  .startbtn{ background:var(--good); border:3px solid var(--ink); color:var(--ink); font-family:'Press Start 2P',monospace; font-size:13px; padding:14px 22px; cursor:pointer; box-shadow:4px 4px 0 var(--ink); }
  .startMenuBtns{ display:flex; flex-direction:column; align-items:center; gap:12px; }
  .startbtn:active{ transform:translate(4px,4px); box-shadow:none; }
  .devnote{ font-size:13px; color:var(--warn); border:1px dashed var(--warn); padding:6px 10px; max-width:380px; }
  .startFooter{ position:absolute; left:0; right:0; bottom:10px; z-index:10; text-align:center; font-size:12px; color:var(--text-dim); line-height:1.6; }
  a, a:visited{ color:#4da6ff; }
  a:hover{ color:#7cc0ff; }
  #tosGateContent .panelBox{ text-align:left; }
  #tosAgreeBtn{ display:block; margin:16px auto 0; }
  .scrollIndicatorTrack{ position:absolute; top:12px; bottom:12px; right:6px; width:6px; border-radius:3px; background:rgba(0,0,0,0.25); z-index:25; display:none; }
  .scrollIndicatorTrack.show{ display:block; }
  .scrollIndicatorThumb{ position:absolute; left:0; right:0; border-radius:3px; background:var(--text-dim); opacity:0.6; }

  .overlay{ position:absolute; inset:0; background:rgba(8,8,6,0.85); display:none; align-items:center; justify-content:center; z-index:30; padding:16px; }
  .overlay.show{ display:flex; }
  .panelBox{ position:relative; background:var(--panel); border:3px solid var(--ink); width:100%; max-width:520px; max-height:92%; display:flex; flex-direction:column; box-shadow:6px 6px 0 rgba(0,0,0,0.5); }
  .panelClose{ position:absolute; top:-14px; right:-14px; z-index:5; }
  .tabs{ display:flex; border-bottom:3px solid var(--ink); }
  .tabbtn{ flex:1; background:var(--panel-light); border:none; color:var(--text-dim); font-family:'Press Start 2P',monospace; font-size:10px; padding:12px 4px; cursor:pointer; }
  .tabbtn.active{ background:var(--panel); color:var(--gold); }
  .supportHead{ background:var(--panel-light); border-bottom:3px solid var(--ink); font-family:'Press Start 2P',monospace; font-size:12px; color:var(--gold); padding:14px 16px; text-align:center; }
  .supportbtns{ display:flex; gap:10px; margin:16px 0; }
  .supportbtn{ flex:1; background:var(--panel-light); border:2px solid var(--ink); color:var(--gold); font-family:'Press Start 2P',monospace; font-size:14px; padding:14px 6px; cursor:pointer; box-shadow:3px 3px 0 var(--ink); }
  .supportbtn:active{ transform:translate(3px,3px); box-shadow:none; }
  .supportStepper{ flex:1; display:flex; align-items:stretch; }
  .supportStepper .stepperGive{ flex:1; min-width:0; display:flex; align-items:center; justify-content:center; border-right:none; }
  .supportStepper .stepperGive span{ overflow:hidden; text-overflow:clip; white-space:nowrap; }
  .stepperArrows{ display:flex; flex-direction:column; flex:0 0 22px; border:2px solid var(--ink); border-left:none; box-shadow:3px 3px 0 var(--ink); }
  .stepperArrowBtn{ flex:1; background:var(--panel-light); border:none; color:var(--gold); font-size:8px; cursor:pointer; line-height:1; padding:0; }
  .stepperArrowBtn:first-child{ border-bottom:2px solid var(--ink); }
  .stepperArrowBtn:hover{ filter:brightness(1.2); }
  .stepperArrowBtn:active{ background:var(--ink); }
  .supportStep{ display:none; }
  .supportStep.show{ display:block; }
  .supportError{ color:#e58989; font-size:13px; margin:8px 0 0; }
  .supportFieldLabel{ display:block; font-size:14px; color:var(--text-dim); margin-bottom:4px; }
  .emailOptInRow{ display:flex; align-items:center; gap:8px; font-size:15px; cursor:pointer; margin-bottom:4px; }
  .emailOptInRow input{ width:16px; height:16px; cursor:pointer; flex-shrink:0; }
  .panelBody{ padding:14px 16px; overflow-y:auto; font-size:17px; }
  .statgrid{ display:grid; grid-template-columns:1fr auto; gap:6px 14px; margin-bottom:14px; }
  .statgrid .lbl{ color:var(--text-dim); }
  .statgrid .val{ text-align:right; }
  .sectionhead{ font-family:'Press Start 2P',monospace; font-size:11px; color:var(--gold); margin:14px 0 8px 0; letter-spacing:1px; }

  /* stats overlay: three-tier hierarchy, deliberately its own visual style */
  .statsHeadline{ display:flex; gap:10px; margin-bottom:6px; }
  .statsHeadline .stat{ flex:1; background:var(--panel-light); border:2px solid var(--ink); padding:12px 8px; text-align:center; }
  .statsHeadline .statVal{ font-family:'Press Start 2P',monospace; font-size:17px; color:var(--gold); }
  .statsHeadline .statLbl{ font-size:11px; color:var(--text-dim); margin-top:4px; text-transform:uppercase; letter-spacing:0.5px; }
  .statsCvToday{ margin-bottom:4px; }
  .statsRecord .val{ color:var(--text-dim); }
  .statsAssessment{ margin-top:16px; padding:10px 12px; border-left:3px solid var(--warn); background:var(--panel-light); font-size:15px; color:var(--text-dim); line-height:1.5; }
  .statsAssessment strong{ color:var(--text-dim); }
  .statsAssessmentCloser{ margin-top:6px; font-style:italic; }
  #readmeOverlay .sectionhead{ margin-top:24px; }
  #readmeOverlay .sectionhead + p{ margin-top:0; }
  .daylist{ list-style:none; padding:0; margin:0; font-size:15px; }
  .daylist li{ display:flex; justify-content:space-between; padding:3px 0; border-bottom:1px solid var(--panel-light); }
  .profit-pos{ color:var(--good); } .profit-neg{ color:var(--danger); }

  .cvBalanceBar{ display:flex; align-items:baseline; gap:8px; background:var(--panel-light); border:2px solid var(--ink); padding:10px 12px; margin-bottom:10px; }
  .cvBalanceBar span{ font-size:20px; color:var(--gold); }
  .cvBalanceBar strong{ font-size:20px; color:var(--gold); font-weight:normal; }
  .outfitnote{ font-size:14px; color:var(--text-dim); margin-bottom:10px; }

  /* store: grid of cards (browse) + a single-item detail view swapped into
     the same panel body, mirroring the existing mail list/detail pattern */
  .storeGrid{ display:grid; grid-template-columns:repeat(auto-fill,minmax(94px,1fr)); gap:10px; }
  .storeCard{ background:var(--panel-light); border:2px solid var(--ink); padding:10px 6px 8px; cursor:pointer; position:relative; display:flex; flex-direction:column; align-items:center; gap:5px; text-align:center; }
  .storeCard.equipped{ outline:2px solid var(--gold); outline-offset:2px; }
  .storeCard.dayblocked{ opacity:.5; }
  .storeCard .icon{ width:34px; height:34px; }
  .storeCard .nm{ font-size:12px; line-height:1.25; min-height:2.4em; display:flex; align-items:center; }
  .storeCard .price{ font-size:12px; color:var(--gold); }
  .storeCard .tag{ font-size:10px; color:var(--warn); line-height:1.2; margin-top:1px; }
  .storeCard .statechip{ position:absolute; top:3px; right:3px; font-size:9px; text-transform:uppercase; letter-spacing:0.5px; padding:2px 4px; border:1px solid var(--ink); background:var(--panel); color:var(--text-dim); }
  .storeCard .statechip.equipped{ background:var(--gold); color:var(--ink); border-color:var(--ink); }
  .storeCard .previewMini{ position:absolute; top:3px; left:3px; font-size:10px; width:18px; height:18px; padding:0; display:flex; align-items:center; justify-content:center; background:var(--panel); border:1px solid var(--ink); color:var(--text); cursor:pointer; }
  .storeCard .previewMini.stop{ background:var(--danger); color:#fff; }

  .storeDetail{ text-align:center; padding:4px 6px; }
  .storeDetail .back{ float:left; background:var(--panel-light); border:2px solid var(--ink); color:var(--text); font-size:14px; padding:5px 10px; cursor:pointer; margin-bottom:14px; }
  .storeDetail .icon{ width:88px; height:88px; margin:8px auto 12px; clear:both; }
  .storeDetail .nm{ font-size:19px; color:var(--gold); margin-bottom:6px; }
  .storeDetail .price{ font-size:16px; color:var(--text); margin-bottom:8px; }
  .storeDetail .tag{ font-size:13px; color:var(--warn); margin-bottom:4px; }
  .storeDetail .note{ font-size:13px; color:var(--text-dim); margin:8px 0; }
  .storeDetail .usdbadge{ display:inline-block; font-size:12px; color:var(--text-dim); background:var(--panel); border:1px dashed var(--text-dim); border-radius:3px; padding:5px 10px; margin:10px 0; cursor:pointer; }
  .storeDetail .previewBtn{ display:block; width:100%; font-size:13px; color:var(--text); background:var(--panel); border:2px solid var(--ink); padding:9px 10px; margin-bottom:10px; cursor:pointer; font-family:inherit; }
  .storeDetail .actionBtn{ display:block; width:100%; background:var(--good); border:3px solid var(--ink); color:var(--ink); font-family:'Press Start 2P',monospace; font-size:12px; padding:14px 10px; cursor:pointer; box-shadow:4px 4px 0 var(--ink); letter-spacing:0.5px; margin-top:6px; }
  .storeDetail .actionBtn:disabled{ background:var(--panel); color:var(--text-dim); cursor:not-allowed; box-shadow:none; }

  .toastwrap{ position:absolute; top:8px; left:50%; transform:translateX(-50%); display:flex; flex-direction:column; gap:6px; z-index:40; align-items:center; pointer-events:none; }
  .toast{ background:var(--gold); color:var(--ink); border:2px solid var(--ink); font-size:14px; padding:6px 12px; box-shadow:3px 3px 0 rgba(0,0,0,.5); animation:toastIn 4.5s ease forwards; }
  @keyframes toastIn{ 0%{opacity:0; transform:translateY(-8px);} 8%{opacity:1; transform:translateY(0);} 85%{opacity:1;} 100%{opacity:0; transform:translateY(-6px);} }
  /* same toast, positioned at a specific point (e.g. the cursor) instead of
     the fixed top-center wrap -- left/top set inline per instance in JS. */
  .toastNear{ position:absolute; z-index:60; pointer-events:none; white-space:nowrap; }

  /* inbox */
  .mailTabs{ display:flex; border-bottom:3px solid var(--ink); }
  .mailTab{ flex:1; background:var(--panel-light); border:none; color:var(--text-dim); font-family:'Space Mono',monospace; font-size:13px; padding:10px 4px; cursor:pointer; }
  .mailTab.active{ background:var(--panel); color:var(--gold); }
  .mailTab .cnt{ background:var(--danger); color:#fff; border-radius:8px; padding:0 5px; font-size:11px; margin-left:5px; }
  .mailList{ list-style:none; margin:0; padding:0; }
  .mailRow{ padding:9px 6px; border-bottom:1px solid var(--panel-light); cursor:pointer; display:flex; flex-direction:column; gap:2px; }
  .mailRow:hover{ background:var(--panel-light); }
  .mailRow .top{ display:flex; justify-content:space-between; font-size:14px; color:var(--text-dim); }
  .mailRow .subj{ font-size:16px; }
  .mailRow.unread .subj{ font-weight:700; color:var(--text); }
  .mailRow.unread .top{ color:var(--gold); }
  .mailEmpty{ color:var(--text-dim); padding:16px 4px; }
  .mailDetail .back{ background:var(--panel-light); border:2px solid var(--ink); color:var(--text); font-size:14px; padding:5px 10px; cursor:pointer; margin-bottom:10px; }
  .mailDetail .from{ color:var(--text-dim); font-size:14px; }
  .mailDetail .subj{ font-size:19px; margin:4px 0 10px 0; color:var(--gold); }
  /* pre-wrap so an email body can use blank lines between paragraphs (the
     onboarding email does). Every other body is a single line with no \n in it,
     so none of them render any differently for it. */
  .mailDetail .body{ font-size:17px; line-height:1.4; white-space:pre-wrap; }
  .replyBox{ margin-top:16px; padding-top:12px; border-top:2px dashed var(--panel-light); }
  .replyBox textarea{ width:100%; min-height:70px; background:var(--panel-light); border:2px solid var(--ink); color:var(--text); font-family:'VT323','Courier New',monospace; font-size:16px; padding:8px; resize:vertical; margin-bottom:8px; }

  /* desktop shell (hidden -- reachable only via the /desktop terminal command) */
  .desktopBox{ max-width:708px; aspect-ratio:4/3; }
  /* container-type:size (not the more common inline-size) because the fix
     below responds to this element's HEIGHT, not its width -- see the
     @container rule near .desktopIcon. */
  .desktopScreen{ container-type:size; container-name:desktopScreen; position:relative; flex:1; min-height:0; margin:14px 16px 16px; border:2px solid var(--ink); background:radial-gradient(120% 140% at 30% 12%, #322f27 0%, var(--monitor) 55%, #15130e 100%); overflow:hidden; box-shadow:inset 0 0 40px 12px rgba(0,0,0,0.55); }
  .desktopScreen::before{ content:''; position:absolute; inset:0; pointer-events:none; background:repeating-linear-gradient(180deg, rgba(0,0,0,0.16) 0px, rgba(0,0,0,0.16) 1px, transparent 2px, transparent 4px); }
  .desktopScreen::after{ content:''; position:absolute; right:10px; bottom:8px; width:6px; height:6px; border-radius:50%; background:var(--monitor-glow); box-shadow:0 0 5px 2px var(--monitor-glow); }

  /* desktop login gate: shown instead of desktopScreen outside office hours --
     same physical "screen" (identical background/scanlines) but no login here
     ever succeeds, since it's a UI block, not real auth. */
  .desktopLoginView{ position:relative; flex:1; min-height:0; margin:14px 16px 16px; border:2px solid var(--ink); background:radial-gradient(120% 140% at 30% 12%, #322f27 0%, var(--monitor) 55%, #15130e 100%); overflow:hidden; box-shadow:inset 0 0 40px 12px rgba(0,0,0,0.55); display:flex; align-items:center; justify-content:center; }
  .desktopLoginView::before{ content:''; position:absolute; inset:0; pointer-events:none; background:repeating-linear-gradient(180deg, rgba(0,0,0,0.16) 0px, rgba(0,0,0,0.16) 1px, transparent 2px, transparent 4px); }
  .loginBox{ position:relative; width:230px; text-align:center; }
  .loginBox.shake{ animation:loginShake 0.4s; }
  @keyframes loginShake{ 0%,100%{ transform:translateX(0); } 20%{ transform:translateX(-6px); } 40%{ transform:translateX(6px); } 60%{ transform:translateX(-4px); } 80%{ transform:translateX(4px); } }
  .loginTitle{ font-family:'Press Start 2P',monospace; font-size:12px; color:var(--monitor-glow); margin-bottom:16px; letter-spacing:1px; }
  .loginRow{ text-align:left; margin-bottom:10px; }
  .loginRow label{ display:block; font-size:12px; color:var(--text-dim); margin-bottom:3px; text-transform:uppercase; letter-spacing:0.5px; }
  .loginRow input{ width:100%; box-sizing:border-box; background:#15130e; border:2px solid var(--monitor-glow); color:var(--monitor-glow); font-family:'Space Mono',monospace; font-size:14px; padding:7px 9px; }
  .loginRow input:focus{ outline:none; }
  .loginSubmitBtn{ width:100%; margin-top:6px; font-size:11px; padding:10px; }
  .loginMsg{ min-height:16px; margin-top:10px; font-size:12px; color:var(--danger); font-weight:700; }
  .loginNote{ margin-top:14px; font-size:11px; color:var(--text-dim); line-height:1.4; }
  /* min(90px, 15%): the two icon columns below sit at left:3% and left:18%, so
     15% of .desktopScreen's width is exactly the column gap -- at any width
     that keeps 15% >= 90px this is just 90px (unchanged from before), but
     below that (a phone-narrow .cabinet) it shrinks with the column spacing
     instead of overflowing into the next column. Found and fixed during the
     mobile runtime pass (audit item (c)): at 359px cabinet width, "Company
     Handbook" and "Solitaire" (and "Email" and "TPS Reports") overlapped into
     illegible garbled text -- not a squint-and-manage case, a wrong-icon-tap
     case. */
  .desktopIcon{ position:absolute; display:flex; flex-direction:column; align-items:center; gap:4px; width:min(90px, 15%); background:none; border:none; cursor:grab; touch-action:none; padding:2px; }
  .desktopIcon .glyph{ font-size:25px; width:39px; height:39px; display:flex; align-items:center; justify-content:center; filter:drop-shadow(1px 1px 0 rgba(0,0,0,.5)); }
  .desktopIcon:active .glyph{ transform:translate(1px,1px); }
  .desktopIcon .lbl{ font-size:10px; color:#fff; text-shadow:1px 1px 0 #000; text-align:center; line-height:1.2; }
  /* The four icon rows are spaced 27% of .desktopScreen's height apart
     (top:4/31/58/85% below), but each icon's glyph+gap+label is a fixed 71px
     tall -- fine at the desktop box's usual ~500px height, but on a
     phone-narrow .cabinet .desktopScreen can be as short as ~156px, where 27%
     is only ~42px and consecutive rows overlap outright (found alongside the
     column-width overlap above, same mobile runtime pass). Below 200px --
     comfortably under any normal width, well above the ~156px phone case --
     shrink the glyph and label together so the whole icon fits inside its own
     row band instead of spilling into the next one. */
  @container desktopScreen (max-height: 200px){
    .desktopIcon{ gap:1px; }
    .desktopIcon .glyph{ font-size:16px; width:24px; height:24px; }
    .desktopIcon .lbl{ font-size:7px; line-height:1.05; }
  }
  #desktopInternetEl{ left:3%; top:4%; }
  #desktopTerminalEl{ left:3%; top:31%; }
  #desktopReadmeEl{ left:3%; top:58%; }
  #desktopTpsEl{ left:3%; top:85%; }
  #desktopEmailEl{ left:18%; top:4%; }
  #desktopSurveyEl{ left:18%; top:31%; }
  #desktopSolitaireEl{ left:18%; top:58%; }
  .desktopSupportIcon{ right:16px; bottom:16px; }
  .desktopSupportIcon .glyph{ font-size:33px; width:51px; height:51px; }
  .internetBlocked{ display:none; position:absolute; inset:0; flex-direction:column; align-items:center; justify-content:center; text-align:center; padding:40px; background:#1a0e0a; }
  .internetBlocked.show{ display:flex; }
  .internetBlocked .iconbtn{ position:absolute; top:12px; right:12px; }
  .ibIcon{ font-size:48px; margin-bottom:10px; }
  .ibTitle{ font-family:'Press Start 2P',monospace; font-size:16px; color:var(--danger); margin-bottom:16px; letter-spacing:1px; }
  .ibBody{ max-width:80%; color:#ddd; font-size:14px; line-height:1.5; }
  .ibBody p{ margin:0 0 10px; }

  /* survey */
  .formfield{ width:100%; box-sizing:border-box; background:var(--panel-light); border:2px solid var(--ink); color:var(--text); font-family:'VT323','Courier New',monospace; font-size:16px; padding:8px 10px; margin-bottom:12px; }
  textarea.formfield{ min-height:70px; resize:vertical; }
  .surveyChoice{ display:block; width:100%; text-align:left; background:var(--panel-light); border:2px solid var(--ink); color:var(--text); font-family:'Space Mono',monospace; font-size:14px; padding:10px 12px; margin-bottom:8px; cursor:pointer; box-shadow:3px 3px 0 var(--ink); }
  .surveyChoice:active{ transform:translate(3px,3px); box-shadow:none; }
  .surveyChoice.selected{ outline:2px solid var(--gold); outline-offset:2px; color:var(--gold); }
  .hp-field{ position:absolute; left:-9999px; width:1px; height:1px; opacity:0; }

  /* TPS reports minigame */
  .tpsBox{ max-width:640px; }
  .solitaireBox{ max-width:580px; max-height:98%; }
  .tpsPaper{ background:#efe9d6; color:var(--ink); border:2px solid var(--ink); padding:14px 16px; position:relative; }
  .tpsMasthead{ display:flex; justify-content:space-between; align-items:flex-start; gap:12px; font-family:'Space Mono',monospace; font-size:12px; border-bottom:2px solid var(--ink); padding-bottom:8px; margin-bottom:6px; }
  .tpsNote{ font-size:12px; color:#5c5844; margin-top:12px; }
  .tpsRow{ display:flex; flex-direction:column; gap:4px; margin-bottom:10px; }
  .tpsRow label{ font-family:'Space Mono',monospace; font-weight:700; font-size:12px; }
  .tpsRow .formfield{ margin-bottom:0; }
  .tpsPriorityCritical{ color:var(--danger); font-weight:700; }
  .tpsStampArea{ border:2px dashed #8f856b; min-height:70px; position:relative; margin:14px 0; display:flex; align-items:center; justify-content:center; }
  .tpsStamp{ border:4px solid var(--good); color:var(--good); background:none; font-family:'Press Start 2P',monospace; font-size:15px; padding:8px 12px; transform:rotate(-8deg); opacity:0; letter-spacing:1px; }
  .tpsStamp.show{ opacity:0.85; }
  .tpsStamp.rejected{ border-color:var(--danger); color:var(--danger); }
  .tpsTrayRow{ display:flex; gap:10px; margin-top:14px; flex-wrap:wrap; }
  .tpsTrayRow .supportbtn{ flex:1; min-width:140px; }
  .supportbtn:disabled{ opacity:0.5; cursor:not-allowed; }
  .tpsQuota{ border:2px solid var(--warn); color:var(--warn); padding:10px 12px; text-align:center; font-size:14px; width:100%; }
  .tpsProblems{ color:var(--danger); font-size:14px; margin-top:12px; line-height:1.5; }
  .tpsProblems ul{ margin:6px 0; padding-left:18px; }

  /* terminal */
  .terminalOutput{ background:#0c0f0a; border:2px solid var(--ink); color:#8fef6a; font-family:'Space Mono',monospace; font-size:13px; padding:10px; height:220px; overflow-y:auto; white-space:pre-wrap; margin-bottom:10px; }
  .terminalInputRow{ display:flex; align-items:center; gap:6px; background:#0c0f0a; border:2px solid var(--ink); padding:8px 10px; }
  .terminalPrompt{ color:#8fef6a; font-family:'Space Mono',monospace; font-size:13px; }
  .terminalInput{ flex:1; min-width:0; background:transparent; border:none; color:#8fef6a; font-family:'Space Mono',monospace; font-size:13px; outline:none; }

  /* quick \-bar */
  .quickBar{ position:absolute; left:14px; right:14px; bottom:14px; z-index:9999; background:rgba(8,8,6,0.94); border:2px solid var(--ink); box-shadow:4px 4px 0 rgba(0,0,0,0.5); display:none; flex-direction:column; opacity:0; transition:opacity 0.25s; }
  .quickBar.show{ display:flex; opacity:1; }
  .quickBar.fading{ opacity:0; }
  .quickBarLog{ max-height:180px; overflow-y:auto; padding:8px 10px 0; color:#8fef6a; font-family:'Space Mono',monospace; font-size:13px; white-space:pre-wrap; }
  .quickBarLog:empty{ padding:0; }
