*,*::before,*::after{box-sizing:border-box;margin:0;padding:0}
@property --pc{syntax:'<color>';inherits:true;initial-value:#4a90d9}
:root{
    --serif:"Iowan Old Style","Palatino Linotype","Book Antiqua",Palatino,Georgia,serif;
    --bg:#f1f4f8;
    --panel:#ffffff;
    --panel-2:#f5f7fa;
    --border:#d9dee6;
    --text:#1d232c;
    --muted:#5c6673;
    --accent:#1e5bb8;
    --accent-bg:#1e5bb8;
    --accent-text:#fff;
    --danger:#c62828;
    --sea:#cfe0ef;
    --sea-grid:#bfd3e6;
    --land-unowned:#e4e7ec;
    --land-stroke:#55606e;
    --cont-stroke:#1d232c;
    --badge-bg:#ffffff;
    --badge-text:#1d232c;
    --overlay:rgba(10,14,20,.55);
    --shadow:0 10px 30px rgba(0,0,0,.18);
    --sel:#ffd54f;
    --target:#ff5252;
    --ok:#2e7d32;
    --ok-text:#2e7d32;
    --danger-text:#c62828;
}
[data-theme="dark"]{
    --bg:#13161c;
    --panel:#1d2129;
    --panel-2:#242933;
    --border:#333a46;
    --text:#e8ecf2;
    --muted:#98a2b3;
    --accent:#4a90d9;
    --accent-bg:#2f6fb8;    /* white text on filled controls: 5.1:1 (the #4a90d9 accent is 3.3:1) */
    --sea:#1f2e40;
    --sea-grid:#263a4f;
    --land-unowned:#4b5563;
    --land-stroke:#0f1319;
    --cont-stroke:#e8ecf2;
    --badge-bg:#0f1319;
    --badge-text:#f5f7fa;
    --overlay:rgba(0,0,0,.65);
    --shadow:0 10px 30px rgba(0,0,0,.5);
    --ok-text:#81c784;      /* 8.0:1 on the dark panel; --ok itself is 2.9:1 */
    --danger-text:#ff8a80;  /* 7.1:1 */
}
html{transition:--pc .5s;font-size:clamp(16px,7px + .55vw,20px)}   /* wide windows get bigger text, not only more room */
html,body{height:100%;font-family:'Inter',system-ui,sans-serif;background:var(--bg);color:var(--text);-webkit-user-select:none;user-select:none}
body{overflow:hidden}

/* ---------------------------------------------------------------- layout, mobile first
   The base is the portrait phone: one screen, no page scroll — header, one-line banner, the map
   at its own 1000:560 aspect, turn box, battle box, then ONE scrolling region (players, board,
   log, game controls). Media queries further down rearrange the same grid for landscape phones,
   tablets, near-square and wide windows. --hh/--tb are the header/toolbar heights the map maths uses. */
.app{--hh:44px;--tb:36px;--gap:6px;height:100vh;height:100dvh;display:flex;flex-direction:column}
.app-header{height:var(--hh);display:flex;align-items:center;justify-content:space-between;gap:8px;padding:0 4px 0 10px;background:var(--panel);border-bottom:1px solid var(--border);flex-shrink:0}
.app-title{font-family:var(--serif);font-variant:small-caps;font-size:1.05rem;font-weight:700;display:flex;align-items:center;gap:7px;letter-spacing:.6px;white-space:nowrap}
.title-icon{display:inline-flex;width:24px;height:24px}
.title-icon .mark,.win-icon .mark{width:100%;height:100%}
.header-actions{display:flex;align-items:center;gap:2px}
.hdr-btn{background:none;border:1px solid transparent;color:var(--text);border-radius:8px;width:36px;height:36px;display:flex;align-items:center;justify-content:center;gap:6px;font:inherit;font-size:.8rem;font-weight:600;cursor:pointer;white-space:nowrap}
.hdr-btn:hover{background:var(--panel-2)}
.hdr-btn svg{width:20px;height:20px}
.hdr-btn .lbl{display:none}
.icon-btn{background:none;border:none;cursor:pointer;color:var(--text);padding:6px;border-radius:8px;display:flex;align-items:center;justify-content:center;width:36px;height:36px}
.icon-btn:hover{background:var(--panel-2)}
.icon-btn svg{width:20px;height:20px}
[data-theme="light"] .icon-moon{display:none}
[data-theme="dark"] .icon-sun{display:none}

.layout{flex:1;min-height:0;display:grid;grid-template-columns:minmax(0,1fr);grid-template-rows:auto auto minmax(0,1fr);grid-template-areas:"bar" "map" "side";gap:var(--gap);padding:var(--gap) 8px}
.map-panel{display:contents}   /* toolbar, map and under-map strip are placed on the grid directly */
.map-toolbar{grid-area:bar;display:flex;align-items:center;gap:8px;min-width:0;min-height:var(--tb)}
.bar-title:empty,.bar-actions:empty,.bar-extra:empty{display:none}
.bar-title{display:flex;align-items:center;flex-shrink:0}
.bar-actions,.bar-extra{display:flex;align-items:center;gap:6px;flex-shrink:0}
.bar-extra{margin-left:auto}
/* phase banner: swatch + whose turn, then the stepper; only the current step below 600 px */
.phase-banner{flex:1 1 auto;min-width:0;height:var(--tb);display:flex;align-items:center;gap:8px;padding:0 6px 0 11px;font-size:.82rem;font-weight:700;background:var(--panel);border:1px solid var(--border);border-radius:10px;box-shadow:inset 3px 0 0 var(--pc);white-space:nowrap;overflow:hidden}
.phase-banner.mine{border-color:var(--pc)}
.pb-sw{display:inline-flex;flex-shrink:0}
.pb-sw:empty{display:none}
.pb-sw .swatch{width:12px;height:12px;display:inline-block;border-radius:50%}
.pb-who{flex:1 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis}
.phase-steps{list-style:none;display:flex;align-items:center;gap:14px;flex-shrink:0;font-size:.74rem;font-weight:600;color:var(--muted)}
.phase-steps li{position:relative;padding:3px 8px;border-radius:999px;display:inline-flex;flex-direction:column;align-items:center}
.phase-steps li[data-label]::after{content:attr(data-label);font-weight:800;height:0;visibility:hidden;overflow:hidden}   /* the lit step's bold width, reserved, so nothing shifts */
.phase-steps li[data-step=attack]::before,.phase-steps li[data-step=fortify]::before,.phase-banner[data-step=setup] li[data-step=reinforce]::before{content:'\203A';position:absolute;left:-10px;color:var(--muted);opacity:.7}
.phase-steps li.on{color:var(--text);font-weight:800;background:color-mix(in srgb,var(--pc) 24%,transparent);box-shadow:inset 0 0 0 1px var(--pc)}
.phase-banner:not([data-step=setup]) li[data-step=setup],.phase-banner:not([data-step=over]) li[data-step=over],.phase-banner[data-step=over] li:not([data-step=over]){display:none}
.phase-banner[data-step=""] .phase-steps{display:none}
.pb-round{flex-shrink:0;font-size:.72rem;font-weight:600;color:var(--muted);font-variant-numeric:tabular-nums;min-width:4.4em;text-align:right}
.pb-short{display:none}
.pb-note{display:none;min-width:0;overflow:hidden;text-overflow:ellipsis;font-size:.72rem;font-weight:600;color:var(--muted)}
.pb-round:empty{display:none}
/* zoom: a floating stack on the map's left edge, below Alaska — open Pacific at the world view */
.zoom-controls{position:absolute;left:6px;top:38%;z-index:15;display:flex;flex-direction:column;gap:4px}
.zoom-btn{width:2rem;height:2rem;border-radius:8px;border:1px solid var(--border);background:color-mix(in srgb,var(--panel) 90%,transparent);color:var(--text);font-size:1.1rem;line-height:1;cursor:pointer;display:flex;align-items:center;justify-content:center;box-shadow:0 1px 4px rgba(0,0,0,.25)}
.zoom-btn svg{width:17px;height:17px}
.zoom-btn:hover{background:var(--panel-2)}
.zoom-btn:disabled{opacity:.45;cursor:default}
.zoom-btn:disabled:hover{background:var(--panel)}
.zoom-controls.at-world #zoomWorld,.zoom-controls:not(.at-world) #zoomMine{display:none}   /* one slot: World ⇄ My territories */

.map-wrap{grid-area:map;position:relative;width:100%;aspect-ratio:1000/560;align-self:start;justify-self:center;min-height:0;background:var(--sea);border:1px solid var(--border);border-radius:12px;overflow:hidden;touch-action:none}
.under-map{grid-area:under;display:none}
.side-panel{grid-area:side;min-height:0;min-width:0;container-type:inline-size;overflow-y:auto;overscroll-behavior:contain}
.side-grid{height:100%;display:flex;flex-direction:column;gap:var(--gap)}
.turn-box,.battle-box{flex:none}
.more{flex:1 1 0;min-height:0;overflow-y:auto;overscroll-behavior:contain;display:flex;flex-direction:column;gap:var(--gap);container-type:inline-size}
.standalone .more{margin-bottom:46px}   /* the site's home pill sits in the strip below */
#map{width:100%;height:100%;display:block;cursor:grab}
#map.dragging{cursor:grabbing}
#map .terr{stroke:var(--land-stroke);stroke-width:1;stroke-linejoin:round;vector-effect:non-scaling-stroke;transition:fill .25s,opacity .25s;cursor:pointer}
#map .terr.unowned{fill:var(--land-unowned)}
#map .terr.dim{opacity:.62}
#map .terr.selectable{filter:brightness(1.12)}
/* highlight layer: cloned outlines above all territories, constant pixel width, dark casing under a light line */
#map .hl{display:none;pointer-events:none}
#map .hl.on{display:inline}
#map .hl path{fill:none;stroke-linejoin:round;vector-effect:non-scaling-stroke}
#map .hl .hl-case{stroke:#000;stroke-opacity:.5;stroke-width:3.6}
#map .hl .hl-line{stroke:#fff;stroke-opacity:.85;stroke-width:1.5}
#map .hl.act .hl-line{animation:hlBreathe 1.8s ease-in-out infinite}
#map .hl.src .hl-case{stroke-opacity:.7;stroke-width:6}
#map .hl.src .hl-line{stroke:var(--sel);stroke-opacity:1;stroke-width:3}
#map .hl.tgt .hl-case{stroke-opacity:.6;stroke-width:5}
#map .hl.tgt .hl-line{stroke:var(--target);stroke-opacity:1;stroke-width:2.4;stroke-dasharray:6 3;animation:hlDash .6s linear infinite}
#map .hl.chosen .hl-line{stroke-dasharray:none;stroke-width:3;animation:none}
@keyframes hlBreathe{0%,100%{stroke-opacity:.55}50%{stroke-opacity:1}}
@keyframes hlDash{to{stroke-dashoffset:-9}}
#map .terr.hover{filter:brightness(1.25)}
#map .sea-link{stroke:var(--cont-stroke);stroke-opacity:.45;stroke-width:1.2;stroke-dasharray:4 4;vector-effect:non-scaling-stroke;fill:none;pointer-events:none}
#map .cont-outline{fill:none;stroke:var(--cont-stroke);stroke-opacity:.35;stroke-width:1.4;stroke-linejoin:round;vector-effect:non-scaling-stroke;pointer-events:none;transition:stroke-opacity .3s}
#map .cont-outline.held{stroke-opacity:.95;stroke-width:2.6;filter:drop-shadow(0 0 3px currentColor)}
#map .cont-outline.focus{stroke-opacity:1;stroke-width:3.4}
#map .cont-outline.flash{animation:contFlash .6s ease-in-out 3}
@keyframes contFlash{0%,100%{stroke-width:2.6}50%{stroke-width:6}}
#map .grat{stroke:var(--sea-grid);stroke-width:1;vector-effect:non-scaling-stroke;pointer-events:none}
#map .sea-label{font-family:var(--serif);font-variant:small-caps;font-weight:700;fill:var(--cont-stroke);fill-opacity:.32;text-anchor:middle;dominant-baseline:central;pointer-events:none}
#map .badge{pointer-events:none}
#map .badge .bshape{fill:var(--badge-bg);stroke:var(--own,#000);stroke-width:1.6;stroke-linejoin:round}
#map .badge text{fill:var(--badge-text);font-family:'Inter',sans-serif;font-weight:700;font-size:10px;text-anchor:middle;dominant-baseline:central}
#map .badge.big text{font-size:8.5px}
#map .badge.pulse .bshape{stroke:var(--sel);stroke-width:2.6}
#map .tname{font-family:'Inter',sans-serif;font-size:6.5px;font-weight:600;fill:var(--cont-stroke);fill-opacity:.92;text-anchor:middle;dominant-baseline:central;pointer-events:none;paint-order:stroke;stroke:var(--sea);stroke-width:1.6;stroke-opacity:.8;stroke-linejoin:round}
#map .tname.hide{display:none}
#map .fx{pointer-events:none}
#map .fx-terr{fill:none;stroke-linejoin:round;vector-effect:non-scaling-stroke}
#map .fx-from{stroke-width:4;animation:fxPulse .5s ease-in-out 4}
#map .fx-to{stroke:var(--target);stroke-width:3.5;stroke-dasharray:5 3;animation:fxDash .4s linear infinite}
#map .fx-to.hit{fill:var(--target);fill-opacity:.55;stroke-dasharray:none;stroke-width:3;animation:fxFlash .9s ease-out forwards}
#map .fx-to.captured{fill-opacity:.7;animation:fxCapture 1.2s ease-out forwards}
#map .fx-arrow-casing{stroke:#000;stroke-opacity:.75;stroke-width:8;stroke-linecap:round;fill:none}
#map .fx-arrow{stroke-width:4.5;stroke-linecap:round;fill:none}
#map .fx-head{opacity:0;stroke:#000;stroke-opacity:.75;stroke-width:2;stroke-linejoin:round;paint-order:stroke}
#map .fx-loss{font-family:'Inter',sans-serif;font-weight:900;font-size:20px;text-anchor:middle;paint-order:stroke;stroke:#000;stroke-width:5px;stroke-linejoin:round}
#map .fx-loss.def{fill:#ff6b6b}
#map .fx-loss.att{fill:#ffd166}
#map .fx-ring{fill:none;stroke-width:3}
@keyframes fxPulse{0%,100%{stroke-opacity:.4;stroke-width:3.5}50%{stroke-opacity:1;stroke-width:6.5}}
@keyframes fxDash{to{stroke-dashoffset:-6}}
@keyframes fxFlash{0%{fill-opacity:.7;stroke-opacity:1}100%{fill-opacity:0;stroke-opacity:0}}
@keyframes fxCapture{0%{fill-opacity:.85;stroke-opacity:1}100%{fill-opacity:0;stroke-opacity:0}}


.amount-picker{display:none;position:absolute;z-index:20;background:var(--panel);border:1px solid var(--border);border-radius:12px;padding:10px 12px;box-shadow:var(--shadow);width:230px}
.amount-picker.active{display:block}
.ap-title{font-size:.78rem;font-weight:700;margin-bottom:6px}
.ap-row{display:flex;align-items:center;gap:8px;margin-top:6px}
.ap-row input[type=range]{flex:1;accent-color:var(--accent)}
.ap-step{flex-shrink:0;width:28px;height:28px;border-radius:7px;border:1px solid var(--border);background:var(--panel-2);color:var(--text);font-size:1rem;cursor:pointer}
.ap-value{font-size:1.4rem;font-weight:800;min-width:40px}
.ap-mini{border:1px solid var(--border);background:var(--panel-2);color:var(--text);border-radius:6px;padding:3px 8px;font:inherit;font-size:.72rem;cursor:pointer}
.ap-buttons{justify-content:flex-end}

.players{display:flex;flex-direction:column;gap:4px;flex-shrink:0}
.player-row{position:relative;overflow:hidden;display:grid;grid-template-columns:14px minmax(0,1fr) auto;align-items:center;gap:8px;padding:6px 10px;border-radius:9px;background:var(--panel);border:1px solid var(--border);font-size:.8rem}
.player-row .share{position:absolute;left:0;bottom:0;height:3px;opacity:.85;transition:width .4s}
.player-row.current{border-color:var(--pc);box-shadow:inset 3px 0 0 var(--pc)}
.player-row.dead{opacity:.45;text-decoration:line-through}
.player-row .swatch{width:14px;height:14px;border-radius:50%;border:2px solid rgba(0,0,0,.25)}
.player-row .pname{font-weight:700;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;display:flex;align-items:center;gap:6px}
.player-row .tag{font-size:.62rem;font-weight:700;padding:1px 5px;border-radius:5px;background:var(--panel-2);color:var(--muted);border:1px solid var(--border)}
.player-row .stats{color:var(--text);font-size:.72rem;white-space:nowrap;display:flex;gap:6px;align-items:center;font-variant-numeric:tabular-nums}
.player-row .stats i{font-style:normal;color:var(--muted)}
.player-row .stats .cards.warn{color:#f0b429}
.player-row .stats .cards.danger{color:var(--danger-text);font-weight:700}
.player-row .stats .inc{color:var(--ok-text);font-weight:700}
.player-row .dot{width:7px;height:7px;border-radius:50%;background:#9e9e9e;display:inline-block}
.player-row .dot.online{background:#43a047}

.turn-box{background:var(--panel);border:1px solid var(--border);border-left:3px solid var(--pc);border-radius:12px;padding:10px 12px;flex-shrink:0}
.turn-title{font-weight:800;font-size:.95rem;display:flex;align-items:center;gap:8px}
.turn-title .swatch{width:12px;height:12px;border-radius:50%;display:inline-block}
.turn-hint{color:var(--muted);font-size:.78rem;margin-top:4px;line-height:1.4}
.actions{display:flex;flex-wrap:wrap;gap:6px;margin-top:10px}
.badge{display:inline-block;min-width:18px;padding:0 5px;border-radius:9px;background:var(--accent-bg);color:#fff;font-size:.68rem;font-weight:700;margin-left:4px;text-align:center}
.badge.warn{background:var(--danger)}

.btn{border:1px solid var(--border);background:var(--panel-2);color:var(--text);border-radius:9px;padding:8px 12px;font:inherit;font-size:.8rem;font-weight:700;cursor:pointer;transition:background .15s,transform .05s}
.btn:hover{filter:brightness(1.05)}
.btn:active{transform:translateY(1px)}
.btn:disabled{opacity:.45;cursor:default}
.btn.primary{background:var(--accent-bg);border-color:var(--accent-bg);color:var(--accent-text)}
.btn.danger{background:var(--danger);border-color:var(--danger);color:#fff}
.btn.small{padding:5px 9px;font-size:.74rem}
.btn.attack{background:#b71c1c;border-color:#b71c1c;color:#fff}

.battle-box{background:var(--panel);border:1px solid var(--border);border-radius:12px;padding:10px 12px;font-size:.8rem;flex-shrink:0}
.battle-head{font-weight:700;margin-bottom:6px;display:flex;justify-content:space-between;align-items:center;gap:6px}
.battle-head .vs{color:var(--muted);font-weight:600}
.dice-row{display:flex;align-items:center;gap:6px;margin:4px 0}
.dice-row .lbl{width:64px;color:var(--muted);font-size:.72rem}
.die{width:26px;height:26px;border-radius:6px;display:inline-flex;align-items:center;justify-content:center;font-weight:800;font-size:.9rem;border:1px solid rgba(0,0,0,.3);box-shadow:inset 0 -2px 0 rgba(0,0,0,.15)}
.die.att{background:#d32f2f;color:#fff}
.die.def{background:#f5f5f5;color:#1a1a1a}
.die.win{outline:2px solid var(--sel)}
.battle-result{margin-top:6px;font-weight:600}
.battle-result .lost{color:var(--danger-text)}
.battle-result .won{color:var(--ok-text)}
.battle-ctl{display:flex;flex-wrap:wrap;gap:6px;margin-top:8px;align-items:center}
.dice-pick{display:inline-flex;border:1px solid var(--border);border-radius:8px}
.dice-pick button{border:none;background:var(--panel-2);color:var(--text);padding:6px 10px;font:inherit;font-weight:700;cursor:pointer;font-size:.78rem}
.dice-pick button.on{background:var(--accent-bg);color:#fff}
.dice-pick button:disabled{opacity:.4;cursor:default}
.odds{color:var(--muted);font-size:.72rem;margin-left:auto}
.odds-line{color:var(--muted);font-size:.74rem;margin-top:6px}
.dice-lbl{color:var(--muted);font-size:.72rem;margin-right:-2px}
.turn-chips{display:flex;flex-wrap:wrap;gap:5px;margin-top:6px}
.turn-chips:empty{display:none}
.chip{font-size:.72rem;line-height:1.3;padding:3px 8px;border-radius:999px;background:var(--panel-2);border:1px solid var(--border);color:var(--text)}
.chip.ok{border-color:var(--ok-text);color:var(--ok-text)}
.chip.income{font-weight:600}
.color-field{display:flex;flex-direction:column;gap:6px;font-size:.78rem;font-weight:600;color:var(--muted)}
.color-pick{display:flex;gap:8px;flex-wrap:wrap}
.cswatch{width:28px;height:28px;border-radius:50%;border:2px solid var(--border);cursor:pointer;padding:0}
.cswatch.on{border-color:var(--text);box-shadow:0 0 0 2px var(--panel),0 0 0 4px var(--accent)}
.speed-pick{display:inline-flex;align-items:center;gap:6px;font-size:.74rem;color:var(--muted);font-weight:600}
.speed-pick select{font:inherit;font-size:.76rem;padding:5px 6px;border-radius:8px;border:1px solid var(--border);background:var(--panel-2);color:var(--text)}

.log-wrap{flex:none;height:13rem;background:var(--panel);border:1px solid var(--border);border-radius:12px;overflow:hidden;display:flex;flex-direction:column}
.log{flex:1;overflow-y:auto;padding:8px 10px;font-size:.74rem;line-height:1.45;color:var(--muted);-webkit-user-select:text;user-select:text}
.log div{padding:1px 0;border-bottom:1px dashed var(--border)}
.log div:last-child{border-bottom:none}
.log .sw{display:inline-block;width:8px;height:8px;border-radius:50%;margin-right:5px;vertical-align:middle}
.log .hi{color:var(--text);font-weight:600}
.log .turnrow{color:var(--text);font-weight:600;margin:5px -10px 2px;padding:3px 10px 3px 8px;border-left:3px solid var(--pc,var(--border));background:var(--panel-2);border-bottom:none}
.log .turnrow.round{font-weight:800}
.log .cap{color:var(--text)}
.log .big{color:var(--text);font-weight:700}
.log .guide{border:none;color:var(--muted);line-height:1.5}
.log .guide b{color:var(--text)}
.log .guide ol{margin:6px 0 6px 18px}
.log .guide li{margin:3px 0}

/* New game / Play with others / Resign. Near-square windows and portrait tablets give the row its own
   strip at the foot of the panel, so it is always on screen. Where the whole sidebar scrolls (landscape
   phones, wide windows) it sits at the foot when there is room and scrolls with the panel otherwise:
   pinned there it covered the turn box's own buttons. On phones layoutSlots() puts it back at the end of
   #more, because a fixed row left the players list a sliver of room. */
.controls{display:flex;flex-wrap:wrap;gap:6px;flex-shrink:0;justify-content:flex-end}
.log-toggle{display:none;align-items:center;justify-content:space-between;width:100%;border:none;background:none;color:var(--text);font:inherit;font-size:.76rem;font-weight:700;padding:8px 10px;cursor:pointer;min-height:36px}
.log-toggle .lt-ico{color:var(--muted);transition:transform .2s}
.log-wrap.open .log-toggle .lt-ico{transform:rotate(180deg)}

/* The overlay scrolls and the dialog centres with margin:auto, so a dialog taller than the
   screen starts at the top instead of being cut off at both ends (iOS). dvh follows Safari's bars. */
.modal-overlay{position:fixed;inset:0;background:var(--overlay);display:none;z-index:100;padding:12px;overflow-y:auto;overscroll-behavior:contain}
.modal-overlay.active{display:flex}
.modal{background:var(--panel);color:var(--text);border-radius:16px;padding:22px;width:100%;max-width:420px;box-shadow:var(--shadow);text-align:center;margin:auto;max-height:calc(100vh - 24px);max-height:calc(100dvh - 24px);overflow-y:auto;overscroll-behavior:contain;position:relative}
.modal:focus{outline:none}
.modal.wide{max-width:560px}
.modal-title{font-family:var(--serif);font-variant:small-caps;font-size:1.45rem;font-weight:700;letter-spacing:.4px;margin-bottom:6px}
.modal-sub{color:var(--muted);font-size:.85rem;margin-bottom:14px;line-height:1.45}
/* actions stay on screen while a long dialog scrolls */
.modal-actions{display:flex;flex-wrap:wrap;justify-content:flex-end;gap:8px;position:sticky;bottom:-22px;z-index:2;margin:16px -22px -22px;padding:12px 22px 22px;background:var(--panel);border-radius:0 0 16px 16px}
.modal-head{display:flex;align-items:center;gap:10px;position:sticky;top:-22px;z-index:2;margin:-22px -22px 8px;padding:16px 16px 8px 22px;background:var(--panel)}
.modal-head .modal-title{flex:1;margin:0;text-align:left}
.modal-x{flex-shrink:0;width:36px;height:36px;border-radius:9px;border:1px solid var(--border);background:var(--panel-2);color:var(--text);font-size:1.3rem;line-height:1;cursor:pointer}
.modal-x:hover{background:var(--border)}
.form-grid{display:grid;grid-template-columns:1fr 1fr;gap:10px 14px;text-align:left}
.form-grid.single{grid-template-columns:1fr}
.form-grid label{display:flex;flex-direction:column;gap:4px;font-size:.74rem;font-weight:600;color:var(--muted)}
.form-grid label.checkbox{flex-direction:row;align-items:center;grid-column:1 / -1;color:var(--text);font-weight:500;font-size:.8rem;gap:8px}
.form-grid input[type=text],.form-grid select{font:inherit;font-size:.85rem;padding:8px 10px;border-radius:8px;border:1px solid var(--border);background:var(--panel-2);color:var(--text);width:100%}
.form-grid input[type=checkbox]{width:16px;height:16px;accent-color:var(--accent)}
.win-icon{font-size:3rem;margin:0 auto 6px;width:64px;height:64px;color:var(--text)}

.cards-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(96px,1fr));gap:8px;margin-top:6px}
.card{border:2px solid var(--border);border-radius:10px;padding:8px 6px;background:var(--panel-2);color:var(--text);font:inherit;cursor:pointer;display:flex;flex-direction:column;align-items:center;gap:4px;min-height:92px;justify-content:center}
.card:disabled{cursor:default;opacity:1}
.card:focus-visible{outline:2px solid var(--accent);outline-offset:2px}
.card.sel{border-color:var(--accent);box-shadow:0 0 0 2px var(--accent) inset}
.card .sym{font-size:1.6rem;line-height:1}
.card .cname{font-size:.68rem;font-weight:700;text-align:center;line-height:1.2}
.card .ctype{font-size:.62rem;color:var(--muted);text-transform:uppercase;letter-spacing:.5px}
.card.owned .cname{color:var(--ok-text)}
.card.wild{background:linear-gradient(135deg,#ffe082,#ffab91)}
.card.wild .cname,.card.wild .ctype{color:#4e342e}

.share-group{display:flex;gap:6px;margin-bottom:12px}
.share-input{flex:1;font:inherit;font-size:.78rem;padding:8px 10px;border-radius:8px;border:1px solid var(--border);background:var(--panel-2);color:var(--text);-webkit-user-select:text;user-select:text}
.lobby-seats{display:flex;flex-direction:column;gap:6px;text-align:left}
.seat-row{display:grid;grid-template-columns:14px 1fr auto;align-items:center;gap:8px;padding:7px 10px;border:1px solid var(--border);border-radius:9px;background:var(--panel-2);font-size:.82rem}
.seat-row .swatch{width:14px;height:14px;border-radius:50%;border:2px solid rgba(0,0,0,.25)}
.seat-row .sname{font-weight:700;display:flex;align-items:center;gap:6px}
.seat-row .tag{font-size:.62rem;font-weight:700;padding:1px 5px;border-radius:5px;background:var(--panel);color:var(--muted);border:1px solid var(--border)}
.seat-row .empty{color:var(--muted);font-style:italic;font-weight:500}
.lobby-host{margin-top:10px}
.lobby-add{display:flex;gap:6px;justify-content:center;align-items:center}
.lobby-add select{font:inherit;font-size:.8rem;padding:6px 8px;border-radius:8px;border:1px solid var(--border);background:var(--panel-2);color:var(--text)}

.rules-body{text-align:left;font-size:.84rem;line-height:1.5;color:var(--text)}
.rules-body h3{font-size:.9rem;margin:12px 0 4px}
.rules-body p,.rules-body ol{margin-bottom:8px}
.rules-body ol{padding-left:20px}
.rules-body li{margin-bottom:4px}

.toast-container{position:fixed;bottom:18px;left:50%;transform:translateX(-50%);display:flex;flex-direction:column;gap:6px;z-index:200;pointer-events:none}
.toast{background:#263238;color:#fff;padding:8px 14px;border-radius:9px;font-size:.8rem;font-weight:600;opacity:0;transform:translateY(8px);transition:opacity .25s,transform .25s;box-shadow:var(--shadow)}
.toast.visible{opacity:1;transform:translateY(0)}

/* touch screens: 44 px targets for everything pressed often, no double-tap zoom on rapid taps */
button,select{touch-action:manipulation}
@media (pointer:coarse){
    .btn{min-height:44px}
    .btn.small{min-height:42px;padding-left:12px;padding-right:12px}
    #rollBtn,#blitzBtn{padding-left:16px;padding-right:16px}
    .dice-pick button{min-width:44px;min-height:42px}
    .zoom-btn{min-width:40px;height:40px}
    .ap-step{width:40px;height:40px}
    .ap-mini{min-height:36px;padding:6px 12px}
    .ap-row input[type=range]{height:32px}
    .icon-btn,.hdr-btn{width:42px;height:42px}
    .modal-x{width:44px;height:44px}
    .speed-pick select{min-height:40px}
    .pop-x{min-width:36px;min-height:36px;margin:-6px -6px -6px 0}
    .pop-row{min-height:40px}
    .cswatch{width:36px;height:36px}
    .amount-picker{width:250px}
    .map-wrap .atk-pop{width:330px}   /* dice, Roll and All in stay on one row at 44 px */
    .ap-step{flex-shrink:0}
}

/* ---------------------------------------------------------------- phone shell details */
.turn-box{padding:8px 10px}
.turn-hint{display:-webkit-box;-webkit-line-clamp:3;-webkit-box-orient:vertical;overflow:hidden}
.actions{justify-content:flex-end}
@media (max-width:599px){
    .phase-steps li:not(.on),.phase-steps li::before,.pb-round{display:none!important}
    .pb-who{flex:0 0 auto}
    .pb-long{display:none}
    .pb-short{display:inline}
    .pb-note:not(:empty){display:block;flex:1 1 auto;text-align:right}
    .turn-title{font-size:.9rem}
    .turn-hint{font-size:.76rem;-webkit-line-clamp:2}
    .turn-chips{flex-wrap:nowrap;overflow-x:auto;scrollbar-width:none}   /* one swipeable line */
    .turn-chips::-webkit-scrollbar{display:none}
    .chip{white-space:nowrap}
    .actions{margin-top:8px}
    .zoom-controls{gap:3px}
    .zoom-btn{width:36px;min-width:36px;height:36px}   /* three fit between Alaska and the map's bottom edge */
    .modal-actions{flex-wrap:wrap}
}
@media (max-width:340px){.zoom-controls{top:34%;gap:2px}}
/* While the attack sheet is up it covers the scrolling region; the turn box drops to its title
   and buttons so Roll, All in, Fortify and End turn all stay on screen. */
.sheet-open .turn-hint,.sheet-open .turn-chips,.sheet-open .turn-box .note,.sheet-open #suggestBtn{display:none}   /* a target is already chosen */
.sheet-open .turn-box .actions{margin-top:6px}
/* short phones: the battle record collapses to one row of small dice beside the result */
@media (max-width:599px) and (max-height:760px),(orientation:landscape) and (max-height:500px),(orientation:landscape) and (min-width:750px) and (max-height:620px){
    .battle-box{display:grid;grid-template-columns:auto minmax(0,1fr);grid-template-areas:"dice head" "dice res";column-gap:10px;row-gap:2px;align-items:center;padding:6px 10px}
    .battle-box .battle-head{grid-area:head;display:block;margin:0!important;font-size:.72rem;font-weight:600;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
    .battle-head .vs{display:none}
    .battle-box .dice-pairs{grid-area:dice;margin:0;gap:3px}
    .battle-box .dlabels{display:none}
    .battle-box .dpair{gap:3px}
    .battle-box .dpair .die{width:19px;height:19px;padding:2.5px;border-radius:5px}
    .battle-box .dpair .die.lose::after{font-size:.95rem}
    .battle-box .battle-result{grid-area:res;margin:0;font-size:.76rem}
}

/* narrow sidebars: the AI tag gives way to the name, the board goes to two columns */
@container (max-width:330px){
    .player-row .tag{display:none}
    .player-row{grid-template-columns:14px minmax(0,1fr);row-gap:1px}
    .player-row .stats{grid-column:2}   /* figures on a second line rather than squeezing the name */
    .side-panel .legend{grid-template-columns:repeat(2,minmax(0,1fr))}
}

/* ---------------------------------------------------------------- landscape phones
   No page scroll: a 40 px header with icon buttons, the map column sized to the height left
   over, and a ~260 px sidebar that scrolls on its own — turn title, buttons and battle first,
   the log behind a toggle, the continent board dropped (the map outlines held continents). */
@media (orientation:landscape) and (max-height:500px){
    .app{--hh:40px;--tb:32px}
    .app-title{font-size:.95rem}
    .title-icon{width:20px;height:20px}
    .icon-btn,.hdr-btn{width:36px;height:36px}
    .layout{grid-template-columns:min(100% - 16rem - var(--gap),(100dvh - var(--hh) - var(--tb) - 3 * var(--gap) - 2px) * 1.7857) minmax(0,1fr);grid-template-rows:auto minmax(0,1fr);grid-template-areas:"bar side" "map side"}
    .side-panel{overflow-y:auto;overscroll-behavior:contain}
    .side-grid{height:auto;min-height:100%}
    .more,.standalone .more{flex:none;overflow:visible;margin-bottom:0}
    .controls{margin-top:auto;gap:4px}
    .controls .btn{padding-left:7px;padding-right:7px;font-size:.74rem;min-height:40px}   /* one line in the ~16rem sidebar */
    .layout .legend{display:none}
    .log-wrap{height:auto}
    .zoom-controls{top:34%;gap:3px}
    .zoom-btn{width:36px;min-width:36px;height:36px}
    .log-toggle{display:flex}
    .log-wrap:not(.open) .log{display:none}
    .log-wrap.open .log{max-height:60vh;border-top:1px solid var(--border)}
    .turn-box{padding:7px 9px}
    .turn-hint{font-size:.74rem;-webkit-line-clamp:2}
    .actions{gap:5px}
}

/* ---------------------------------------------------------------- tablets and up */
@media (min-width:600px) and (min-height:501px){
    .app{--gap:8px}
    .hdr-btn{width:auto;padding:6px 10px;border-color:var(--border)}
    .hdr-btn .lbl{display:inline}
    .hdr-btn svg{display:none}
    .turn-box{padding:10px 12px}
}
/* From 760 px the toolbar doubles as the app bar: title, banner, header buttons (and from
   900 px the turn actions, moved there by layoutSlots() in app.js). The banner gets a stable
   width so the actions beside it don't jump as the text changes. */
@media (min-width:760px) and (min-height:501px){
    .app{--hh:0px;--tb:48px}
    .app-header{display:none}
    .layout{padding:6px 10px 10px}
    .bar-title .app-title{font-size:1.2rem}
    .bar-title .title-text{display:none}
    .phase-banner{flex:0 1 30rem;height:40px;font-size:.85rem;padding-right:12px}
    .bar-extra .hdr-btn{width:36px;padding:0;border-color:transparent}
    .bar-extra .hdr-btn .lbl{display:none}
    .bar-extra .hdr-btn svg{display:block}
    .bar-actions .btn{padding-top:7px;padding-bottom:7px}
}
@media (min-width:1100px) and (min-height:501px){
    .bar-title .title-text{display:inline}
    .bar-extra .hdr-btn{width:auto;padding:6px 10px;border-color:var(--border)}
    .bar-extra .hdr-btn .lbl{display:inline}
    .bar-extra .hdr-btn svg{display:none}
}
.embedded .app{--hh:0px}
.embedded .app-header,.embedded .app-title{display:none}   /* the landing-page viewer shows its own title bar */

/* portrait tablets: the full-width map, then turn + battle | the scrolling rest, side by side */
@media (orientation:portrait) and (min-width:600px){
    .side-grid{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);grid-template-rows:auto minmax(0,1fr) auto;grid-template-areas:"turn battle" "more more" "ctl ctl"}
    .battle-hidden .side-grid{grid-template-areas:"turn turn" "more more" "ctl ctl"}
    .turn-box{grid-area:turn}
    .battle-box{grid-area:battle}
    /* players and board | log, then the New game / Resign row across the foot */
    .more{grid-area:more;margin-bottom:0;display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);grid-template-rows:auto auto minmax(0,1fr);grid-template-areas:"players log" "legend log" ". log";column-gap:var(--gap);align-content:stretch}
    .more .players{grid-area:players}
    .more .legend{grid-area:legend;grid-template-columns:repeat(2,minmax(0,1fr))}
    .more .log-wrap{grid-area:log;min-height:12rem;height:auto}
    .controls{grid-area:ctl}
    /* standalone, the controls row is the strip the home pill sits in: buttons right, pill left */
    .standalone .more{margin-bottom:0}
    .standalone .controls{min-height:46px;padding-left:150px;align-items:center}
}

/* near-square windows (4:3 … 3:2): the map as wide as the height allows, a strip of
   turn | battle | rest under it */
@media (orientation:landscape) and (min-width:600px) and (min-height:501px) and (max-aspect-ratio:1499/1000){   /* exactly 3:2 is wide */
    .app{--strip:clamp(190px,26vh,250px)}
    .layout{grid-template-rows:auto auto minmax(var(--strip),1fr)}
    .map-wrap{width:min(100%,(100dvh - var(--hh) - var(--tb) - var(--strip) - 4 * var(--gap) - 16px) * 1.7857)}
    .side-grid{display:grid;grid-template-columns:minmax(0,1.1fr) minmax(0,.9fr) minmax(0,1.3fr);grid-template-rows:minmax(0,1fr) auto;grid-template-areas:"turn battle more" "turn battle ctl"}
    .battle-hidden .side-grid{grid-template-columns:minmax(0,1.1fr) minmax(0,1.3fr);grid-template-areas:"turn more" "turn ctl"}
    .turn-box{grid-area:turn;min-width:0;min-height:0;overflow-y:auto}
    .battle-box{grid-area:battle;min-width:0;min-height:0;overflow-y:auto}
    .more,.standalone .more{grid-area:more;min-width:0;margin-bottom:0}
    .controls{grid-area:ctl}
    .side-panel .legend{grid-template-columns:repeat(2,minmax(0,1fr))}
    .standalone .turn-box{margin-bottom:46px}   /* the home pill sits under it */
    /* the strip is short: chips on one swipeable line, a two-line hint, so the buttons stay visible */
    .turn-hint{-webkit-line-clamp:2}
    .turn-chips{flex-wrap:nowrap;overflow-x:auto;scrollbar-width:none}
    .turn-chips::-webkit-scrollbar{display:none}
    .chip{white-space:nowrap}
    .log-wrap{flex:1 0 9rem;height:auto}
}

/* short near-square strips: compact buttons so the row stays on one line in the narrow rest column */
@media (orientation:landscape) and (min-width:600px) and (min-height:501px) and (max-aspect-ratio:1499/1000) and (max-height:700px){
    .controls{gap:4px}
    .controls .btn{padding-left:7px;padding-right:7px;font-size:.74rem}
}

/* wide windows (3:2 and wider): map column capped at the height left × 1000/560 so the map box
   has no empty bands; the sidebar takes the rest. Under 2:1 the map is width-bound and leaves
   room beneath it, which takes the continent board (and, under 7:4, the battle record). */
@media (orientation:landscape) and (min-width:750px) and (min-height:501px) and (min-aspect-ratio:3/2){
    .app{--side:21rem;--under:0px}
    .layout{grid-template-columns:min(100% - var(--side) - var(--gap),(100dvh - var(--hh) - var(--tb) - var(--under) - 3 * var(--gap) - 18px) * 1.7857) minmax(0,1fr);grid-template-rows:auto auto auto minmax(0,1fr);grid-template-areas:"bar bar" "map side" "under side" ". side"}
    .under-map{display:flex;gap:var(--gap);align-items:flex-start;min-width:0}
    .under-map:empty{display:none}
    .under-map .legend{flex:1 1 auto;min-width:0;grid-template-columns:repeat(6,minmax(0,1fr))}
    .more{display:contents;container-type:normal}   /* no box, so it can't be a size container */
    .players{order:-1}
    .log-wrap{flex:1 1 0;min-height:6rem;height:auto}
    .side-grid{gap:10px}
    /* a wide sidebar splits in two: players, turn, battle, controls | board and log */
    @container (min-width:36rem){
        .side-grid{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);grid-template-rows:auto auto auto auto minmax(0,1fr);grid-template-areas:"players legend" "turn log" "battle log" "ctl log" ". log";column-gap:12px}
        .players{grid-area:players}
        .turn-box{grid-area:turn}
        .battle-box{grid-area:battle}
        .legend{grid-area:legend}
        .log-wrap{grid-area:log;min-height:0}
        .controls{grid-area:ctl}
    }
}
@media (orientation:landscape) and (min-width:750px) and (min-height:501px) and (min-aspect-ratio:3/2) and (max-aspect-ratio:2/1){.app{--under:4.4rem}}
@media (orientation:landscape) and (min-width:750px) and (min-height:501px) and (min-aspect-ratio:3/2) and (max-aspect-ratio:7/4){
    .app{--under:9.5rem}
    .under-map .legend{grid-template-columns:repeat(3,minmax(0,1fr))}
    .under-map.with-battle .legend{flex:0 0 56%}
    .under-map .battle-box{flex:1 1 0;min-width:0}
}


.sound-wrap{position:relative}
.icon-btn.muted .icon-sound-on{display:none}
.icon-btn:not(.muted) .icon-sound-off{display:none}
.sound-menu{display:none;position:absolute;right:0;top:40px;z-index:50;background:var(--panel);border:1px solid var(--border);border-radius:12px;padding:10px 12px;box-shadow:var(--shadow);width:220px;text-align:left}
.sound-menu.active{display:block}
.sound-menu label{display:flex;align-items:center;gap:8px;font-size:.8rem;font-weight:600;padding:5px 0;cursor:pointer}
.sound-menu label.vol{flex-direction:column;align-items:stretch;gap:4px;font-size:.72rem;color:var(--muted)}
.sound-menu input[type=range]{width:100%;accent-color:var(--accent)}
.sound-menu label.menu-field{flex-direction:column;align-items:stretch;gap:4px;font-size:.72rem;color:var(--muted);border-top:1px solid var(--border);margin-top:4px;padding-top:9px}
.sound-menu select{font:inherit;font-size:.8rem;font-weight:600;padding:5px 6px;border-radius:8px;border:1px solid var(--border);background:var(--panel-2);color:var(--text)}
button.chip{font-family:inherit;cursor:pointer}
.chip.speed{border-style:dashed}
.chip.speed:hover{border-color:var(--accent)}
.sound-menu input[type=checkbox]{width:15px;height:15px;accent-color:var(--accent)}
.sound-note{font-size:.66rem;color:var(--muted);margin-top:4px;line-height:1.3}

/* attack popover on the map */
.atk-pop{display:none;position:absolute;z-index:19;background:var(--panel);border:1px solid var(--border);border-radius:12px;padding:8px 10px 10px;box-shadow:var(--shadow);width:290px;font-size:.78rem}
.atk-pop.active{display:block}
.atk-pop.sheet{position:fixed;width:auto;max-height:min(75vh,440px);overflow-y:auto;z-index:60}   /* docked by dockSheet() in app.js */
.atk-pop.sheet .pop-rows{max-height:none}
/* the sheet keeps dice, Roll and All in on one row: no "Dice" label, a one-line heading */
.atk-pop.sheet .pop-head > span{white-space:nowrap;overflow:hidden;text-overflow:ellipsis;min-width:0}
.atk-pop.sheet .dice-lbl{display:none}
.atk-pop.sheet .battle-ctl{flex-wrap:nowrap;margin-top:4px}
.atk-pop.sheet .dice-pick button{min-width:40px}
.atk-pop.sheet .odds-line{margin-top:5px}
.pop-head{display:flex;align-items:center;justify-content:space-between;gap:8px;margin-bottom:6px;font-weight:600}
.pop-x{border:none;background:none;color:var(--muted);font-size:.95rem;cursor:pointer;padding:2px 6px;border-radius:6px;line-height:1}
.pop-x:hover{background:var(--panel-2);color:var(--text)}
.pop-rows{display:flex;flex-direction:column;gap:4px;max-height:260px;overflow-y:auto}
.pop-row{display:grid;grid-template-columns:1fr auto auto;align-items:center;gap:4px 10px;text-align:left;border:1px solid var(--border);background:var(--panel-2);color:var(--text);border-radius:8px;padding:6px 8px;font:inherit;cursor:pointer}
.pop-row:hover{border-color:var(--accent)}
.pr-name{font-weight:700}
.pr-d{color:var(--muted);font-weight:600;margin-left:4px}
.pr-p{font-weight:800;font-variant-numeric:tabular-nums}
.pr-p.good{color:var(--ok-text)}
.pr-p.bad{color:var(--danger-text)}
.pr-l{color:var(--muted);font-variant-numeric:tabular-nums}
.pop-row .ap-tags{grid-column:1 / -1}
.pop-foot{color:var(--muted);font-size:.68rem;margin-top:6px}
.ap-tags{display:flex;flex-wrap:wrap;gap:4px;margin-top:6px}
.stake{font-size:.68rem;font-weight:700;padding:2px 7px;border-radius:999px;background:rgba(255,213,79,.14);color:var(--text);border:1px solid rgba(255,213,79,.45)}
/* turn-box notes */
.note{display:flex;align-items:flex-start;gap:8px;margin-top:8px;padding:7px 8px;border-radius:9px;background:var(--panel-2);border:1px solid var(--border);font-size:.76rem;line-height:1.4}
.note .note-ico{flex-shrink:0}
.note > span:nth-child(2){flex:1}
.note .btn{flex-shrink:0}
.note.coach{border-color:rgba(255,213,79,.5)}
/* map: coach hint outline, threat marker, lost-territory flash, resigned hatching */
#map .hl.hint .hl-line{stroke:#4dd0e1;stroke-opacity:1;stroke-width:3;stroke-dasharray:none;animation:none}
#map .hl.hint .hl-case{stroke-width:6;stroke-opacity:.7}
#map .bwarn{display:none}
#map .bwarn circle{fill:#e53935;stroke:#fff;stroke-width:1}
#map .bwarn text{fill:#fff;font-family:'Inter',sans-serif;font-weight:900;font-size:6.5px;text-anchor:middle;dominant-baseline:central}
#map .hatch{display:none;pointer-events:none}
#map .fx-lost{stroke:var(--target);stroke-width:3.5;animation:fxLost 1s ease-in-out 3}
@keyframes fxLost{0%,100%{stroke-opacity:0}50%{stroke-opacity:1}}
/* online quit dialog */
.quit-opts{display:flex;flex-direction:column;gap:6px;margin-top:10px;text-align:left}
.quit-note{font-size:.74rem;color:var(--muted);margin:0 0 8px}
/* pass-and-play hand-off */
.handoff{display:none;position:fixed;inset:0;z-index:150;background:color-mix(in srgb,var(--pc,#333) 55%,#000);align-items:center;justify-content:center;padding:20px}
.handoff.active{display:flex}
.handoff-card{background:var(--panel);border-radius:16px;padding:28px 30px;text-align:center;box-shadow:var(--shadow);border-top:6px solid var(--pc,var(--accent));max-width:380px;width:100%}
.handoff-pre{color:var(--muted);font-size:.85rem}
.handoff-name{font-size:1.8rem;font-weight:800;margin:6px 0 18px}
.handoff-note{font-size:.85rem;line-height:1.4;color:var(--muted);margin:-8px 0 16px}
/* cards: newest card */
.card{position:relative}
.card .cnew{position:absolute;top:4px;right:4px;font-size:.58rem;font-weight:800;text-transform:uppercase;background:var(--accent-bg);color:#fff;border-radius:5px;padding:1px 5px}
.name-fields{display:contents}
.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}

/* per-colour shapes on swatches (badges use SVG paths, see SHAPE_PATH) */
:is(.sw,.swatch,.cswatch).shape-circle,:is(.sw,.swatch,.cswatch).shape-octagon{border-radius:50%}
:is(.sw,.swatch,.cswatch).shape-square{border-radius:2px}
:is(.sw,.swatch,.cswatch).shape-diamond{clip-path:polygon(50% 0,100% 50%,50% 100%,0 50%);border-radius:0}
:is(.sw,.swatch,.cswatch).shape-hexagon{clip-path:polygon(25% 6%,75% 6%,100% 50%,75% 94%,25% 94%,0 50%);border-radius:0}
:is(.sw,.swatch,.cswatch).shape-pentagon{clip-path:polygon(50% 0,100% 38%,81% 100%,19% 100%,0 38%);border-radius:0}
:is(.sw,.swatch,.cswatch).shape-shield{clip-path:polygon(0 0,100% 0,100% 55%,50% 100%,0 55%);border-radius:0}
.swatch.shape-diamond,.swatch.shape-hexagon,.swatch.shape-pentagon,.swatch.shape-shield{border:none;width:15px;height:15px}
.cswatch.shape-diamond,.cswatch.shape-hexagon,.cswatch.shape-pentagon,.cswatch.shape-shield{border:none}
/* live continent board (replaces the static legend) */
.legend{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:6px;flex-shrink:0}
.cb-row{display:flex;flex-direction:column;gap:3px;padding:5px 7px;border:1px solid var(--border);border-radius:9px;background:var(--panel);font-size:.7rem;color:var(--muted);min-width:0;cursor:default}
.cb-row.held{border-color:color-mix(in srgb,var(--text) 35%,var(--border))}
.cb-name{color:var(--text);font-weight:700;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.cb-name b{color:var(--ok-text)}
.cb-bar{display:flex;gap:1px;height:6px;border-radius:3px;overflow:hidden}
.cb-bar i{flex:1;display:block}
.cb-own{white-space:nowrap;overflow:hidden;text-overflow:ellipsis;display:flex;align-items:center;gap:4px;min-height:14px}
.cb-own b{color:var(--text)}
.cb-own .sw{width:8px;height:8px;display:inline-block}
/* turn ribbon */
.turn-ribbon{position:absolute;top:10px;left:50%;transform:translate(-50%,-14px);z-index:18;display:flex;align-items:center;gap:8px;padding:6px 14px;border-radius:999px;background:var(--panel);border:1px solid var(--border);border-bottom:3px solid var(--rc,var(--accent));font-family:var(--serif);font-variant:small-caps;font-weight:700;font-size:1rem;letter-spacing:.4px;box-shadow:var(--shadow);opacity:0;pointer-events:none;transition:opacity .25s,transform .25s}
.turn-ribbon.show{opacity:1;transform:translate(-50%,0)}
.turn-ribbon.light{font-size:.82rem;padding:4px 11px;box-shadow:none;opacity:0}
.turn-ribbon.light.show{opacity:.85}
.turn-ribbon .sw{width:10px;height:10px;display:inline-block}
.handoff-name{font-family:var(--serif);font-variant:small-caps}

/* placement / move animations */
#map .fx-move{stroke-linecap:round;fill:none}
#map .fx-loss.gain{fill:#7ee08a}
/* dice: compared pairs with pips */
.dice-pairs{display:flex;align-items:stretch;gap:8px;margin:6px 0 2px}
.dlabels{display:flex;flex-direction:column;justify-content:space-around;color:var(--muted);font-size:.7rem;min-width:58px}
.dpair{display:flex;flex-direction:column;gap:5px;align-items:center}
.dpair .die{width:28px;height:28px;border-radius:7px;display:grid;align-items:stretch;justify-items:stretch;grid-template-columns:repeat(3,1fr);grid-template-rows:repeat(3,1fr);padding:4px;border:1px solid rgba(0,0,0,.35);box-shadow:inset 0 -2px 0 rgba(0,0,0,.18);position:relative}
.dpair .die i{display:block;border-radius:50%;margin:1.2px}
.dpair .die i.on{background:var(--pip,#fff)}
.dpair .die.lose{opacity:.38}
.dpair .die.lose::after{content:'×';position:absolute;inset:0;display:flex;align-items:center;justify-content:center;font-weight:900;font-size:1.3rem;color:var(--danger-text);text-shadow:0 0 3px #000}
.dpair .die.win{outline:2px solid var(--sel);outline-offset:1px}
.dpair .die.idle{opacity:.6}
.dpair .die.none{visibility:hidden}
.dice-pairs.rolling .dpair .die{animation:dieRoll .38s cubic-bezier(.3,1.4,.6,1) both;animation-delay:calc(var(--i) * 40ms)}
@keyframes dieRoll{0%{transform:translateY(-10px) rotate(-200deg) scale(.6);opacity:0}70%{transform:translateY(2px) rotate(12deg) scale(1.05);opacity:1}100%{transform:none}}
/* card faces */
.card{--card-bg:var(--panel-2);overflow:hidden;padding:0 0 8px;justify-content:flex-start;gap:4px;min-height:132px}
.chead{display:flex;align-items:center;gap:5px;width:100%;padding:4px 7px;background:color-mix(in srgb,var(--ct,#888) 70%,var(--card-bg));color:#1d232c;font-size:.62rem;font-weight:800;text-transform:uppercase;letter-spacing:.5px}
.chead svg{width:18px;height:18px;flex-shrink:0}
.chead.wild-head{background:linear-gradient(90deg,var(--accent-bg),color-mix(in srgb,var(--accent-bg) 55%,#f2b01e));color:#fff}
.csil{width:74%;height:54px;margin-top:2px}
.csil path{stroke:rgba(0,0,0,.35);stroke-width:.6;vector-effect:non-scaling-stroke}
.card .cname{padding:0 6px}
.cribbon{font-size:.6rem;font-weight:800;color:#1d232c;background:#f2b01e;border-radius:4px;padding:1px 6px}
.card.wild{background:var(--card-bg)}
.card.wild .cname,.card.wild .ctype{color:var(--text)}
.card.wild .ctype{color:var(--muted)}
.card .ctype{padding:0 6px}
/* reduced motion: the OS setting or the sound-menu box */
.reduce-motion *,.reduce-motion *::before,.reduce-motion *::after{animation-duration:.001ms!important;animation-iteration-count:1!important;transition-duration:.001ms!important}
/* …but keep the battle's information visible as still highlights instead of flashes */
.reduce-motion #map .fx-to.hit{animation:none!important;fill-opacity:.45;stroke-opacity:1}
.reduce-motion #map .fx-to.captured{animation:none!important;fill-opacity:.6}
.reduce-motion #map .fx-from{animation:none!important;stroke-opacity:1;stroke-width:5}
.reduce-motion #map .fx-lost{animation:none!important;stroke-opacity:1}

/* game over: sweep, confetti, stats */
#map .fx-sweep{stroke-width:2;fill-opacity:.55}
.confetti{position:absolute;inset:auto 0 30% 0;height:0;pointer-events:none;z-index:25}
.confetti i{position:absolute;bottom:0;width:7px;height:11px;border-radius:2px;display:block}
.go-stats{margin:10px 0 2px}
.go-chart svg{width:100%;height:92px;display:block;border-radius:8px;overflow:hidden;background:var(--panel-2)}
.go-axis{display:flex;justify-content:space-between;color:var(--muted);font-size:.66rem;margin-top:3px}
.go-table{width:100%;border-collapse:collapse;margin-top:10px;font-size:.76rem;font-variant-numeric:tabular-nums}
.go-table th{color:var(--muted);font-weight:600;font-size:.68rem;text-align:right;padding:3px 4px}
.go-table td{text-align:right;padding:4px;border-top:1px solid var(--border)}
.go-table td:first-child{text-align:left;font-weight:700;display:flex;align-items:center;gap:6px}
.go-table tr.win td{color:var(--text)}
.go-table tr.win td:first-child::after{content:'★';color:#f2b01e}
.go-table .swatch{width:11px;height:11px;display:inline-block}

/* territory info chip: follows the pointer on desktop; on touch it appears after a tap that
   isn't a move, or on a long press */
.info-chip{position:absolute;left:0;top:0;z-index:17;max-width:min(320px,calc(100% - 12px));padding:6px 10px;border-radius:9px;background:var(--panel);border:1px solid var(--border);box-shadow:var(--shadow);font-size:.74rem;line-height:1.35;color:var(--text);pointer-events:none;opacity:0;transition:opacity .12s}
.info-chip.on{opacity:1}
.info-chip b{font-weight:700}
.info-chip .ic-sub{color:var(--muted)}
#map{-webkit-touch-callout:none}
/* the amount picker as a bottom sheet when the map box is narrow (same rule as the attack popover) */
.amount-picker.sheet{position:fixed;width:auto;z-index:60;padding:12px 14px;overflow-y:auto}   /* docked by dockSheet() in app.js */
/* full screen toggle (shown only where the Fullscreen API works; no room for it on small phones) */
.icon-btn{flex-shrink:0}
@media (max-width:420px){#fullscreenBtn{display:none!important}}
.icon-btn.fs-on .icon-fs-on{display:none}
.icon-btn:not(.fs-on) .icon-fs-off{display:none}
/* installed as a home-screen app: the site's "← jeffbrand.ca" pill would leave the app */
@media (display-mode:standalone),(display-mode:fullscreen){#jb-back-pill{display:none!important}}

/* phones and landscape phones: dialogs end above the site's home pill */
@media (max-width:599px),(orientation:landscape) and (max-height:500px){
    .standalone .modal-overlay{padding-bottom:52px}
    .standalone .modal{max-height:calc(100vh - 64px);max-height:calc(100dvh - 64px)}
}

/* the last roll's result inside a sheet that had to rise over the battle record (short phones) */
.pop-last{font-size:.74rem;font-weight:600;color:var(--muted);margin:-2px 0 6px;padding-bottom:6px;border-bottom:1px solid var(--border)}
.pop-last .lost{color:var(--danger-text)}
/* setup dialogs: one column on phones (the selects need the width) */
@media (max-width:600px){.form-grid{grid-template-columns:1fr}}
/* phones: toasts above the site's home pill */
@media (max-width:599px){.standalone .toast-container{bottom:64px}}
/* short portrait phones (SE in Safari and the like): the no-scroll shell would leave the players,
   log and New game / Play with others a few pixels of room, so the page scrolls instead and the
   first screen still holds the map, the turn box and the battle record */
@media (max-width:599px) and (max-height:620px) and (orientation:portrait){
    .app{height:auto;min-height:100vh;min-height:100dvh}
    body{overflow-y:auto}
    .layout{grid-template-rows:auto auto auto}
    .more,.standalone .more{flex:none;overflow:visible}
    .side-panel{overflow:visible}
    .side-grid{height:auto}
}
/* app bar at 760–899 px: only the current step, so the name and the buttons beside it keep their room */
@media (min-width:760px) and (max-width:899px) and (min-height:501px){
    .phase-steps li:not(.on),.phase-steps li::before{display:none!important}
    .pb-who{flex:0 0 auto}
}

/* the docked picker: OK / Cancel stay pinned at the bottom of its box even when it must scroll,
   and step aside (right-aligned) for the site's home pill */
.amount-picker.sheet .ap-buttons{position:sticky;bottom:-12px;margin:6px -14px -12px;padding:8px 14px 12px;background:var(--panel)}
.amount-picker.sheet.pill-clear .ap-buttons{padding-left:150px}
.amount-picker .pop-last{margin:0 0 6px}
/* embedded on a short landscape screen the header buttons share the toolbar: only the current step */
@media (orientation:landscape) and (max-height:500px){
    .embedded .phase-steps li:not(.on),.embedded .phase-steps li::before,.embedded .pb-round{display:none!important}
    .embedded .pb-who{flex:0 0 auto}
}

/* ---- optional rule variants (round limit, capitals, two-player balance) */
#map .badge .bcap{display:none}
#map .badge .bcap.on{display:inline}
#map .badge .bcap path{stroke-linejoin:round}
#map .badge .bcap-case{fill:none;stroke:#1b1710;stroke-width:3.2}
#map .badge .bcap-star{fill:#f0c23a;stroke:#fff3c4;stroke-width:.7}
#map .badge .bcap-dot{stroke:#1b1710;stroke-width:.8}
#map .badge .bcap.preview .bcap-star{fill:none;stroke:#f0c23a;stroke-width:1.5;stroke-dasharray:2.2 1.3}
#map .badge .bcap.preview .bcap-case{stroke-width:2.8;stroke-dasharray:2.2 1.3}
.player-row .stats .pts{font-weight:700}
.player-row .stats .caps{color:#d9a400;font-weight:700}
[data-theme="dark"] .player-row .stats .caps{color:#f0c23a}
.chip.warn{border-color:#d9a400;color:var(--text);background:color-mix(in srgb,#f0b429 18%,var(--panel-2))}
.cb-row.cb-caps{grid-column:1 / -1}
.cb-caps-list{display:flex;flex-wrap:wrap;gap:4px 12px;min-width:0}
.cb-caps-list span{display:inline-flex;align-items:center;gap:4px;white-space:nowrap}
.cb-caps-list b{color:var(--text)}
.cb-caps-list i{font-style:normal}
.cb-caps-list .sw{width:8px;height:8px;display:inline-block}
.form-grid fieldset.variants{grid-column:1 / -1;display:grid;grid-template-columns:1fr 1fr;gap:8px 14px;margin:2px 0 0;padding:8px 12px 10px;border:1px solid var(--border);border-radius:10px;min-width:0}
.form-grid fieldset.variants legend{font-size:.74rem;font-weight:700;color:var(--text);padding:0 4px}
.form-grid fieldset.variants legend span{font-weight:500;color:var(--muted)}
@media (max-width:600px){.form-grid fieldset.variants{grid-template-columns:1fr}}
/* keyboard play on the map: the map is one tab stop; the focused territory gets a white-haloed
   ring on top of the highlight layer, in the selection colour of what it sits on */
#map:focus{outline:none}
#map:focus-visible{outline:2px solid var(--accent);outline-offset:-2px}
#map .hl.kbd .hl-case{stroke:#fff;stroke-opacity:.95;stroke-width:8}
#map .hl.kbd .hl-line{stroke:#1565c0;stroke-opacity:1;stroke-width:3.5;stroke-dasharray:none;animation:none}
#map .hl.kbd.k-src .hl-line{stroke:#b28704}
#map .hl.kbd.k-tgt .hl-line{stroke:var(--target)}
#map .terr.kbd{filter:brightness(1.18)}
/* the dice buttons keep the group's rounded ends without clipping their focus rings */
.dice-pick button:first-child{border-radius:7px 0 0 7px}
.dice-pick button:last-child{border-radius:0 7px 7px 0}
.dice-pick button:focus-visible{outline:2px solid var(--accent);outline-offset:1px;position:relative;z-index:1}
.pop-row:focus-visible,.pop-x:focus-visible{outline:2px solid var(--accent);outline-offset:-2px}
/* ---- replay value: style tags, daily button, career record ---- */
.player-row .tag.style,.seat-row .tag.style{color:var(--text);border-style:dashed}
.player-row .pname .nm{min-width:0;overflow:hidden;text-overflow:ellipsis}
.player-row .pname>.tag,.player-row .pname>.dot{flex:none}
.player-row .tag.lvl .ic{font-size:.7rem;line-height:1;margin-right:2px}
.player-row.tight .tag.lvl .ic{display:none}
.daily-btn{display:inline-flex;flex-direction:column;align-items:flex-start;line-height:1.2;text-align:left}
.daily-btn .sub{font-size:.68rem;font-weight:500;color:var(--muted)}
.daily-btn.done .sub{color:var(--ok-text, var(--ok))}
.rec-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(120px,1fr));gap:8px;margin-bottom:12px}
.rec-grid .rc{background:var(--panel-2);border:1px solid var(--border);border-radius:10px;padding:8px 10px}
.rec-grid .rc b{display:block;font-size:1.15rem}
.rec-grid .rc span{font-size:.7rem;color:var(--muted)}
.rec-h{font-size:.78rem;text-transform:uppercase;letter-spacing:.04em;color:var(--muted);margin:12px 0 6px}
.rec-table{width:100%;border-collapse:collapse;font-size:.8rem}
.rec-table th,.rec-table td{padding:4px 6px;border-bottom:1px solid var(--border);text-align:left}
.rec-table td.n,.rec-table th.n{text-align:right;font-variant-numeric:tabular-nums}
#recordBody{text-align:left}
.ach-list{display:grid;grid-template-columns:repeat(auto-fill,minmax(210px,1fr));gap:6px}
.ach{display:flex;gap:8px;align-items:flex-start;padding:6px 8px;border:1px solid var(--border);border-radius:10px;background:var(--panel-2)}
.ach .ai{font-size:1.3rem;line-height:1}
.ach b{display:block;font-size:.8rem}
.ach span{font-size:.7rem;color:var(--muted)}
.ach.locked{opacity:.45;filter:grayscale(1)}
#recordBody{max-height:62vh;overflow:auto}
/* ---------------------------------------------------------------- online: roles, watch, nudge, invites (multiplayer.js) */
.note.mp .mp-btns{display:flex;gap:6px;flex-wrap:wrap;justify-content:flex-end;flex-shrink:0}
.note.mp.reclaim{border-color:var(--accent)}
.note.mp.watch{border-color:var(--muted)}
.note.mp.slow{border-color:rgba(255,183,77,.6)}
.player-row .tag.clock{white-space:nowrap}
.player-row .tag.clock.slow{color:var(--danger-text);border-color:currentColor}
@container (max-width:330px){ .player-row .tag.clock{display:inline-block} }
.mp-games{margin-top:10px;display:flex;flex-direction:column;gap:6px}
.mpg-title{font-size:.72rem;font-weight:800;text-transform:uppercase;letter-spacing:.06em;color:var(--muted)}
.mpg-row{display:flex;align-items:center;gap:8px;padding:6px 8px;border:1px solid var(--border);border-radius:9px;background:var(--panel-2);font-size:.8rem}
.mpg-name{flex:1;min-width:0;display:flex;flex-direction:column;gap:2px}
.mpg-name b{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.mpg-name small{font-weight:500;color:var(--muted);font-size:.7rem;line-height:1.5}
.mpg-badge{font-size:.64rem;font-weight:800;padding:0 5px;border-radius:6px;border:1px solid var(--border);color:var(--muted);white-space:nowrap;margin-right:2px}
.mpg-badge.turn{color:var(--ok-text);border-color:var(--ok-text)}
.mpg-badge.lobby{color:var(--accent);border-color:var(--accent)}
.mpg-badge.ai{color:var(--danger-text);border-color:var(--danger-text)}
.lobby-settings{margin:-4px 0 10px;font-size:.74rem;color:var(--muted)}
.seat-row .dot{width:7px;height:7px;border-radius:50%;background:#9e9e9e;display:inline-block;flex-shrink:0}
.seat-row .dot.online{background:#43a047}
.share-group{flex-wrap:wrap}
.share-group .share-input{min-width:160px}
@media (max-width:520px){ .share-group .share-input{flex:1 1 100%} }
.qr-box{display:flex;justify-content:center;margin:0 0 12px}
.qr-box[hidden]{display:none}
.qr-box svg{width:168px;height:168px;background:#fff;border-radius:8px;padding:0}
.qr-box svg path,.qr-box svg rect{shape-rendering:crispEdges}

/* rows carrying score / capitals figures: the figures move to a second line, the name keeps its room */
.player-row.two-line{grid-template-columns:14px minmax(0,1fr);row-gap:1px}
.player-row.two-line .stats{grid-column:2}
@media (pointer:coarse){#mpGames .pop-x{min-width:44px;min-height:44px}}
@media (pointer:coarse){.sound-menu select{min-height:40px}button.chip{min-height:36px}}

/* ---------------------------------------------------------------- secret missions (variant) */
.form-grid label.checkbox .opt-note{font-size:.7rem;font-weight:600;color:var(--muted);margin-left:auto;white-space:nowrap}
.form-grid label.checkbox.off{color:var(--muted)}
.chip.mission{border-color:var(--pc);background:color-mix(in srgb,var(--pc) 12%,var(--panel-2));font-weight:600;order:-1}
.chip.mission .c-short{display:none}
/* where the chips are one swipeable line (phones, the short strip under near-square maps): the short form */
@media (max-width:599px),(orientation:landscape) and (min-width:600px) and (min-height:501px) and (max-aspect-ratio:1499/1000){
    .chip.mission .c-long{display:none}
    .chip.mission .c-short{display:inline}
}
.mission-modal{max-width:400px}
.mcard{--mc-paper:#fbf6e9;--mc-ink:#3b2f1e;--mc-seal:var(--mc);margin:6px 0 4px;border-radius:12px;border:2px solid var(--mc);background:linear-gradient(170deg,#fffaf0,#f3ead3);color:var(--mc-ink);box-shadow:0 2px 0 color-mix(in srgb,var(--mc) 45%,transparent);overflow:hidden}
.mcard-head{display:flex;align-items:center;gap:8px;padding:8px 12px;background:color-mix(in srgb,var(--mc) 22%,#f3ead3);font-family:var(--serif);font-variant:small-caps;font-weight:700;letter-spacing:.6px;font-size:.9rem;border-bottom:1px solid color-mix(in srgb,var(--mc) 40%,transparent)}
.mcard-ico{width:30px;height:30px;flex:0 0 auto;color:var(--mc-ink)}
.mcard-text{font-family:var(--serif);font-size:1.12rem;line-height:1.35;font-weight:700;padding:12px 14px 4px}
.mcard-note{font-size:.78rem;line-height:1.35;margin:4px 14px 2px;padding:6px 8px;border-radius:8px;background:color-mix(in srgb,#f0b429 22%,transparent);border:1px solid color-mix(in srgb,#b8860b 45%,transparent)}
.mcard-goals{text-align:left;list-style:none;padding:6px 14px 12px;display:grid;gap:6px}
.mcard-goals li{display:grid;grid-template-columns:minmax(0,1fr) 34% auto;align-items:center;gap:8px;font-size:.8rem}
.mcard-goals .mg-l{font-weight:600;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.mcard-goals .mg-bar{height:8px;border-radius:999px;background:color-mix(in srgb,var(--mc-ink) 14%,transparent);overflow:hidden}
.mcard-goals .mg-bar i{display:block;height:100%;border-radius:inherit;background:var(--mc)}
.mcard-goals .mg-v{font-variant-numeric:tabular-nums;font-weight:700;text-align:right;white-space:nowrap}
.mcard-goals li.met .mg-v::after{content:' \2713'}
/* "Third continent": the value can be several names, so it gets its own wrapping line under label + bar */
.mcard-goals li.wide{grid-template-columns:minmax(0,1fr) 34%;row-gap:2px}
.mcard-goals li.wide .mg-v{grid-column:1/-1;text-align:left;white-space:normal;overflow-wrap:anywhere;font-weight:600}
.mcard-done{margin:0 14px 12px;font-weight:800;text-transform:uppercase;letter-spacing:.06em;font-size:.74rem;color:#2e7d32}
.mission-sub{margin-top:8px}
[data-theme="dark"] .mcard{background:linear-gradient(170deg,#2e2a22,#25221c);--mc-ink:#efe6d2;--mc-paper:#3a342a;color:var(--mc-ink)}
[data-theme="dark"] .mcard-head{background:color-mix(in srgb,var(--mc) 30%,#25221c)}
[data-theme="dark"] .mcard-done{color:var(--ok-text)}
.go-missions ul{text-align:left;list-style:none;display:grid;gap:5px;font-size:.76rem}
.go-missions li{display:flex;align-items:flex-start;gap:7px;line-height:1.35;padding:4px 6px;border-radius:8px}
.go-missions li .swatch{width:11px;height:11px;display:inline-block;flex:0 0 auto;margin-top:3px}
.go-missions li.won{background:color-mix(in srgb,#f0b429 18%,var(--panel-2))}
.go-missions i{color:var(--muted)}
.go-missions .mr-done{font-weight:800;color:var(--ok-text)}
.go-missions .mr-done::before{content:'\2713 '}
.go-missions .mr-prog{color:var(--muted);display:block}
