/* Loading Dock — area by tiling and decomposing. SABE Learn */
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }

:root{
    /* SABE Learn tokens — matches css/style.css */
    --bg:#F7F6F2;
    --bg-alt:#EEECEA;
    --paper:#FFFFFF;
    --bg-purple:#EDEAFF;
    --bg-yellow:#FFF9E0;
    --bg-teal:#E2F8F3;
    --bg-coral:#FFEEEA;

    --ink:#0B0F1A;
    --ink-2:#374151;
    --ink-3:#71717A;

    --purple:#5533E8;
    --purple-dark:#3D1FC9;
    --yellow:#F5C200;
    --yellow-dark:#C9A000;
    --yellow-ink:#5C4600;
    --coral:#E84530;
    --coral-dark:#C43320;
    --teal:#009E82;
    --teal-dark:#007A65;

    --border:#DDDBD4;
    --border-2:#C8C5BC;

    --shadow-xs:0 1px 2px rgba(0,0,0,.06);
    --shadow-sm:0 2px 6px rgba(0,0,0,.08);
    --shadow:0 4px 14px rgba(0,0,0,.09);
    --shadow-lg:0 8px 24px rgba(0,0,0,.10);

    --r-xs:2px; --r:6px; --r-lg:10px; --r-xl:14px;
    --t:.2s cubic-bezier(.4,0,.2,1);

    /* dock theme */
    --deck:#EFEBE1;        /* the bed planking */
    --deck-2:#E7E2D6;
    --rail:#6B7280;        /* bed rails */
    --gridline:#CFC9BA;
    --crate:#E8C77A;       /* cargo already aboard */
    --crate-edge:#A9812F;
    --chalk:#5533E8;       /* ruled / cut lines */
    --tapec:#E84530;       /* the measuring tape */

    /* ---- industrial chrome: this is dispatch software, not a consumer app ----
       Sharp corners, 1px steel rules, condensed signage type for labels and a
       mono for every number, because on a dock every number is a reading. */
    --cond:'Barlow Condensed','Barlow',Impact,sans-serif;
    --mono:'IBM Plex Mono',ui-monospace,SFMono-Regular,Menlo,monospace;

    --steel-900:#12161b;   /* the ground */
    --steel-800:#1b2128;
    --steel-700:#242b34;   /* panel face */
    --steel-600:#39434f;   /* rules */
    --steel-500:#4d5866;
    --steel-300:#93a0b0;   /* muted label */
    --steel-100:#dbe2ea;   /* body */
    --hazard:#F2A81C;      /* caution yellow: headers, armed tools */
    --signal:#12D6A4;      /* go, correct, money */
    --alarm:#FF5B3D;       /* stop, wrong */
    --paper-w:#EDE6D4;     /* the work order */
    --paper-ink:#211C12;
    --paper-rule:#C6BCA2;

    /* deck sizing — set by fitDeck() */
    --u:18px;              /* one square foot */
    --w:12; --h:6;
}

[hidden]{display:none!important}

html,body{
    min-height:100%;
    font-family:'Barlow','Inter',-apple-system,BlinkMacSystemFont,sans-serif;
    background:var(--steel-900);
    color:var(--steel-100);
    -webkit-font-smoothing:antialiased;
    -webkit-user-select:none; user-select:none;
    -webkit-tap-highlight-color:transparent;
}
body{overflow-y:auto; overflow-x:hidden;}

/* The ground is poured in CSS rather than painted: a texture that sits under
   body text has to be guaranteed quiet, and every generated "plain concrete"
   came back as warehouse racking. */
.game-viewport{min-height:100dvh;display:flex;align-items:flex-start;justify-content:center;width:100%;
    background:
      repeating-linear-gradient(90deg,rgba(255,255,255,.014) 0 1px,transparent 1px 5px),
      repeating-linear-gradient(0deg,rgba(0,0,0,.30) 0 1px,transparent 1px 132px),
      radial-gradient(130% 90% at 50% -10%,#28313c 0%,#171d24 55%,#0e1217 100%)}

.back-link{position:absolute;top:10px;left:12px;z-index:40;
    font-family:var(--cond);font-size:.8125rem;font-weight:700;letter-spacing:.16em;
    text-transform:uppercase;color:var(--steel-300);text-decoration:none;
    padding:5px 11px;border:1px solid var(--steel-600);background:rgba(14,18,23,.82)}
.back-link:hover{color:var(--hazard);border-color:var(--hazard)}

#app{width:100%;max-width:1200px;padding:46px 14px 30px;display:flex;flex-direction:column;gap:10px;
    touch-action:none}

/* ---------- dispatch status bar ---------- */
#hud{display:flex;align-items:center;gap:13px;flex-wrap:wrap;position:relative;
    background:linear-gradient(#2b343f,#1d242b);
    border:1px solid var(--steel-600);border-top:3px solid var(--hazard);padding:8px 14px}
.bay{font-family:var(--mono);font-size:.75rem;font-weight:700;letter-spacing:.1em;
    color:#0f1318;background:var(--hazard);padding:3px 8px}
.hud-tier{font-family:var(--cond);font-size:1.1875rem;font-weight:700;letter-spacing:.07em;
    text-transform:uppercase;color:#fff}
#dots{display:flex;gap:7px;margin-right:auto}
#dots i{width:10px;height:10px;border-radius:50%;background:#2b333d;display:block;
    box-shadow:inset 0 0 0 1px #0b0e12, inset 0 1px 1px rgba(255,255,255,.09)}
#dots i.on{background:var(--signal);box-shadow:0 0 7px rgba(18,214,164,.85),inset 0 0 0 1px #0b0e12}
#dots i.miss{background:var(--alarm);box-shadow:0 0 7px rgba(255,91,61,.8),inset 0 0 0 1px #0b0e12}
#dots i.now{background:var(--hazard);box-shadow:0 0 8px rgba(242,168,28,.9),inset 0 0 0 1px #0b0e12;
    animation:blink 1.7s steps(1,end) infinite}
@keyframes blink{0%,62%{opacity:1}63%,100%{opacity:.3}}
.hud-right{display:flex;gap:14px;align-items:center;font-family:var(--cond);font-size:.8125rem;
    font-weight:600;letter-spacing:.15em;text-transform:uppercase;color:var(--steel-300)}
.hud-right b{font-family:var(--mono);font-size:1rem;font-weight:700;color:var(--signal);
    background:#0d1116;border:1px solid var(--steel-600);padding:2px 9px;margin-left:9px;
    text-shadow:0 0 9px rgba(18,214,164,.55)}

/* ---------- the task strip ---------- */
#prompt{background:linear-gradient(#262e38,#1d242c);border:1px solid var(--steel-600);
    padding:11px 16px 12px 22px;position:relative}
#prompt::before{content:'';position:absolute;left:0;top:0;bottom:0;width:7px;
    background:repeating-linear-gradient(135deg,var(--hazard) 0 7px,#14181e 7px 14px)}
#promptText{font-family:var(--cond);font-size:1.3125rem;font-weight:700;letter-spacing:.02em;color:#fff}
#promptSub{font-size:.875rem;color:var(--steel-300);margin-top:1px;min-height:1.1em}
#prompt.bad{border-color:var(--alarm)}
#prompt.bad::before{background:repeating-linear-gradient(135deg,var(--alarm) 0 7px,#14181e 7px 14px)}
#prompt.bad #promptText{color:#FFC0B2}
#prompt.good{border-color:var(--signal)}
#prompt.good::before{background:repeating-linear-gradient(135deg,var(--signal) 0 7px,#14181e 7px 14px)}
#prompt.good #promptText{color:#8FF2D9}

/* ---------- the camera feed ----------
   Every CCTV convention is about degradation — scanlines, noise, desaturation —
   and this game is won by reading a grid precisely. So the treatment lives in
   the margins: brackets, labels, a REC lamp, and a vignette that only reaches
   the outermost edge. Nothing tints, blurs or stripes the floor itself. */
#cctv{position:absolute;inset:7px;pointer-events:none;z-index:20;
    font-family:var(--mono);font-size:.6875rem;font-weight:600;letter-spacing:.08em}
#cctv::after{content:'';position:absolute;inset:0;
    box-shadow:inset 0 0 44px rgba(8,10,14,.30)}
.cbr{position:absolute;width:20px;height:20px;border:2px solid rgba(255,255,255,.62);
    filter:drop-shadow(0 1px 2px rgba(0,0,0,.8))}
.cbr.tl{top:9px;left:9px;border-right:none;border-bottom:none}
.cbr.tr{top:9px;right:9px;border-left:none;border-bottom:none}
.cbr.bl{bottom:9px;left:9px;border-right:none;border-top:none}
.cbr.br{bottom:9px;right:9px;border-left:none;border-top:none}
.ctag{position:absolute;color:rgba(255,255,255,.9);
    text-shadow:0 1px 3px rgba(0,0,0,.95),0 0 10px rgba(0,0,0,.7)}
.ctag.tl{top:11px;left:37px}
.ctag.tr{top:11px;right:37px;display:flex;align-items:center;gap:6px}
.ctag.bl{bottom:11px;left:37px}
.ctag.br{bottom:11px;right:37px}
.rec{width:8px;height:8px;border-radius:50%;background:#FF3B2F;
    box-shadow:0 0 9px rgba(255,59,47,.95);animation:rec 2.1s steps(1,end) infinite}
@keyframes rec{0%,55%{opacity:1}56%,100%{opacity:.12}}

/* ---------- the verdict ----------
   Stamped onto the camera feed rather than murmured in the task strip: the
   result of a call is the loudest moment in the round and it should land like
   a stamp hitting paper. */
#verdict{position:absolute;left:50%;top:50%;z-index:30;pointer-events:none;
    transform:translate(-50%,-50%) rotate(-1.5deg);
    width:max-content;max-width:min(520px,82%);padding:16px 30px 17px 26px;
    border:2px solid var(--steel-600);border-left:10px solid var(--hazard);
    background:linear-gradient(rgba(22,27,33,.96),rgba(14,18,23,.96));
    box-shadow:0 18px 50px rgba(0,0,0,.65), inset 0 1px 0 rgba(255,255,255,.08);
    display:flex;flex-direction:column;gap:3px;
    animation:stamp .42s cubic-bezier(.2,1.5,.4,1) both}
@keyframes stamp{
    0%{opacity:0;transform:translate(-50%,-50%) rotate(-9deg) scale(2.5)}
    60%{opacity:1}
    100%{opacity:1;transform:translate(-50%,-50%) rotate(-1.5deg) scale(1)}}
#verdict .vhead{font-family:var(--cond);font-size:clamp(1.6rem,3.4vw,2.5rem);font-weight:700;
    letter-spacing:.06em;text-transform:uppercase;color:#fff;line-height:1}
#verdict .vsub{font-family:var(--mono);font-size:.8125rem;color:var(--steel-300);
    letter-spacing:.02em;line-height:1.5;white-space:normal}
#verdict.good{border-left-color:var(--signal)}
#verdict.good .vhead{color:#8FF2D9}
#verdict.bad{border-left-color:var(--alarm)}
#verdict.bad .vhead{color:#FFC0B2}
#verdict.bad{animation:stamp .42s cubic-bezier(.2,1.5,.4,1) both, shake .4s .42s both}
@keyframes shake{
    0%,100%{transform:translate(-50%,-50%) rotate(-1.5deg)}
    20%{transform:translate(calc(-50% - 9px),-50%) rotate(-3deg)}
    45%{transform:translate(calc(-50% + 8px),-50%) rotate(0deg)}
    72%{transform:translate(calc(-50% - 4px),-50%) rotate(-2deg)}}
#verdict.away{animation:vaway .4s ease-in both}
@keyframes vaway{to{opacity:0;transform:translate(-50%,-64%) rotate(-1.5deg) scale(.94)}}

/* money leaving the bay and landing in the shift-pay readout */
.cashfly{position:fixed;z-index:80;pointer-events:none;transform:translate(-50%,-50%);
    font-family:var(--mono);font-size:1.5rem;font-weight:700;color:var(--signal);
    text-shadow:0 0 14px rgba(18,214,164,.85),0 2px 6px rgba(0,0,0,.9);
    transition:transform .62s cubic-bezier(.4,0,.25,1), opacity .62s ease-in}
.cashfly.loss{color:var(--alarm);text-shadow:0 0 14px rgba(255,91,61,.85),0 2px 6px rgba(0,0,0,.9)}
.hud-right b.hit{animation:payhit .5s cubic-bezier(.3,1.6,.4,1)}
.hud-right b.drop{animation:paydrop .5s ease-out;color:var(--alarm);
    text-shadow:0 0 10px rgba(255,91,61,.6)}
@keyframes payhit{0%{transform:scale(1)}35%{transform:scale(1.4);
    box-shadow:0 0 0 3px rgba(18,214,164,.35)}100%{transform:scale(1)}}
@keyframes paydrop{0%,100%{transform:translateX(0)}25%{transform:translateX(-6px)}
    60%{transform:translateX(5px)}}

/* ---------- stage: the bay window and the console beside it ---------- */
/* The trailer is a wide object, so the bay gets the full width and the console
   sits under it as a row of modules — the way a dispatch terminal is laid out,
   and it stops the manifest and the dispatch panel being stacked in a column. */
#stage{display:flex;flex-direction:column;gap:10px}

/* ============================ THE YARD ============================ */
#deckWrap{width:100%;flex:none;height:clamp(290px,48vh,530px);padding:7px;overflow:hidden;
    position:relative;display:flex;flex-direction:column;border-radius:3px;
    background:linear-gradient(#20262e,#151a20);border:1px solid #0a0d11;
    box-shadow:inset 0 1px 0 rgba(255,255,255,.07), 0 10px 26px rgba(0,0,0,.6)}
#feed{flex:1;display:flex;overflow:hidden;position:relative;background:#cfcabd;
    box-shadow:inset 0 0 0 1px #05070a}
#yard{position:relative;width:100%;padding:40px 16px 36px;display:flex;
    justify-content:center;align-items:center;min-height:230px;
    background:url(assets/bay.png) center/cover no-repeat}
/* the bay floor is busy; knock it back so the freight stays the loudest thing */
#yard::before{content:'';position:absolute;inset:0;pointer-events:none;
    background:rgba(243,240,232,.30)}

/* a forklift goes about its business behind the truck */
#forklift{position:absolute;left:0;top:6px;width:72px;height:54px;z-index:1;pointer-events:none;
    background:url(assets/forklift.png) center/contain no-repeat;opacity:.92;
    animation:trundle 26s linear infinite}
@keyframes trundle{
    0%  {transform:translateX(-90px) scaleX(1)}
    40% {transform:translateX(min(560px,70vw)) scaleX(1)}
    45% {transform:translateX(min(560px,70vw)) scaleX(-1)}
    92% {transform:translateX(-90px) scaleX(-1)}
    100%{transform:translateX(-90px) scaleX(1)}}

/* the bed plus its two rulers, laid out as a small grid */
#bedGrid{display:grid;grid-template-columns:auto auto;grid-template-rows:auto auto;gap:3px;
    position:relative;z-index:2;--cabw:60px;--cabgap:36px;
    /* the cab hangs off the front, so shove the grid over to centre the whole rig */
    margin-left:calc(var(--cabw) - 20px)}
#cornerPad{grid-area:1/1}
/* The rulers have to sit ON the trailer, not behind it: the side rail is drawn
   inside #deck and was covering the one control level 2 depends on. */
#rulerTop{grid-area:1/2;position:relative;height:16px;z-index:9}
#rulerLeft{grid-area:2/1;position:relative;width:16px;z-index:9}

/* ============================ THE TRUCK ============================
   #deck is the trailer interior and nothing else — exactly w x h square feet.
   Every rail, wheel, door and the cab hangs off it by a negative offset, so the
   lattice the maths depends on is never disturbed by the scenery. */
#deck{grid-area:2/2;position:relative;box-sizing:content-box;
    width:calc(var(--w) * var(--u));height:calc(var(--h) * var(--u));
    background:url(assets/floor.png) left top/auto calc(7 * var(--u)) repeat;
    box-shadow:inset 0 0 0 1px rgba(60,44,28,.45), inset 0 0 30px rgba(44,30,14,.34),
               0 12px 22px rgba(30,24,16,.34)}

.rig{position:absolute;inset:0;pointer-events:none;z-index:0}

/* trailer side walls, seen from above as ribbed aluminium */
.rail{position:absolute;left:-3px;right:-3px;height:13px;z-index:6;
    background:linear-gradient(#eef1f4,#b3bac1 45%,#79818a);
    border:1px solid #545b63;border-radius:3px;box-shadow:0 2px 5px rgba(0,0,0,.3)}
.rail::after{content:'';position:absolute;inset:2px 5px;
    background:repeating-linear-gradient(90deg,transparent 0,transparent 5px,
        rgba(84,91,99,.42) 5px,rgba(84,91,99,.42) 6px)}
.rail.top{top:-14px}
.rail.bot{bottom:-14px}

/* wheels, poking out from under the trailer */
.bogie{position:absolute;bottom:-27px;height:15px;width:36px;z-index:5;border-radius:2px;
    background:repeating-linear-gradient(90deg,#272b31 0,#272b31 10px,transparent 10px,transparent 14px);
    filter:drop-shadow(0 2px 2px rgba(0,0,0,.4))}
.bogie.rear {right:calc(var(--u) * 0.8)}
.bogie.front{right:calc(var(--u) * 3.2)}

/* the cab, scaled off the trailer's width so the rig stays in proportion */
.cabart{position:absolute;top:50%;right:100%;margin-right:var(--cabgap,36px);
    /* ratio of the TRIMMED art: the box edge is now the painted edge, so the
       coupling at the cab's rear lines up with the gooseneck spanning the gap */
    height:calc(var(--h) * var(--u) + 36px);aspect-ratio:498/294;
    transform:translateY(-50%);z-index:7;
    background:url(assets/cab.png) center/contain no-repeat;
    filter:drop-shadow(0 7px 11px rgba(30,24,16,.4));
    animation:idlebob 3.6s ease-in-out infinite}
@keyframes idlebob{0%,100%{transform:translateY(-50%)}50%{transform:translateY(calc(-50% + 1.5px))}}

.puff{position:absolute;left:50%;top:24%;width:13px;height:13px;border-radius:50%;
    background:radial-gradient(circle,rgba(255,255,255,.9),rgba(255,255,255,0) 70%);
    animation:puff 2.9s ease-out infinite}
@keyframes puff{0%{opacity:0;transform:scale(.4)}
    20%{opacity:.7}
    100%{opacity:0;transform:scale(2.2) translate(5px,-24px)}}

/* The coupling. A trailer does not hitch to the back of a tractor — its
   kingpin drops into the fifth-wheel plate, the dark horseshoe sitting over the
   rear axles. Measured off the art, that plate is at 81% of the cab's width, so
   the gooseneck reaches back from the trailer's nose, over the tractor frame,
   and ends on the plate. It is drawn ABOVE the cab because that is the real
   stacking order: the trailer's neck overhangs the tractor. */
.hitch{position:absolute;top:50%;right:100%;margin-right:-6px;z-index:8;
    width:calc(var(--cabgap,36px) + var(--cabw,60px) * 0.19 + 6px);
    height:clamp(14px,calc(var(--h) * var(--u) * .24),38px);
    transform:translateY(-50%);
    background:linear-gradient(#656e79,#3c444e 55%,#2b313a);
    border-top:2px solid #22272d;border-bottom:2px solid #22272d;
    border-radius:3px 2px 2px 3px;
    box-shadow:inset 0 2px 0 rgba(255,255,255,.15), 0 4px 9px rgba(0,0,0,.55)}
/* two frame rails running the length of the gooseneck */
.hitch::before{content:'';position:absolute;left:0;right:0;top:20%;bottom:20%;
    background:linear-gradient(180deg,
        #7f8893 0 24%, transparent 24% 76%, #7f8893 76% 100%);
    opacity:.85}
/* the kingpin, seated in the plate at the far end */
.hitch::after{content:'';position:absolute;left:11px;top:50%;width:14px;height:14px;
    transform:translate(-50%,-50%);border-radius:50%;
    background:radial-gradient(circle,#aab3bd 0 30%,#3d444d 31% 100%);
    box-shadow:0 0 0 2px #1d2228, 0 1px 3px rgba(0,0,0,.7)}

/* the front bulkhead you load up against */
.sill{position:absolute;top:-14px;bottom:-14px;left:100%;width:4px;z-index:6;
    background:linear-gradient(90deg,#9aa2aa,#5f666e);border:1px solid #4d545c;border-radius:0 2px 2px 0}
.bulkhead{position:absolute;top:-14px;bottom:-14px;right:100%;width:8px;z-index:6;
    background:linear-gradient(90deg,#868e96,#c9cfd5);
    border:1px solid #545b63;border-radius:3px 0 0 3px}

/* rear doors, hinged on the trailer's back corners and swaying a little */
.door{position:absolute;left:calc(100% + 3px);width:13px;height:calc(50% + 14px);z-index:6;
    background:linear-gradient(90deg,#d5dade,#9aa2aa 55%,#79818a);
    border:1px solid #4d545c;border-radius:2px;box-shadow:2px 3px 8px rgba(0,0,0,.35)}
.door::after{content:'';position:absolute;inset:3px 2px;
    background:repeating-linear-gradient(180deg,transparent 0,transparent 4px,
        rgba(77,84,92,.4) 4px,rgba(77,84,92,.4) 5px)}
.door{transition:transform .5s cubic-bezier(.22,.9,.28,1)}
.door.up{top:-14px;transform-origin:left top;transform:rotate(-28deg)}
.door.dn{bottom:-14px;transform-origin:left bottom;transform:rotate(28deg)}
.door.closed{transform:rotate(0)!important;animation:none!important}
.door.swaying{transition:none}
.door.up.swaying{animation:swayA 7s ease-in-out infinite alternate}
.door.dn.swaying{animation:swayB 7s ease-in-out infinite alternate}
@keyframes swayA{from{transform:rotate(-25deg)}to{transform:rotate(-32deg)}}
@keyframes swayB{from{transform:rotate(25deg)} to{transform:rotate(32deg)}}

.cell{position:absolute;width:var(--u);height:var(--u);z-index:1}
#deck.gridded .cell{box-shadow:inset 0 0 0 1px rgba(255,246,222,.5)}
#deck.countable .cell{cursor:pointer}
.cell.ticked::after{content:'';position:absolute;inset:13%;border-radius:2px;
    background:var(--teal);opacity:.6;box-shadow:0 0 0 1px rgba(255,255,255,.55)}

/* ---- freight already aboard: the reason the free space is an odd shape ---- */
.cargo{position:absolute;z-index:5;border-radius:2px;
    background-size:calc(var(--u) * 2) calc(var(--u) * 2);background-repeat:repeat;
    box-shadow:0 0 0 1px rgba(38,26,12,.55), 0 5px 10px rgba(24,18,10,.45),
               inset 0 0 0 2px rgba(255,255,255,.10)}
.strap{position:absolute;top:-1px;bottom:-1px;width:7px;
    background:linear-gradient(90deg,rgba(0,0,0,.35),rgba(126,92,44,.95),rgba(0,0,0,.35));
    box-shadow:0 0 3px rgba(0,0,0,.45)}
.strap.a{left:20%} .strap.b{left:68%}

/* chalk lines — the same tool rules the grid on L2 and cuts pieces on L3+ */
.cut{position:absolute;z-index:4;background:var(--chalk)}
.cut.v{width:2px;top:-3px;bottom:-3px;margin-left:-1px}
.cut.h{height:2px;left:-3px;right:-3px;margin-top:-1px}
.cut.ghost{opacity:.35}

/* piece tint + letter, shown once a cut makes real rectangles */
.piece{position:absolute;z-index:2;border-radius:2px;pointer-events:none;
    display:flex;align-items:center;justify-content:center;font-weight:800;font-size:.875rem}
/* a wash light enough to leave the planking visible, strong enough to read
   against it — a 6% tint that worked on white paper vanishes on oiled timber */
/* Enough wash to tell the pieces apart, not enough to bury the planking —
   the tint is an annotation on the trailer, not a repaint of it. */
.piece.ok{background:rgba(120,90,255,.16);color:var(--purple-dark);
    box-shadow:inset 0 0 0 2px rgba(85,51,232,.55)}
.piece.ok.alt{background:rgba(0,190,160,.16);box-shadow:inset 0 0 0 2px rgba(0,158,130,.6)}
.piece.lit{background:rgba(120,90,255,.34)}
.piece.bad{background:rgba(232,69,48,.12);color:var(--coral-dark)}
.piece b{background:rgba(255,255,255,.8);border-radius:3px;padding:0 5px;line-height:1.4}

/* measuring — an edge you can tape, and the number once you have */
.edge{position:absolute;z-index:6}
.edge.h{height:14px;margin-top:-7px}
.edge.v{width:14px;margin-left:-7px}
#app.taping .edge{cursor:pointer;background:rgba(232,69,48,.16);border-radius:3px}
#app.taping .edge:hover{background:rgba(232,69,48,.34)}
/* A dimension line, drawn the way a drawing draws one: the line spans the exact
   extent being measured, a cap closes each end, and the figure sits on the
   middle of it — so the number is tied to a span instead of floating near one. */
.dimline{position:absolute;z-index:8;pointer-events:none;--dc:var(--tapec)}
.dimline.h{height:0;border-top:2px solid var(--dc)}
.dimline.v{width:0;border-left:2px solid var(--dc)}
.dimline::before,.dimline::after{content:'';position:absolute;background:var(--dc);border-radius:1px}
.dimline.h::before,.dimline.h::after{top:-7px;width:2px;height:16px}
.dimline.h::before{left:-1px} .dimline.h::after{right:-1px}
.dimline.v::before,.dimline.v::after{left:-7px;height:2px;width:16px}
.dimline.v::before{top:-1px} .dimline.v::after{bottom:-1px}
.dimline b{position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);
    background:var(--dc);color:#fff;font-size:.6875rem;font-weight:800;line-height:1.45;
    padding:0 5px;border-radius:3px;white-space:nowrap;
    box-shadow:0 1px 3px rgba(0,0,0,.35)}
/* Colour says what a dimension belongs to: red is the trailer itself, caution
   yellow is freight already aboard. Cream on cream washed out over pale cargo
   like straw, and the halo alone was doing too much work. */
/* the trailer's height figure rides up its line so it clears the gooseneck,
   which runs across the middle of that same lane */
.dimline.v.bed b{top:27%}
.dimline.on{--dc:#F2A81C;filter:drop-shadow(0 1px 2px rgba(20,14,4,.9))}
.dimline.on b{color:#1A1408;box-shadow:0 1px 3px rgba(0,0,0,.5)}

/* rulers — live only on the level where you rule the grid in yourself */
/* chalk-coloured and haloed, so a notch reads against grey metal as easily as
   against concrete */
.tick{position:absolute;background:rgba(85,51,232,.92);border-radius:1px;
    box-shadow:0 0 0 1px rgba(255,255,255,.75)}
#rulerTop .tick{width:2px;top:1px;height:31px}
#rulerLeft .tick{height:2px;left:1px;width:24px}
#bedGrid.live .hit{position:absolute;z-index:3;cursor:pointer;border-radius:3px}
#bedGrid.live .hit:hover{background:rgba(85,51,232,.16)}
/* generous touch targets: this is the one level where the ruler is the control */
#rulerTop .hit{top:-4px;bottom:-4px;width:26px;margin-left:-13px}
#rulerLeft .hit{left:-4px;right:-4px;height:26px;margin-top:-13px}
.rlabel{position:absolute;font-size:.75rem;font-weight:800;color:var(--ink-2);white-space:nowrap}
#rulerTop .rlabel{left:50%;top:-2px;transform:translate(-50%,-100%)}
#rulerLeft .rlabel{top:50%;left:-2px;transform:translate(-100%,-50%)}

/* the rig pulls out of frame, cab first — far enough that the tractor clears
   too, which is why the distance is the trailer plus the cab, not a flat % */
#bedGrid.driving{animation:driveoff 1.15s cubic-bezier(.42,0,.88,.42) forwards}
@keyframes driveoff{to{transform:translateX(var(--drive,-140%))}}
/* the next one reverses back in along the same path, easing to a stop */
#bedGrid.backing{animation:backin 1s cubic-bezier(.17,.66,.3,1) both}
@keyframes backin{from{transform:translateX(var(--drive,-140%))}to{transform:none}}
#bedGrid.driving .cabart,#bedGrid.backing .cabart{animation:none}
#bedGrid.driving .puff,#bedGrid.backing .puff{animation-duration:.55s}

/* ---- the crates going on, once the call is right ---- */
/* crates that would not fit, stranded on the dock — they belong to the yard,
   not the trailer, so they stay behind when it pulls out */
.crate.spill{position:absolute;z-index:3;border-radius:2px;background-repeat:repeat;
    box-shadow:0 0 0 2px var(--alarm), inset 0 0 0 2px rgba(255,255,255,.25),
               0 4px 9px rgba(20,14,6,.55);
    animation:spillin .3s cubic-bezier(.3,1.5,.5,1) both}
@keyframes spillin{from{opacity:0}}

.crate{position:absolute;z-index:4;border-radius:2px;
    background-size:calc(var(--u) * 2) calc(var(--u) * 2);background-repeat:repeat;
    box-shadow:0 0 0 1.5px #6d4b22, inset 0 0 0 2px rgba(255,238,196,.38),
               0 3px 7px rgba(24,18,10,.42);
    animation:thud .26s cubic-bezier(.3,1.5,.5,1) both}
@keyframes thud{from{transform:scale(.55) translateY(-20px);opacity:0}to{transform:none;opacity:1}}

/* ---------- console modules ---------- */
#side{display:flex;flex-direction:row;flex-wrap:wrap;align-items:stretch;gap:10px;width:100%}
#manifest{flex:1 1 340px;min-width:280px}
#workCard{flex:1 1 250px;min-width:210px}
#dispatch{flex:1 1 300px;min-width:250px;display:flex;flex-direction:column}
#dispatch .bigbox{margin-bottom:auto}
.panelcard{position:relative;padding:11px 13px 12px;border:1px solid var(--steel-600);
    background:url(assets/ui-steel.png) center/320px repeat, linear-gradient(#262e37,#1e242c);
    background-blend-mode:soft-light,normal;
    box-shadow:inset 0 1px 0 rgba(255,255,255,.05), 0 3px 10px rgba(0,0,0,.4)}
/* a stencilled header bar, bled to the panel edges */
.cardhead{margin:-11px -13px 10px;padding:5px 12px;
    background:linear-gradient(#333d4a,#252d36);border-bottom:1px solid var(--steel-600);
    font-family:var(--cond);font-size:.8125rem;font-weight:700;text-transform:uppercase;
    letter-spacing:.17em;color:var(--hazard)}

/* ---- the manifest is a printed work order, not a card ---- */
#manifest{background:var(--paper-w);border:1px solid #b9ae92;color:var(--paper-ink);
    padding:11px 100px 11px 31px;min-height:120px;
    box-shadow:0 3px 10px rgba(0,0,0,.45)}
/* continuous-feed sprocket holes down the left edge */
#manifest::before{content:'';position:absolute;left:0;top:0;bottom:0;width:21px;
    background-color:#E2DAC5;
    background-image:radial-gradient(circle at 10.5px 11px,#BFB398 3.4px,transparent 3.9px);
    background-size:21px 22px;border-right:1px dashed #B9AE92}
#manifest .cardhead{margin:-11px -100px 9px -31px;padding:5px 12px 5px 31px;
    background:var(--paper-ink);border-bottom:none;color:var(--paper-w);letter-spacing:.2em}
#manifest::after{content:'';position:absolute;right:-6px;bottom:-2px;width:104px;height:126px;
    background:url(assets/foreman.png) right bottom/contain no-repeat;pointer-events:none;
    filter:drop-shadow(-2px 2px 4px rgba(30,24,16,.3))}
.mline{display:flex;justify-content:space-between;align-items:baseline;gap:10px;
    padding:4px 0;border-bottom:1px dotted var(--paper-rule)}
.mline span{font-family:var(--cond);font-size:.75rem;font-weight:600;letter-spacing:.13em;
    text-transform:uppercase;color:#6E6148;white-space:nowrap}
.mline b{font-family:var(--mono);font-size:.875rem;font-weight:700;color:var(--paper-ink);text-align:right}
.mnote{font-size:.78125rem;color:#6E6148;margin-top:6px;line-height:1.45}

.cratefig{display:flex;align-items:center;gap:18px;margin:16px 0 4px;padding:30px 4px 6px 56px}
/* one crate at its real proportions, with a side length written on each side —
   never the two numbers side by side, which would do the multiplying for them */
.cratebox{position:relative;width:calc(var(--cw) * 30px);height:calc(var(--ch) * 30px);
    min-width:66px;min-height:66px;border-radius:2px;
    background-size:34px 34px;background-repeat:repeat;
    box-shadow:0 0 0 1.5px #6d4b22, inset 0 0 0 2px rgba(255,238,196,.4), 0 2px 5px rgba(24,18,10,.35)}
.clab{position:absolute;font-family:var(--mono);font-size:.8125rem;font-weight:700;color:#fff;
    background:var(--tapec);border-radius:2px;padding:2px 7px;white-space:nowrap;
    box-shadow:0 1px 3px rgba(0,0,0,.3)}
/* a cap at each end, so the chip reads as bounding that side and not floating near it */
.clab::before,.clab::after{content:'';position:absolute;background:var(--tapec)}
.clab.top{bottom:calc(100% + 9px);left:50%;transform:translateX(-50%)}
.clab.top::before,.clab.top::after{top:50%;width:calc(50% - 2px);height:2px}
.clab.top::before{right:100%;margin-right:4px} .clab.top::after{left:100%;margin-left:4px}
.clab.side{right:calc(100% + 9px);top:50%;transform:translateY(-50%)}
.clab.side::before,.clab.side::after{left:50%;height:calc(50% - 2px);width:2px}
.clab.side::before{bottom:100%;margin-bottom:4px} .clab.side::after{top:100%;margin-top:4px}
.cratecap{display:flex;flex-direction:column;gap:3px}
.cratecap b{font-family:var(--cond);font-size:1.0625rem;font-weight:700;letter-spacing:.13em;
    text-transform:uppercase;color:var(--paper-ink);line-height:1}
.cratecap span{font-family:var(--mono);font-size:.8125rem;color:#6E6148}

/* ---- the tally sheet ---- */
#workRows{display:flex;flex-direction:column;gap:0}
.wrow{display:flex;align-items:center;gap:9px;padding:5px 0;
    border-bottom:1px solid rgba(255,255,255,.055)}
.wchip{width:24px;height:24px;flex:0 0 24px;border-radius:0;background:#333d4a;
    border:1px solid var(--steel-600);color:var(--hazard);
    font-family:var(--cond);font-weight:700;font-size:.875rem;
    display:flex;align-items:center;justify-content:center;cursor:default}
.wchip.minus{background:#4a2b25;border-color:#6b3a30;color:#FFB0A0}
.wlabel{flex:1;font-family:var(--cond);font-size:.9375rem;font-weight:600;letter-spacing:.06em;
    text-transform:uppercase;color:var(--steel-300)}
/* every number is a reading: mono, inset, glowing faintly like a meter */
.wrow input,.bigbox input{font-family:var(--mono);font-size:.9375rem;font-weight:700;
    color:var(--signal);width:78px;padding:6px 8px;border:1px solid var(--steel-600);
    border-radius:0;background:#0d1116;text-align:center;
    -webkit-user-select:text;user-select:text;
    box-shadow:inset 0 2px 4px rgba(0,0,0,.65)}
.wrow input:focus,.bigbox input:focus{outline:none;border-color:var(--hazard);color:#fff;
    box-shadow:inset 0 2px 4px rgba(0,0,0,.65), 0 0 0 2px rgba(242,168,28,.25)}
.wrow input.bad,.bigbox input.bad{border-color:var(--alarm);color:#FFC0B2;
    box-shadow:inset 0 2px 4px rgba(0,0,0,.65), 0 0 0 2px rgba(255,91,61,.3)}
.wunit{font-family:var(--mono);font-size:.6875rem;color:var(--steel-300);width:38px}
.wempty{font-size:.84375rem;color:var(--steel-300);line-height:1.5}
.wtotal{border-top:1px solid var(--steel-600);margin-top:3px;padding-top:9px}

.bigbox{display:flex;align-items:center;gap:10px;margin-top:0;border-top:none;padding-top:0}
.bigbox .wlabel{font-weight:700;color:#fff;font-size:1rem}
.bigbox input{width:98px;font-size:1.375rem;letter-spacing:.06em;padding:9px 8px}

/* ---- steel switches ---- */
#tools{display:flex;flex-wrap:wrap;gap:7px}
.tool{font-family:var(--cond);font-size:.8125rem;font-weight:700;letter-spacing:.07em;
    text-transform:uppercase;color:var(--steel-100);cursor:pointer;border-radius:0;
    background:linear-gradient(#3b4552,#2a323b);border:1px solid var(--steel-600);
    padding:7px 10px;transition:none;
    box-shadow:inset 0 1px 0 rgba(255,255,255,.08), 0 2px 0 #161b21}
.tool:hover{border-color:var(--hazard);color:#fff}
.tool:active{transform:translateY(2px);box-shadow:inset 0 1px 0 rgba(255,255,255,.08),0 0 0 #161b21}
.tool.on{background:linear-gradient(#FFC04A,#D08C0C);border-color:#8A5C08;color:#1A1408;
    box-shadow:inset 0 2px 5px rgba(0,0,0,.45)}
.tool.tape.on{background:linear-gradient(#FF8468,#E0431F);border-color:#A5301C;color:#2A0D07}

/* ---- the action button ---- */
.btn{font-family:var(--cond);font-size:1.1875rem;font-weight:700;letter-spacing:.16em;
    text-transform:uppercase;color:#08110E;cursor:pointer;border-radius:0;border:1px solid #06856A;
    background:linear-gradient(#3BE9BD,#07A785);padding:11px 20px;transition:none;
    box-shadow:0 4px 0 #04624F, inset 0 1px 0 rgba(255,255,255,.45)}
.btn:hover{background:linear-gradient(#54F0C9,#0BB894)}
.btn:active{transform:translateY(4px);box-shadow:0 0 0 #04624F, inset 0 1px 0 rgba(255,255,255,.45)}
.btn.ghost{background:linear-gradient(#3b4552,#2a323b);color:var(--steel-100);
    border:1px solid var(--steel-600);box-shadow:0 4px 0 #161b21}
.btn.ghost:hover{background:linear-gradient(#46515f,#333c46)}
.btn:disabled{opacity:.4;cursor:default;transform:none}
#shipBtn{width:100%}

/* drag layer */
#fx{position:fixed;inset:0;pointer-events:none;z-index:60}
.ghosttool{position:absolute;transform:translate(-50%,-50%);border-radius:0;
    font-family:var(--cond);font-size:.875rem;font-weight:700;letter-spacing:.1em;
    text-transform:uppercase;padding:7px 11px;
    background:var(--hazard);color:#1A1408;border:1px solid #8A5C08;
    box-shadow:0 4px 12px rgba(0,0,0,.5)}
.ghosttool.tape{background:var(--alarm);color:#2A0D07;border-color:#A5301C}

/* ---------- the shift board ---------- */
.overlay{position:fixed;inset:0;z-index:70;background:rgba(6,9,12,.88);
    display:flex;align-items:center;justify-content:center;padding:20px;overflow-y:auto}
.overlay .panel{max-width:560px;width:100%;padding:26px 26px 28px;text-align:center;
    border:1px solid var(--steel-600);border-top:4px solid var(--hazard);border-radius:0;
    background:url(assets/ui-steel.png) center/340px repeat, linear-gradient(#28313b,#1c232a);
    background-blend-mode:soft-light,normal;
    box-shadow:0 24px 70px rgba(0,0,0,.75), inset 0 1px 0 rgba(255,255,255,.06)}
.overlay h1{font-family:var(--cond);font-size:clamp(2.1rem,6.5vw,3.1rem);font-weight:700;
    letter-spacing:.07em;text-transform:uppercase;color:#fff;margin-bottom:4px;line-height:1}
.overlay h1 span{color:var(--hazard)}
.overlay p{font-size:.9375rem;color:var(--steel-300);line-height:1.6;margin-bottom:18px}

.tiers{display:flex;flex-direction:column;gap:6px;margin-bottom:20px;text-align:left}
.trow{display:flex;align-items:center;gap:11px;padding:10px 13px;border-radius:0;
    border:1px solid var(--steel-600);cursor:pointer;
    background:linear-gradient(#2e3844,#232a33)}
.trow:hover{border-color:var(--hazard);background:linear-gradient(#39445230,#2a323c)}
.trow .tn{font-family:var(--cond);font-size:1.0625rem;font-weight:700;letter-spacing:.07em;
    text-transform:uppercase;color:#fff}
.trow .tb{font-family:var(--mono);font-size:.6875rem;color:var(--steel-300);
    margin-left:auto;text-align:right;letter-spacing:.02em}
.trow.lock{opacity:.38;cursor:default;background:linear-gradient(#232a33,#1c222a)}
.trow.lock:hover{border-color:var(--steel-600)}

.stars{font-size:2rem;color:var(--hazard);letter-spacing:6px;margin-bottom:4px;
    text-shadow:0 0 14px rgba(242,168,28,.5)}
.big-score{font-family:var(--mono);font-size:2.5rem;font-weight:700;letter-spacing:.02em;color:#fff}
#endCash{font-family:var(--mono);font-size:1rem;color:var(--signal);margin-bottom:6px;
    text-shadow:0 0 10px rgba(18,214,164,.4)}
.end-actions{display:flex;flex-direction:column;gap:8px;margin-top:18px}

/* ---------- TEACHER GUIDE ---------- */
.tg-section{background:#F7F6F2;border-top:4px solid var(--hazard);color:#0B0F1A;padding:56px 24px 64px;
    font-family:'Inter',sans-serif;color:var(--ink);line-height:1.6}
.tg-inner{max-width:960px;margin:0 auto}
.tg-eyebrow{font-size:.75rem;font-weight:700;text-transform:uppercase;letter-spacing:.09em;color:var(--teal);margin:0 0 8px;display:block}
.tg-heading{font-size:clamp(1.5rem,3vw,2rem);font-weight:800;margin:0 0 10px;letter-spacing:-.02em}
.tg-intro{font-size:1rem;color:var(--ink-2);max-width:680px;margin:0 0 32px;line-height:1.7}
.tg-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(260px,1fr));gap:18px;margin-bottom:36px}
.tg-card{background:var(--paper);border:2px solid var(--border);border-radius:var(--r-lg);padding:22px}
.tg-card h3{font-size:.9375rem;font-weight:700;margin:0 0 12px}
.tg-card ul{list-style:none;padding:0;margin:0;display:flex;flex-direction:column;gap:8px}
.tg-card li{font-size:.875rem;color:var(--ink-2);padding-left:18px;position:relative;line-height:1.55}
.tg-card li::before{content:'→';position:absolute;left:0;color:var(--teal);font-size:.75rem;top:3px}
.tg-std{font-weight:700;color:var(--purple)}
.tg-faq{border-top:2px solid var(--border);padding-top:24px;display:flex;flex-direction:column;gap:10px}
.tg-faq details{border:2px solid var(--border);border-radius:var(--r);padding:14px 18px;background:var(--paper)}
.tg-faq summary{font-weight:700;font-size:.9375rem;cursor:pointer;list-style:none;color:var(--ink)}
.tg-faq summary::-webkit-details-marker{display:none}
.tg-faq summary::before{content:'+ ';color:var(--teal)}
.tg-faq details[open] summary::before{content:'− '}
.tg-faq details p{margin:10px 0 0;font-size:.875rem;color:var(--ink-2);line-height:1.6}

@media (max-width:880px){
    #app{padding:38px 8px 24px}
    #stage{flex-direction:column}
    #side{flex-direction:column}
    /* min-widths tuned for a console row will burst a 320px phone once stacked */
    #manifest,#workCard,#dispatch{min-width:0;flex:1 1 auto}
    /* the foreman's gutter and the enlarged crate figure set a min-content width
       of ~330px, which bursts a 320px phone — pull both in rather than let the
       page scroll sideways */
    #manifest{padding:11px 76px 11px 26px}
    #manifest .cardhead{margin:-11px -76px 9px -26px;padding-left:26px}
    #manifest::after{width:80px;height:98px}
    .cratefig{padding:26px 2px 6px 44px;gap:12px}
    .cratecap b{font-size:.9375rem}
    #deckWrap{height:auto}
    #feed{overflow-x:auto;overflow-y:hidden}
    .ctag.br{display:none}
    #deckWrap{width:100%;padding:6px;overflow:hidden;flex:0 0 auto}
    /* the yard grows past the panel and pans, rather than squeezing the trailer
       down to something no finger can hit */
    #yard{width:max-content;min-width:100%;padding:38px 14px 32px}
    #side{width:100%;flex:0 0 auto}
}

@media (prefers-reduced-motion: reduce){
    #forklift,.cabart,.puff,.door,.crate{animation:none!important}
    #bedGrid.backing,#bedGrid.driving{animation-duration:.01s!important}
    .door{transition:none}
}
