/* planner_rd.css — the planner redesign: the planner's look since RD9
   (2026-10-13), built on its own page /rust-base-planner-v2 before that.
   docs/build-plans/PLANNER_REDESIGN.md. Loaded ONLY by the redesign's template
   (templates/rust_base_planner_v2.html), and every rule is scoped under
   `.pl-rd.pl-v3srv` — the body carries both classes only there — so nothing here
   can reach the old look (/rust-base-planner-old for its four weeks, and the
   admin preview). test_planner_rd.OldPageTest pins that the old look carries
   none of it.

   RD1 is the FRAME: the map fills the planner area, a top-left bar (name, saved
   line, Undo/Redo), a top-right bar (full screen, Share), a right column (3D/2D,
   the floor line, reset view) and zoom. Today's controls are MOVED into it with
   their ids (the pre-paint script in the template, gshell.js for the rest).
   RD2 is the LEFT RAIL and its PANELS (the dock): the parts, cost, raid, rules,
   view layers, settings and saves, each moved into a panel the same way. What
   is still in the old canvas bar (Row, Count, Rotate, Step, Snap) waits for
   RD3/RD4. Values are the published designs' and the prototype's
   (C:\Users\jonte\Desktop\here\planner-redesign-final\).

   ⚠ Specificity: planner.css's overlay rules are `.pl-v3srv .pl-canvas .x`
   (0,3,0). Every rule here leads with `.pl-rd.pl-v3srv` (0,2,0), so the same
   shape outranks it by one class and source order never has to be relied on. */

.pl-rd.pl-v3srv .pl-app {
    --rd-bg: #0A0A0C;
    --rd-text: #EDEAE4;
    --rd-muted: #B5AFA6;
    --rd-accent: #CD412B;
    --rd-amber: #E5A33D;
    --rd-line: rgba(255, 255, 255, .11);
    --rd-cross: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round'%3E%3Ccircle cx='12' cy='12' r='7'/%3E%3Cpath d='M12 2v4M12 18v4M2 12h4M18 12h4'/%3E%3C/svg%3E");
    --rd-tick: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m5 12 5 5 9-10'/%3E%3C/svg%3E");
    --rd-font: "Barlow", system-ui, sans-serif;
    --rd-head: "Oswald", var(--rb-font-head, sans-serif);
    --rd-mono: "JetBrains Mono", ui-monospace, monospace;
    --rd-headh: 40px;         /* the slim title line (Q2) */
    --rd-gap: 16px;           /* the map's edge inset */
    --rd-rail: 44px;          /* the left rail's button */
    --rd-panew: 344px;        /* a dock panel's width (300 below 1000px) */
    --rd-dockw: 0px;          /* the dock's width + its gap, while a panel shows */
    /* Where the free map starts: past the rail and whatever panel is open.
       Everything that sits beside the dock (the old bar, the hint, the toast,
       the selection bar) is left-bounded by this one value. */
    --rd-left: calc(var(--rd-gap) + var(--rd-rail) + 12px + var(--rd-dockw));
}
.pl-rd.pl-v3srv .pl-app.rd-dock-open { --rd-dockw: calc(var(--rd-panew) + 12px); }
/* The ad under the app keeps a thumb's width clear of the app's bottom edge
   (the hotbar, on a phone): no tap meant for the tool can land on it. */
.pl-rd.pl-v3srv .rd-adgap { padding-top: 40px; }

/* ---- the slot furniture (both widths) ---------------------------------- */
.pl-rd.pl-v3srv .rd-tl,
.pl-rd.pl-v3srv .rd-tr,
.pl-rd.pl-v3srv .rd-rcol,
.pl-rd.pl-v3srv .rd-zoom {
    position: absolute; z-index: 8;
    display: flex; align-items: flex-start;
    pointer-events: none;           /* the gaps keep panning the map */
}
.pl-rd.pl-v3srv .rd-tl > *,
.pl-rd.pl-v3srv .rd-tr > *,
.pl-rd.pl-v3srv .rd-rcol > *,
.pl-rd.pl-v3srv .rd-zoom > * { pointer-events: auto; }
.pl-rd.pl-v3srv .rd-tl { left: var(--rd-gap); top: var(--rd-gap); gap: 10px; }
.pl-rd.pl-v3srv .rd-tr { right: var(--rd-gap); top: var(--rd-gap); gap: 8px; }
.pl-rd.pl-v3srv .rd-rcol {
    right: var(--rd-gap); top: 76px;          /* hangs under Share, as designed */
    flex-direction: column; align-items: flex-end; gap: 10px;
}
.pl-rd.pl-v3srv .rd-zoom { right: var(--rd-gap); bottom: var(--rd-gap); }
/* RD4: gshell measures the map; when the right column would reach the zoom
   pair, the pair goes (the design's short-window rule, the wheel zooms). */
.pl-rd.pl-v3srv .pl-app.rd-nozoom .rd-zoom { display: none; }
/* R-RD: the Stability view's legend, left of the zoom pair (in its place
   when the pair has gone). gshell paints the bar from the view's stops. */
.pl-rd.pl-v3srv .rd-legend {
    position: absolute; z-index: 8; right: calc(var(--rd-gap) + 56px); bottom: var(--rd-gap);
    display: flex; align-items: center; gap: 8px; height: 34px; padding: 0 10px;
    background: rgba(10, 10, 12, .8); border: 1px solid rgba(255, 255, 255, .12); border-radius: 2px;
    font: 500 12px/1 Barlow, sans-serif; color: #C9C4BB; pointer-events: none;
}
.pl-rd.pl-v3srv .rd-legend[hidden] { display: none; }
.pl-rd.pl-v3srv .rd-legend i { width: 54px; height: 8px; border-radius: 4px; }
.pl-rd.pl-v3srv .pl-app.rd-nozoom .rd-legend { right: var(--rd-gap); }
/* R-RD: a message wears the design's dress (v7/v8 .toast) — a neutral
   hairline and a drop shadow, not planner.css's red accent edge — and reads
   from the left. Placement is below, per width; the phone's tighter padding
   comes later in the file and wins. */
.pl-rd.pl-v3srv .pl-canvas .pl-toast {
    padding: 11px 16px; background: rgba(10, 10, 12, .94); color: #EDEAE4;
    border: 1px solid rgba(255, 255, 255, .14); border-radius: 2px;
    box-shadow: 0 10px 30px rgba(0, 0, 0, .6);
    font: 500 14px/1.35 Barlow, sans-serif; text-align: left;
}
.pl-rd.pl-v3srv .rd-hist,
.pl-rd.pl-v3srv .rd-fsslot,
.pl-rd.pl-v3srv .rd-shareslot { display: flex; gap: 6px; position: relative; }
.pl-rd.pl-v3srv .rd-stack { display: flex; flex-direction: column; }
.pl-rd.pl-v3srv .rd-stack:empty { display: none; }

/* ---- the square button (.sb in the prototype) ---------------------------
   One look for the new buttons AND the moved chips, so the moved ones stop
   reading as sidebar chips. */
.pl-rd.pl-v3srv .rd-sb,
.pl-rd.pl-v3srv .rd-stack > .pl-chip,
.pl-rd.pl-v3srv .rd-hist > .pl-chip,
.pl-rd.pl-v3srv .rd-fsslot > .pl-fs {
    position: relative; inset: auto;
    width: 44px; height: 44px; min-width: 0; padding: 0; margin: 0;
    display: grid; place-items: center;
    font: 600 14px/1 var(--rd-head); letter-spacing: .06em; text-transform: uppercase;
    color: #D8D3CA;
    background: linear-gradient(180deg, rgba(40, 39, 43, .93), rgba(21, 21, 24, .93));
    border: 1px solid var(--rd-line); border-radius: 2px;
    box-shadow: inset 0 1px 0 rgba(255, 255, 255, .07), inset 0 -1px 0 rgba(0, 0, 0, .55),
                0 2px 8px rgba(0, 0, 0, .45);
    -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px);
    cursor: pointer; white-space: nowrap;
}
.pl-rd.pl-v3srv .rd-sb:hover,
.pl-rd.pl-v3srv .rd-stack > .pl-chip:hover:not(:disabled),
.pl-rd.pl-v3srv .rd-hist > .pl-chip:hover:not(:disabled),
.pl-rd.pl-v3srv .rd-fsslot > .pl-fs:hover {
    color: #fff; border-color: rgba(255, 255, 255, .24);
    background: linear-gradient(180deg, rgba(54, 52, 56, .96), rgba(29, 29, 32, .96));
}
.pl-rd.pl-v3srv .rd-sb.rd-on,
.pl-rd.pl-v3srv .rd-stack > .pl-chip.pl-active {
    color: #fff; border-color: var(--rd-accent);
    background: linear-gradient(180deg, rgba(205, 65, 43, .42), rgba(118, 34, 22, .62));
    box-shadow: inset 0 1px 0 rgba(255, 255, 255, .14), 0 0 0 1px rgba(205, 65, 43, .3),
                0 2px 10px rgba(0, 0, 0, .5);
}
.pl-rd.pl-v3srv .rd-sb:focus-visible,
.pl-rd.pl-v3srv .rd-stack > .pl-chip:focus-visible,
.pl-rd.pl-v3srv .rd-hist > .pl-chip:focus-visible,
.pl-rd.pl-v3srv .rd-fsslot > .pl-fs:focus-visible,
.pl-rd.pl-v3srv .rd-name:focus-visible,
.pl-rd.pl-v3srv .rd-ib:focus-visible,
.pl-rd.pl-v3srv .rd-tb:focus-visible,
.pl-rd.pl-v3srv .rd-mini:focus-visible {
    outline: none; box-shadow: 0 0 0 3px rgba(205, 65, 43, .6);
}
.pl-rd.pl-v3srv .rd-sb:disabled,
.pl-rd.pl-v3srv .rd-stack > .pl-chip:disabled,
.pl-rd.pl-v3srv .rd-hist > .pl-chip:disabled {
    /* Keep the dark face and dim only the mark: an opacity on the whole
       button turns it into a see-through green square over the map. */
    opacity: 1; color: rgba(216, 211, 202, .3); cursor: default;
}
.pl-rd.pl-v3srv .rd-sb svg { width: 20px; height: 20px; fill: none; stroke: currentColor;
    stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }

/* A stack is one block: only its end buttons are rounded, and the borders
   between buttons collapse into one hairline. */
.pl-rd.pl-v3srv .rd-stack > * { border-radius: 0; }
.pl-rd.pl-v3srv .rd-stack > :first-child { border-radius: 2px 2px 0 0; }
.pl-rd.pl-v3srv .rd-stack > :last-child { border-radius: 0 0 2px 2px; }
.pl-rd.pl-v3srv .rd-stack > :only-child { border-radius: 2px; }
.pl-rd.pl-v3srv .rd-stack > * + * { margin-top: -1px; }
.pl-rd.pl-v3srv .rd-stack > .pl-active,
.pl-rd.pl-v3srv .rd-stack > .rd-on { z-index: 1; }
.pl-rd.pl-v3srv .rd-flab { height: 30px; font: 600 12px/1 var(--rd-head); letter-spacing: .08em; }
.pl-rd.pl-v3srv .rd-flab.rd-num { font: 500 12px/1 var(--rd-mono); letter-spacing: 0; text-transform: none; }

/* The moved chips keep their text for screen readers and their ids for every
   listener; only what is DRAWN changes. */
.pl-rd.pl-v3srv .rd-stack > #planner-plan { font-size: 0; }
.pl-rd.pl-v3srv .rd-stack > #planner-plan::after {
    content: "2D"; font: 600 14px/1 var(--rd-head); letter-spacing: .06em;
}
/* ONE view button at every width (owner, 2026-10-12: "clicking it changes to
   2d, 3d, 2d, 3d"): today's toggle, naming the view you are IN — "3D", lit
   "2D" in the top view (v8's .vtog). #planner-rd-3d stays in the page, unseen,
   so its lit state still mirrors the view for anything that reads it. */
.pl-rd.pl-v3srv .rd-stack > #planner-plan[aria-pressed="false"]::after { content: "3D"; }
.pl-rd.pl-v3srv .rd-stack > #planner-rd-3d { display: none; }
.pl-rd.pl-v3srv .rd-stack > #planner-plan { border-radius: 2px; margin-top: 0; }
.pl-rd.pl-v3srv .rd-stack > #planner-viewline-inc,
.pl-rd.pl-v3srv .rd-stack > #planner-viewline-dec { font-size: 0; }
.pl-rd.pl-v3srv .rd-stack > #planner-viewline-inc::after,
.pl-rd.pl-v3srv .rd-stack > #planner-viewline-dec::after {
    content: ""; width: 20px; height: 20px; background: currentColor;
    -webkit-mask: var(--rd-chev) center / 20px 20px no-repeat;
    mask: var(--rd-chev) center / 20px 20px no-repeat;
}
.pl-rd.pl-v3srv .rd-stack > #planner-viewline-inc {
    --rd-chev: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 15 6-6 6 6'/%3E%3C/svg%3E");
}
.pl-rd.pl-v3srv .rd-stack > #planner-viewline-dec {
    --rd-chev: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
}
.pl-rd.pl-v3srv .rd-stack > #planner-resetview .pl-chip-txt { display: none; }
.pl-rd.pl-v3srv .rd-stack > #planner-resetview .pl-ico { display: block; width: 20px; height: 20px; }
.pl-rd.pl-v3srv .rd-hist > .pl-chip { font-size: 0; }
/* The hidden word is still a grid item: with the chip's gap it pushed the
   icon 3px off centre (owner, 2026-10-12). One cell, centred. */
.pl-rd.pl-v3srv .rd-hist > .pl-chip,
.pl-rd.pl-v3srv .rd-stack > #planner-plan,
.pl-rd.pl-v3srv .rd-stack > #planner-viewline-inc,
.pl-rd.pl-v3srv .rd-stack > #planner-viewline-dec { gap: 0; place-items: center; place-content: center; }
.pl-rd.pl-v3srv .rd-hist > .pl-chip::after {
    content: ""; width: 20px; height: 20px; background: currentColor;
    -webkit-mask: var(--rd-ico) center / 20px 20px no-repeat;
    mask: var(--rd-ico) center / 20px 20px no-repeat;
}
.pl-rd.pl-v3srv .rd-hist > #planner-undo {
    --rd-ico: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M9 14 4 9l5-5'/%3E%3Cpath d='M4 9h10.5a5.5 5.5 0 0 1 0 11H11'/%3E%3C/svg%3E");
}
.pl-rd.pl-v3srv .rd-hist > #planner-redo {
    --rd-ico: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m15 14 5-5-5-5'/%3E%3Cpath d='M20 9H9.5a5.5 5.5 0 0 0 0 11H13'/%3E%3C/svg%3E");
}
.pl-rd.pl-v3srv .rd-fsslot > .pl-fs svg { width: 20px; height: 20px; }

/* ---- the name + saved line (.bname) ------------------------------------ */
.pl-rd.pl-v3srv .rd-logo {
    width: 44px; height: 44px; flex: none; display: grid; place-items: center;
    background: var(--rd-accent); color: #fff; border-radius: 2px;
    font: 700 18px/1 var(--rd-head); letter-spacing: .02em;
    box-shadow: inset 0 1px 0 rgba(255, 255, 255, .2), inset 0 -2px 0 rgba(0, 0, 0, .25),
                0 2px 8px rgba(0, 0, 0, .5);
}
.pl-rd.pl-v3srv button.rd-logo { padding: 0; border: 0; cursor: pointer; }
.pl-rd.pl-v3srv button.rd-logo:hover { filter: brightness(1.12); }
.pl-rd.pl-v3srv button.rd-logo:focus-visible { outline: 2px solid #fff; outline-offset: 2px; }
.pl-rd.pl-v3srv .rd-name {
    display: flex; flex-direction: column; justify-content: center; gap: 3px;
    min-height: 44px; min-width: 0; max-width: 320px; padding: 5px 12px 5px 10px;
    text-align: left; cursor: pointer; color: var(--rd-text);
    background: rgba(10, 10, 12, .55); border: 1px solid transparent; border-radius: 2px;
    -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px);
}
.pl-rd.pl-v3srv .rd-name:hover { background: rgba(10, 10, 12, .75); border-color: rgba(255, 255, 255, .16); }
.pl-rd.pl-v3srv .rd-nm {
    display: flex; align-items: center; gap: 6px; min-width: 0;
    font: 600 17px/1.1 var(--rd-head); letter-spacing: .05em; text-transform: uppercase;
}
.pl-rd.pl-v3srv .rd-nm > span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }
.pl-rd.pl-v3srv .rd-nm svg { width: 14px; height: 14px; flex: none; fill: none; stroke: currentColor;
    stroke-width: 2.2; stroke-linecap: round; stroke-linejoin: round; }
.pl-rd.pl-v3srv .rd-st {
    display: flex; align-items: center; gap: 6px; min-width: 0;
    font: 500 12px/1 var(--rd-font); color: var(--rd-muted); white-space: nowrap;
}
.pl-rd.pl-v3srv .rd-dot { width: 7px; height: 7px; border-radius: 50%; flex: none; background: #6B665F; }
.pl-rd.pl-v3srv .rd-name[data-saved="saved"] .rd-dot { background: #5FA85A; }
.pl-rd.pl-v3srv .rd-name[data-saved="browser"] .rd-dot { background: var(--rd-amber); }
.pl-rd.pl-v3srv .rd-name[data-saved="failed"] .rd-dot { background: var(--rd-accent); }
.pl-rd.pl-v3srv .rd-name[data-saved="changed"] .rd-dot { background: var(--rd-amber); }

/* ---- Share (the moved .pl-share-row) ------------------------------------ */
.pl-rd.pl-v3srv .rd-shareslot .pl-share-row { display: flex; margin: 0; padding: 0; position: relative; }
.pl-rd.pl-v3srv .rd-shareslot #planner-copy {
    display: inline-flex; align-items: center; gap: 9px; height: 44px; margin: 0;
    padding: 0 18px 0 14px; width: auto;
    font: 700 15px/1 var(--rd-head); letter-spacing: .14em; text-transform: uppercase;
    color: #fff; background: linear-gradient(180deg, rgba(40, 39, 43, .93), rgba(21, 21, 24, .93));
    border: 1px solid var(--rd-line); border-radius: 2px;
    box-shadow: inset 0 1px 0 rgba(255, 255, 255, .07), inset 0 -1px 0 rgba(0, 0, 0, .55),
                0 2px 8px rgba(0, 0, 0, .45);
    cursor: pointer; white-space: nowrap;
}
.pl-rd.pl-v3srv .rd-shareslot #planner-copy::before {
    content: ""; width: 19px; height: 19px; flex: none; background: var(--rd-accent);
    -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='18' cy='5' r='2.6'/%3E%3Ccircle cx='6' cy='12' r='2.6'/%3E%3Ccircle cx='18' cy='19' r='2.6'/%3E%3Cpath d='m8.3 10.8 7.4-4.4M8.3 13.2l7.4 4.4'/%3E%3C/svg%3E") center / contain no-repeat;
    mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='18' cy='5' r='2.6'/%3E%3Ccircle cx='6' cy='12' r='2.6'/%3E%3Ccircle cx='18' cy='19' r='2.6'/%3E%3Cpath d='m8.3 10.8 7.4-4.4M8.3 13.2l7.4 4.4'/%3E%3C/svg%3E") center / contain no-repeat;
}
.pl-rd.pl-v3srv .rd-shareslot #planner-copy:hover:not(:disabled) { border-color: rgba(255, 255, 255, .24);
    background: linear-gradient(180deg, rgba(54, 52, 56, .96), rgba(29, 29, 32, .96)); }
.pl-rd.pl-v3srv .rd-shareslot #planner-copy:disabled { opacity: 1; color: rgba(216, 211, 202, .35); cursor: default; }
.pl-rd.pl-v3srv .rd-shareslot #planner-copy:disabled::before { background: rgba(205, 65, 43, .4); }
.pl-rd.pl-v3srv .rd-shareslot #planner-copy:focus-visible { outline: none; box-shadow: 0 0 0 3px rgba(205, 65, 43, .6); }
/* The share status line is never drawn here: the popover repeats it while
   it is up, and a toast says it otherwise (gshell.js). Drawn, it outlived
   the popover and sat over the 2D/3D button (owner, 2026-10-12). */
.pl-rd.pl-v3srv .rd-shareslot #planner-share-msg { display: none; }


/* ======================= the frame (every width since RD6) =============== */
@media all {
    /* Q1 (owner 2026-09-27): keep the site header; the planner fills the rest
       of the window below it. The card that used to frame the tool goes; the
       page below keeps its 1200px column (same inset the card gave it). */
    .pl-rd.pl-v3srv .rd-outer { margin-top: 0; }
    .pl-rd.pl-v3srv .pl-wrap {
        max-width: none; width: 100%; padding-left: 0; padding-right: 0;
    }
    .pl-rd.pl-v3srv .pl-wrap > :not(.pl-app) {
        margin-left: max(24px, calc(50% - 588px));
        margin-right: max(24px, calc(50% - 588px));
    }
    .pl-rd.pl-v3srv .pl-app {
        --plw: 100%;
        display: grid; position: relative;
        width: 100%; margin: 0; padding: 0; gap: 0; overflow: hidden;
        grid-template-columns: minmax(0, 1fr);
        grid-template-rows: var(--rd-headh) minmax(0, 1fr);
        height: calc(100vh - var(--rd-nav, 64px));
        height: calc(100dvh - var(--rd-nav, 64px));
        min-height: 480px;
        border: none; border-radius: 0; background: var(--rd-bg);
    }
    /* Q2 (owner 2026-09-27): the H1 stays, as one slim line. The pitch
       paragraph under it goes (the article below the tool carries it). */
    .pl-rd.pl-v3srv .pl-head {
        grid-row: 1; grid-column: 1;
        display: flex; align-items: center; padding: 0 var(--rd-gap);
        border-bottom: 1px solid rgba(255, 255, 255, .08); background: var(--rd-bg);
        min-width: 0; overflow: hidden;
    }
    .pl-rd.pl-v3srv .pl-head p { display: none; }
    .pl-rd.pl-v3srv .pl-head-top { margin: 0; gap: 10px; min-width: 0; flex-wrap: nowrap; }
    .pl-rd.pl-v3srv .pl-head h1 {
        margin: 0; font: 600 15px/1 var(--rd-head); letter-spacing: .06em;
        text-transform: uppercase; color: var(--rd-muted);
        white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
    }
    .pl-rd.pl-v3srv .pl-canvas {
        grid-row: 2; grid-column: 1; order: 0;
        height: auto; min-height: 0; max-height: none; aspect-ratio: auto;
        border: none; border-radius: 0;
    }

    /* The old canvas bar is empty on desktop since RD3 (RD2's panels took the
       view and overlay controls, the hands label took Row, Count, Rotate,
       Step and Snap), so it goes — on the phone too since RD6, whose own
       top and bottom bars hold what it held. */
    .pl-rd.pl-v3srv .pl-cbar { display: none; }

    /* RD4: the hover card (.hinfo) — today's info panel in the design's
       card, at the top right under Share, left of the right column. gshell
       adds its "Turn it" line and the rd-aside class (an open panel, the slot
       menu or a toast would cover it: the card steps aside, never they). */
    .pl-rd.pl-v3srv .pl-canvas .pl-info {
        right: 70px; top: 76px; left: auto; bottom: auto; width: 220px; max-width: none;
        display: flex; flex-direction: column; gap: 6px; padding: 10px 12px;
        font: 500 12.5px/1.25 var(--rd-font); color: #B5AFA6;
        background: rgba(10, 10, 12, .9); border: 1px solid rgba(255, 255, 255, .12);
        border-radius: 2px; box-shadow: 0 6px 20px rgba(0, 0, 0, .45);
        pointer-events: none;
    }
    .pl-rd.pl-v3srv .pl-canvas .pl-info[hidden] { display: none; }
    .pl-rd.pl-v3srv .pl-canvas .pl-info.rd-aside { visibility: hidden; }
    .pl-rd.pl-v3srv .pl-canvas .pl-info .pl-info-title {
        font: 600 14px/1.15 var(--rd-head); letter-spacing: .06em; text-transform: uppercase;
        color: var(--rd-text);
    }
    .pl-rd.pl-v3srv .pl-canvas .pl-info .pl-info-line { display: block; }
    .pl-rd.pl-v3srv .pl-canvas .pl-info .pl-info-hp { font: 600 13px/1.2 var(--rd-head); color: var(--rd-text); }
    .pl-rd.pl-v3srv .pl-canvas .pl-info .pl-info-risk { color: #E5A33D; }
    .pl-rd.pl-v3srv .pl-canvas .pl-info .pl-info-bad { color: #F08A74; }
    .pl-rd.pl-v3srv .pl-canvas .pl-info .rd-info-turn {
        display: flex; align-items: center; justify-content: space-between; gap: 8px;
        padding-top: 6px; border-top: 1px solid rgba(255, 255, 255, .08);
    }
    .pl-rd.pl-v3srv .pl-canvas .pl-info .rd-info-keys { display: inline-flex; gap: 4px; }
    .pl-rd.pl-v3srv .pl-canvas .pl-info kbd {
        font: 600 10.5px/1 var(--rd-mono); padding: 2px 5px; border-radius: 2px;
        color: #D8D3CA; background: rgba(255, 255, 255, .08); border: 1px solid var(--rd-line);
    }
    /* The starter hint sits ABOVE the hotbar block, whose height gshell
       mirrors into --rd-both (the grades stack over the hotbar below 980px,
       and the hands label can wrap). It is centred in the map area the rail,
       the dock and the column leave free, like the selection bar: centred on
       the canvas, it ran under the panels. */
    .pl-rd.pl-v3srv .pl-canvas .pl-hint {
        top: auto; bottom: calc(var(--rd-gap) + var(--rd-both, 134px) + 8px);
        left: var(--rd-left); right: 76px;
        transform: none; width: fit-content; max-width: none; margin: 0 auto;
    }
    /* The toast sits BETWEEN the two top bars, bounded by their measured
       widths (--rd-tlw grows with the base's name), so a message never lies
       over the name or Share. Below 1000px that gap is too narrow to read in,
       so it drops under them into the free map area, like the selection bar
       (it is pointer-events: none, so over that bar it blocks no click). */
    .pl-rd.pl-v3srv .pl-canvas .pl-toast {
        top: var(--rd-gap); bottom: auto; z-index: 12; transform: none;
        left: calc(var(--rd-gap) + var(--rd-tlw, 332px) + 12px);
        right: calc(var(--rd-gap) + var(--rd-trw, 198px) + 12px);
        width: fit-content; max-width: 560px; margin: 0 auto;
    }
    @media (max-width: 999px) {
        .pl-rd.pl-v3srv .pl-canvas .pl-toast { top: 76px; left: var(--rd-left); right: 76px; }
        /* RD5: the Share popover opens at that height and above the toast,
           so while it is open a message stops short of it — never under it. */
        .pl-rd.pl-v3srv .pl-app.rd-sharing .pl-canvas .pl-toast { right: calc(2 * var(--rd-gap) + 370px + 12px); }
    }
    /* RD4: the selection bar lives in the bottom column (gshell moves it
       there, between the hands label and the hotbar), so it can never sit on
       either, and the panels stop above it (--rd-both measures the column).
       The design's groups are gshell's .rd-sgp spans. Before gshell runs it
       is still on the map; it is hidden then (nothing is selected at boot). */
    .pl-rd.pl-v3srv .pl-canvas .pl-selbar.rd-selbar {
        position: static; inset: auto; transform: none; z-index: auto; margin: 0;
        display: flex; flex-wrap: wrap; align-items: center; justify-content: center;
        gap: 6px 10px; padding: 6px 8px 6px 12px;
        max-width: min(calc(100% - 180px), 1180px); min-width: 0;
        background: rgba(10, 10, 12, .88); border: 1px solid rgba(205, 65, 43, .45);
        border-radius: 2px; box-shadow: 0 6px 20px rgba(0, 0, 0, .4);
        font-family: var(--rd-font);
    }
    .pl-rd.pl-v3srv .pl-canvas .pl-selbar.rd-selbar[hidden] { display: none; }
    .pl-rd.pl-v3srv .rd-selbar .pl-selcount { margin: 0; font: 500 13px/1 var(--rd-font); color: #C9C4BB; }
    .pl-rd.pl-v3srv .rd-selbar .rd-sgp {
        display: flex; flex-wrap: wrap; align-items: center; gap: 4px;
        padding-left: 10px; border-left: 1px solid rgba(255, 255, 255, .12);
    }
    .pl-rd.pl-v3srv .rd-selbar .rd-sgp:not(:has(> :not([hidden]))) { display: none; }
    .pl-rd.pl-v3srv .rd-selbar .pl-selbar-pair { gap: 4px; }
    .pl-rd.pl-v3srv .rd-selbar .pl-chip {
        min-height: 30px; margin: 0; padding: 0 9px;
        display: inline-flex; align-items: center;
        font: 600 11.5px/1 var(--rd-head); letter-spacing: .08em; text-transform: uppercase;
        color: #EDEAE4; background: #1F1F23; border: 1px solid rgba(255, 255, 255, .2);
        border-radius: 2px; box-shadow: none;
    }
    .pl-rd.pl-v3srv .rd-selbar .pl-chip:hover { border-color: rgba(255, 255, 255, .4); color: #fff; }
    .pl-rd.pl-v3srv .rd-selbar .pl-chip.pl-active,
    .pl-rd.pl-v3srv .rd-selbar .pl-chip[aria-pressed="true"] {
        border-color: var(--rd-accent); background: rgba(205, 65, 43, .28);
    }
    .pl-rd.pl-v3srv .rd-selbar .pl-chip[data-act="delete"] { border-color: rgba(205, 65, 43, .7); color: #FFB8A8; }
    .pl-rd.pl-v3srv .rd-selbar .pl-chip:focus-visible { outline: none; box-shadow: 0 0 0 3px rgba(205, 65, 43, .6); }
    .pl-rd.pl-v3srv .rd-selbar .pl-selturn { font: 600 13px/1 var(--rd-mono); color: var(--rd-text); }
    .pl-rd.pl-v3srv .rd-selbar .pl-honey { border-top-color: rgba(255, 255, 255, .12); }

    /* RD4: the tools column. Delete reads red, as in the design; Row is its
       button now, so the old Row chip leaves the hands label (it stays in the
       page for T and the gates), and Count shows only while Row is on. */
    .pl-rd.pl-v3srv .rd-sb.rd-danger { color: #F2A897; }
    .pl-rd.pl-v3srv .rd-sb.rd-danger.rd-on,
    .pl-rd.pl-v3srv .rd-sb.rd-danger:hover { color: #fff; }
    .pl-rd.pl-v3srv #planner-rd-handsctl > #planner-rowmode { display: none; }
    .pl-rd.pl-v3srv .pl-app:not(.rd-row-on) #planner-rd-handsctl > #planner-rowcount { display: none; }
    /* The feedback pill goes: the rail's Feedback button opens the same dialog
       (feedback.js answers any [data-fbk-open] click). */
    .pl-rd.pl-v3srv .pl-canvas .pl-fbw,
    .pl-rd.pl-v3srv .pl-canvas .pl-fbw-mini { display: none; }
    @media (max-width: 999px) {
        .pl-rd.pl-v3srv .pl-app { --rd-panew: 300px; }
    }

    /* ---- RD3: the hands label, the grades strip and the hotbar (.bottom) --
       Centred in the WHOLE canvas (never in the space a panel leaves), so a
       slot never moves under the pointer when a panel opens. The block lets
       clicks through; only its children take them. */
    .pl-rd.pl-v3srv .rd-bottom {
        position: absolute; z-index: 23; left: 0; right: 0; bottom: 14px;
        display: flex; flex-direction: column; align-items: center; gap: 8px;
        pointer-events: none; font-family: var(--rd-font); color: var(--rd-text);
    }
    .pl-rd.pl-v3srv .rd-bottom > * { pointer-events: auto; }
    /* The ✓ of a pinned tap (a finger on a tablet gets this frame) is drawn
       over every bar and panel (up to the Share popover's 30); gshell's
       keepConfirm keeps it beside them rather than on top of them. */
    .pl-rd.pl-v3srv .pl-canvas .pl-confirm { z-index: 31; }
    .pl-rd.pl-v3srv .rd-vh {
        position: absolute; width: 1px; height: 1px; overflow: hidden;
        clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap;
    }
    .pl-rd.pl-v3srv .rd-panel-box {
        background: rgba(17, 17, 20, .92);
        border: 1px solid rgba(255, 255, 255, .12); border-radius: 2px;
        box-shadow: 0 10px 30px rgba(0, 0, 0, .5);
        -webkit-backdrop-filter: blur(8px); backdrop-filter: blur(8px);
    }

    /* The hands label: what is armed, its grade, its cost, Q/E; then the
       armed tool's own controls (Row, Count, Rotate, Step, Snap — moved here
       by the pre-paint script, ids intact). */
    .pl-rd.pl-v3srv .rd-hands {
        display: flex; align-items: center; flex-wrap: wrap; justify-content: center;
        gap: 6px 12px; min-height: 32px; max-width: min(900px, calc(100% - 180px));
        padding: 3px 6px 3px 12px;
        background: rgba(10, 10, 12, .8); border: 1px solid rgba(255, 255, 255, .1);
        border-radius: 2px;
    }
    .pl-rd.pl-v3srv .rd-hl {
        display: flex; align-items: center; gap: 10px; min-width: 0;
        font: 500 13px/1 var(--rd-font); color: var(--rd-muted); white-space: nowrap;
    }
    .pl-rd.pl-v3srv .rd-hl .rd-hn {
        font: 600 14px/1 var(--rd-head); letter-spacing: .08em; text-transform: uppercase;
        color: var(--rd-text);
    }
    .pl-rd.pl-v3srv .rd-hl .rd-hsep { width: 1px; height: 14px; background: rgba(255, 255, 255, .16); }
    .pl-rd.pl-v3srv .rd-hl .rd-hg { display: inline-flex; align-items: center; gap: 6px; color: var(--rd-text); }
    .pl-rd.pl-v3srv .rd-hl .rd-hsw { width: 12px; height: 12px; border-radius: 1px; border: 1px solid rgba(255, 255, 255, .2); }
    .pl-rd.pl-v3srv .rd-hl .rd-hsw[data-tier="twig"] { background: #b99a5e; }
    .pl-rd.pl-v3srv .rd-hl .rd-hsw[data-tier="wood"] { background: #8a5a34; }
    .pl-rd.pl-v3srv .rd-hl .rd-hsw[data-tier="stone"] { background: #7d7a72; }
    .pl-rd.pl-v3srv .rd-hl .rd-hsw[data-tier="sheetmetal"] { background: #5d6771; }
    .pl-rd.pl-v3srv .rd-hl .rd-hsw[data-tier="armored"] { background: #3f4347; }
    .pl-rd.pl-v3srv .rd-hl .rd-hcost { display: inline-flex; align-items: center; gap: 8px;
        font: 600 13px/1 var(--rd-mono); color: var(--rd-text); }
    .pl-rd.pl-v3srv .rd-hl .rd-hcost > span { display: inline-flex; align-items: center; gap: 4px; }
    .pl-rd.pl-v3srv .rd-hl .rd-hcost .pl-ico { width: 18px; height: 18px; }
    .pl-rd.pl-v3srv .rd-hl kbd, .pl-rd.pl-v3srv .rd-fly kbd {
        font: 600 10.5px/1 var(--rd-mono); padding: 2px 5px; border-radius: 2px;
        color: #D8D3CA; background: rgba(255, 255, 255, .08); border: 1px solid var(--rd-line);
    }
    .pl-rd.pl-v3srv .rd-hc { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
    .pl-rd.pl-v3srv .rd-hc:empty { display: none; }
    .pl-rd.pl-v3srv .rd-hc > [hidden] { display: none; }
    .pl-rd.pl-v3srv .rd-hc .pl-chip,
    .pl-rd.pl-v3srv .rd-hc .pl-level {
        margin: 0; height: 26px; min-height: 0; padding: 0 9px;
        display: inline-flex; align-items: center; gap: 6px;
        font: 600 11.5px/1 var(--rd-head); letter-spacing: .06em; text-transform: uppercase;
        color: #D8D3CA; background: rgba(255, 255, 255, .05);
        border: 1px solid var(--rd-line); border-radius: 2px; box-shadow: none;
    }
    .pl-rd.pl-v3srv .rd-hc .pl-level { padding: 0 3px 0 8px; }
    .pl-rd.pl-v3srv .rd-hc .pl-level .pl-cap { font: inherit; color: var(--rd-muted); }
    .pl-rd.pl-v3srv .rd-hc .pl-level .pl-chip { height: 20px; width: 22px; padding: 0; justify-content: center;
        font-size: 14px; background: none; border-color: transparent; }
    .pl-rd.pl-v3srv .rd-hc .pl-level .pl-level-label { min-width: 22px; text-align: center;
        font: 500 12px/1 var(--rd-mono); color: var(--rd-text); }
    /* RD8: the foundation STEP readout keeps today's two promises in the rd
       face. The rule above is (0,5,0), so it beat planner.css's amber
       `.pl-level-label.pl-level-armed` (a non-zero step read the plain text
       colour), and the 12px mono overflowed today's 52px reservation (the
       readout measured 52 / 53.45 / 61.34 px across the step values, so the
       - / + beside it walked under the finger). One width holds "+60.00"
       armed and unarmed. Gate: run_camera's `step` / `shift` checks on v2. */
    .pl-rd.pl-v3srv .rd-hc .pl-level #planner-foundheight-label { min-width: 64px;
        font-variant-numeric: tabular-nums; }
    .pl-rd.pl-v3srv .rd-hc .pl-level .pl-level-label.pl-level-armed { color: var(--rb-warn, #E0A33A); }
    .pl-rd.pl-v3srv .rd-hc .pl-chip:hover { color: #fff; border-color: rgba(255, 255, 255, .24); }
    .pl-rd.pl-v3srv .rd-hc .pl-chip[aria-pressed="true"],
    .pl-rd.pl-v3srv .rd-hc .pl-chip.pl-active {
        color: #fff; background: rgba(205, 65, 43, .22); border-color: var(--rd-accent);
    }
    .pl-rd.pl-v3srv .rd-hc .pl-chip:disabled { opacity: .4; cursor: default; }

    .pl-rd.pl-v3srv .rd-hbrow { display: flex; align-items: flex-end; gap: 12px; }

    /* The grades strip: today's five tier chips as 44px swatch tiles, the
       grade's number in the corner (Shift+1…5). */
    .pl-rd.pl-v3srv .rd-grades { padding: 5px; }
    .pl-rd.pl-v3srv .rd-grades .pl-tiers {
        display: flex; flex-wrap: nowrap; gap: 5px; margin: 0; padding: 0; border: none;
        overflow: visible;
    }
    .pl-rd.pl-v3srv .rd-grades .pl-tiers[data-label]::before { display: none; }
    .pl-rd.pl-v3srv .rd-grades .pl-tiers .pl-chip {
        flex: none; width: 44px; height: 44px; cursor: pointer;
    }
    .pl-rd.pl-v3srv .rd-grades .pl-tiers .pl-chip::before {
        height: 100%; border: 1px solid rgba(255, 255, 255, .14); border-radius: 2px;
    }
    .pl-rd.pl-v3srv .rd-grades .pl-tiers .pl-chip .pl-ico-tier {
        top: 50%; width: 26px; height: 26px;
    }
    .pl-rd.pl-v3srv .rd-grades .pl-tiers .pl-chip[data-rd-gk]::after {
        content: "\21E7" attr(data-rd-gk); position: absolute; right: 2px; bottom: 1px;
        font: 600 9.5px/1 var(--rd-mono); color: rgba(255, 255, 255, .85);
        text-shadow: 0 0 2px #000, 0 0 3px #000;
    }
    .pl-rd.pl-v3srv .rd-grades .pl-tiers .pl-chip.pl-active::before {
        border: 1px solid rgba(255, 255, 255, .14);
        box-shadow: 0 0 0 2px #0A0A0C, 0 0 0 4px var(--rd-accent);
    }
    .pl-rd.pl-v3srv .rd-grades .pl-tiers .pl-chip:focus-visible { outline: none; }
    .pl-rd.pl-v3srv .rd-grades .pl-tiers .pl-chip:focus-visible::before {
        box-shadow: 0 0 0 2px #0A0A0C, 0 0 0 4px #fff;
    }
    /* Grade does nothing for a deployable, a door or a tool: the strip dims. */
    .pl-rd.pl-v3srv .rd-grades.rd-dim { opacity: .45; }
    /* Both strips sit in the design's dark tray (.grades / .hotbar, v7 + v8). */
    .pl-rd.pl-v3srv .rd-grades,
    .pl-rd.pl-v3srv .rd-hotbar {
        background: rgba(10, 10, 12, .62); border: 1px solid rgba(255, 255, 255, .1); border-radius: 2px;
    }

    /* The hotbar: nine slots and the "+" that opens All parts. */
    .pl-rd.pl-v3srv .rd-hotbar { display: flex; gap: 5px; padding: 5px; }
    .pl-rd.pl-v3srv .rd-slot {
        position: relative; flex: none; width: 64px; height: 64px; padding: 0;
        display: grid; place-items: center; cursor: pointer;
        background: rgba(34, 34, 38, .9); border: 1px solid rgba(255, 255, 255, .12);
        border-radius: 2px; color: var(--rd-text);
    }
    .pl-rd.pl-v3srv .rd-slot:hover { border-color: rgba(255, 255, 255, .3); background: rgba(46, 46, 51, .95); }
    .pl-rd.pl-v3srv .rd-slot:focus-visible { outline: none; box-shadow: 0 0 0 2px #fff; }
    .pl-rd.pl-v3srv .rd-slot .pl-ico { width: 44px; height: 44px; pointer-events: none; }
    .pl-rd.pl-v3srv .rd-slot svg.pl-ico { width: 32px; height: 32px; fill: none; stroke: currentColor; stroke-width: 1.6; }
    .pl-rd.pl-v3srv .rd-slot .rd-sn {
        position: absolute; left: 5px; top: 4px; pointer-events: none;
        font: 600 12px/1 var(--rd-head); color: #D8D3CA;
    }
    .pl-rd.pl-v3srv .rd-slot.rd-empty .rd-sn { color: rgba(216, 211, 202, .45); }
    .pl-rd.pl-v3srv .rd-slot.rd-on {
        background: rgba(205, 65, 43, .28); border: 2px solid var(--rd-accent);
    }
    .pl-rd.pl-v3srv .rd-slot.rd-tgt { border: 2px solid var(--rd-amber); }
    .pl-rd.pl-v3srv .rd-slot.rd-add {
        background: none; border: 1px dashed rgba(255, 255, 255, .28); color: #B5AFA6;
    }
    .pl-rd.pl-v3srv .rd-slot.rd-add:hover { color: #fff; border-color: rgba(255, 255, 255, .5); }
    .pl-rd.pl-v3srv .rd-slot.rd-add svg { width: 22px; height: 22px; fill: none; stroke: currentColor;
        stroke-width: 2; stroke-linecap: round; }

    /* A slot's right-click menu: the slot's family, then All parts. */
    .pl-rd.pl-v3srv .rd-fly {
        position: absolute; z-index: 26; bottom: calc(100% + 8px); padding: 8px 10px 10px;
    }
    .pl-rd.pl-v3srv .rd-fly[hidden] { display: none; }
    /* The menu opens where the hint line sits; while it is open it is the thing
       to read, so the hint steps aside. */
    .pl-rd.pl-v3srv .pl-app.rd-fly-open .pl-canvas .pl-hint { visibility: hidden; }
    .pl-rd.pl-v3srv .rd-fly-h {
        display: flex; align-items: center; justify-content: space-between; gap: 16px;
        margin: 0 0 8px; font: 600 11.5px/1 var(--rd-head); letter-spacing: .12em;
        text-transform: uppercase; color: var(--rd-muted);
    }
    .pl-rd.pl-v3srv .rd-fly-o { display: flex; gap: 5px; }
    .pl-rd.pl-v3srv .rd-fly .rd-slot { width: 54px; height: 54px; }
    .pl-rd.pl-v3srv .rd-fly .rd-slot .pl-ico { width: 36px; height: 36px; }
    .pl-rd.pl-v3srv .rd-fly .rd-slot svg.pl-ico, .pl-rd.pl-v3srv .rd-fly .rd-slot > svg { width: 26px; height: 26px; }
    .pl-rd.pl-v3srv .rd-fly .rd-slot > svg { fill: none; stroke: currentColor; stroke-width: 1.8;
        stroke-linecap: round; stroke-linejoin: round; }

    /* All parts (the Parts panel since RD3): search, "Put it in slot", reset. */
    .pl-rd.pl-v3srv .rd-ap { flex: none; padding: 10px 14px 2px; }
    .pl-rd.pl-v3srv .rd-ap-search {
        width: 100%; height: 32px; padding: 0 10px; box-sizing: border-box;
        font: 400 14px/1 var(--rd-font); color: var(--rd-text);
        background: #17171A; border: 1px solid var(--rd-line); border-radius: 2px;
    }
    .pl-rd.pl-v3srv .rd-ap-search:focus { outline: none; border-color: rgba(205, 65, 43, .7); }
    .pl-rd.pl-v3srv .rd-ap-caprow {
        display: flex; align-items: baseline; justify-content: space-between; gap: 10px; margin: 0 0 6px;
    }
    .pl-rd.pl-v3srv .rd-ap-cap {
        display: block; font: 600 11.5px/1 var(--rd-head);
        letter-spacing: .12em; text-transform: uppercase; color: var(--rd-muted);
    }
    .pl-rd.pl-v3srv .rd-ap-slots { display: flex; gap: 4px; }
    .pl-rd.pl-v3srv .rd-ap-slots button {
        flex: 1 1 0; min-width: 0; height: 30px; padding: 0; cursor: pointer;
        font: 600 13px/1 var(--rd-head); color: #D8D3CA;
        background: rgba(255, 255, 255, .05); border: 1px solid var(--rd-line); border-radius: 2px;
    }
    .pl-rd.pl-v3srv .rd-ap-slots button:hover { color: #fff; border-color: rgba(255, 255, 255, .28); }
    .pl-rd.pl-v3srv .rd-ap-slots button[aria-pressed="true"] {
        color: #fff; background: var(--rd-accent); border-color: var(--rd-accent);
    }
    /* The group tabs (owner, 2026-10-12): ONE row that scrolls sideways — four
       wrapped rows left the list a third of the panel. ‹ › sit over its ends,
       fading the tabs under them, while more groups hide past an edge. */
    .pl-rd.pl-v3srv .rd-ptabw { position: relative; margin: 8px 0 0; }
    .pl-rd.pl-v3srv .rd-ptabs {
        position: relative; display: flex; flex-wrap: nowrap; gap: 4px;
        overflow-x: auto; overscroll-behavior-x: contain; scrollbar-width: none;
    }
    .pl-rd.pl-v3srv .rd-ptabs::-webkit-scrollbar { display: none; }
    .pl-rd.pl-v3srv .rd-ptarr {
        position: absolute; top: 0; bottom: 0; z-index: 1; width: 34px; padding: 0; cursor: pointer;
        font: 600 20px/1 var(--rd-font); color: #fff; border: none;
    }
    .pl-rd.pl-v3srv .rd-ptarr[hidden] { display: none; }
    .pl-rd.pl-v3srv .rd-ptarr[data-rd-pdir="-1"] {
        left: 0; text-align: left; background: linear-gradient(90deg, rgb(17, 17, 20) 55%, rgba(17, 17, 20, 0));
    }
    .pl-rd.pl-v3srv .rd-ptarr[data-rd-pdir="1"] {
        right: 0; text-align: right; background: linear-gradient(270deg, rgb(17, 17, 20) 55%, rgba(17, 17, 20, 0));
    }
    .pl-rd.pl-v3srv .rd-ptabs button {
        flex: none; height: 28px; padding: 0 9px; cursor: pointer; white-space: nowrap;
        font: 500 12.5px/1 var(--rd-font); color: #B9B4AB;
        background: transparent; border: 1px solid var(--rd-line); border-radius: 14px;
    }
    .pl-rd.pl-v3srv .rd-ptabs button:hover { color: #fff; border-color: rgba(255, 255, 255, .28); }
    .pl-rd.pl-v3srv .rd-ptabs button:focus-visible { outline: none; box-shadow: 0 0 0 2px rgba(205, 65, 43, .6); }
    .pl-rd.pl-v3srv .rd-ptabs button[aria-pressed="true"] {
        color: #fff; background: rgba(205, 65, 43, .2); border-color: var(--rd-accent);
    }
    .pl-rd.pl-v3srv .pl-catgroup.rd-tabout { display: none !important; }
    /* the slot digits, at the foot: next to the hotbar they fill */
    .pl-rd.pl-v3srv .rd-ap-foot {
        flex: none; padding: 9px 14px 10px; border-top: 1px solid rgba(255, 255, 255, .08);
    }
    .pl-rd.pl-v3srv .rd-ap-reset {
        flex: none; padding: 0; background: none; border: none; cursor: pointer;
        font: 500 12.5px/1 var(--rd-font); color: #DD5F47; text-decoration: underline;
        text-underline-offset: 3px;
    }
    /* a chip the search filters out, and a whole group left empty */
    .pl-rd.pl-v3srv .rd-pb .rd-nomatch { display: none !important; }
    /* today's deployables-only find box (D7): All parts has its own search,
       which already covers every part, so a second box is not shown here. */
    .pl-rd.pl-v3srv .pl-find { display: none !important; }
    /* the slot number a part already holds, in the chip's corner */
    .pl-rd.pl-v3srv .rd-pb .pl-palette [data-rd-in]::after {
        content: attr(data-rd-in); position: absolute; left: 4px; top: 3px;
        font: 600 10.5px/1 var(--rd-head); color: #DD5F47;
    }
    .pl-rd.pl-v3srv .rd-pb .pl-palette [data-rd-in] { position: relative; }

    @media (max-width: 1200px) {
        .pl-rd.pl-v3srv .rd-slot { width: 56px; height: 56px; }
        .pl-rd.pl-v3srv .rd-slot .pl-ico { width: 38px; height: 38px; }
        .pl-rd.pl-v3srv .rd-grades .pl-tiers .pl-chip { width: 40px; height: 40px; }
        .pl-rd.pl-v3srv .rd-grades .pl-tiers .pl-chip .pl-ico-tier { width: 22px; height: 22px; }
    }
    @media (max-width: 980px) {
        .pl-rd.pl-v3srv .rd-hbrow { flex-direction: column; align-items: center; gap: 8px; }
    }

    /* ---- the left rail (.rail) ------------------------------------------ */
    .pl-rd.pl-v3srv .rd-rail {
        position: absolute; z-index: 25; left: var(--rd-gap); top: 76px;
        display: flex; flex-direction: column; gap: 6px;
        pointer-events: none;
    }
    .pl-rd.pl-v3srv .rd-rail > * { pointer-events: auto; }
    .pl-rd.pl-v3srv .rd-sep { height: 1px; margin: 4px 6px; background: rgba(255, 255, 255, .14); }
    .pl-rd.pl-v3srv .rd-rb[aria-disabled="true"] { color: rgba(216, 211, 202, .38); cursor: default; }
    .pl-rd.pl-v3srv .rd-rb[aria-disabled="true"]:hover {
        color: rgba(216, 211, 202, .38); border-color: var(--rd-line);
        background: linear-gradient(180deg, rgba(40, 39, 43, .93), rgba(21, 21, 24, .93));
    }
    .pl-rd.pl-v3srv .rd-badge {
        position: absolute; right: -5px; bottom: -5px; min-width: 18px; height: 18px; padding: 0 4px;
        border-radius: 9px; background: var(--rd-amber); color: #111;
        font: 700 11px/18px var(--rd-head); letter-spacing: 0; text-align: center;
        box-shadow: 0 0 0 2px rgba(10, 10, 12, .9);
    }
    .pl-rd.pl-v3srv .rd-badge[hidden] { display: none; }

    /* ---- the dock and its panels (.dock / .pane) -------------------------
       A child of .pl-app placed in the canvas's grid area (see the template
       note: outside the canvas so typing in a panel never flies the camera).
       The dock itself lets clicks through to the map; only panels take them. */
    .pl-rd.pl-v3srv .rd-dock {
        grid-row: 2; grid-column: 1; position: absolute; z-index: 24;
        left: calc(var(--rd-gap) + var(--rd-rail) + 12px); top: 76px;
        /* stops above whatever of the hotbar block sits UNDER the dock's
           column (--rd-dfoot, measured by gshell.js: the grades strip on a
           narrower window, nothing on a wide one, where a panel runs on to the
           window's foot — owner, 2026-10-12). --rd-both until it is measured. */
        bottom: calc(14px + var(--rd-dfoot, var(--rd-both, 134px)) + 8px);
        width: var(--rd-panew);
        display: flex; flex-direction: column; gap: 8px;
        pointer-events: none; container-type: size;
    }
    .pl-rd.pl-v3srv .pl-app:not(.rd-dock-open) .rd-dock { visibility: hidden; }
    .pl-rd.pl-v3srv .rd-pane {
        pointer-events: auto;
        display: flex; flex-direction: column; flex: 0 1 auto; min-height: 0; max-height: 100%;
        color: var(--rd-text); font-family: var(--rd-font);
        background: rgba(17, 17, 20, .95);
        border: 1px solid rgba(255, 255, 255, .12); border-radius: 2px;
        box-shadow: 0 14px 40px rgba(0, 0, 0, .6);
        -webkit-backdrop-filter: blur(10px); backdrop-filter: blur(10px);
    }
    .pl-rd.pl-v3srv .rd-pane[hidden] { display: none; }
    .pl-rd.pl-v3srv .rd-pane.rd-pinned { border-top: 2px solid var(--rd-accent); }
    .pl-rd.pl-v3srv .rd-pane.rd-tall:not(.rd-fold) { flex: 1 1 auto; }
    /* Raid, Rust rules and Layers used to stop at half the dock (52cqh); they
       grow with what they hold now, to the dock's foot (owner, 2026-10-12:
       less scrolling). Only one panel is ever unfolded, so none is crowded. */
    .pl-rd.pl-v3srv .rd-pane.rd-fold { flex: none; }
    .pl-rd.pl-v3srv .rd-ph {
        display: flex; align-items: center; gap: 9px; flex: none;
        height: 46px; padding: 0 5px 0 12px;
        border-bottom: 1px solid rgba(255, 255, 255, .08);
    }
    .pl-rd.pl-v3srv .rd-pane.rd-fold .rd-ph { border-bottom: none; }
    .pl-rd.pl-v3srv .rd-hi { width: 18px; height: 18px; flex: none; fill: none; stroke: #DD5F47;
        stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
    .pl-rd.pl-v3srv .rd-ti { flex: 1 1 auto; min-width: 0; margin: 0; display: flex; }
    .pl-rd.pl-v3srv .rd-tb {
        flex: 1 1 auto; min-width: 0; padding: 0; text-align: left; cursor: default;
        background: none; border: none; color: var(--rd-text);
        font: 600 15px/1 var(--rd-head); letter-spacing: .09em; text-transform: uppercase;
        white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
    }
    .pl-rd.pl-v3srv .rd-pane.rd-fold .rd-tb { cursor: pointer; }
    .pl-rd.pl-v3srv .rd-pane.rd-fold .rd-tb::after {
        content: ""; display: inline-block; width: 7px; height: 7px; margin: 0 0 3px 9px;
        border: solid #9B968E; border-width: 0 2px 2px 0; transform: rotate(45deg);
    }
    .pl-rd.pl-v3srv .rd-fsum { display: none; font: 500 12.5px/1 var(--rd-font); color: #9B968E; white-space: nowrap; }
    .pl-rd.pl-v3srv .rd-pane.rd-fold .rd-fsum:not(:empty) { display: block; }
    .pl-rd.pl-v3srv .rd-ib {
        width: 36px; height: 36px; flex: none; padding: 0; display: grid; place-items: center;
        background: none; border: none; border-radius: 2px; color: #B5AFA6; cursor: pointer;
    }
    .pl-rd.pl-v3srv .rd-ib:hover { color: #fff; background: rgba(255, 255, 255, .06); }
    .pl-rd.pl-v3srv .rd-ib[aria-pressed="true"] { color: #DD5F47; }
    .pl-rd.pl-v3srv .rd-ib svg { width: 17px; height: 17px; fill: none; stroke: currentColor;
        stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
    .pl-rd.pl-v3srv .rd-pb {
        display: flex; flex-direction: column; flex: 1 1 auto; min-height: 0;
        overflow-y: auto; overscroll-behavior: contain; scrollbar-width: thin;
    }
    .pl-rd.pl-v3srv .rd-pane.rd-fold .rd-pb { display: none; }
    .pl-rd.pl-v3srv .rd-pb > * { flex-shrink: 0; }
    /* RD9 — the way back to the old look for its four weeks (Q3, owner
       2026-10-12; RD10 removes it): one quiet line at the Settings panel's
       foot. A sibling of the scrolling body, so it never scrolls away, and
       gone with the body while the panel is folded. */
    .pl-rd.pl-v3srv .rd-oldlook {
        display: flex; align-items: center; flex: none; min-height: 36px; padding: 0 14px;
        border-top: 1px solid rgba(255, 255, 255, .08);
        font: 500 12.5px/1 var(--rd-font); color: #9B968E; text-decoration: none;
    }
    .pl-rd.pl-v3srv .rd-oldlook:hover { color: #fff; text-decoration: underline; }
    .pl-rd.pl-v3srv .rd-oldlook:focus-visible { outline: none; box-shadow: inset 0 0 0 2px rgba(205, 65, 43, .6); }
    .pl-rd.pl-v3srv .rd-pane.rd-fold .rd-oldlook { display: none; }

    /* The Parts panel holds the old sidebar whole (tools, inserts, grades).
       Its tabs and its Base tab go: the Base tab's contents have panels of
       their own now. */
    .pl-rd.pl-v3srv .rd-pb > .pl-palette {
        position: static; flex: 1 1 auto; min-height: 0; width: auto; margin: 0;
        display: flex; flex-direction: column; overflow: hidden;
        background: none; border: none; border-radius: 0; box-shadow: none;
    }
    .pl-rd.pl-v3srv .rd-pb > .pl-palette > .pl-sbtabs,
    .pl-rd.pl-v3srv .rd-pb > .pl-palette > .pl-mgrip,
    .pl-rd.pl-v3srv .rd-pb > .pl-palette #planner-basetab { display: none; }

    /* The cost panel keeps planner.css's Base-tab look (the body carries
       .pl-basetab for exactly that); only its own heading goes, the panel's
       title says it. */
    .pl-rd.pl-v3srv .rd-pb > .pl-cost { display: block; }
    .pl-rd.pl-v3srv .rd-pb > .pl-cost > #planner-cost-upkeep { border-bottom: none; }
    .pl-rd.pl-v3srv .rd-pb > #planner-cost-raid { border-bottom: none; }
    /* R-RD: the Cost panel in the design's shape (v7 .h / .rgrid / .rc /
       .linkb / .upk / .seg). gcosts still writes every node; gshell names the
       sections and the tiles (paintCost), and this lays them out. */
    .pl-rd.pl-v3srv [data-rd-body="cost"] #planner-cost-build,
    .pl-rd.pl-v3srv [data-rd-body="cost"] #planner-cost-upkeep {
        display: flex; flex-direction: column; gap: 7px;
        padding: 12px 14px 4px; border-bottom: none;
    }
    .pl-rd.pl-v3srv [data-rd-body="cost"] #planner-cost-build:empty,
    .pl-rd.pl-v3srv [data-rd-body="cost"] #planner-cost-upkeep:empty { display: none; }
    .pl-rd.pl-v3srv [data-rd-body="cost"] #planner-cost-upkeep { padding-bottom: 14px; }
    .pl-rd.pl-v3srv [data-rd-body="cost"] .pl-cost-h {
        display: flex; align-items: center; gap: 8px; margin: 0;
        font: 600 12px/1 var(--rd-head); letter-spacing: .12em; text-transform: uppercase; color: #9B968E;
    }
    .pl-rd.pl-v3srv [data-rd-body="cost"] .pl-cost-h .pl-why { margin: 0; }
    .pl-rd.pl-v3srv [data-rd-body="cost"] .rd-cv {
        margin-left: auto; color: #C9C4BB;
        font: 500 12px/1 var(--rd-font); letter-spacing: 0; text-transform: none;
    }
    .pl-rd.pl-v3srv [data-rd-body="cost"] .rd-cv[hidden] { display: none; }
    .pl-rd.pl-v3srv [data-rd-body="cost"] .rd-ch { margin-top: 7px; }
    .pl-rd.pl-v3srv [data-rd-body="cost"] .pl-cards {
        display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 6px;
    }
    .pl-rd.pl-v3srv [data-rd-body="cost"] #planner-cost-upkeep .pl-cards { grid-template-columns: repeat(3, minmax(0, 1fr)); }
    .pl-rd.pl-v3srv [data-rd-body="cost"] .pl-card {
        display: block; min-width: 0; padding: 8px 9px;
        background: #1F1F23; border: 1px solid rgba(255, 255, 255, .06); border-radius: 2px;
    }
    .pl-rd.pl-v3srv [data-rd-body="cost"] .pl-amt {
        display: block; font: 600 16px/1 var(--rd-head); letter-spacing: .02em; color: var(--rd-text);
    }
    .pl-rd.pl-v3srv [data-rd-body="cost"] .pl-card .pl-lbl { display: none; }
    .pl-rd.pl-v3srv [data-rd-body="cost"] .rd-tn {
        display: block; margin-top: 3px; font: 500 11px/1.15 var(--rd-font); color: #9B968E;
    }
    .pl-rd.pl-v3srv [data-rd-body="cost"] .rd-linkb {
        align-self: flex-start; margin: 2px 0 0; padding: 0; cursor: pointer;
        background: none; border: 0; color: #DD5F47;
        font: 600 13px/1.2 var(--rd-font); text-decoration: underline; text-underline-offset: 3px;
    }
    .pl-rd.pl-v3srv [data-rd-body="cost"] .rd-linkb:hover { color: #F07A62; }
    .pl-rd.pl-v3srv [data-rd-body="cost"] .pl-tcs { margin: 0; }
    .pl-rd.pl-v3srv [data-rd-body="cost"] .pl-bparts { border: 1px solid rgba(255, 255, 255, .07); padding: 0 10px; }
    .pl-rd.pl-v3srv [data-rd-body="cost"] .pl-bparts[hidden] { display: none; }
    .pl-rd.pl-v3srv [data-rd-body="cost"] .pl-tc {
        column-gap: 10px; row-gap: 4px; padding: 7px 6px; border-top: 1px solid rgba(255, 255, 255, .07);
    }
    .pl-rd.pl-v3srv [data-rd-body="cost"] .pl-tcs .pl-tc:first-child { border-top: 0; padding-top: 7px; }
    .pl-rd.pl-v3srv [data-rd-body="cost"] .pl-tcbox {
        appearance: none; -webkit-appearance: none; width: 22px; height: 22px; margin: 0; cursor: pointer;
        background: #0E0E10; border: 1px solid rgba(255, 255, 255, .3); border-radius: 2px;
    }
    .pl-rd.pl-v3srv [data-rd-body="cost"] .pl-tcbox:checked {
        background: #CD412B var(--rd-tick) center / 14px no-repeat; border-color: #CD412B;
    }
    .pl-rd.pl-v3srv [data-rd-body="cost"] .pl-tcbox:focus-visible { outline: 2px solid rgba(205, 65, 43, .6); outline-offset: 2px; }
    .pl-rd.pl-v3srv [data-rd-body="cost"] .pl-tc-name {
        font: 600 13px/1.2 var(--rd-font); color: var(--rd-text); white-space: normal;
    }
    .pl-rd.pl-v3srv [data-rd-body="cost"] .pl-tc-warn .pl-tc-name { color: var(--rd-amber); }
    .pl-rd.pl-v3srv [data-rd-body="cost"] .pl-tc-name .pl-tc-meta {
        margin-left: 6px; font: 400 11.5px/1.2 var(--rd-font); color: #8A857D;
    }
    .pl-rd.pl-v3srv [data-rd-body="cost"] .pl-tcn { font: 600 12.5px/1 var(--rd-head); color: #D6D1C8; }
    .pl-rd.pl-v3srv [data-rd-body="cost"] .pl-tcgo {
        width: 30px; height: 30px; border: none; border-radius: 2px; font-size: 18px; color: #B5AFA6;
    }
    .pl-rd.pl-v3srv [data-rd-body="cost"] .pl-tcgo:hover,
    .pl-rd.pl-v3srv [data-rd-body="cost"] .pl-tcgo:focus-visible { color: #fff; background: rgba(255, 255, 255, .06); }
    .pl-rd.pl-v3srv [data-rd-body="cost"] .pl-upmeta,
    .pl-rd.pl-v3srv [data-rd-body="cost"] .pl-upwarn { margin: 0; }
    .pl-rd.pl-v3srv [data-rd-body="cost"] .pl-scope { margin: 12px 14px 0; }
    .pl-rd.pl-v3srv [data-rd-body="cost"] .pl-scope[hidden] { display: none; }
    .pl-rd.pl-v3srv [data-rd-body="cost"] .pl-scope.rd-seg {
        display: flex; gap: 3px; padding: 3px;
        background: #0E0E10; border: 1px solid rgba(255, 255, 255, .1); border-radius: 2px;
    }
    .pl-rd.pl-v3srv [data-rd-body="cost"] .rd-seg > .pl-chip {
        flex: 1 1 0; min-width: 0; min-height: 34px; margin: 0; padding: 0 6px; cursor: pointer;
        background: none; border: none; border-radius: 2px; box-shadow: none;
        font: 600 12px/1 var(--rd-head); letter-spacing: .1em; text-transform: uppercase; color: #B5AFA6;
    }
    .pl-rd.pl-v3srv [data-rd-body="cost"] .rd-seg > .pl-chip[aria-pressed="true"] {
        background: #2A2A30; color: #fff; box-shadow: inset 0 -2px 0 #CD412B;
    }
    /* The Parts list folds behind "Split by…" with the split (gshell toggles
       .rd-split on the body), and a building row's numbers carry no icon. */
    .pl-rd.pl-v3srv [data-rd-body="cost"]:not(.rd-split) #planner-cost-bom { display: none; }
    .pl-rd.pl-v3srv [data-rd-body="cost"] #planner-cost-bom { margin: 0 14px 10px; }
    .pl-rd.pl-v3srv [data-rd-body="cost"] .pl-tc-sum .pl-tcico { display: none; }
    .pl-rd.pl-v3srv [data-rd-body="cost"] .pl-tc-sum { column-gap: 14px; }
    /* gcosts' ⌖ glyph is a hair at 18px; the design's crosshair is drawn. */
    .pl-rd.pl-v3srv [data-rd-body="cost"] .pl-tcgo { display: grid; place-items: center; font-size: 0; }
    .pl-rd.pl-v3srv [data-rd-body="cost"] .pl-tcgo::before {
        content: ""; width: 18px; height: 18px; background: currentColor;
        -webkit-mask: var(--rd-cross) center / contain no-repeat; mask: var(--rd-cross) center / contain no-repeat;
    }
    .pl-rd.pl-v3srv .rd-pb > .pl-raidbox,
    .pl-rd.pl-v3srv .rd-pb > .pl-raidopts,
    .pl-rd.pl-v3srv .rd-pb > #planner-raidpro-row { margin: 0 14px 12px; }
    /* Settings: the card's own heading and rule go (the panel has both). */
    .pl-rd.pl-v3srv .rd-pb > .pl-set { margin: 0; padding: 12px 14px; border-top: none; }
    .pl-rd.pl-v3srv .rd-pb > .pl-set > .pl-cost-h { display: none; }
    /* Bases: the "Saves" caption goes (the panel's title is My bases). */
    .pl-rd.pl-v3srv .rd-pb > .pl-saves-panel::before { display: none; }

    /* Prose lines in a panel. */
    .pl-rd.pl-v3srv .rd-pb > p { margin: 10px 14px 0; font: 400 13px/1.45 var(--rd-font); color: var(--rd-muted); }
    .pl-rd.pl-v3srv .rd-pb > p:last-child { margin-bottom: 12px; }
    .pl-rd.pl-v3srv .rd-pb > .rd-status { color: var(--rd-text); }
    .pl-rd.pl-v3srv .rd-pb > .pl-atrisk[hidden],
    .pl-rd.pl-v3srv .rd-pb > .pl-isolate[hidden] { display: none; }
    .pl-rd.pl-v3srv .rd-rstep {
        display: flex; align-items: center; gap: 8px; margin: 10px 14px 0;
    }
    .pl-rd.pl-v3srv .rd-rstep[hidden] { display: none; }
    .pl-rd.pl-v3srv .rd-rsl {
        flex: 1 1 auto; display: flex; align-items: center; justify-content: center; gap: 8px;
        font: 500 13px/1 var(--rd-font); color: var(--rd-text);
    }
    .pl-rd.pl-v3srv .rd-rsl kbd {
        font: 600 11px/1 var(--rd-mono); padding: 3px 6px; border-radius: 2px;
        color: #D8D3CA; background: rgba(255, 255, 255, .08); border: 1px solid var(--rd-line);
    }
    .pl-rd.pl-v3srv .rd-mini {
        width: 36px; height: 32px; padding: 0; cursor: pointer;
        font: 600 18px/1 var(--rd-head); color: #D8D3CA;
        background: rgba(255, 255, 255, .05); border: 1px solid var(--rd-line); border-radius: 2px;
    }
    .pl-rd.pl-v3srv .rd-mini:hover { color: #fff; border-color: rgba(255, 255, 255, .24); }

    /* On/off chips become full-width switch rows (the prototype's .sw). The
       chip keeps its id, its text and its aria-pressed; the switch is drawn
       from aria-pressed, so it can never disagree with the control. */
    .pl-rd.pl-v3srv .rd-pb > .pl-chip[aria-pressed] {
        display: flex; align-items: center; justify-content: space-between; gap: 12px;
        width: 100%; min-height: 48px; margin: 0; padding: 0 14px;
        text-align: left; cursor: pointer;
        font: 500 14px/1.2 var(--rd-font); letter-spacing: 0; text-transform: none;
        color: var(--rd-text); background: none;
        border: none; border-bottom: 1px solid rgba(255, 255, 255, .07); border-radius: 0;
        box-shadow: none;
    }
    .pl-rd.pl-v3srv .rd-pb > .pl-chip[aria-pressed]:hover { background: rgba(255, 255, 255, .04); }
    .pl-rd.pl-v3srv .rd-pb > .pl-chip[aria-pressed]:focus-visible { outline: none; box-shadow: inset 0 0 0 2px rgba(205, 65, 43, .6); }
    .pl-rd.pl-v3srv .rd-pb > .pl-chip[aria-pressed]::after {
        content: ""; flex: none; width: 34px; height: 20px; border-radius: 10px;
        background: radial-gradient(circle at 10px 10px, #D8D3CA 6px, transparent 6.5px), #3A383D;
        transition: background .15s;
    }
    .pl-rd.pl-v3srv .rd-pb > .pl-chip[aria-pressed="true"]::after {
        background: radial-gradient(circle at 24px 10px, #fff 6px, transparent 6.5px), var(--rd-accent);
    }

    /* The view line in the Layers panel: one row, its own look. */
    .pl-rd.pl-v3srv .rd-pb > #planner-viewline {
        display: flex; align-items: center; flex-wrap: wrap; gap: 8px;
        margin: 0; padding: 12px 14px; background: none; border: none;
        border-bottom: 1px solid rgba(255, 255, 255, .07);
    }
    .pl-rd.pl-v3srv .rd-pb > #planner-viewline .pl-cap {
        flex: 1 1 auto; font: 500 14px/1.2 var(--rd-font); color: var(--rd-text);
        letter-spacing: 0; text-transform: none;
    }
    .pl-rd.pl-v3srv .rd-pb > #planner-viewline .pl-viewline-num {
        width: 64px; height: 32px; padding: 0 8px; text-align: center;
        font: 500 13px/1 var(--rd-mono); color: var(--rd-text);
        background: #17171A; border: 1px solid var(--rd-line); border-radius: 2px;
    }
    .pl-rd.pl-v3srv .rd-pb > #planner-viewline .pl-chip { height: 32px; margin: 0; }

    /* ---- My bases (RD5) --------------------------------------------------
       The card is THE base on the canvas (.bcur in the design): its name, the
       pencil, whether it is saved and where saves go. Then Save (Ctrl+S) and
       New base, then today's Saves panel as "Save a copy as…" and the list. */
    .pl-rd.pl-v3srv .rd-bcur {
        display: flex; gap: 12px; margin: 12px 14px 0; padding: 12px;
        background: rgba(205, 65, 43, .08); border: 1px solid rgba(205, 65, 43, .5); border-radius: 2px;
    }
    .pl-rd.pl-v3srv .rd-bcur[data-state="empty"],
    .pl-rd.pl-v3srv .rd-bcur[data-state="none"] { background: rgba(255, 255, 255, .03); border-color: rgba(255, 255, 255, .14); }
    .pl-rd.pl-v3srv .rd-bt { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 6px; }
    .pl-rd.pl-v3srv .rd-bnb {
        display: flex; align-items: center; gap: 8px; min-width: 0; max-width: 100%; padding: 2px 4px; margin: -2px -4px;
        background: none; border: 1px solid transparent; border-radius: 2px; color: var(--rd-text); cursor: pointer;
        text-align: left;
    }
    .pl-rd.pl-v3srv .rd-bnb[hidden] { display: none; }
    .pl-rd.pl-v3srv .rd-bnb:hover { border-color: rgba(255, 255, 255, .18); }
    .pl-rd.pl-v3srv .rd-bnb:focus-visible { outline: none; box-shadow: 0 0 0 3px rgba(205, 65, 43, .6); }
    .pl-rd.pl-v3srv .rd-bn {
        min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
        font: 600 18px/1.15 var(--rd-head); letter-spacing: .05em; text-transform: uppercase;
    }
    .pl-rd.pl-v3srv .rd-bnb svg { width: 15px; height: 15px; flex: none; fill: none; stroke: #9B968E;
        stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
    .pl-rd.pl-v3srv .rd-bnb:hover svg { stroke: #fff; }
    .pl-rd.pl-v3srv .rd-bren { display: flex; gap: 6px; }
    .pl-rd.pl-v3srv .rd-bren[hidden] { display: none; }
    .pl-rd.pl-v3srv .rd-bren input {
        flex: 1 1 auto; min-width: 0; height: 34px; padding: 0 10px;
        font: 600 15px/1 var(--rd-head); letter-spacing: .04em; color: var(--rd-text);
        background: #0E0E10; border: 1px solid var(--rd-accent); border-radius: 2px;
    }
    .pl-rd.pl-v3srv .rd-bren input:focus { outline: none; box-shadow: 0 0 0 2px rgba(205, 65, 43, .35); }
    .pl-rd.pl-v3srv .rd-bren .pl-btn { height: 34px; padding: 0 12px; }
    .pl-rd.pl-v3srv .rd-bstate { display: flex; align-items: center; gap: 7px; font: 500 12.5px/1.3 var(--rd-font); color: var(--rd-muted); }
    .pl-rd.pl-v3srv .rd-bcur[data-state="clean"] .rd-dot { background: #5FA85A; }
    .pl-rd.pl-v3srv .rd-bcur[data-state="dirty"] .rd-dot { background: var(--rd-amber); }
    .pl-rd.pl-v3srv .rd-bt .pl-saves-where {
        margin: 0; padding: 0; border: none; font: 400 12px/1.4 var(--rd-font); color: #9B968E;
    }
    .pl-rd.pl-v3srv .rd-bmsg { margin: 0; font: 500 12.5px/1.35 var(--rd-font); color: var(--rd-amber); }
    .pl-rd.pl-v3srv .rd-bmsg:empty { display: none; }
    .pl-rd.pl-v3srv .rd-bacts { display: flex; gap: 8px; margin: 10px 14px 0; }
    .pl-rd.pl-v3srv .rd-bacts > * {
        flex: 1 1 0; min-width: 0; height: 40px; margin: 0; padding: 0 10px;
        display: inline-flex; align-items: center; justify-content: center; gap: 8px;
        font: 600 13px/1 var(--rd-head); letter-spacing: .1em; text-transform: uppercase;
        border-radius: 2px; white-space: nowrap;
    }
    .pl-rd.pl-v3srv .rd-bacts > #planner-save-clear { color: #D8D3CA; background: rgba(255, 255, 255, .05); border: 1px solid var(--rd-line); }
    .pl-rd.pl-v3srv .rd-bacts > #planner-save-clear:hover { color: #fff; border-color: rgba(255, 255, 255, .24); }
    .pl-rd.pl-v3srv .rd-bacts svg { width: 16px; height: 16px; flex: none; fill: none; stroke: currentColor;
        stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
    .pl-rd.pl-v3srv .rd-bacts kbd {
        font: 600 10px/1 var(--rd-mono); letter-spacing: 0; padding: 2px 4px; border-radius: 2px;
        color: rgba(255, 255, 255, .85); background: rgba(0, 0, 0, .22); border: 1px solid rgba(255, 255, 255, .18);
    }
    .pl-rd.pl-v3srv .rd-pb > .pl-saves-panel { padding-top: 12px; }
    .pl-rd.pl-v3srv .rd-bh {
        margin: 12px 0 8px; font: 600 12px/1 var(--rd-head); letter-spacing: .14em; text-transform: uppercase;
        color: #9B968E;
    }
    /* "Save a copy as…" and Save copy on one row (the design's grey .btn). */
    .pl-rd.pl-v3srv .rd-pb .pl-saves-new { flex-wrap: wrap; gap: 8px; margin: 0 0 4px; }
    .pl-rd.pl-v3srv .rd-pb #planner-save-name {
        flex: 1 1 0; min-width: 0; height: 40px; padding: 0 12px;
        font: 500 14px/1 var(--rd-font); color: var(--rd-text);
        background: #0E0E10; border: 1px solid rgba(255, 255, 255, .14); border-radius: 2px;
    }
    .pl-rd.pl-v3srv .rd-pb #planner-save-name:focus { outline: none; border-color: var(--rd-accent); }
    .pl-rd.pl-v3srv .rd-pb #planner-save-btn {
        flex: none; height: 40px; margin: 0; padding: 0 14px;
        font: 600 13px/1 var(--rd-head); letter-spacing: .1em; text-transform: uppercase;
        color: #EDEAE4; background: #1F1F23; border: 1px solid rgba(255, 255, 255, .2); border-radius: 2px;
    }
    .pl-rd.pl-v3srv .rd-pb #planner-save-btn:hover { color: #fff; border-color: rgba(255, 255, 255, .34); }
    .pl-rd.pl-v3srv .rd-pb #planner-saves-msg { flex: 1 0 100%; }
    .pl-rd.pl-v3srv .rd-pb #planner-saves-msg:empty { display: none; }
    /* The heading with its count, then Find a base. */
    .pl-rd.pl-v3srv .rd-bh { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; }
    .pl-rd.pl-v3srv .rd-bcount { font: 500 12px/1 var(--rd-font); letter-spacing: 0; text-transform: none; color: #9B968E; }
    .pl-rd.pl-v3srv .rd-bfind {
        display: flex; align-items: center; gap: 8px; height: 34px; margin: 0 0 8px; padding: 0 10px;
        background: #0E0E10; border: 1px solid rgba(255, 255, 255, .14); border-radius: 2px;
    }
    .pl-rd.pl-v3srv .rd-bfind[hidden] { display: none; }
    .pl-rd.pl-v3srv .rd-bfind:focus-within { border-color: var(--rd-accent); }
    .pl-rd.pl-v3srv .rd-bfind svg { width: 15px; height: 15px; flex: none; fill: none; stroke: #9B968E;
        stroke-width: 2; stroke-linecap: round; }
    .pl-rd.pl-v3srv .rd-bfind input {
        flex: 1 1 auto; min-width: 0; height: 100%; padding: 0; background: none; border: none;
        font: 500 13.5px/1 var(--rd-font); color: var(--rd-text);
    }
    .pl-rd.pl-v3srv .rd-bfind input:focus { outline: none; }
    .pl-rd.pl-v3srv .rd-pb .rd-bnone { margin: 4px 0 8px; font: 400 13px/1.4 var(--rd-font); color: #9B968E; }
    .pl-rd.pl-v3srv .rd-pb .rd-bnone[hidden] { display: none; }
    /* A row: the name and "N pieces" under it, the trash on the right; the
       Load chip is stretched over the whole row, so the row opens the base. */
    .pl-rd.pl-v3srv .rd-pb .pl-saves-list { max-height: none; overflow: visible; }
    .pl-rd.pl-v3srv .rd-pb .pl-save-row {
        position: relative; display: grid; grid-template-columns: minmax(0, 1fr) auto; column-gap: 8px; row-gap: 3px;
        align-items: center; margin: 0 0 4px; padding: 9px 6px 9px 12px;
        background: transparent; border: 1px solid transparent; border-radius: 2px;
    }
    .pl-rd.pl-v3srv .rd-pb .pl-save-row[hidden] { display: none; }
    .pl-rd.pl-v3srv .rd-pb .pl-save-row:hover { background: rgba(255, 255, 255, .04); }
    .pl-rd.pl-v3srv .rd-pb .pl-save-row .pl-save-name {
        grid-column: 1; grid-row: 1; cursor: pointer; font: 600 14px/1.2 var(--rd-font); color: var(--rd-text);
    }
    .pl-rd.pl-v3srv .rd-pb .pl-save-row .rd-bmeta {
        grid-column: 1; grid-row: 2; font: 400 12px/1.2 var(--rd-font); color: #9B968E;
    }
    .pl-rd.pl-v3srv .rd-pb .pl-save-row .rd-open {
        position: absolute; inset: 0; z-index: 1; width: auto; height: auto; min-height: 0; margin: 0; padding: 0;
        font-size: 0; color: transparent; background: none; border: none; border-radius: 2px; cursor: pointer;
    }
    .pl-rd.pl-v3srv .rd-pb .pl-save-row .rd-open:focus-visible { outline: none; box-shadow: inset 0 0 0 2px rgba(205, 65, 43, .8); }
    .pl-rd.pl-v3srv .rd-pb .pl-save-row .rd-trash {
        grid-column: 2; grid-row: 1 / 3; position: relative; z-index: 2;
        display: inline-flex; align-items: center; justify-content: center;
        width: 34px; height: 34px; min-height: 0; margin: 0; padding: 0;
        color: #9B968E; background: none; border: 1px solid transparent; border-radius: 2px; cursor: pointer;
    }
    .pl-rd.pl-v3srv .rd-pb .pl-save-row .rd-trash:hover { color: #fff; border-color: rgba(255, 255, 255, .18); }
    .pl-rd.pl-v3srv .rd-pb .pl-save-row .rd-trash:focus-visible { outline: none; box-shadow: 0 0 0 2px rgba(205, 65, 43, .8); }
    .pl-rd.pl-v3srv .rd-pb .pl-save-row .rd-trash svg { width: 17px; height: 17px; fill: none; stroke: currentColor;
        stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; }
    .pl-rd.pl-v3srv .rd-pb .pl-save-row.rd-cur { background: rgba(205, 65, 43, .08); border-color: rgba(205, 65, 43, .5); }
    /* The file row as the design's footer links. */
    .pl-rd.pl-v3srv .rd-pb .pl-saves-file { gap: 4px 14px; }
    .pl-rd.pl-v3srv .rd-pb .pl-saves-file .pl-chip {
        min-height: 0; height: auto; padding: 4px 0; background: none; border: none; border-radius: 0;
        font: 500 13px/1.2 var(--rd-font); letter-spacing: 0; text-transform: none; color: #E0614A;
        text-decoration: underline; text-underline-offset: 3px;
    }
    .pl-rd.pl-v3srv .rd-pb .pl-saves-file .pl-chip:hover { color: #fff; }
    .pl-rd.pl-v3srv .rd-ask {
        margin: -2px 0 8px; padding: 10px 12px; list-style: none;
        background: rgba(229, 163, 61, .08); border: 1px solid rgba(229, 163, 61, .45); border-radius: 2px;
    }
    .pl-rd.pl-v3srv .rd-ask p { margin: 0 0 8px; font: 500 13px/1.35 var(--rd-font); color: var(--rd-text); }
    .pl-rd.pl-v3srv .rd-askacts { display: flex; align-items: center; flex-wrap: wrap; gap: 6px; }
    .pl-rd.pl-v3srv .rd-askacts .pl-btn { height: 32px; margin: 0; padding: 0 10px; font-size: 12.5px; }
    .pl-rd.pl-v3srv .rd-askacts .pl-btn:not(.rd-pri) { color: #D8D3CA; background: rgba(255, 255, 255, .05); border: 1px solid var(--rd-line); }
    .pl-rd.pl-v3srv .rd-link {
        height: 32px; padding: 0 8px; background: none; border: none; cursor: pointer;
        font: 500 13px/1 var(--rd-font); color: #B5AFA6; text-decoration: underline; text-underline-offset: 3px;
    }
    .pl-rd.pl-v3srv .rd-link:hover { color: #fff; }
    .pl-rd.pl-v3srv .rd-ask button:focus-visible { outline: none; box-shadow: 0 0 0 3px rgba(205, 65, 43, .6); }
    /* Submit from the rules panel: a plain full-width line, not a switch. */
    .pl-rd.pl-v3srv .rd-pb > .rd-rsub { margin: 12px 14px 0; justify-content: center; }
    .pl-rd.pl-v3srv .rd-pb > .rd-rsub[hidden] { display: none; }

    /* ---- the Share popover (RD5) ---------------------------------------- */
    .pl-rd.pl-v3srv .rd-pop {
        position: absolute; z-index: 30; right: var(--rd-gap); top: 70px; width: 370px; max-width: calc(100% - 2 * var(--rd-gap));
        color: var(--rd-text); font-family: var(--rd-font);
        background: rgba(17, 17, 20, .97); border: 1px solid rgba(255, 255, 255, .12); border-radius: 2px;
        box-shadow: 0 14px 40px rgba(0, 0, 0, .6);
        -webkit-backdrop-filter: blur(10px); backdrop-filter: blur(10px);
    }
    .pl-rd.pl-v3srv .rd-pop[hidden] { display: none; }
    .pl-rd.pl-v3srv .rd-pop .rd-ti { font: 600 15px/1 var(--rd-head); letter-spacing: .09em; text-transform: uppercase; align-items: center; }
    .pl-rd.pl-v3srv .rd-pop .rd-pb { padding: 12px 14px 8px; gap: 0; overflow: visible; }
    .pl-rd.pl-v3srv .rd-pop .rd-sh { margin: 0 0 8px; font: 600 13px/1.3 var(--rd-font); color: var(--rd-text); }
    .pl-rd.pl-v3srv .rd-pop .rd-sh span { font-weight: 400; color: #9B968E; }
    .pl-rd.pl-v3srv .rd-linkbox {
        display: flex; align-items: stretch; height: 44px;
        background: #0E0E10; border: 1px solid rgba(255, 255, 255, .14); border-radius: 2px;
    }
    .pl-rd.pl-v3srv .rd-linkbox .rd-u {
        flex: 1 1 auto; min-width: 0; display: flex; align-items: center; padding: 0 10px;
        overflow: hidden; white-space: nowrap; text-overflow: ellipsis;
        font: 500 12.5px/1 var(--rd-mono); color: #D8D3CA; user-select: all;
    }
    .pl-rd.pl-v3srv .rd-linkbox .pl-btn { flex: none; min-width: 104px; height: auto; margin: 0; border-radius: 0 2px 2px 0; }
    .pl-rd.pl-v3srv .rd-sharemsg { margin: 6px 0 0; font: 500 12.5px/1.35 var(--rd-font); color: var(--rd-text); }
    .pl-rd.pl-v3srv .rd-sharemsg:empty { display: none; }
    .pl-rd.pl-v3srv .rd-pop .rd-row {
        display: flex; align-items: center; gap: 12px; width: 100%; margin: 0; padding: 12px 2px;
        text-align: left; cursor: pointer; color: var(--rd-text);
        background: none; border: none; border-bottom: 1px solid rgba(255, 255, 255, .07); border-radius: 0;
    }
    .pl-rd.pl-v3srv .rd-pop .rd-row:first-of-type { margin-top: 10px; border-top: 1px solid rgba(255, 255, 255, .07); }
    .pl-rd.pl-v3srv .rd-pop .rd-row:last-child { border-bottom: none; }
    .pl-rd.pl-v3srv .rd-pop .rd-row[hidden] { display: none; }
    .pl-rd.pl-v3srv .rd-pop .rd-row:hover { background: rgba(255, 255, 255, .04); }
    .pl-rd.pl-v3srv .rd-pop .rd-row:focus-visible,
    .pl-rd.pl-v3srv .rd-linkbox .pl-btn:focus-visible { outline: none; box-shadow: inset 0 0 0 2px rgba(205, 65, 43, .6); }
    .pl-rd.pl-v3srv .rd-pop .rd-row svg { width: 20px; height: 20px; flex: none; fill: none; stroke: #DD5F47;
        stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
    .pl-rd.pl-v3srv .rd-rl { display: flex; flex-direction: column; gap: 3px; font: 600 14px/1.2 var(--rd-font); }
    .pl-rd.pl-v3srv .rd-rl small { font: 400 12px/1.3 var(--rd-font); color: #9B968E; }

    /* Short windows: zoom goes (the wheel does it). Nothing else may: the
       right column is 76 + 284 = 360px and the app's min-height leaves the map
       440px, so it always fits — and the floor stack HOLDS the moved view-line
       −/+ (ids intact), so hiding it would hide those controls outright.
       The rail's eight buttons are 76 + 8×44 + 7×6 + 9 = 479px: at 38px they
       are 431, which the 440px floor holds. */
    @media (max-height: 760px) {
        .pl-rd.pl-v3srv .rd-zoom { display: none; }
        .pl-rd.pl-v3srv .rd-rail .rd-rb { width: 38px; height: 38px; }
        /* RD4: the tools column made the right column 76 + 569px; at 38px
           it is 76 + 491, which a 700px window's map still holds. */
        .pl-rd.pl-v3srv .rd-rcol { gap: 6px; }
        .pl-rd.pl-v3srv .rd-rcol .rd-sb,
        .pl-rd.pl-v3srv .rd-rcol .rd-stack > .pl-chip { width: 38px; height: 38px; }
        .pl-rd.pl-v3srv .rd-rcol .rd-sb svg { width: 18px; height: 18px; }
        .pl-rd.pl-v3srv .pl-app { --rd-rail: 38px; }
    }

    /* Full screen: the frame is the whole window. */
    .pl-rd.pl-v3srv .pl-app:fullscreen,
    .pl-rd.pl-v3srv .pl-app.pl-max {
        height: 100vh; height: 100dvh; min-height: 0;
        grid-template-rows: 0 minmax(0, 1fr); overflow: hidden;
    }
    /* The fallback overlay (no native fullscreen: an iframe, iPad Safari, a
       refused request) has to restate planner.css's `position: fixed` — the
       frame's `position: relative` above has the same specificity and loads
       later, and would leave the map in the page flow under the header. */
    .pl-rd.pl-v3srv .pl-app.pl-max { position: fixed; inset: 0; z-index: 2000; width: auto; }
}

/* ======================= RD6: the phone controls, hidden off it ============ */
/* The phone's own buttons (the top bar, the two folding buttons in the right
   column, + PARTS, the grab handles, the menu drawer and its scrim) exist at
   every width and show only under the phone query below. The old drawer's
   tab bar and its "current tool" line belong to today's page: never here. */
.pl-rd.pl-v3srv .rd-mtop,
.pl-rd.pl-v3srv .rd-mfb,
.pl-rd.pl-v3srv .rd-mparts,
.pl-rd.pl-v3srv .rd-grab,
.pl-rd.pl-v3srv .rd-scrim,
.pl-rd.pl-v3srv .rd-menu,
.pl-rd.pl-v3srv .rd-tdot,
.pl-rd.pl-v3srv #planner-mbar,
.pl-rd.pl-v3srv #planner-mcur { display: none; }

/* ======================= RD6: phones, a phone on its side, tablets ======== */
/* ⚠ This query is gshell.js's PHONE_Q, character for character: the CSS and
   the script must agree on what a phone is, or a sheet opens in a layout that
   has no scrim. A small upright tablet (an iPad mini, 744 wide) is a phone here;
   from 768 wide up (a tablet upright, as the v8 design draws it — R-RD) and
   any tablet on its side keep the desktop frame. */
@media (max-width: 767px), (max-height: 500px) and (max-width: 960px) {
    /* The phone sheet's title bar carries the piece count (v8). */
    .pl-rd.pl-v3srv #planner-rd-panel-cost .rd-fsum:not(:empty) {
        display: block; font: 500 15px/1 var(--rd-font); color: var(--rd-text);
    }
    .pl-rd.pl-v3srv [data-rd-body="cost"] .rd-seg > .pl-chip { min-height: 40px; }
    .pl-rd.pl-v3srv .pl-app {
        --rd-gap: 10px;
        --rd-sat: env(safe-area-inset-top, 0px);
        --rd-sab: env(safe-area-inset-bottom, 0px);
        --rd-sal: env(safe-area-inset-left, 0px);
        --rd-sar: env(safe-area-inset-right, 0px);
        --rd-mt: calc(62px + var(--rd-sat));     /* under the top bar */
        font-size: 15px;
    }
    /* A phone has no Ctrl key to name (Save still answers Ctrl+S from one). */
    .pl-rd.pl-v3srv #planner-rd-save > kbd { display: none; }
    /* Owner decision D10 (TERRAIN_MODE.md): the Ground chooser and See-through
       are DESKTOP-only. Today's page hides them with the whole card; here the
       phone reaches Settings through the Menu for the FOV, so the two rows go
       and the card stays. RD8; gated by run_terrain's 390 half. */
    .pl-rd.pl-v3srv .pl-ground-set,
    .pl-rd.pl-v3srv .pl-seethrough-set { display: none; }
    /* Today's phone rule (planner.css §6e), restated for this page: a sticky
       site nav would sit over the top bar once the page is scrolled. */
    .pl-rd.pl-v3srv #header.navbar { position: static; }
    /* Only what a builder touches every few seconds stays on the map. The
       name, Share and Reset view are rows in the menu drawer; Undo / Redo
       sit by the build bar (gshell moves them); zoom is the pinch. */
    .pl-rd.pl-v3srv .rd-tl,
    .pl-rd.pl-v3srv .rd-shareslot,
    .pl-rd.pl-v3srv .rd-rail,
    .pl-rd.pl-v3srv .rd-zoom,
    .pl-rd.pl-v3srv .rd-legend,
    .pl-rd.pl-v3srv .rd-slot.rd-add { display: none; }
    /* Reset view stays on the phone, under Tools: one tap brings a base that
       a pinch threw off the screen back (owner, 2026-10-12). */
    .pl-rd.pl-v3srv .rd-rcol > [data-rd-slot="reset"] { order: 9; }
    .pl-rd.pl-v3srv .rd-rcol > [data-rd-slot="reset"] > .pl-chip { width: 44px; height: 44px; }

    /* ---- the top bar: Menu · Cost / Raid / Rules · Full screen ---------- */
    .pl-rd.pl-v3srv .rd-mtop {
        display: flex; align-items: center; gap: 8px;
        position: absolute; z-index: 30;
        left: calc(10px + var(--rd-sal)); right: calc(10px + 44px + 8px + var(--rd-sar));
        top: calc(10px + var(--rd-sat));
        pointer-events: none;
    }
    .pl-rd.pl-v3srv .rd-mtop > * { pointer-events: auto; }
    .pl-rd.pl-v3srv .rd-tr { top: calc(10px + var(--rd-sat)); right: calc(10px + var(--rd-sar)); z-index: 30; }
    /* While a sheet is open the top bar stays ABOVE the scrim: the pill is
       how you go from Cost to Raid, and a tap on it must not close instead. */
    .pl-rd.pl-v3srv .pl-app.rd-sheet .rd-mtop,
    .pl-rd.pl-v3srv .pl-app.rd-sheet .rd-tr { z-index: 47; }
    .pl-rd.pl-v3srv .rd-mbtn {
        flex: none; width: 44px; height: 44px; padding: 0; display: grid; place-items: center;
        color: #D8D3CA; cursor: pointer;
        background: linear-gradient(180deg, rgba(40, 39, 43, .93), rgba(21, 21, 24, .93));
        border: 1px solid var(--rd-line); border-radius: 2px;
        box-shadow: inset 0 1px 0 rgba(255, 255, 255, .07), 0 2px 8px rgba(0, 0, 0, .45);
    }
    .pl-rd.pl-v3srv .rd-mbtn[aria-expanded="true"] { color: #fff; border-color: var(--rd-accent); }
    .pl-rd.pl-v3srv .rd-mbtn svg { width: 22px; height: 22px; fill: none; stroke: currentColor;
        stroke-width: 2; stroke-linecap: round; }
    /* The planner's menu is the RB tile (owner, 2026-10-12), so it is not a
       second copy of the site's ☰ just above it. */
    .pl-rd.pl-v3srv #planner-rd-menu { background: var(--rd-accent); color: #fff; border-color: transparent;
        box-shadow: inset 0 1px 0 rgba(255, 255, 255, .2), inset 0 -2px 0 rgba(0, 0, 0, .25), 0 2px 8px rgba(0, 0, 0, .5); }
    .pl-rd.pl-v3srv #planner-rd-menu[aria-expanded="true"] { border-color: #fff; }
    .pl-rd.pl-v3srv .rd-mrb { font: 700 17px/1 var(--rd-head); letter-spacing: .02em; }
    .pl-rd.pl-v3srv .rd-ipill {
        flex: 1 1 auto; min-width: 0; display: flex; height: 44px;
        background: rgba(14, 14, 16, .9); border: 1px solid var(--rd-line); border-radius: 2px;
        box-shadow: 0 2px 10px rgba(0, 0, 0, .45);
    }
    .pl-rd.pl-v3srv .rd-ipill > button {
        position: relative; flex: 1 1 0; min-width: 0; margin: 0; padding: 0 4px;
        display: flex; align-items: center; justify-content: center; gap: 6px;
        background: none; border: 0; color: #C9C4BB; cursor: pointer;
        font: 600 13px/1 var(--rd-head); letter-spacing: .1em; text-transform: uppercase;
    }
    .pl-rd.pl-v3srv .rd-ipill > button + button { border-left: 1px solid rgba(255, 255, 255, .08); }
    .pl-rd.pl-v3srv .rd-ipill > button > span:not(.rd-badge) { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
    .pl-rd.pl-v3srv .rd-ipill > button svg { width: 19px; height: 19px; flex: none; fill: none; stroke: currentColor;
        stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; }
    .pl-rd.pl-v3srv .rd-ipill > button[aria-expanded="true"] {
        color: #fff; background: linear-gradient(180deg, rgba(205, 65, 43, .42), rgba(118, 34, 22, .62));
    }
    .pl-rd.pl-v3srv .rd-ipill > button[aria-expanded="true"] svg { color: #FFB5A5; }
    .pl-rd.pl-v3srv .rd-ipill > button:focus-visible { outline: none; box-shadow: inset 0 0 0 2px rgba(205, 65, 43, .7); }
    .pl-rd.pl-v3srv .rd-ipill .rd-badge {
        top: 4px; bottom: auto; left: calc(50% - 26px); right: auto;
        min-width: 16px; height: 16px; padding: 0 3px; font-size: 10.5px; line-height: 16px;
    }

    /* ---- the right column: 2D / 3D, the floor, the wrench -------------- */
    .pl-rd.pl-v3srv .rd-rcol { right: calc(10px + var(--rd-sar)); top: calc(64px + var(--rd-sat)); gap: 8px; }
    .pl-rd.pl-v3srv .rd-mfb {
        display: grid; grid-template-rows: auto auto; align-content: center; justify-items: center; gap: 2px;
    }
    .pl-rd.pl-v3srv .rd-mfb svg { width: 18px; height: 18px; }
    .pl-rd.pl-v3srv .rd-mcap {
        display: block; max-width: 40px; overflow: hidden; text-overflow: ellipsis;
        font: 600 11px/1 var(--rd-head); letter-spacing: .04em; text-transform: uppercase;
    }
    .pl-rd.pl-v3srv .rd-mfb[aria-expanded="true"] { color: #fff; border-color: var(--rd-accent); }
    .pl-rd.pl-v3srv .pl-app.rd-tool-lit .rd-tdot {
        display: block; position: absolute; top: 5px; right: 5px; width: 8px; height: 8px; border-radius: 50%;
        background: var(--rd-amber); box-shadow: 0 0 0 2px #0A0A0C;
    }
    /* The floor stack and the tools fold out to the LEFT of their button. */
    .pl-rd.pl-v3srv .rd-rcol > .rd-floor,
    .pl-rd.pl-v3srv .rd-rcol > .rd-tools { display: none; }
    .pl-rd.pl-v3srv .pl-app.rd-fopen .rd-rcol,
    .pl-rd.pl-v3srv .pl-app.rd-topen .rd-rcol { z-index: 46; }
    .pl-rd.pl-v3srv .pl-app.rd-fopen .rd-rcol > .rd-floor,
    .pl-rd.pl-v3srv .pl-app.rd-topen .rd-rcol > .rd-tools {
        display: flex; flex-direction: column; align-items: stretch;
        position: absolute; right: calc(100% + 8px); top: 0; padding: 6px;
        background: rgba(17, 17, 20, .97); border: 1px solid rgba(255, 255, 255, .14); border-radius: 2px;
        box-shadow: 0 10px 28px rgba(0, 0, 0, .6); animation: rd-pin .12s ease-out;
    }
    .pl-rd.pl-v3srv .pl-app.rd-fopen .rd-rcol > .rd-floor { min-width: 70px; }
    .pl-rd.pl-v3srv .pl-app.rd-fopen .rd-rcol > .rd-floor > * { width: auto; height: 44px; }
    .pl-rd.pl-v3srv .pl-app.rd-fopen .rd-rcol > .rd-floor > .rd-flab { order: -2; }
    .pl-rd.pl-v3srv .pl-app.rd-topen .rd-rcol > .rd-tools { width: 212px; gap: 2px; }
    .pl-rd.pl-v3srv .pl-app.rd-topen .rd-rcol > .rd-tools > .rd-sb {
        width: 100%; height: 44px; margin: 0; padding: 0 12px;
        display: flex; justify-content: flex-start; gap: 12px;
        border-color: transparent; border-radius: 2px; background: none; box-shadow: none;
    }
    /* the longest label ("Pick a part off the base") squeezed its icon */
    .pl-rd.pl-v3srv .pl-app.rd-topen .rd-rcol > .rd-tools > .rd-sb > svg { flex: none; }
    .pl-rd.pl-v3srv .pl-app.rd-topen .rd-rcol > .rd-tools > .rd-sb::after {
        content: attr(data-s); font: 500 15px/1.2 var(--rd-font); letter-spacing: 0; text-transform: none;
        color: var(--rd-text); text-align: left;
    }
    .pl-rd.pl-v3srv .pl-app.rd-topen .rd-rcol > .rd-tools > .rd-sb.rd-on {
        border-color: var(--rd-accent);
        background: linear-gradient(180deg, rgba(205, 65, 43, .42), rgba(118, 34, 22, .62));
    }
    .pl-rd.pl-v3srv .pl-app.rd-topen .rd-rcol > .rd-tools > .rd-sb.rd-danger::after { color: #F2A897; }

    /* ---- the build zone: everything a thumb needs, at the bottom ------- */
    /* A thumb that slips up the bar must not carry the page (and the planner)
       away: the bar only pans sideways (owner, 2026-10-12). */
    .pl-rd.pl-v3srv .rd-bottom { touch-action: pan-x; }
    /* "›": more slots this way, gone once the bar is at its end. */
    .pl-rd.pl-v3srv .rd-hbmore {
        display: block; grid-row: 2; grid-column: 2; justify-self: end; align-self: center; z-index: 2;
        pointer-events: none; margin-right: 2px; color: #fff;
        font: 700 22px/1 var(--rd-head); text-shadow: 0 1px 4px rgba(0, 0, 0, .9);
    }
    .pl-rd.pl-v3srv .rd-hbmore.rd-end { display: none; }
    .pl-rd.pl-v3srv .rd-bottom {
        left: 0; right: 0; bottom: calc(8px + var(--rd-sab));
        padding: 0 calc(10px + var(--rd-sar)) 0 calc(10px + var(--rd-sal));
        align-items: stretch; gap: 6px;
    }
    .pl-rd.pl-v3srv .rd-hands {
        align-self: center; max-width: 100%; min-height: 28px; padding: 3px 6px 3px 10px;
        flex-wrap: wrap; row-gap: 4px; overflow: hidden; font-size: 12.5px;
    }
    /* The label keeps v8's name | grade | cost whole; the armed part's own
       controls (Rotate, Step) wrap to a line of their own beneath it rather
       than squeezing the name away. No Q/E on a phone, so no "rotate" word. */
    .pl-rd.pl-v3srv .rd-hl { min-width: 0; max-width: 100%; flex: 0 0 auto; overflow: hidden; }
    .pl-rd.pl-v3srv .rd-hl .rd-hq,
    .pl-rd.pl-v3srv .rd-hl .rd-hsep:has(+ .rd-hq) { display: none; }
    .pl-rd.pl-v3srv .rd-hl .rd-hn { flex: 0 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; }
    .pl-rd.pl-v3srv .rd-hl kbd,
    .pl-rd.pl-v3srv .rd-hl .rd-hk { display: none; }
    .pl-rd.pl-v3srv .rd-hc { flex-wrap: nowrap; }
    .pl-rd.pl-v3srv .rd-hc .pl-chip,
    .pl-rd.pl-v3srv .rd-hc .pl-level { height: 44px; }
    .pl-rd.pl-v3srv .rd-hc .pl-level .pl-chip { height: 44px; width: 44px; }
    /* The ramp's Low/High halves (P43) are not .pl-chip: planner.css gives them
       a thumb's size up to 640px only, and a phone on its side is 774 wide
       (measured 37x26 there). */
    .pl-rd.pl-v3srv .rd-hc .pl-level .pl-segdir-half { min-height: 44px; min-width: 44px; }
    .pl-rd.pl-v3srv .rd-hbrow {
        display: grid; grid-template-columns: auto minmax(0, 1fr) auto; align-items: center; gap: 6px;
    }
    .pl-rd.pl-v3srv .rd-hbrow > .rd-hist { grid-row: 1; grid-column: 1; align-self: stretch; gap: 4px; }
    .pl-rd.pl-v3srv .rd-hbrow > .rd-hist > .pl-chip { width: 46px; height: auto; min-height: 44px; background: rgba(14, 14, 16, .82); }
    .pl-rd.pl-v3srv .rd-grades { grid-row: 1; grid-column: 2 / -1; justify-self: end; padding: 4px; }
    .pl-rd.pl-v3srv .rd-grades .pl-tiers { gap: 4px; }
    .pl-rd.pl-v3srv .rd-grades .pl-tiers .pl-chip { width: 44px; height: 44px; }
    .pl-rd.pl-v3srv .rd-grades .pl-tiers .pl-chip .pl-ico-tier { width: 24px; height: 24px; }
    .pl-rd.pl-v3srv .rd-grades .pl-tiers .pl-chip[data-rd-gk]::after { display: none; }
    /* The bar scrolls: five slots and HALF the sixth show, and the right edge
       fades, so it reads as "more this way". */
    .pl-rd.pl-v3srv .rd-hotbar {
        grid-row: 2; grid-column: 1 / 3; min-width: 0; align-self: stretch;
        container-type: inline-size; padding: 4px 0 4px 4px;
        overflow-x: auto; overflow-y: hidden; scroll-snap-type: x mandatory;
        scrollbar-width: none; overscroll-behavior-x: contain;
        -webkit-mask-image: linear-gradient(90deg, #000 calc(100% - 34px), rgba(0, 0, 0, .25));
        mask-image: linear-gradient(90deg, #000 calc(100% - 34px), rgba(0, 0, 0, .25));
    }
    .pl-rd.pl-v3srv .rd-hotbar::-webkit-scrollbar { display: none; }
    .pl-rd.pl-v3srv .rd-hotbar::after { content: ""; flex: none; width: 1px; }
    .pl-rd.pl-v3srv .rd-slot {
        width: calc((100cqi - 20px) / 5.5); height: auto; aspect-ratio: 1; max-width: 60px;
        scroll-snap-align: start;
        -webkit-touch-callout: none; -webkit-user-select: none; user-select: none;
    }
    .pl-rd.pl-v3srv .rd-slot .pl-ico { width: 72%; height: 72%; }
    .pl-rd.pl-v3srv .rd-slot .rd-sn { font-size: 11px; }
    /* Hold a slot: a bar fills, then its swap menu opens. */
    .pl-rd.pl-v3srv .rd-slot.rd-holding::before {
        content: ""; position: absolute; left: 0; bottom: 0; z-index: 3; height: 4px; width: 0;
        background: var(--rd-amber); animation: rd-holdfill .42s linear forwards;
    }
    /* + PARTS stands still beside the bar: it never scrolls away. */
    .pl-rd.pl-v3srv .rd-mparts {
        grid-row: 2; grid-column: 3; align-self: stretch;
        display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 3px;
        width: 58px; margin: 4px 0; padding: 0; cursor: pointer; color: var(--rd-text);
        background: #1A1A1D; border: 1px solid rgba(255, 255, 255, .18); border-radius: 2px;
        box-shadow: 0 2px 8px rgba(0, 0, 0, .4);
    }
    .pl-rd.pl-v3srv .rd-mparts:active,
    .pl-rd.pl-v3srv .rd-mparts[aria-expanded="true"] { background: #29292E; border-color: var(--rd-accent); }
    .pl-rd.pl-v3srv .rd-mparts svg { width: 22px; height: 22px; fill: none; stroke: currentColor;
        stroke-width: 2; stroke-linecap: round; }
    .pl-rd.pl-v3srv .rd-mparts span { font: 600 12px/1 var(--rd-head); letter-spacing: .1em; text-transform: uppercase; }
    /* A slot's swap menu rises from the bar's left edge, inside the screen. */
    .pl-rd.pl-v3srv .rd-fly { left: 0; right: auto; max-width: calc(100vw - 20px); overflow-x: auto; }
    .pl-rd.pl-v3srv .rd-fly .rd-slot { width: 52px; height: 52px; max-width: none; }

    /* The selection bar spans the screen; every action stays on it. */
    .pl-rd.pl-v3srv .pl-canvas .pl-selbar.rd-selbar {
        align-self: stretch; max-width: none; justify-content: flex-start; gap: 6px; padding: 8px;
    }
    .pl-rd.pl-v3srv .rd-selbar .pl-selcount { flex: 1 0 100%; }
    .pl-rd.pl-v3srv .rd-selbar .rd-sgp { padding-left: 0; border-left: 0; gap: 6px; }
    .pl-rd.pl-v3srv .rd-selbar .pl-chip { min-height: 40px; padding: 0 10px; }
    /* The group turn: 44px targets, never behind anything (the ✓ and the
       turn trio are the phone's only way to place and turn a group). */
    .pl-rd.pl-v3srv .rd-selbar [data-act="turnl"],
    .pl-rd.pl-v3srv .rd-selbar [data-act="turnr"] { min-width: 44px; min-height: 44px; justify-content: center; font-size: 18px; }
    /* The ✓ is drawn over the scrim (44) and a sheet (45), so a sheet opened
       over a pinned piece never takes its tap; gshell.keepConfirm keeps it
       beside the bars, the menu and the open sheet, never on them. */
    .pl-rd.pl-v3srv .pl-canvas .pl-confirm { z-index: 46; }
    /* A group Copy/Move keeps its bar: the turn trio is the phone's only way
       to turn it (no Q/E), so a sheet opened during the drag stops above the
       bottom bar, and the bar stays over the scrim. */
    .pl-rd.pl-v3srv .pl-app:has(.rd-selbar [data-act="turnl"]:not([hidden])) .rd-bottom { z-index: 46; }
    .pl-rd.pl-v3srv .pl-app:has(.rd-selbar [data-act="turnl"]:not([hidden])) .rd-dock,
    .pl-rd.pl-v3srv .pl-app:has(.rd-selbar [data-act="turnl"]:not([hidden])) .rd-pop {
        bottom: calc(var(--rd-both, 0px) + 8px + var(--rd-sab));
    }

    /* ---- sheets: every panel rises from the bottom edge ---------------- */
    .pl-rd.pl-v3srv .rd-dock {
        left: 0; right: 0; top: var(--rd-mt); bottom: 0; width: auto; z-index: 45;
        justify-content: flex-end; gap: 0;
    }
    .pl-rd.pl-v3srv .rd-pane {
        border-radius: 10px 10px 0 0; border-bottom: 0; max-height: 100%;
        padding-bottom: var(--rd-sab); animation: rd-sheet .18s ease-out;
    }
    .pl-rd.pl-v3srv .rd-pane.rd-pinned { border-top: 1px solid rgba(255, 255, 255, .12); }
    .pl-rd.pl-v3srv .rd-pane.rd-tall:not(.rd-fold) { flex: 0 1 auto; }
    .pl-rd.pl-v3srv .rd-pane.rd-drag,
    .pl-rd.pl-v3srv .rd-pop.rd-drag { animation: none; transition: none; }
    .pl-rd.pl-v3srv .rd-ph { position: relative; height: 52px; }
    .pl-rd.pl-v3srv .rd-pinb { display: none; }
    .pl-rd.pl-v3srv .rd-ib { width: 44px; height: 44px; }
    .pl-rd.pl-v3srv .rd-grab {
        display: block; position: absolute; left: 50%; top: 0; z-index: 3;
        width: 96px; height: 22px; margin-left: -48px; touch-action: none; cursor: grab;
    }
    .pl-rd.pl-v3srv .rd-grab::before {
        content: ""; position: absolute; left: 50%; top: 6px; width: 40px; height: 4px; margin-left: -20px;
        border-radius: 2px; background: rgba(255, 255, 255, .3);
    }
    .pl-rd.pl-v3srv .rd-pop {
        left: 0; right: 0; top: auto; bottom: 0; width: auto; max-width: none;
        max-height: calc(100% - var(--rd-mt)); overflow-y: auto; z-index: 45;
        padding-bottom: var(--rd-sab); border-radius: 10px 10px 0 0; border-bottom: 0;
        animation: rd-sheet .18s ease-out;
    }
    .pl-rd.pl-v3srv .rd-pop .rd-row { min-height: 52px; }
    .pl-rd.pl-v3srv .rd-linkbox .pl-btn { min-height: 44px; }
    /* The scrim: behind a sheet, over the map. A sheet that changes the map
       (raid, rules, layers) leaves it undimmed. */
    .pl-rd.pl-v3srv .rd-scrim {
        display: block; position: absolute; inset: 0; z-index: 44;
        margin: 0; padding: 0; border: 0; background: rgba(0, 0, 0, .5);
    }
    .pl-rd.pl-v3srv .rd-scrim[hidden] { display: none; }
    .pl-rd.pl-v3srv .rd-scrim.rd-clear { background: transparent; }

    /* Bigger targets inside the sheets. */
    .pl-rd.pl-v3srv .rd-pb > .pl-chip[aria-pressed] { min-height: 52px; }
    .pl-rd.pl-v3srv .rd-oldlook { min-height: 44px; }
    .pl-rd.pl-v3srv .rd-ap-slots button { height: 38px; }
    .pl-rd.pl-v3srv .rd-bacts > * { height: 44px; }
    /* My bases on a touch screen: 44 px targets, and 16 px in the two
       fields so iOS does not zoom in on focus. */
    .pl-rd.pl-v3srv .rd-pb #planner-save-name,
    .pl-rd.pl-v3srv .rd-pb #planner-save-btn { height: 44px; }
    .pl-rd.pl-v3srv .rd-pb #planner-save-name,
    .pl-rd.pl-v3srv .rd-bfind input { font-size: 16px; }
    .pl-rd.pl-v3srv .rd-bfind { height: 44px; }
    .pl-rd.pl-v3srv .rd-pb .pl-save-row .rd-trash { width: 44px; height: 44px; }
    .pl-rd.pl-v3srv .rd-pb .pl-saves-file .pl-chip { min-height: 44px; display: inline-flex; align-items: center; }
    .pl-rd.pl-v3srv .rd-bren input,
    .pl-rd.pl-v3srv .rd-bren .pl-btn { height: 44px; }
    .pl-rd.pl-v3srv .rd-bnb { min-height: 32px; }
    .pl-rd.pl-v3srv .rd-askacts .pl-btn { height: 40px; }
    .pl-rd.pl-v3srv .rd-mini { width: 44px; height: 40px; }
    /* ⚠ iOS zooms the page in on any focused field under 16px, and the map
       then traps the pinch (CLAUDE.md, "Form controls under 16px"). */
    .pl-rd.pl-v3srv .rd-ap-search,
    .pl-rd.pl-v3srv .rd-bren input,
    .pl-rd.pl-v3srv .rd-pb > #planner-viewline .pl-viewline-num,
    .pl-rd.pl-v3srv .rd-pb input[type="text"],
    .pl-rd.pl-v3srv .rd-pb input[type="search"],
    .pl-rd.pl-v3srv .rd-pb input[type="number"],
    .pl-rd.pl-v3srv .rd-pb select,
    .pl-rd.pl-v3srv .rd-pb textarea { font-size: 16px; }
    .pl-rd.pl-v3srv .rd-ap-search { height: 44px; }

    /* ---- the menu drawer, from the left (the side its button is on) ---- */
    .pl-rd.pl-v3srv .rd-menu {
        display: flex; flex-direction: column;
        position: absolute; z-index: 46; left: 0; top: 0; bottom: 0; width: min(320px, 86%);
        padding: var(--rd-sat) 0 var(--rd-sab) var(--rd-sal);
        color: var(--rd-text); font-family: var(--rd-font);
        background: rgba(17, 17, 20, .98); border-right: 1px solid rgba(255, 255, 255, .12);
        border-radius: 0 10px 10px 0; box-shadow: 0 14px 40px rgba(0, 0, 0, .6);
        animation: rd-drawer .2s ease-out;
    }
    .pl-rd.pl-v3srv .rd-menu[hidden] { display: none; }
    .pl-rd.pl-v3srv .rd-dhead {
        display: flex; align-items: center; gap: 8px; flex: none;
        padding: 10px 8px 10px 14px; border-bottom: 1px solid rgba(255, 255, 255, .08);
    }
    .pl-rd.pl-v3srv .rd-dhead .rd-logo { width: 36px; height: 36px; font-size: 15px; box-shadow: none; }
    .pl-rd.pl-v3srv .rd-dhead .rd-ti { font: 600 15px/1 var(--rd-head); letter-spacing: .09em; text-transform: uppercase; align-items: center; }
    .pl-rd.pl-v3srv .rd-mbody {
        display: flex; flex-direction: column; gap: 2px; flex: 1 1 auto; min-height: 0;
        padding: 8px; overflow-y: auto; overscroll-behavior: contain;
    }
    .pl-rd.pl-v3srv .rd-dbase {
        display: flex; align-items: center; gap: 12px; min-width: 0; margin: 0 0 6px; padding: 8px;
        text-align: left; cursor: pointer; color: var(--rd-text);
        background: #1B1B1F; border: 1px solid rgba(205, 65, 43, .4); border-radius: 2px;
    }
    .pl-rd.pl-v3srv .rd-dbase:active { background: #26262B; }
    .pl-rd.pl-v3srv .rd-dthumb {
        flex: none; width: 56px; height: 44px; display: grid; place-items: center;
        background: #0E0E10; border: 1px solid rgba(255, 255, 255, .1); border-radius: 2px; color: #9B968E;
    }
    .pl-rd.pl-v3srv .rd-dthumb svg { width: 22px; height: 22px; fill: none; stroke: currentColor; stroke-width: 1.8;
        stroke-linecap: round; stroke-linejoin: round; }
    .pl-rd.pl-v3srv .rd-dtxt { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 4px; }
    .pl-rd.pl-v3srv .rd-dtxt b {
        overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
        font: 600 16px/1.15 var(--rd-head); letter-spacing: .04em; text-transform: uppercase;
    }
    .pl-rd.pl-v3srv .rd-dtxt small { font: 500 12.5px/1.2 var(--rd-font); color: var(--rd-muted);
        overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
    .pl-rd.pl-v3srv .rd-dbase em {
        flex: none; font: 600 11.5px/1 var(--rd-head); font-style: normal; letter-spacing: .1em;
        text-transform: uppercase; color: #DD5F47;
    }
    .pl-rd.pl-v3srv .rd-mrow {
        display: flex; align-items: center; gap: 12px; width: 100%; min-height: 52px; margin: 0; padding: 8px 10px;
        text-align: left; cursor: pointer; color: var(--rd-text);
        background: none; border: 0; border-radius: 2px;
    }
    .pl-rd.pl-v3srv .rd-mrow:active { background: rgba(255, 255, 255, .06); }
    .pl-rd.pl-v3srv .rd-mrow:focus-visible,
    .pl-rd.pl-v3srv .rd-dbase:focus-visible,
    .pl-rd.pl-v3srv .rd-mbtn:focus-visible { outline: none; box-shadow: inset 0 0 0 2px rgba(205, 65, 43, .6); }
    .pl-rd.pl-v3srv .rd-mrow[hidden] { display: none; }
    .pl-rd.pl-v3srv .rd-mrow[aria-disabled="true"] { color: rgba(216, 211, 202, .45); cursor: default; }
    .pl-rd.pl-v3srv .rd-lic {
        flex: none; width: 36px; height: 36px; display: grid; place-items: center; color: #DD5F47;
        background: rgba(255, 255, 255, .04); border: 1px solid rgba(255, 255, 255, .08); border-radius: 2px;
    }
    .pl-rd.pl-v3srv .rd-lic svg { width: 20px; height: 20px; fill: none; stroke: currentColor; stroke-width: 1.8;
        stroke-linecap: round; stroke-linejoin: round; }
    .pl-rd.pl-v3srv .rd-mrow .rd-rl { font: 600 15px/1.15 var(--rd-font); }
    .pl-rd.pl-v3srv .rd-mrow .rd-badge { position: static; margin-left: auto; }
    .pl-rd.pl-v3srv .rd-dsep { flex: none; height: 1px; margin: 6px 10px; background: rgba(255, 255, 255, .08); }

    /* ---- what floats on the map ---------------------------------------- */
    /* A message sits under the top bar, left of the right column; over an
       open sheet it rises above it (it is pointer-events: none). */
    .pl-rd.pl-v3srv .pl-canvas .pl-toast,
    .pl-rd.pl-v3srv .pl-app.rd-sharing .pl-canvas .pl-toast {
        top: var(--rd-mt); left: calc(10px + var(--rd-sal)); right: calc(64px + var(--rd-sar)); bottom: auto;
        z-index: 43; width: auto; max-width: none; margin: 0; transform: none;
        padding: 10px 12px; font-size: 14px; line-height: 1.35;
    }
    .pl-rd.pl-v3srv .pl-app.rd-sheet .pl-canvas .pl-toast { z-index: 48; box-shadow: 0 6px 24px rgba(0, 0, 0, .6); }
    .pl-rd.pl-v3srv .pl-canvas .pl-hint {
        top: auto; left: calc(10px + var(--rd-sal)); right: calc(64px + var(--rd-sar));
        bottom: calc(8px + var(--rd-sab) + var(--rd-both, 150px) + 8px);
    }
    .pl-rd.pl-v3srv .pl-canvas .pl-info { left: calc(10px + var(--rd-sal)); right: auto; top: var(--rd-mt);
        width: min(240px, calc(100% - 84px)); }

    /* ---- the All parts sheet ------------------------------------------- */
    /* The sheet holds the old sidebar whole, exactly as the desktop panel
       does - but planner.css lays that sidebar out as the parts grid only
       at >= 769px, and today's phone look (a category tab strip over one
       sideways row of chips) is scoped off this page. So the desktop grid is
       restated here, and the whole sheet body scrolls as one: on a phone on
       its side a scroller inside a scroller left the list 38px of height
       under the search and the nine slots. */
    .pl-rd.pl-v3srv .rd-pb > .pl-palette { flex: none; overflow: visible; gap: 12px; padding: 0 12px 12px; }
    .pl-rd.pl-v3srv .rd-pb > .pl-palette .pl-cattabs { display: none; }
    /* a thumb's group tabs */
    .pl-rd.pl-v3srv .rd-ptabs { gap: 6px; }
    .pl-rd.pl-v3srv .rd-ptabs button { height: 36px; padding: 0 12px; font-size: 14px; border-radius: 18px; }
    .pl-rd.pl-v3srv .rd-ap { padding-bottom: 10px; }
    /* the whole sheet scrolls as one, so the slot digits ride its bottom edge */
    .pl-rd.pl-v3srv .rd-ap-foot { position: sticky; bottom: 0; z-index: 2; background: rgb(17, 17, 20); }
    .pl-rd.pl-v3srv .rd-pb > .pl-palette .pl-tools {
        margin: 0; display: flex; flex-direction: column; gap: 8px; align-items: stretch;
    }
    .pl-rd.pl-v3srv .rd-pb > .pl-palette .pl-catgroup {
        display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 6px;
    }
    .pl-rd.pl-v3srv .rd-pb > .pl-palette .pl-catlabel { display: block; grid-column: 1 / -1; margin: 2px 0 0; }
    .pl-rd.pl-v3srv .rd-pb > .pl-palette .pl-tools .pl-chip,
    .pl-rd.pl-v3srv .rd-pb > .pl-palette .pl-doors .pl-chip {
        min-height: 44px; font-size: 14px; padding: 6px 8px; justify-content: flex-start;
        min-width: 0; white-space: normal; overflow-wrap: anywhere;
        -webkit-hyphens: auto; hyphens: auto; text-align: left; line-height: 1.15;
    }
    .pl-rd.pl-v3srv .rd-pb > .pl-palette .pl-doors:not([hidden]) {
        margin: 0; display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 6px;
    }
}

/* The narrowest phones: Undo / Redo and the five grades share one line. */
@media (max-width: 359px) {
    .pl-rd.pl-v3srv .rd-hbrow > .rd-hist > .pl-chip { width: 40px; }
    .pl-rd.pl-v3srv .rd-grades { padding: 3px; }
    .pl-rd.pl-v3srv .rd-grades .pl-tiers { gap: 3px; }
    .pl-rd.pl-v3srv .rd-grades .pl-tiers .pl-chip { width: 37px; height: 37px; }
}

/* ======================= a phone on its side ============================= */
/* Wide and short: the H1 line goes (the article under the tool carries it,
   and Full screen gives the rest back), the grades stand up along the left
   edge, the build bar is one row, and a panel opens on the right, full
   height, with the map in view on the left. */
@media (max-height: 500px) and (max-width: 960px) {
    /* RD9, the owner's real phone on its side (Galaxy A53, Chrome): the address
       bar leaves the page 774x298, not the 390 a desktop window gives it, and
       the site header took 56 of those: Tools sat under + PARTS, and with a
       part in the hands the map was a 60px strip. On its side the header goes
       as well (it is back the moment the phone stands up). `--rd-nav` is READ
       off the header, so the app takes the whole height by itself. */
    body.pl-rd.pl-v3srv #header { display: none; }
    .pl-rd.pl-v3srv .pl-app { min-height: 0; grid-template-rows: 0 minmax(0, 1fr); }
    .pl-rd.pl-v3srv .pl-head { overflow: hidden; border: 0; }
    .pl-rd.pl-v3srv .rd-ipill { flex: 0 1 420px; margin: 0 auto; }
    .pl-rd.pl-v3srv .rd-bottom { padding-left: calc(62px + var(--rd-sal)); gap: 4px; }
    .pl-rd.pl-v3srv .rd-grades {
        position: absolute; left: calc(10px + var(--rd-sal)); bottom: 0; padding: 4px;
    }
    .pl-rd.pl-v3srv .rd-grades .pl-tiers { flex-direction: column; gap: 3px; }
    /* The column shrinks on a shorter phone so its top (Twig) stays below
       the menu button (a 360-375 px landscape put the menu on Twig). */
    .pl-rd.pl-v3srv .rd-grades .pl-tiers .pl-chip {
        width: 38px; min-height: 0; height: clamp(28px, calc((100vh - 200px) / 5), 38px);
        height: clamp(28px, calc((100dvh - 200px) / 5), 38px);
    }
    .pl-rd.pl-v3srv .rd-grades .pl-tiers .pl-chip .pl-ico-tier { width: 22px; height: 22px; }
    .pl-rd.pl-v3srv .rd-hbmore { grid-row: 1; }
    /* a 360px sheet cannot spare the digits' 90px for good: they scroll with the list */
    .pl-rd.pl-v3srv .rd-ap-foot { position: static; }
    /* No room under Tools on a phone on its side (it met + PARTS): Reset
       view is in the menu there, as before. */
    .pl-rd.pl-v3srv .rd-rcol > [data-rd-slot="reset"] { display: none; }
    .pl-rd.pl-v3srv .rd-hbrow > .rd-hist { grid-row: 1; grid-column: 1; }
    .pl-rd.pl-v3srv .rd-hbrow > .rd-hist > .pl-chip { width: 44px; }
    .pl-rd.pl-v3srv .rd-hotbar { grid-row: 1; grid-column: 2; }
    .pl-rd.pl-v3srv .rd-slot { max-width: 56px; }
    .pl-rd.pl-v3srv .rd-mparts { grid-row: 1; grid-column: 3; width: 54px; }
    .pl-rd.pl-v3srv .rd-hands { min-height: 26px; padding: 2px 6px 2px 10px; }
    /* 390 px of height: the selection bar stops short of the right column
       (2D / ALL / TOOLS), and while it is up the hands label steps aside —
       it would say only "Select", and a toast has nowhere else to go. */
    .pl-rd.pl-v3srv .pl-canvas .pl-selbar.rd-selbar { margin-right: calc(54px + var(--rd-sar)); }
    .pl-rd.pl-v3srv .rd-bottom:has(> .rd-selbar:not([hidden])) > .rd-hands { display: none; }
    .pl-rd.pl-v3srv .pl-canvas .pl-toast,
    .pl-rd.pl-v3srv .pl-app.rd-sharing .pl-canvas .pl-toast {
        left: 50%; right: auto; transform: translateX(-50%);
        width: max-content; max-width: min(460px, calc(100% - 140px));
    }
    /* A message never sits on an open panel: it moves into the map left. */
    .pl-rd.pl-v3srv .pl-app.rd-sheet .pl-canvas .pl-toast {
        left: calc(10px + var(--rd-sal)); right: calc(min(420px, 66%) + 8px);
        transform: none; width: auto; max-width: none;
    }
    .pl-rd.pl-v3srv .pl-app.rd-menu-open .pl-canvas .pl-toast {
        left: calc(min(320px, 56%) + 8px); right: calc(64px + var(--rd-sar));
        transform: none; width: auto; max-width: none;
    }
    .pl-rd.pl-v3srv .pl-canvas .pl-hint { left: calc(62px + var(--rd-sal)); }
    /* …and so does the first-visit hint, centred in what the panel leaves. */
    .pl-rd.pl-v3srv .pl-app.rd-sheet .pl-canvas .pl-hint { right: calc(min(420px, 66%) + 8px); }
    .pl-rd.pl-v3srv .pl-app.rd-menu-open .pl-canvas .pl-hint { left: calc(min(320px, 56%) + 8px); }
    /* The tool list opens as two columns so it fits the short screen, each
       as wide as the one column upright ("Pick a part off the base" fits). */
    .pl-rd.pl-v3srv .pl-app.rd-topen .rd-rcol > .rd-tools {
        display: grid; grid-template-columns: 1fr 1fr; width: 424px;
    }
    .pl-rd.pl-v3srv .pl-app.rd-fopen .rd-rcol > .rd-floor {
        max-height: calc(100vh - 90px); max-height: calc(100dvh - 90px); overflow-y: auto;
    }
    .pl-rd.pl-v3srv .rd-dock {
        left: auto; right: 0; top: var(--rd-mt); bottom: 0; width: min(420px, 66%);
    }
    .pl-rd.pl-v3srv .rd-pane,
    .pl-rd.pl-v3srv .rd-pane.rd-half:not(.rd-fold),
    .pl-rd.pl-v3srv .rd-pane.rd-tall:not(.rd-fold) {
        flex: 1 1 auto; max-height: 100%;
        border: 0; border-left: 1px solid rgba(255, 255, 255, .14); border-radius: 10px 0 0 10px;
        padding-right: var(--rd-sar); animation: rd-side .18s ease-out;
    }
    .pl-rd.pl-v3srv .rd-pop {
        left: auto; right: 0; top: var(--rd-mt); bottom: 0; width: min(420px, 66%); max-height: none;
        border: 0; border-left: 1px solid rgba(255, 255, 255, .14); border-radius: 10px 0 0 10px;
        padding-right: var(--rd-sar); animation: rd-side .18s ease-out;
    }
    .pl-rd.pl-v3srv .rd-menu { width: min(320px, 56%); }
    .pl-rd.pl-v3srv .rd-grab { display: none; }
}

/* ======================= big screens (RD6) =============================== */
/* Past 1920×1080 the furniture grows with the window (gshell's scaleUi sets
   --rd-uz: 1.75 at 3840×2160); the map itself is never zoomed, so the GL
   canvas and its pointer maths are untouched.
   ⚠ --rd-both, --rd-tlw and --rd-trw are MEASURED (getBoundingClientRect: the
   size on screen, zoom already in it). A zoomed element multiplies its own
   offsets by the zoom, so a measured value in one is divided back out, or
   it is counted twice. */
.pl-rd.pl-v3srv .pl-app.rd-big .rd-tl,
.pl-rd.pl-v3srv .pl-app.rd-big .rd-tr,
.pl-rd.pl-v3srv .pl-app.rd-big .rd-rcol,
.pl-rd.pl-v3srv .pl-app.rd-big .rd-zoom,
.pl-rd.pl-v3srv .pl-app.rd-big .rd-legend,
.pl-rd.pl-v3srv .pl-app.rd-big .rd-rail,
.pl-rd.pl-v3srv .pl-app.rd-big .rd-dock,
.pl-rd.pl-v3srv .pl-app.rd-big .rd-bottom,
.pl-rd.pl-v3srv .pl-app.rd-big .rd-pop,
.pl-rd.pl-v3srv .pl-app.rd-big .pl-head,
.pl-rd.pl-v3srv .pl-app.rd-big .pl-canvas .pl-toast,
.pl-rd.pl-v3srv .pl-app.rd-big .pl-canvas .pl-hint,
.pl-rd.pl-v3srv .pl-app.rd-big .pl-canvas .pl-info { zoom: var(--rd-uz); }
.pl-rd.pl-v3srv .pl-app.rd-big { --rd-headh: calc(40px * var(--rd-uz)); }
.pl-rd.pl-v3srv .pl-app.rd-big .rd-dock { bottom: calc(22px + var(--rd-dfoot, var(--rd-both, 134px)) / var(--rd-uz)); }
.pl-rd.pl-v3srv .pl-app.rd-big .pl-canvas .pl-hint { bottom: calc(24px + var(--rd-both, 134px) / var(--rd-uz)); }
.pl-rd.pl-v3srv .pl-app.rd-big .pl-canvas .pl-toast {
    left: calc(28px + var(--rd-tlw, 332px) / var(--rd-uz));
    right: calc(28px + var(--rd-trw, 198px) / var(--rd-uz));
}

/* ---- the Guide (RD7) ----------------------------------------------------
   gshell builds the card and the ring and places both in the map's own
   coordinates, off the real control's rect, every tick. The card is not
   modal and not zoomed on 4K (its placement reads its own box, so it is
   SIZED by --rd-uz instead). While it is open the starter hint steps aside:
   one line on the map at a time. */
.pl-rd.pl-v3srv .pl-app.rd-guiding .pl-canvas .pl-hint { display: none; }
/* The hands label carries Rotate only while the part in hand can turn (the
   design's showTurn); a greyed chip there is a control that does nothing. */
.pl-rd.pl-v3srv #planner-rd-handsctl #planner-rotate:disabled { display: none; }
/* With a mouse and keys the label's "Q E" is the rotate control, as in v7;
   the chip stays for a finger, which has no Q or E. */
@media (hover: hover) and (pointer: fine) {
    .pl-rd.pl-v3srv .rd-hands:has(.rd-hq) #planner-rotate { display: none; }
}
/* ---- the empty-base greeting (R-RD)--------------------------------------
   Today's first-visit hint, worn as the design's .emptymsg: "Empty base" over
   one line, centred in the free map band (the left/right the hint already
   keeps clear of the rail, the column and a side sheet), 44% down - 40% on
   the phone. gshell writes the two lines; it never moves or hides it. */
.pl-rd.pl-v3srv .pl-app .pl-canvas .pl-hint {
    top: 44%; bottom: auto; transform: translateY(-50%);
    display: flex; flex-direction: column; align-items: center; gap: 10px;
    background: none; border: 0; padding: 0; white-space: normal; text-align: center;
    color: var(--rd-text); text-shadow: 0 1px 3px rgba(0, 0, 0, .7);
}
.pl-rd.pl-v3srv .pl-app.rd-big .pl-canvas .pl-hint { bottom: auto; }
.pl-rd.pl-v3srv .pl-hint .rd-et { font: 600 26px/1 var(--rd-head); letter-spacing: .08em; text-transform: uppercase; }
.pl-rd.pl-v3srv .pl-hint .rd-ed { font: 500 15px/1.4 var(--rd-font); color: #C9C4BB; }
.pl-rd.pl-v3srv .pl-hint kbd {
    font: 700 11px/1 var(--rd-mono); padding: 3px 5px; border-radius: 2px; margin: 0 2px;
    color: var(--rd-text); background: #26262B; border: 1px solid rgba(255, 255, 255, .16); text-shadow: none;
}
@media (max-width: 767px), (max-height: 500px) and (max-width: 960px) {
    .pl-rd.pl-v3srv .pl-app .pl-canvas .pl-hint { top: 40%; }
    .pl-rd.pl-v3srv .pl-hint .rd-et { font-size: 20px; }
    .pl-rd.pl-v3srv .pl-hint .rd-ed { font-size: 14px; }
}
/* A message says what just happened, for a few seconds, and takes no clicks:
   while the guide is up it rises above the card (as it does over an open
   sheet) rather than being read from under it. */
.pl-rd.pl-v3srv .pl-app.rd-guiding .pl-canvas .pl-toast { z-index: 72; box-shadow: 0 6px 24px rgba(0, 0, 0, .6); }
.pl-rd.pl-v3srv .rd-guide {
    position: absolute; z-index: 70; left: 0; top: 0;
    width: calc(340px * var(--rd-uz, 1)); max-width: calc(100% - 16px); box-sizing: border-box;
    padding: calc(12px * var(--rd-uz, 1)) calc(14px * var(--rd-uz, 1));
    color: var(--rd-text); font-family: var(--rd-font); font-size: calc(14px * var(--rd-uz, 1));
    background: rgba(17, 17, 20, .98); border: 1px solid rgba(229, 163, 61, .55); border-radius: 2px;
    box-shadow: 0 18px 44px rgba(0, 0, 0, .7);
    -webkit-backdrop-filter: blur(10px); backdrop-filter: blur(10px);
    animation: rd-pin .18s ease-out;
}
/* The offer that opened by itself, beside the ? on the rail: a callout,
   its arrow pointing at the button (owner, 2026-10-12). */
.pl-rd.pl-v3srv .rd-guide.rd-gnear::before {
    content: ""; position: absolute; left: -7px; top: calc(50% - 7px);
    width: 12px; height: 12px; background: inherit; transform: rotate(45deg);
    border-left: inherit; border-bottom: inherit;
}
/* the hotbar's "›" is the phone's (its rule is in the phone block) */
.rd-hbmore { display: none; }
/* The empty-base hint steps aside while a tapped ghost waits for its ✓: it
   lay over the very piece being placed (owner, 2026-10-12). */
.pl-rd.pl-v3srv .pl-app:has(#planner-confirm:not([hidden])) .pl-canvas .pl-hint { visibility: hidden; }
/* (7) No keyboard, no key hints: the kbd chips, the ⇧1-⇧5 on the grades and
   the "(R)" in the raid sentence are for a keyboard. */
@media (hover: none) and (pointer: coarse) {
    .pl-rd.pl-v3srv .pl-app kbd,
    .pl-rd.pl-v3srv .pl-kh,
    .pl-rd.pl-v3srv .rd-hl .rd-hk,
    .pl-rd.pl-v3srv .rd-hl .rd-hq,
    .pl-rd.pl-v3srv .rd-grades .pl-tiers .pl-chip[data-rd-gk]::after { display: none; }
    .pl-rd.pl-v3srv .rd-hc .pl-chip,
    .pl-rd.pl-v3srv .rd-hc .pl-level { min-height: 44px; }
    .pl-rd.pl-v3srv .rd-hc .pl-level .pl-chip,
    .pl-rd.pl-v3srv .rd-hc .pl-level .pl-segdir-half { min-height: 44px; min-width: 44px; }
}
.pl-rd.pl-v3srv .rd-guide[hidden],
.pl-rd.pl-v3srv .rd-guide-ring[hidden] { display: none; }
.pl-rd.pl-v3srv .rd-guide.rd-away,
.pl-rd.pl-v3srv .rd-guide-ring.rd-away,
.pl-rd.pl-v3srv .rd-guide.rd-crowd,
.pl-rd.pl-v3srv .rd-guide-ring.rd-crowd { visibility: hidden; }
.pl-rd.pl-v3srv .rd-ghead { display: flex; align-items: center; gap: 8px; margin: 0 0 8px; }
.pl-rd.pl-v3srv .rd-geye {
    font: 600 calc(11.5px * var(--rd-uz, 1))/1 var(--rd-head); letter-spacing: .12em; text-transform: uppercase;
    color: var(--rd-amber);
}
.pl-rd.pl-v3srv .rd-gnum { flex: 1 1 auto; font: 600 calc(11px * var(--rd-uz, 1))/1 var(--rd-head); letter-spacing: .12em; text-transform: uppercase; color: var(--rd-amber); }
.pl-rd.pl-v3srv .rd-gx {
    flex: none; width: calc(32px * var(--rd-uz, 1)); height: calc(32px * var(--rd-uz, 1)); margin: -6px -8px -6px 0;
    display: inline-flex; align-items: center; justify-content: center;
    background: none; border: none; border-radius: 2px; color: #B5AFA6; cursor: pointer;
}
.pl-rd.pl-v3srv .rd-gx svg { width: 60%; height: 60%; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; }
.pl-rd.pl-v3srv .rd-gx:hover { color: #fff; background: rgba(255, 255, 255, .06); }
.pl-rd.pl-v3srv .rd-gbar { height: 3px; margin: 0 0 12px; background: #26262B; }
.pl-rd.pl-v3srv .rd-gbar i { display: block; height: 100%; width: 0; background: var(--rd-amber); transition: width .25s ease; }
.pl-rd.pl-v3srv .rd-gtitle {
    margin: 0 0 6px; font: 600 calc(18px * var(--rd-uz, 1))/1.15 var(--rd-head); letter-spacing: .05em;
    text-transform: uppercase; color: var(--rd-text);
}
.pl-rd.pl-v3srv .rd-gtext { margin: 0 0 14px; font: 500 1em/1.45 var(--rd-font); color: #B5AFA6; }
.pl-rd.pl-v3srv .rd-gtext kbd {
    font: 600 .8em/1 var(--rd-mono); padding: 2px 5px; border-radius: 2px; white-space: nowrap;
    color: var(--rd-text); background: rgba(255, 255, 255, .08); border: 1px solid var(--rd-line);
}
.pl-rd.pl-v3srv .rd-gfoot { display: flex; align-items: center; gap: 8px; }
.pl-rd.pl-v3srv .rd-gfoot .pl-btn {
    height: calc(34px * var(--rd-uz, 1)); margin: 0; padding: 0 calc(14px * var(--rd-uz, 1)); white-space: nowrap;
    font: 600 calc(13px * var(--rd-uz, 1))/1 var(--rd-head); letter-spacing: .1em; text-transform: uppercase;
    border-radius: 2px;
}
.pl-rd.pl-v3srv .rd-gfoot .pl-btn:not(.rd-pri) { color: #EDEAE4; background: #1F1F23; border: 1px solid rgba(255, 255, 255, .2); }
.pl-rd.pl-v3srv .rd-gfoot .pl-btn.rd-pri { color: #fff; background: var(--rd-accent); border: 1px solid var(--rd-accent); }
.pl-rd.pl-v3srv .rd-gfoot .pl-btn:focus-visible,
.pl-rd.pl-v3srv .rd-gx:focus-visible { outline: none; box-shadow: 0 0 0 3px rgba(205, 65, 43, .6); }
.pl-rd.pl-v3srv .rd-gstat { flex: 1 1 auto; font: 600 calc(13px * var(--rd-uz, 1))/1.2 var(--rd-font); color: #8A857D; }
.pl-rd.pl-v3srv .rd-gstat.rd-gok { color: #4fae6d; }
.pl-rd.pl-v3srv .rd-gsr {
    position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap;
}
.pl-rd.pl-v3srv .rd-guide-ring {
    position: absolute; z-index: 69; left: 0; top: 0; pointer-events: none; box-sizing: border-box;
    border: 2px solid var(--rd-amber); border-radius: 4px;
    box-shadow: 0 0 0 3px rgba(229, 163, 61, .22), 0 0 18px rgba(229, 163, 61, .35);
    animation: rd-ring 1.6s ease-in-out infinite;
}
@keyframes rd-ring {
    0%, 100% { box-shadow: 0 0 0 3px rgba(229, 163, 61, .22), 0 0 18px rgba(229, 163, 61, .35); }
    50% { box-shadow: 0 0 0 7px rgba(229, 163, 61, .10), 0 0 26px rgba(229, 163, 61, .5); }
}
@media (max-width: 480px) {
    .pl-rd.pl-v3srv .rd-guide { width: calc(100% - 16px); }
}
/* A phone on its side: the map is ~330px tall and its one free band, between
   the top bars and the hotbar, ~165px. The card goes wider and tighter so it
   fits that band instead of lying over the grades or the hands. */
@media (max-height: 480px) and (min-width: 600px) {
    .pl-rd.pl-v3srv .rd-guide { width: 420px; padding: 8px 12px; }
    .pl-rd.pl-v3srv .rd-ghead { margin-bottom: 4px; }
    .pl-rd.pl-v3srv .rd-gbar { margin-bottom: 8px; }
    .pl-rd.pl-v3srv .rd-gtitle { margin-bottom: 4px; font-size: 16px; }
    .pl-rd.pl-v3srv .rd-gtext { margin-bottom: 8px; line-height: 1.35; }
    .pl-rd.pl-v3srv .rd-gfoot .pl-btn { height: 32px; }
}
/* RD9: and on a REAL phone on its side the address bar leaves ~298px, so that
   band is ~140px (measured on the owner's Galaxy A53: 774x298). Wider still,
   and tighter again, so the offer ends above the hands label (136px). */
@media (max-height: 340px) and (min-width: 600px) {
    .pl-rd.pl-v3srv .rd-guide { width: 520px; padding: 5px 12px; }
    .pl-rd.pl-v3srv .rd-ghead { margin-bottom: 2px; }
    .pl-rd.pl-v3srv .rd-gbar { margin-bottom: 4px; }
    .pl-rd.pl-v3srv .rd-gtitle { margin-bottom: 2px; }
    .pl-rd.pl-v3srv .rd-gtext { margin-bottom: 6px; line-height: 1.25; }
    /* The same band holds a message (62-103) over the empty-base greeting or
       the selection bar: the greeting sits lower, and the bar's count rides
       on the row of its actions instead of taking a row of its own (the bar
       was 123px of a 140px band, and lay under the message). */
    .pl-rd.pl-v3srv .pl-app .pl-canvas .pl-hint { top: 50%; }
    .pl-rd.pl-v3srv .rd-selbar .pl-selcount { flex: 0 0 auto; }
}

@keyframes rd-sheet { from { transform: translateY(24px); opacity: 0; } to { transform: none; opacity: 1; } }
@keyframes rd-side { from { transform: translateX(28px); opacity: 0; } to { transform: none; opacity: 1; } }
@keyframes rd-drawer { from { transform: translateX(-28px); opacity: 0; } to { transform: none; opacity: 1; } }
@keyframes rd-pin { from { transform: translateX(8px); opacity: 0; } to { transform: none; opacity: 1; } }
@keyframes rd-holdfill { from { width: 0; } to { width: 100%; } }
@media (prefers-reduced-motion: reduce) {
    .pl-rd.pl-v3srv .rd-pane,
    .pl-rd.pl-v3srv .rd-pop,
    .pl-rd.pl-v3srv .rd-menu,
    .pl-rd.pl-v3srv .rd-rcol > *,
    .pl-rd.pl-v3srv .rd-guide,
    .pl-rd.pl-v3srv .rd-guide-ring { animation: none; }
}
/* RD8: the 16px iOS focus-zoom floor, off the phone frame too. An iPad at
   820 runs the DESKTOP frame and is still iOS Safari (today's page widened its
   floors to 900 for the same reason, planner.css), and one in landscape is
   wider still, so the floor also follows a coarse pointer. Measured before
   this at 820: the parts search 14px, the view-line field 13px, the rename
   field 15px. Same selectors as the rules they override, placed after them:
   a media query adds no specificity.
   ⚠ And EVERY typable control under a coarse pointer, not only these three:
   today's floors (planner.css) all stop at 900, so on an iPad in landscape
   (1180, 1366) the save name, the CopyPaste boxes, the submit form and the
   feedback form still read 12.5-14px (measured, RD8 review). The :is() line
   is (0,3,1) and beats each of those rules; the view-line field and the
   save name keep their own lines because their rd rules carry an id
   (R-RD: the save name's 14px design rule beat the :is() line on a tablet). */
@media (max-width: 900px), (pointer: coarse) {
    .pl-rd.pl-v3srv .rd-ap-search,
    .pl-rd.pl-v3srv .rd-bren input,
    .pl-rd.pl-v3srv .rd-pb #planner-save-name,
    .pl-rd.pl-v3srv .rd-pb > #planner-viewline .pl-viewline-num,
    .pl-rd.pl-v3srv :is(input:not([type=checkbox], [type=radio], [type=range], [type=file], [type=color]), textarea, select) { font-size: 16px; }
}
/* R-RD review: a touch tablet 768 px and wider (an iPad upright, or on its
   side) gets the DESKTOP frame, so the phone block's 44 px targets never
   reached it — My bases there was 34-40 px under a finger. Same selectors as
   the phone block, so equal specificity, and later in source. */
@media (pointer: coarse) {
    .pl-rd.pl-v3srv .rd-pb #planner-save-name,
    .pl-rd.pl-v3srv .rd-pb #planner-save-btn { height: 44px; }
    .pl-rd.pl-v3srv .rd-bfind { height: 44px; }
    .pl-rd.pl-v3srv .rd-pb .pl-save-row .rd-trash { width: 44px; height: 44px; }
    .pl-rd.pl-v3srv .rd-pb .pl-saves-file .pl-chip { min-height: 44px; display: inline-flex; align-items: center; }
    .pl-rd.pl-v3srv .rd-bren input,
    .pl-rd.pl-v3srv .rd-bren .pl-btn { height: 44px; }
}
