  :root{
    --ink:#e9edf5; --dim:#8d97ab; --faint:#8a94a8;
    --line:rgba(255,255,255,.10);
    --glass:linear-gradient(180deg,rgba(20,24,32,.80),rgba(11,13,19,.86));
    --accent:#7fd8ff;
    --ok:#57e39a; --warn:#ffcf5c; --bad:#ff6b81;
    --sans:ui-sans-serif,-apple-system,"Segoe UI",Inter,Roboto,Helvetica,Arial,sans-serif;
    --mono:ui-monospace,"SF Mono",Menlo,Consolas,monospace;
    --pad:18px;
    --dur:.16s;
  }
  *{box-sizing:border-box}
  /* dvh, not %: iOS Safari's toolbars change the visible height as you scroll
     and a percentage height keeps measuring the larger one, which pushed a
     bottom-anchored panel below the fold. */
  /* This is a game, not a document. Dragging a course across the arena was
     starting text selections, raising the long-press callout, flashing tap
     highlights and rubber-banding the page -- all of it native behaviour that
     has no meaning here. The one exception is the text inputs, which are
     restored below; everything else is inert to a finger except through the
     handlers the game installs. */
  html,body{height:100%;height:100dvh;margin:0;background:#05060a;overflow:hidden;
            overscroll-behavior:none;touch-action:none;
            -webkit-user-select:none;user-select:none;
            -webkit-touch-callout:none;-webkit-tap-highlight-color:transparent}
  body{font:13px/1.45 var(--sans);color:var(--ink);-webkit-font-smoothing:antialiased;touch-action:none}
  canvas{display:block;width:100%;height:100%;touch-action:none}

  /* height:100dvh, not just inset:0. A fixed element on iOS is laid out
     against the LAYOUT viewport, which stays tall while Safari's toolbars are
     on screen -- so a bottom-anchored panel hangs below the visible area and
     gets clipped. dvh follows what is actually visible. */
  .ui{position:fixed;inset:0;height:100dvh;pointer-events:none;z-index:5}
  .ui.hidden{opacity:0;transition:opacity .3s}
  .ui > *{pointer-events:auto}

  /* ------------------------------------------------------------- roster */
  .roster{
    position:absolute;top:var(--pad);left:var(--pad);display:flex;flex-direction:column;gap:8px;
    width:224px;
  }
  .card{
    background:var(--glass);border:1px solid var(--line);border-radius:11px;padding:9px 11px 10px;
    backdrop-filter:blur(16px) saturate(130%);-webkit-backdrop-filter:blur(16px) saturate(130%);
    box-shadow:0 14px 34px -18px rgba(0,0,0,.9);
    position:relative;overflow:hidden;transition:border-color var(--dur),opacity var(--dur);
  }
  .card::before{content:"";position:absolute;left:0;top:0;bottom:0;width:3px;background:var(--liv)}
  .card.self{border-color:color-mix(in srgb, var(--liv) 45%, transparent)}
  .card.dead{opacity:.38;filter:grayscale(.7)}
  .card .top{display:flex;align-items:baseline;gap:7px;margin-bottom:7px}
  .card .nm{font-size:11.5px;font-weight:600;letter-spacing:.06em;color:#dbe3f0;
            white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
  .card .you{font:10px/1 var(--mono);letter-spacing:.1em;color:var(--liv);flex:none}
  .card .st{margin-left:auto;font:10px/1 var(--mono);letter-spacing:.08em;color:var(--faint);flex:none}
  .card .st.rdy{color:var(--ok)}
  .bar{height:4px;border-radius:2px;background:rgba(255,255,255,.09);overflow:hidden;margin-top:4px}
  .bar > i{display:block;height:100%;border-radius:2px;transition:width .25s ease}
  .bar.sh > i{background:linear-gradient(90deg,#4aa8ff,#7fd8ff)}
  .bar.hu > i{background:linear-gradient(90deg,#ff6b81,#ffa07a)}
  .bar.ch > i{background:linear-gradient(90deg,#8a7bff,#c9a7ff)}
  .lbl{display:flex;justify-content:space-between;font:9.5px/1.5 var(--mono);
       letter-spacing:.1em;color:var(--faint);margin-top:6px}

  /* A rival's card, shown beside the pointer while you are over their ship.
     Four permanent cards spent a corner of the screen on information that
     matters for a moment at a time. */
  .peek{position:absolute;left:0;top:0;width:224px;pointer-events:none;z-index:3;
        opacity:0;transform:translate(-50%,-115%);transition:opacity .12s ease}
  .peek.on{opacity:1}

  /* -------------------------------------------------------------- orders */
  /* Bottom right, and wide enough that ARM and COMMIT keep their labels on
     one line beside each other -- at 266px they had about 125px a side, which
     is less than "CHARGING 100%" needs, so they stacked. */
  .orders{
    position:absolute;right:var(--pad);bottom:var(--pad);width:344px;
    background:var(--glass);border:1px solid var(--line);border-radius:13px;
    backdrop-filter:blur(18px) saturate(130%);-webkit-backdrop-filter:blur(18px) saturate(130%);
    box-shadow:0 22px 56px -22px rgba(0,0,0,.92);overflow:hidden;
  }
  .orders header{display:flex;align-items:center;gap:8px;padding:11px 13px 10px;border-bottom:1px solid var(--line)}
  .orders header .t{font:11px/1 var(--mono);letter-spacing:.18em;color:#cfd8e8}
  .clock{margin-left:auto;font:12px/1 var(--mono);letter-spacing:.06em;color:var(--dim);
         font-variant-numeric:tabular-nums}
  .clock.urgent{color:var(--warn)}
  .clock.crit{color:var(--bad)}
  .obody{padding:11px 13px 13px}
  .row{margin:10px 0}
  .row:first-child{margin-top:2px}
  .rhead{display:flex;justify-content:space-between;align-items:baseline;margin-bottom:5px}
  .rhead label{font:10px/1 var(--mono);letter-spacing:.14em;color:#98a2b6}
  .rhead b{font:11.5px/1 var(--mono);color:#c8d2e4;font-variant-numeric:tabular-nums;font-weight:500}
  input[type=range]{-webkit-appearance:none;appearance:none;width:100%;height:16px;background:transparent;margin:0;cursor:ew-resize;display:block}
  input[type=range]::-webkit-slider-runnable-track{height:3px;border-radius:2px;
    background:linear-gradient(90deg,var(--accent) 0 calc(var(--p,.5)*100%),rgba(255,255,255,.11) calc(var(--p,.5)*100%) 100%)}
  input[type=range]::-moz-range-track{height:3px;border-radius:2px;background:rgba(255,255,255,.11)}
  input[type=range]::-moz-range-progress{height:3px;border-radius:2px;background:var(--accent)}
  input[type=range]::-webkit-slider-thumb{-webkit-appearance:none;width:12px;height:12px;border-radius:50%;
    margin-top:-4.5px;background:#e7eefb;box-shadow:0 0 0 1.5px rgba(0,0,0,.6),0 1px 4px rgba(0,0,0,.6)}
  input[type=range]::-moz-range-thumb{width:12px;height:12px;border:0;border-radius:50%;background:#e7eefb;
    box-shadow:0 0 0 1.5px rgba(0,0,0,.6)}
  input[type=range]:focus-visible{outline:none}
  input[type=range]:focus-visible::-webkit-slider-thumb{box-shadow:0 0 0 3px rgba(127,216,255,.55)}

  /* What the course costs. Two figures and a bar -- nothing to set here, the
     only control is the drag out on the arena. */
  .split2{display:flex;gap:10px;margin:2px 0 8px}
  .split2 .fig{flex:1;min-width:0}
  .split2 .k{display:block;font:9.5px/1.5 var(--mono);letter-spacing:.12em;color:var(--faint)}
  .split2 b{font:15px/1.2 var(--mono);color:var(--ink);font-variant-numeric:tabular-nums;font-weight:500}
  .split2 .fig:last-child b{color:var(--ok)}
  .meter{height:4px;border-radius:2px;background:rgba(255,255,255,.09);overflow:hidden;margin-bottom:11px}
  .meter > i{display:block;height:100%;width:50%;border-radius:2px;background:var(--accent);
             transition:width .12s linear,background .12s linear}
  /* Side by side while there is room for both labels, stacked when there is
     not -- a 266px panel in landscape left about 125px a side, which is less
     than "CHARGING 100%" needs. */
  .two{display:flex;gap:8px;flex-wrap:wrap}
  .two .btn{flex:1 1 128px;min-width:0}
  .two .btn.fire{margin-top:0}
  .two .btn.commit{margin-top:0}

  .btn{
    display:flex;align-items:center;justify-content:center;gap:8px;width:100%;
    /* The label must never wrap: a long one folding onto a second line reads
       as the button being too small for its own text even when nothing
       overflows. The keyboard chip is the part that gives way. */
    white-space:nowrap;
    font:600 12px/1 var(--sans);letter-spacing:.05em;color:#cfd8e8;
    background:rgba(255,255,255,.055);
    border:1px solid var(--line);border-radius:9px;
    padding:11px 12px;cursor:pointer;
    transition:background var(--dur),border-color var(--dur),color var(--dur);
  }
  .btn:hover{background:rgba(255,255,255,.10);color:#fff;border-color:rgba(255,255,255,.18)}
  .btn:active{transform:translateY(1px)}
  .btn:disabled{opacity:.4;cursor:not-allowed}
  .btn:focus-visible{outline:none;box-shadow:0 0 0 3px rgba(127,216,255,.5)}
  .btn.fire{margin-top:4px}
  .btn.fire[aria-pressed="true"]{background:rgba(255,107,129,.18);border-color:rgba(255,107,129,.6);color:#ffd9df}
  /* The one action worth taking, marked by weight rather than by colour. */
  /* The play button measured L*17 -- the darkest control on a dark card, which
     reads as disabled. One flat fill, lifted, in a blue taken from the arena's
     own wall sheen. No gradient, no glow. */
  .btn.primary, .btn.commit{
    color:#eaf7ff;
    background:rgba(34,96,138,.72);
    border-color:rgba(127,216,255,.52);
  }
  .btn.primary:hover, .btn.commit:hover{
    background:rgba(44,120,170,.86);border-color:rgba(127,216,255,.66);color:#fff}
  .btn.commit{margin-top:9px}
  .btn.commit.done{background:rgba(87,227,154,.16);border-color:rgba(87,227,154,.5);color:#d6ffe9}
  /* Match over: the orders controls step aside for the rematch button. The
     controls are hidden, not removed -- the next match needs them back. */
  #oRematch{display:none}
  .orders.over .split2, .orders.over .meter, .orders.over .two{display:none}
  .orders.over #oRematch{display:block;width:100%}
  .kbd{font:10px/1 var(--mono);padding:3px 5px;border-radius:4px;background:rgba(255,255,255,.09);
       color:#9fb0c8;flex:0 1 auto;min-width:0;overflow:hidden}
  .two .btn{gap:6px;padding-left:8px;padding-right:8px}

  /* --------------------------------------------------------------- notes */
  .banner{
    position:absolute;left:50%;top:34%;transform:translate(-50%,-50%);text-align:center;
    pointer-events:none;transition:opacity .3s
  }
  .banner h2{margin:0;font:600 34px/1 var(--sans);letter-spacing:.16em;text-transform:uppercase;
             text-shadow:0 4px 40px rgba(0,0,0,.9)}
  .banner p{margin:9px 0 0;font:11px/1 var(--mono);letter-spacing:.22em;color:var(--dim);text-transform:uppercase}

  /* -------------------------------------------------------------- lobby */
  /* There is a match running behind this, so the veil cannot be a sheet of
     paint. It is a pool of shade centred on the dialog: dense enough under the
     text to keep it legible, gone by the edges of the frame where the fight
     is. No backdrop blur -- the whole point of what is behind is thin, sharp
     beams, and a blur is exactly what destroys them. */
  .veil{position:absolute;inset:0;display:grid;place-items:center;
        --vx:50%;
        background:
          radial-gradient(52% 64% at var(--vx) 50%,
            rgba(3,4,8,.62) 0%, rgba(3,4,8,.52) 34%,
            rgba(3,4,8,.22) 62%, rgba(3,4,8,.04) 78%, rgba(3,4,8,0) 100%),
          linear-gradient(180deg, rgba(3,4,8,.30), rgba(3,4,8,0) 14%,
                          rgba(3,4,8,0) 86%, rgba(3,4,8,.30))}

  /* Given room, the dialog moves off the middle and the match gets the rest of
     the frame. Centring both meant the one thing worth looking at was always
     directly behind the one thing you have to read. The pool of shade moves
     with the dialog. */
  @media (min-width: 1100px){
    .veil{place-items:center start;padding-left:min(9vw,150px);--vx:26%}
    /* ...and on the other side when the battle is on the left. At demo zoom the
       viewport already spans most of the arena, so the camera cannot pan a
       left-hand fight clear of a left-hand dialog -- it just loses the right
       half of the field off the edge instead. The side is chosen once, before
       the first frame, from where the staged fight actually is. */
    .veil.right{place-items:center end;padding-left:0;padding-right:min(9vw,150px);--vx:74%}
  }

  /* While the lobby is up, the match furniture belongs to a game the viewer
     has not joined yet -- it would read as a broken HUD over the demo. */
  .ui.lobbyup .orders, .ui.lobbyup .roster,
  .ui.lobbyup .giz,    .ui.lobbyup .banner {display:none}
  .modal{
    position:relative;
    width:min(430px,calc(100vw - 32px));border:1px solid transparent;
    /* See-through: there is a match going on behind this and the card was
       hiding it. The blur is what keeps the text readable over whatever
       happens to pass -- it takes the detail out of the background without
       taking the light or the colour. */
    background:linear-gradient(180deg,rgba(18,22,30,.42),rgba(10,12,18,.52));
    backdrop-filter:blur(13px) saturate(130%);-webkit-backdrop-filter:blur(13px) saturate(130%);
    border-radius:16px;padding:24px;
    /* Lifted off the scene, not dropped into a pit: the card sits over a live
       match, and a heavy shadow made it look pasted on rather than floating. */
    box-shadow:0 20px 52px -34px rgba(0,0,0,.70), 0 0 30px -18px rgba(150,175,215,.20)
  }
  /* A light rim, painted into a one-pixel ring by masking out the middle. It
     is one colour with the light falling across it -- bright where the key is,
     fading round the far side -- rather than a run through the spectrum. A
     flat 10%-white hairline disappeared against a scene this dark. */
  .modal::after{
    content:"";position:absolute;inset:0;border-radius:inherit;padding:1.2px;
    pointer-events:none;
    /* A beam, not a paint job: white nearly all the way round, with the
       faintest spectrum bleeding off it the way the lasers fringe coming
       through glass. The tints stay close to white on purpose -- push their
       saturation up and it stops reading as light and starts reading as a
       gradient border. */
    background:linear-gradient(118deg,
      rgba(255,255,255,.92) 0%,   rgba(216,241,255,.78) 13%,
      rgba(255,255,255,.95) 27%,  rgba(255,228,246,.76) 40%,
      rgba(255,255,255,.95) 53%,  rgba(228,255,242,.76) 67%,
      rgba(255,255,255,.95) 80%,  rgba(228,236,255,.78) 92%,
      rgba(255,255,255,.92) 100%);
    -webkit-mask:linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
            mask:linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
    -webkit-mask-composite:xor;      mask-composite:exclude;
  }
  .modal h1{margin:0 0 3px;font:600 21px/1 var(--sans);letter-spacing:.30em;text-transform:uppercase}
  .modal .status:empty{display:none}
  .modal .sub{margin:0 0 20px;font:10.5px/1.5 var(--mono);letter-spacing:.14em;color:var(--faint);text-transform:uppercase}
  .modal .fld{margin:12px 0}
  .modal label{display:block;font:10px/1 var(--mono);letter-spacing:.14em;color:#98a2b6;margin-bottom:6px}
  .modal input[type=text]{
    width:100%;font:13px/1 var(--mono);letter-spacing:.10em;color:var(--ink);
    background:rgba(255,255,255,.05);border:1px solid var(--line);border-radius:8px;padding:11px 12px
  }
  .modal input[type=text]:focus{outline:none;border-color:rgba(127,216,255,.55)}
  /* The callsign and room code are the only things worth selecting. */
  input,textarea{-webkit-user-select:text;user-select:text;touch-action:auto}
  .modal .btn{margin-top:8px}
  .modal .or{display:flex;align-items:center;gap:10px;margin:16px 0 8px;
             font:9.5px/1 var(--mono);letter-spacing:.16em;color:var(--faint)}
  .modal .or::before,.modal .or::after{content:"";flex:1;height:1px;background:var(--line)}
  .status{margin-top:14px;font:10.5px/1.5 var(--mono);letter-spacing:.06em;color:var(--dim);min-height:1.5em}
  .status.err{color:var(--bad)}

  /* Under the panel. The handle is dragged around the arena and would
     otherwise sail over the top of the orders card, including over COMMIT. */
  .giz{position:absolute;inset:0;overflow:hidden;pointer-events:none;z-index:1}
  .orders,.roster,.veil{z-index:2}
  .giz.idle{opacity:0;transition:opacity .5s ease .2s}
  .giz svg{position:absolute;inset:0;width:100%;height:100%;overflow:visible}
  .hnd{position:absolute;width:34px;height:34px;margin:-17px 0 0 -17px;border:0;padding:0;
       background:none;cursor:grab;pointer-events:auto;touch-action:none}
  .giz.idle .hnd{pointer-events:none}
  .hnd i{position:absolute;inset:11px;border-radius:50%;background:#e7eefb;
         box-shadow:0 0 0 1.5px rgba(0,0,0,.65),0 0 14px 2px rgba(127,216,255,.55)}
  .hnd:hover i,.hnd:focus-visible i{inset:9px;box-shadow:0 0 0 1.5px rgba(0,0,0,.65),0 0 20px 3px rgba(127,216,255,.9)}
  .hnd:focus-visible{outline:none}

  @media (hover:none){ .giz.idle{opacity:1} .giz.idle .hnd{pointer-events:auto} }
  @media (max-width:760px){
    :root{--pad:10px}
    /* Keep clear of the notch and the home indicator. viewport-fit=cover was
       already set, so the page draws under both; without these the top of the
       roster sat under the status bar and COMMIT under the home indicator. */
    .roster{top:calc(var(--pad) + env(safe-area-inset-top));
            left:calc(var(--pad) + env(safe-area-inset-left));
            right:calc(var(--pad) + env(safe-area-inset-right))}
    .orders{bottom:calc(var(--pad) + env(safe-area-inset-bottom));
            left:calc(var(--pad) + env(safe-area-inset-left));
            right:calc(var(--pad) + env(safe-area-inset-right));
            /* and never taller than what is left of the screen */
            max-height:calc(100dvh - 2*var(--pad) - env(safe-area-inset-top)
                            - env(safe-area-inset-bottom));
            display:flex;flex-direction:column}
    .obody{overflow-y:auto;overscroll-behavior:contain}
    .roster{width:auto;left:var(--pad);right:var(--pad);flex-direction:row;gap:6px}
    .card{flex:1;min-width:0;padding:7px 8px 8px}
    .card .lbl{display:none}
    /* Four cards across a phone leaves ~90px each, and "PLANNING" alone is
       most of that: the status was being clipped mid-word. Let it drop under
       the callsign instead, and shrink to suit. */
    .card .top{flex-wrap:wrap;gap:0 6px;margin-bottom:5px}
    .card .nm{font-size:10.5px;flex:1 1 auto}
    .card .st{margin-left:0;flex:1 0 100%;font-size:9px;letter-spacing:.06em}
    .card .you{font-size:9px}
    .orders{right:var(--pad);left:var(--pad);width:auto;top:auto;bottom:var(--pad)}

    /* Touch targets. A 3px rail with a 12px thumb is a mouse control; on glass
       it wants a finger's worth of height to grab, without the rail itself
       getting fatter. */
    /* The start screen sits at the bottom on a phone, where a thumb is, and
       leaves the top two thirds of the glass to the match running behind it. */
    .veil{place-items:end center;--vx:50%;
          padding:0 0 calc(var(--pad) + env(safe-area-inset-bottom));
          background:
            radial-gradient(120% 52% at 50% 108%,
              rgba(3,4,8,.80) 0%, rgba(3,4,8,.66) 42%,
              rgba(3,4,8,.24) 74%, rgba(3,4,8,0) 100%),
            linear-gradient(180deg, rgba(3,4,8,.34), rgba(3,4,8,0) 26%)}
    .modal{width:calc(100vw - 20px - env(safe-area-inset-left) - env(safe-area-inset-right));
           padding:18px;max-height:calc(100dvh - 24px - env(safe-area-inset-bottom));
           overflow-y:auto;overscroll-behavior:contain}
    .modal h1{font-size:19px}
    .modal .sub{margin-bottom:14px}
    .modal .fld{margin:9px 0}

    /* 16px or iOS zooms the whole page in when the field takes focus, and
       leaves it zoomed -- which then breaks every drag on the arena. */
    .modal input[type=text]{font-size:16px}

    /* No keyboard on a phone, so the chips are pure decoration -- and they are
       the only thing standing between a long label and a comfortable button. */
    .btn .kbd{display:none}

    input[type=range]{height:34px}
    input[type=range]::-webkit-slider-thumb{width:20px;height:20px;margin-top:-8.5px}
    input[type=range]::-moz-range-thumb{width:20px;height:20px}
    .btn{padding:14px 12px}
    .obody{padding:12px 13px 14px}
    .row{margin:12px 0}
  }
  @media (prefers-reduced-motion:reduce){ *{transition-duration:.01ms !important} }
  .sr{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;
      clip:rect(0 0 0 0);white-space:nowrap;border:0}

  /* --------------------------------------------------- the (?) and the manual */
  /* A question mark on the corner of the start card. It has to be legible over
     a live dogfight and it must not compete with PRACTICE, so it is a hairline
     ring that only fills in under the pointer. */
  .qmark{
    position:absolute;top:13px;right:13px;width:26px;height:26px;padding:0;flex:none;z-index:2;
    display:grid;place-items:center;
    font:12px/1 var(--mono);color:var(--faint);
    background:rgba(255,255,255,.045);border:1px solid var(--line);border-radius:50%;
    cursor:pointer;
    transition:color var(--dur),border-color var(--dur),background var(--dur);
  }
  .qmark:hover{color:var(--ink);border-color:rgba(127,216,255,.55);background:rgba(127,216,255,.10)}
  .qmark:focus-visible{outline:2px solid rgba(127,216,255,.55);outline-offset:2px}
  .qmark.close{font-size:16px;line-height:1}

  .veil[hidden]{display:none}
  /* The manual is a reading surface, so it takes the middle of the frame --
     unlike the lobby, which steps aside to let the demo be seen. */
  .veil.center{place-items:center;padding:0 14px;--vx:50%}
  .guideveil{background:
      radial-gradient(60% 70% at 50% 50%, rgba(3,4,8,.80) 0%, rgba(3,4,8,.68) 45%,
                      rgba(3,4,8,.34) 74%, rgba(3,4,8,.06) 100%),
      linear-gradient(180deg, rgba(3,4,8,.42), rgba(3,4,8,.10) 30%,
                      rgba(3,4,8,.10) 70%, rgba(3,4,8,.42))}

  /* Wider than the lobby card and denser behind the text: this one is read,
     not glanced at. The article is the frame and does not scroll; .gbody does. */
  .modal.guide{
    width:min(690px,calc(100vw - 28px));max-height:min(86dvh,860px);
    padding:0;overflow:hidden;display:flex;flex-direction:column;text-align:left;
    background:linear-gradient(180deg,rgba(17,20,28,.86),rgba(9,11,16,.90));
  }
  .ghead{padding:22px 30px 15px;border-bottom:1px solid var(--line);flex:none}
  .guide h2{margin:0 0 4px;font:600 17px/1.3 var(--sans);letter-spacing:.24em;text-transform:uppercase}
  .guide .sub{margin:0}
  .gbody{
    padding:4px 30px 28px;overflow-y:auto;overscroll-behavior:contain;
    /* A page of prose is the one thing here you are meant to be able to select
       and to flick through with a thumb; the rest of the document forbids both. */
    -webkit-user-select:text;user-select:text;touch-action:pan-y;
    scrollbar-width:thin;scrollbar-color:rgba(255,255,255,.20) transparent;
    /* Text does not get to end in a half-cut line against the header rule: it
       fades out as it goes under it, and again at the bottom edge, which also
       says there is more below without spending a chevron on saying so. */
    -webkit-mask-image:linear-gradient(180deg,transparent 0,#000 14px,
                                       #000 calc(100% - 18px),transparent 100%);
            mask-image:linear-gradient(180deg,transparent 0,#000 14px,
                                       #000 calc(100% - 18px),transparent 100%);
  }
  .gbody::-webkit-scrollbar{width:10px}
  .gbody::-webkit-scrollbar-thumb{background:rgba(255,255,255,.17);border-radius:6px;
                                  border:3px solid transparent;background-clip:content-box}
  .gbody::-webkit-scrollbar-thumb:hover{background:rgba(255,255,255,.28);background-clip:content-box}
  .guide h3{
    margin:22px 0 9px;padding-top:16px;border-top:1px solid var(--line);
    font:10.5px/1.4 var(--mono);letter-spacing:.17em;text-transform:uppercase;color:var(--accent)
  }
  .guide p{margin:0 0 11px;font-size:13px;line-height:1.65;color:#c1cade}
  .guide .lead{margin-top:18px;font-size:13.5px;color:#dee5f1}
  .guide b,.guide strong{color:var(--ink);font-weight:600}
  .guide em{color:#cfd8e8;font-style:italic}
  .guide a{color:var(--accent);text-decoration:none;border-bottom:1px solid rgba(127,216,255,.38)}
  .guide a:hover{border-bottom-color:var(--accent)}
  .guide a:focus-visible{outline:2px solid rgba(127,216,255,.55);outline-offset:3px;border-radius:2px}
  /* The keys, as a two-column list rather than a table: the left column is set
     in the same mono the HUD uses for anything you press. */
  .guide .keys{display:grid;grid-template-columns:auto 1fr;gap:5px 14px;margin:14px 0 4px}
  .guide .keys dt{font:10px/1.5 var(--mono);letter-spacing:.1em;color:#cfd8e8;
                  background:rgba(255,255,255,.05);border:1px solid var(--line);
                  border-radius:5px;padding:2px 7px;justify-self:start;white-space:nowrap}
  .guide .keys dd{margin:0;font-size:12.5px;line-height:1.9;color:var(--dim)}
  .guide .foot{margin:22px 0 0;padding-top:14px;border-top:1px solid var(--line);
               font:9.5px/1.7 var(--mono);letter-spacing:.08em;color:var(--faint)}

  @media (max-width:760px){
    .qmark{top:11px;right:11px}
    .veil.center{padding:0 8px}
    .modal.guide{width:calc(100vw - 16px);max-height:88dvh}
    .ghead{padding:17px 18px 12px}
    .guide h2{font-size:15px;letter-spacing:.18em}
    .gbody{padding:2px 18px 22px}
    .guide h3{margin-top:18px}
  }
