/* Yard Layout - mobile first, widening to a two column planner on larger screens. */

:root {
    /*
     * What the browser paints for itself: scrollbars, the space behind the page, the
     * spinners on a number field, the popup a <select> opens.
     *
     * It has to be declared here, against the same three states as the palette, and not
     * as a <meta> tag. The meta only knows the operating system's preference, so a reader
     * whose system is dark and who then pressed the light button on this page got a light
     * page with black scrollbars down the side of it.
     */
    color-scheme: light;
    --bg: #faf8f4;
    --surface: #ffffff;
    --ink: #22201c;
    --muted: #6f6a60;
    --line: #e3ded3;
    /* The logo's own green, taken darker. The artwork's #5A8B3E cannot carry this job,
       against the page it reaches 3.81:1 and under white label text 4.04:1, both short of
       the 4.5:1 that body-sized text needs, but the mismatch that showed once the logo
       went in was hue rather than depth: the artwork sits at hue 98 and the old accent at
       124, which is a different green rather than a deeper one. This is the artwork's hue
       and saturation held, its lightness dropped to 30%, and it clears the bar at 5.90:1
       on the page and 6.26:1 under white. */
    --accent: #456A2F;
    --accent-soft: rgba(69, 106, 47, 0.12);
    /* Text sitting on the accent, rather than #fff written out at each of its uses:
       the dark palette keeps the accent light enough that its label has to go dark. */
    --on-accent: #ffffff;
    /* Destructive. */
    --danger: #a33a2a;
    --danger-soft: rgba(163, 58, 42, 0.08);
    /* Hairline around a colour swatch, so a pale material still reads as a tile. */
    --swatch-line: rgba(34, 32, 28, 0.14);
    /*
     * The sketch is paper, in both themes.
     *
     * The canvas paints this colour itself (PAPER in planner.ts) and the box around it
     * matches, so the sheet reads as one surface. It does not darken with the rest of the
     * page: a plan is a drawing on paper, the material colours are mixed against a light
     * ground, and inverting it would make every swatch a lie about what gets built.
     */
    --paper: #f6f4f0;
    /*
     * The rest of the paper's palette, and the reason it is a separate set.
     *
     * The zoom buttons, the wall menu, the hint line and the save warning are positioned
     * over the sketch, not over the page. They inherited --ink and --muted, which in dark
     * meant pale grey text on a near-white sheet. The zoom controls were invisible, so
     * anything that sits on the paper takes its colours from here, and these are declared
     * once and never redefined by either dark block: the sheet does not change theme, so
     * neither does anything resting on it.
     */
    --paper-ink: #22201c;
    --paper-muted: #6f6a60;
    --paper-line: #e3ded3;
    --paper-surface: #ffffff;
    /* The strip that says a save was refused. It sits on the paper, so it stays light. */
    --warn-line: #d9a441;
    --warn-bg: #fdf6e6;
    --warn-ink: #6b4c12;
    --radius: 10px;
    --shadow: 0 1px 2px rgba(34, 32, 28, 0.06), 0 8px 24px rgba(34, 32, 28, 0.05);
    --shadow-pop: 0 12px 28px rgba(34, 32, 28, 0.18);
    --shadow-float: 0 6px 20px rgba(34, 32, 28, 0.18);
    --shadow-chip: 0 1px 3px rgba(34, 32, 28, 0.18);
}

/*
 * Dark. Only the tokens move; every rule below is written once, against them.
 *
 * Three blocks rather than one, because the theme has three states. An explicit choice
 * stamps data-theme on the root and must win in both directions, and the default, no
 * attribute at all, follows the operating system. The media query is therefore guarded
 * against a root that has explicitly asked for light.
 */
@media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) {
        color-scheme: dark;
        --bg: #17181a;
        --surface: #202225;
        --ink: #e8e6e1;
        --muted: #a19c93;
        --line: #34363a;
        /* The page went dark, so the accent goes the other way: the artwork's hue and
           saturation held, lightness lifted until it clears 4.5:1 on the dark ground
           instead of on the light one. Its label flips dark to match. */
        --accent: #8FBF6A;
        --accent-soft: rgba(143, 191, 106, 0.16);
        --on-accent: #14210b;
        --danger: #e08573;
        --danger-soft: rgba(224, 133, 115, 0.14);
        --swatch-line: rgba(255, 255, 255, 0.22);
        --shadow: 0 1px 2px rgba(0, 0, 0, 0.4), 0 8px 24px rgba(0, 0, 0, 0.35);
        --shadow-pop: 0 12px 28px rgba(0, 0, 0, 0.55);
        --shadow-float: 0 6px 20px rgba(0, 0, 0, 0.5);
        --shadow-chip: 0 1px 3px rgba(0, 0, 0, 0.45);
    }
}

:root[data-theme="dark"] {
    color-scheme: dark;
    --bg: #17181a;
    --surface: #202225;
    --ink: #e8e6e1;
    --muted: #a19c93;
    --line: #34363a;
    --accent: #8FBF6A;
    --accent-soft: rgba(143, 191, 106, 0.16);
    --on-accent: #14210b;
    --danger: #e08573;
    --danger-soft: rgba(224, 133, 115, 0.14);
    --swatch-line: rgba(255, 255, 255, 0.22);
    --shadow: 0 1px 2px rgba(0, 0, 0, 0.4), 0 8px 24px rgba(0, 0, 0, 0.35);
    --shadow-pop: 0 12px 28px rgba(0, 0, 0, 0.55);
    --shadow-float: 0 6px 20px rgba(0, 0, 0, 0.5);
    --shadow-chip: 0 1px 3px rgba(0, 0, 0, 0.45);
}

* {
    box-sizing: border-box;
}

/* A class rule with display beats the hidden attribute, which left the wall menu
   and the corner buttons permanently on screen, swallowing clicks. */
[hidden] {
    display: none !important;
}

html {
    -webkit-text-size-adjust: 100%;
}

body {
    margin: 0;
    background: var(--bg);
    color: var(--ink);
    font-family: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", sans-serif;
    font-size: 16px;
    line-height: 1.55;
}

h1, h2, h3 {
    line-height: 1.2;
    margin: 0 0 0.5em;
}

h1 {
    font-size: clamp(1.6rem, 4.5vw, 2.4rem);
    letter-spacing: -0.02em;
}

a {
    color: var(--accent);
}

/*
 * Placeholder text.
 *
 * Set explicitly because the browsers do not theme it: Chrome paints every placeholder a
 * fixed #757575 whatever the page is, which is 3.5:1 on the dark surface, under the 4.5:1
 * that text needs, and visibly murky. Firefox instead takes the input's own colour at 54%
 * opacity, which lands somewhere else again, so the opacity is pinned as well and both end
 * up at the one colour this palette already uses for quieter text.
 */
::placeholder {
    color: var(--muted);
    opacity: 1;
}

.wrap {
    width: 100%;
    max-width: 1440px;
    margin-inline: auto;
    padding-inline: max(16px, env(safe-area-inset-left)) max(16px, env(safe-area-inset-right));
}

.skip-link {
    position: absolute;
    left: -9999px;
}

.skip-link:focus {
    left: 8px;
    top: 8px;
    z-index: 10;
    background: var(--surface);
    padding: 8px 12px;
    border-radius: var(--radius);
}

/* The name set as the wordmark rather than in the page's own type.
 *
 * The artwork used to be laid over the words, which were left in flow at full size and
 * painted in "transparent" so it could borrow their width. That kept the sentence whole
 * for find-on-page and the clipboard, and it is why the sizing below used to be a plain
 * width:100%. It also meant the h1 carried text coloured in nothing underneath an image,
 * which is close to the wording of Google's hidden-text policy. The name lives in the
 * artwork's alt attribute now, so nothing is hidden, and the artwork is an ordinary inline
 * image that has to carry its own size.
 *
 * Both numbers come off the file. It is 1304 x 307, so 4.2476 as wide as it is tall, and
 * its baseline sits 60px up from the bottom, which is 0.195 of its height: below that line
 * there is nothing but the descender of the y. Height is set and the width follows.
 *
 * 1.22em is what the overlay measured on the page it is replacing, 1.20em in the h1,
 * 1.21em in the footer, 1.30em in a question, the spread coming from the width of the two
 * words in each place. One value for all three now that the artwork sets its own size.
 * The offset drops it by its own descender so it sits on the baseline of the line it is in
 * rather than above it. */
.brandmark {
    white-space: nowrap;
}

.brandmark__art {
    height: 1.22em;
    width: auto;
    max-width: none;
    vertical-align: -0.238em;
}

/* ---- chrome ---------------------------------------------------------- */

.site-header {
    background: var(--surface);
    border-bottom: 1px solid var(--line);
}

.site-header__inner {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    min-height: 60px;
    flex-wrap: wrap;
}

.brand {
    display: inline-flex;
    align-items: center;
    text-decoration: none;
}

/* One image, so only the height is set: the width follows the artwork instead of being
   asserted a second time here and stretching it if the artwork is ever redrawn. */
.brand__logo {
    display: block;
    height: 30px;
    width: auto;
}

/*
 * Which of the two wordmarks is showing.
 *
 * The artwork is drawn in the brand green and a near-black, and the near-black half of the
 * name disappears on a dark page. <picture> cannot do this job: its media queries see the
 * operating system's preference and know nothing about a theme chosen with the button here.
 * So both are in the markup and this decides, in the same three blocks the palette uses.
 *
 * Hiding is shared; showing is not. The header logo is a block on a line of its own, and
 * the wordmark is a word inside a sentence, putting it back as a block would drop the
 * rest of the heading onto the next line.
 */
.brandmark__art--dark,
.brand__logo--dark {
    display: none;
}

@media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) .brandmark__art--light,
    :root:not([data-theme="light"]) .brand__logo--light {
        display: none;
    }

    :root:not([data-theme="light"]) .brandmark__art--dark {
        display: inline;
    }

    :root:not([data-theme="light"]) .brand__logo--dark {
        display: block;
    }
}

:root[data-theme="dark"] .brandmark__art--light,
:root[data-theme="dark"] .brand__logo--light {
    display: none;
}

:root[data-theme="dark"] .brandmark__art--dark {
    display: inline;
}

:root[data-theme="dark"] .brand__logo--dark {
    display: block;
}

/* Forced colours needs nothing of its own here any more.

   It used to, because "transparent" is not a colour that mode keeps: the hidden words came
   back underneath the artwork, so the artwork had to stand down. There are no hidden words
   now. Forced colours leaves images alone, and the two schemes report the light and dark
   preferences the swap above already reads, High Contrast Black asks for dark and gets
   the light-inked wordmark, White asks for light and gets the dark-inked one, so the
   right one is showing on the right ground without being told. */

.site-nav {
    display: flex;
    gap: 4px;
}

.site-nav a {
    display: inline-flex;
    align-items: center;
    min-height: 44px;
    padding: 0 12px;
    border-radius: var(--radius);
    text-decoration: none;
    color: var(--muted);
    font-weight: 550;
}

.site-nav a:hover {
    background: var(--accent-soft);
    color: var(--accent);
}

/* Sits in the nav row as a third item, sized like the two links beside it. Only one of
   the two glyphs is ever shown: the one for the theme the button would switch to. */
.theme-toggle {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 44px;
    min-height: 44px;
    padding: 0;
    border: none;
    border-radius: var(--radius);
    background: none;
    color: var(--muted);
    font-size: 1.15rem;
    line-height: 1;
    cursor: pointer;
}

.theme-toggle:hover {
    background: var(--accent-soft);
    color: var(--accent);
}

/* aria-pressed carries which theme is on, so the glyphs follow it rather than needing a
   second class kept in step with it. Pressed means dark, and dark offers the sun. */
.theme-toggle__sun {
    display: none;
}

.theme-toggle[aria-pressed="true"] .theme-toggle__sun {
    display: inline;
}

.theme-toggle[aria-pressed="true"] .theme-toggle__moon {
    display: none;
}

.site-footer {
    margin-top: 48px;
    padding: 24px 0 calc(40px + env(safe-area-inset-bottom));
    border-top: 1px solid var(--line);
    color: var(--muted);
    font-size: 0.85rem;
}

.site-footer p {
    margin: 0 0 4px;
}

/* ---- intro ----------------------------------------------------------- */

/* The heading and the line under it are centred over the planner. The measure stays at
   720px, because a line of body text as wide as the sketch is a line nobody finishes,
   but a left-aligned block that narrow, above something nearly twice as wide, reads as
   having drifted off to one side rather than as sitting at the top of the page. */
.intro {
    padding-top: 28px;
    padding-bottom: 8px;
    max-width: 720px;
    margin-inline: auto;
    text-align: center;
}

/* The column is centred; the words inside it are not. A centred heading is a heading, but
   five lines of centred body text are ragged down both edges and every line starts in a
   different place, which is why the eye keeps losing them. */
.intro-lede {
    max-width: 720px;
    margin-block: 0;
    margin-inline: auto;
    color: var(--muted);
}

/* ---- planner shell --------------------------------------------------- */

.planner {
    display: grid;
    gap: 16px;
    padding-top: 20px;
    grid-template-areas:
        "stage"
        "tools"
        "totals";
}

.planner__stage {
    grid-area: stage;
    min-width: 0;
}

.planner__tools {
    grid-area: tools;
}

.planner__totals {
    grid-area: totals;
}

.panel {
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: 14px;
    padding: 14px;
    box-shadow: var(--shadow);
}

.panel__title {
    font-size: 0.8rem;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--muted);
    margin-bottom: 12px;
}

.panel__hint {
    margin: 12px 0 0;
    font-size: 0.8rem;
    color: var(--muted);
}

/* ---- action menu ------------------------------------------------------ */

/* A row of joined buttons reads as a mode switch, Replace / Add layer sits right below
   it doing exactly that, so three destructive actions in that shape looked like a
   choice of state rather than three things that happen the moment you touch them. One
   button opening a menu instead, where each item can say in a line what it takes away
   and what it leaves. */
.menu-anchor {
    position: relative;
    display: inline-flex;
}

.action-menu {
    position: fixed;
    z-index: 40;
    display: flex;
    flex-direction: column;
    gap: 2px;
    padding: 6px;
    border: 1px solid var(--line);
    border-radius: var(--radius);
    background: var(--surface);
    box-shadow: var(--shadow-pop);
}

.action-menu__item {
    display: flex;
    flex-direction: column;
    gap: 2px;
    padding: 10px 12px;
    border: none;
    border-radius: 7px;
    background: none;
    font: inherit;
    text-align: left;
    color: var(--ink);
    cursor: pointer;
}

.action-menu__item:hover {
    background: var(--accent-soft);
}

.action-menu__name {
    font-weight: 600;
    font-size: 0.92rem;
}

/* The part that answers "and what happens to the rest of my plan?" at the moment of
   the decision, rather than in a tooltip a phone never shows. */
.action-menu__note {
    font-size: 0.76rem;
    line-height: 1.35;
    color: var(--muted);
}

/* The only one that also forgets the saved plan, so it is marked as the different kind
   of thing it is. */
.action-menu__item--danger {
    margin-top: 4px;
    border-top: 1px solid var(--line);
    border-radius: 0 0 7px 7px;
    padding-top: 12px;
}

.action-menu__item--danger .action-menu__name {
    color: var(--danger);
}

.action-menu__item--danger:hover {
    background: var(--danger-soft);
}

/* A saved plan and the button that deletes it, on one line. The name takes the room and
   the × takes what is left, so a long name never pushes the delete off the edge. */
.action-menu__row {
    display: flex;
    align-items: stretch;
    gap: 2px;
}

.action-menu__row .action-menu__item {
    flex: 1;
    min-width: 0;
}

.action-menu__row .action-menu__name {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* The plan you are looking at. Not a button, because there is nowhere to switch to. */
.action-menu__row.is-active .action-menu__item {
    cursor: default;
}

.action-menu__row.is-active .action-menu__name::before {
    content: "\2713\00a0";
    color: var(--accent);
}

.action-menu__row.is-active .action-menu__item:hover {
    background: none;
}

.action-menu__delete {
    flex: none;
    width: 34px;
    border: none;
    border-radius: 7px;
    background: none;
    font-size: 1.1rem;
    line-height: 1;
    color: var(--muted);
    cursor: pointer;
}

.action-menu__delete:hover {
    background: var(--danger-soft);
    color: var(--danger);
}

.action-menu__rule {
    margin: 4px 2px;
    border: none;
    border-top: 1px solid var(--line);
}

/* Names the group of rows under it, so the examples do not read as three more saved
   plans somebody has forgotten making. */
.action-menu__heading {
    margin: 6px 10px 2px;
    font-size: 0.68rem;
    text-transform: uppercase;
    letter-spacing: 0.07em;
    color: var(--muted);
}

/* Saving is silent when it works, so the one time it does not has to say so plainly and
   keep saying it. Sits directly under the sketch, where the work it is about is. */
.save-warning {
    margin: 8px 2px 0;
    padding: 10px 12px;
    border: 1px solid var(--warn-line);
    border-left-width: 4px;
    border-radius: var(--radius);
    background: var(--warn-bg);
    font-size: 0.82rem;
    line-height: 1.45;
    color: var(--warn-ink);
}

/* ---- stage ----------------------------------------------------------- */

/* Three bars stack above the sketch and each answers one question: which plan is this,
   what is it drawn on, and what shape is the yard. Everything used to share the first
   row, a grid-size box, four exports and two menus in one undifferentiated run. */
.stage-bar {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
    margin-bottom: 10px;
}

/* Hand it over, take a copy away, throw work out. Grouped so they read as one cluster
   and can move to the far end together on a screen wide enough for the gap to say
   something. */
.stage-bar__actions {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
}

/* 16px keeps iOS from zooming the page when an input takes focus. */
input[type="number"] {
    font: inherit;
    font-size: 16px;
    width: 4.5em;
    border: none;
    background: transparent;
    color: var(--ink);
    padding: 2px 0;
    min-width: 0;
}

input[type="number"]:focus {
    outline: 2px solid var(--accent);
    outline-offset: 2px;
    border-radius: 4px;
}

.button {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-height: 44px;
    padding: 0 16px;
    border-radius: var(--radius);
    border: 1px solid var(--accent);
    background: var(--accent);
    color: var(--on-accent);
    font: inherit;
    font-weight: 550;
    text-decoration: none;
    cursor: pointer;
}

.button--ghost {
    background: var(--surface);
    color: var(--muted);
    border-color: var(--line);
}


.button--ghost:hover {
    color: var(--ink);
    border-color: var(--muted);
}

/* The one control in the stage bar, so it carries real contrast rather than the muted
   ghost it used to share with a second button beside it. */
.button--outline {
    background: var(--surface);
    color: var(--ink);
    border-color: var(--muted);
}

.button--outline:hover,
.button--outline[aria-expanded="true"] {
    color: var(--accent);
    border-color: var(--accent);
    background: var(--accent-soft);
}

/* Still the label on the View switch; the bar it was named for now sits on the sketch. */
.shape-bar__label {
    font-size: 0.72rem;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--muted);
    margin-right: 2px;
}

.chip {
    display: inline-flex;
    align-items: center;
    min-height: 40px;
    padding: 0 14px;
    border-radius: 999px;
    border: 1px solid var(--line);
    background: var(--surface);
    color: var(--ink);
    font: inherit;
    font-size: 0.85rem;
    font-weight: 550;
    cursor: pointer;
}

.chip:hover {
    border-color: var(--muted);
}

.chip.is-selected {
    background: var(--accent);
    border-color: var(--accent);
    color: var(--on-accent);
}

.chip--ghost {
    color: var(--muted);
}

/* ---- map view ---------------------------------------------------------- */

.view-bar {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px;
    margin-bottom: 10px;
}

.view-bar__find {
    display: flex;
    align-items: center;
    gap: 6px;
    flex: 1 1 260px;
    min-width: 0;
}

/* 16px for the same reason the number inputs carry it: anything smaller and iOS
   zooms the whole page when the box takes focus. */
.view-bar__find input[type="search"] {
    flex: 1 1 auto;
    min-width: 0;
    font: inherit;
    font-size: 16px;
    min-height: 44px;
    padding: 0 12px;
    border: 1px solid var(--line);
    border-radius: var(--radius);
    background: var(--surface);
    color: var(--ink);
}

.view-bar__find input[type="search"]:focus {
    outline: 2px solid var(--accent);
    outline-offset: 1px;
}

.map-bar {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    align-items: center;
    gap: 6px 16px;
    margin-bottom: 10px;
    padding: 8px 12px;
    border: 1px solid var(--line);
    border-radius: var(--radius);
    background: var(--surface);
}

.map-bar__credit {
    margin: 0;
    min-width: 0;
    font-size: 0.75rem;
    color: var(--muted);
}

.map-bar__place {
    display: block;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    color: var(--ink);
    font-weight: 550;
}

/* The Maps terms require the credit to stay visible, so it lives in the page rather
   than on the sketch, where the fade slider or a pan could carry it off. */
.map-bar__attribution {
    display: block;
}

.map-bar #map-remove {
    justify-self: end;
}

@media (max-width: 560px) {
    .map-bar {
        grid-template-columns: minmax(0, 1fr);
    }

    .map-bar #map-remove {
        justify-self: start;
    }

    /* Two chips and a search box will not share a row on a phone, and a wrapped row is
       another row of sketch below the fold. Give the box its own line deliberately. */
    .view-bar__find {
        flex-basis: 100%;
    }
}

.canvas-wrap {
    /* Matches the paper the canvas paints, so the sheet reads as one surface. */
    background: var(--paper);
    border: 1px solid var(--line);
    border-radius: 14px;
    box-shadow: var(--shadow);
    /* The canvas fills this box exactly; panning and zooming move the drawing
       inside it, so there is nothing to scroll and no edge to run into. */
    overflow: hidden;
    overscroll-behavior: contain;

    /*
     * The strip of shape buttons is absolute, and an absolute box is placed against the
     * padding box, so widening the top padding does not move the strip. It moves the
     * canvas down out from under it. That is the whole trick: the buttons used to sit on
     * top of the ruler numbers along the top edge, and now the ruler starts below them.
     *
     * The height of a chip is the only unknown, and it has exactly two values.
     */
    --sketch-bar-height: 34px;
    /* 10px above the strip, what .sketch-bar's own top says, and 8px under it. */
    --sheet-chrome: calc(18px + var(--sketch-bar-height));
    padding: var(--sheet-chrome) 8px 8px;

    /* The drawing area is what these numbers are about, so the band above it is added on
       top rather than taken out of them. The sheet is a little taller than it was besides:
       the strip stopped costing a row of drawing, so it could afford to be. */
    height: calc(min(60vh, 480px) + var(--sheet-chrome));
    height: calc(min(60dvh, 480px) + var(--sheet-chrome));
}

@media (pointer: coarse) {
    /* Matches the 44px the chips grow to for a finger. */
    .canvas-wrap {
        --sketch-bar-height: 44px;
    }
}

#plan-canvas {
    display: block;
    /* Essential: lets a finger drag paint instead of scrolling the page. */
    touch-action: none;
    -webkit-user-select: none;
    user-select: none;
    -webkit-tap-highlight-color: transparent;
    cursor: crosshair;
}

#plan-canvas.is-tracing {
    cursor: cell;
}

.stage-note {
    margin: 8px 2px 0;
    font-size: 0.8rem;
    color: var(--muted);
}

/* ---- tools ----------------------------------------------------------- */

/* The material list is long, so it scrolls inside the panel rather than running
   on down the page and pushing the sketch out of view. */
.tool-scroll {
    max-height: 46vh;
    max-height: 46dvh;
    overflow-y: auto;
}

.tool-grid {
    display: grid;
    grid-template-columns: 1fr;
    gap: 8px;
}

.tool {
    display: flex;
    align-items: center;
    gap: 10px;
    min-height: 52px;
    padding: 8px 10px;
    border: 1px solid var(--line);
    border-radius: var(--radius);
    background: var(--surface);
    font: inherit;
    color: var(--ink);
    text-align: left;
    cursor: pointer;
    min-width: 0;
}

.tool:hover {
    border-color: var(--muted);
}

.tool.is-selected {
    border-color: var(--accent);
    box-shadow: inset 0 0 0 1px var(--accent), 0 0 0 3px var(--accent-soft);
}

.tool__swatch {
    flex: none;
    width: 30px;
    height: 30px;
    border-radius: 7px;
    border: 1px solid var(--swatch-line);
    display: grid;
    place-items: center;
    font-size: 15px;
    line-height: 1;
    /* See .total-row__swatch: the glyph belongs to the sheet, not to the page. */
    color: var(--paper-ink);
}

/* A placed item paints no area, so there is no colour to swatch: the chip is the symbol
   itself, standing on nothing, the same way it stands on the sheet. It needs no ground
   under it because the symbol carries its own solid body, which is what makes it readable
   over a lawn on the drawing and over the picker's own panel here. */
.tool--point .tool__swatch {
    border: 0;
    background: none !important;
}

.tool__label {
    display: flex;
    flex-direction: column;
    min-width: 0;
}

.tool__name {
    font-weight: 550;
    font-size: 0.9rem;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.tool__meta {
    font-size: 0.72rem;
    color: var(--muted);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* ---- totals ---------------------------------------------------------- */

.totals__empty {
    margin: 0;
    color: var(--muted);
    font-size: 0.9rem;
}

.total-row {
    display: grid;
    grid-template-columns: 24px minmax(0, 1fr) auto;
    gap: 10px;
    align-items: start;
    padding: 10px 0;
    border-bottom: 1px solid var(--line);
}

.total-row__swatch {
    width: 22px;
    height: 22px;
    border-radius: 6px;
    border: 1px solid var(--swatch-line);
    display: grid;
    place-items: center;
    font-size: 12px;
    margin-top: 2px;
    /* A swatch is the colour the material paints on the sheet, and the symbol on it is
       drawn the same way there, so it takes the paper's ink rather than the page's,
       inheriting --ink put a pale glyph on a near-white eraser swatch in dark. */
    color: var(--paper-ink);
}

/* A placed item has no fill colour on the sheet: it is a white disc with a symbol on it.
   The row says the same thing, which also keeps the symbol readable, since most of the
   colours these materials carry are too dark to draw ink on. */
.total-row__swatch--point {
    border: 0;
    background: none;
}

.total-row__name {
    font-weight: 550;
    font-size: 0.92rem;
}

.total-row__qty {
    font-size: 0.8rem;
    color: var(--muted);
}

.total-row__cost {
    font-variant-numeric: tabular-nums;
    font-size: 0.85rem;
    font-weight: 550;
    white-space: nowrap;
    text-align: right;
}

.depth-field {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    margin-top: 6px;
    font-size: 0.78rem;
    color: var(--muted);
    border: 1px solid var(--line);
    border-radius: 8px;
    padding: 2px 8px;
    min-height: 36px;
}

.depth-field input {
    width: 3.6em;
}

.totals__grand {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 12px;
    padding-top: 12px;
}

.totals__grand-label {
    font-size: 0.8rem;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--muted);
}

.totals__grand-value {
    font-size: 1.05rem;
    font-weight: 650;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

.totals__disclaimer {
    margin: 6px 0 0;
    font-size: 0.74rem;
    color: var(--muted);
}

/* ---- reference & prose ----------------------------------------------- */

.notice {
    margin-top: 16px;
    padding: 12px 16px;
    border: 1px solid var(--line);
    border-radius: var(--radius);
    background: var(--surface);
}

.reference {
    margin-top: 40px;
}

.reference__note {
    color: var(--muted);
    font-size: 0.88rem;
    margin-top: 0;
}

.table-scroll {
    overflow-x: auto;
    border: 1px solid var(--line);
    border-radius: 14px;
    background: var(--surface);
}

.reference__table {
    border-collapse: collapse;
    width: 100%;
    min-width: 520px;
    font-size: 0.88rem;
}

.reference__table th,
.reference__table td {
    text-align: left;
    padding: 10px 14px;
    border-bottom: 1px solid var(--line);
    font-weight: 400;
    white-space: nowrap;
}

.reference__table thead th {
    font-size: 0.74rem;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--muted);
    font-weight: 600;
}

.reference__table tbody th {
    font-weight: 550;
}

.reference__table tbody tr:last-child th,
.reference__table tbody tr:last-child td {
    border-bottom: none;
}

.swatch {
    display: inline-block;
    width: 14px;
    height: 14px;
    border-radius: 4px;
    border: 1px solid var(--swatch-line);
    vertical-align: -2px;
    margin-right: 6px;
}

.prose {
    padding-top: 28px;
    max-width: 720px;
}

.prose p {
    color: var(--muted);
}

.prose h2 {
    font-size: 1.15rem;
    margin-top: 30px;
}

.guide-list {
    list-style: none;
    padding: 0;
    margin: 24px 0;
    display: grid;
    gap: 12px;
}

.guide-list li {
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: 14px;
    padding: 16px;
}

/* The library is grouped, so a card's own heading sits a level below the group's. */
.guide-list h2,
.guide-list h3 {
    font-size: 1.05rem;
    margin-bottom: 4px;
}

.guide-group {
    margin-top: 32px;
    font-size: 0.78rem;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--muted);
}

.guide-group + .guide-list {
    margin-top: 12px;
}

.guide-list p {
    margin: 0;
    font-size: 0.9rem;
}

.guide-list__status {
    margin-top: 8px !important;
    font-size: 0.72rem !important;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--accent);
}

/* ---- wide screens ---------------------------------------------------- */

@media (min-width: 900px) {
    /* Far more room for the sketch once there is a second column. The band the button
       strip sits in is added on top, as everywhere: these numbers are the drawing. */
    .canvas-wrap {
        height: calc(min(78vh, 880px) + var(--sheet-chrome));
        height: calc(min(78dvh, 880px) + var(--sheet-chrome));
    }

    .planner {
        grid-template-columns: minmax(0, 1fr) 340px;
        grid-template-rows: auto 1fr;
        align-items: start;
        grid-template-areas:
            "stage tools"
            "stage totals";
    }

    /* The two right-hand panels together match the sketch, and each scrolls inside
       itself, so the material list never pushes the sketch off the screen. */
    .planner__tools {
        display: flex;
        flex-direction: column;
        /*
         * The two panels split the column roughly evenly, and together they come to about
         * the height of the sketch beside them.
         *
         * The materials used to take twice the room the totals did, which had the totals
         * showing a row and a half: the one number the whole site exists to produce,
         * behind a scrollbar. The list of materials is a picker that scrolls by design and
         * loses nothing by being shorter; the totals are the answer, and are read.
         */
        max-height: min(40vh, 440px);
        max-height: min(40dvh, 440px);
    }

    .tool-scroll {
        flex: 1;
        overscroll-behavior: contain;
        /* The column's own height decides this now, not the phone cap. */
        max-height: none;
        min-height: 0;
        /* Room for the scrollbar so the chips do not sit under it. */
        padding-right: 4px;
    }

    .planner__totals {
        display: flex;
        flex-direction: column;
        /* See .planner__tools above for why these two are the size they are. A cap, not a
           height: a plan with two materials on it makes a short panel rather than a tall
           one with a hole in the bottom.

           The larger share, because the rows here are not a uniform height. A material
           bought by the yard carries a depth box and the bagged-against-bulk comparison,
           which is 200px of row on its own against 60px for a tree. */
        max-height: min(54vh, 580px);
        max-height: min(54dvh, 580px);
    }

    .planner__totals > div {
        flex: 1;
        min-height: 0;
        overflow-y: auto;
        overscroll-behavior: contain;
        padding-right: 4px;
    }

    /* The heading used to be pinned to the left edge here, flush with the sketch below it.
       On a wide screen that put a 720px column against the left of a 1440px page, which
       read as text that had slid off to one side rather than as a heading. It centres over
       the planner now; the auto margins on the base rules are all that is needed for that,
       so the override that used to sit here is gone rather than set back to auto. */

    /* Puts the gap between the plan you have open and the things you can do to it. On a
       phone the row wraps, and an auto margin there just strands them at opposite ends
       of their lines. */
    .stage-bar__actions {
        margin-left: auto;
    }
}

.mode-bar {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    margin-bottom: 10px;
}

.mode-bar .chip {
    flex: 1 1 auto;
    justify-content: center;
    min-height: 38px;
}

.seg {
    display: inline-flex;
    gap: 0;
}

.seg .chip:first-child {
    border-top-right-radius: 0;
    border-bottom-right-radius: 0;
}

.seg .chip:last-child {
    border-top-left-radius: 0;
    border-bottom-left-radius: 0;
    margin-left: -1px;
}

.chip:disabled {
    opacity: 0.4;
    cursor: default;
}

/* Sits under the sketch on every width now, so the margin is above it rather than
   below. */
.shape-help {
    margin: 12px 2px 0;
    font-size: 0.78rem;
    color: var(--muted);
}

/* ---- on-canvas controls ---------------------------------------------- */

.canvas-wrap {
    position: relative;
}

.canvas-hint {
    position: absolute;
    left: 10px;
    bottom: 10px;
    margin: 0;
    max-width: calc(100% - 76px);
    padding: 5px 10px;
    border-radius: 999px;
    background: rgba(255, 255, 255, 0.9);
    border: 1px solid var(--paper-line);
    font-size: 0.76rem;
    color: var(--paper-muted);
    pointer-events: none;
}

.canvas-actions {
    position: absolute;
    top: 10px;
    right: 10px;
    display: flex;
    gap: 6px;
    /* Above the sketch bar in the other corner: on a narrow sheet the two can meet, and
       the buttons that finish a half-drawn shape are the more urgent of the pair. */
    z-index: 6;
}

/* ---- the sketch bar ----------------------------------------------------- */

/*
 * What shape the yard is, undo and redo, and the size of a square, sitting on the
 * drawing they act on rather than in three rows of chrome above it. It takes the paper's
 * palette, not the page's: the sheet stays light when the site goes dark.
 *
 * The whole strip is absolute, because the canvas is measured from the box it is in.
 */
/*
 * The rail the strip runs in. It holds the position the strip used to hold itself, and it
 * is what everything that must not slide is pinned to: the two arrows, and Clear.
 *
 * The track takes whatever width Clear leaves and the strip scrolls inside it, so Clear
 * keeps its place at the end however far along the tools have been pushed.
 */
.sketch-rail {
    position: absolute;
    top: 10px;
    left: 10px;
    z-index: 5;
    /* Room for the corner actions in the other corner before this reaches them. */
    max-width: calc(100% - 130px);
    display: flex;
    align-items: center;
    gap: 8px;
}

.sketch-rail__track {
    /* What the arrows are positioned against. */
    position: relative;
    /* Shrinks to fit beside Clear; min-width is what actually lets it, since a scroll
       container's own contents would otherwise hold it open at its full width. */
    flex: 0 1 auto;
    min-width: 0;
}

/* Clear never shrinks and never scrolls away. It is the one thing here somebody needs to
   be able to reach without first discovering that the row beside it moves. */
.sketch-rail__pin {
    flex: 0 0 auto;
}

/*
 * An arrow at whichever end still has buttons behind it. The fade says something is cut
 * off; this says which way to go for it, and goes there when pressed.
 *
 * Over the faded end rather than beside it: there is no room beside it on a phone, and
 * the chip it covers is the one too clipped to read anyway.
 */
.rail-arrow {
    position: absolute;
    top: 0;
    bottom: 0;
    z-index: 1;
    width: 30px;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 0;
    border: 1px solid var(--paper-line);
    border-radius: 999px;
    background: rgba(255, 255, 255, 0.97);
    color: var(--paper-ink);
    font: inherit;
    font-size: 1.1rem;
    line-height: 1;
    cursor: pointer;
    box-shadow: 0 1px 4px rgba(34, 32, 28, 0.2);
}

.rail-arrow--left {
    left: -4px;
}

/* Only 2px over the end here: the rail's gap and then Clear are just beyond it. */
.rail-arrow--right {
    right: -2px;
}

.rail-arrow:hover {
    border-color: var(--accent);
    color: var(--accent);
}

.sketch-bar {
    display: flex;
    align-items: center;
    gap: 6px;

    /*
     * It used to be transparent to the pointer, so that a drag starting between two chips
     * drew on the sketch underneath instead of dying on an invisible strip of toolbar.
     * There is no sketch underneath any more: the strip sits in the band of padding
     * above the canvas, so the whole strip takes the pointer, and the gaps between the
     * chips are somewhere to put a thumb and push the row along.
     */
    pointer-events: auto;

    /*
     * One row, at every width, sliding sideways when it does not fit. Two reasons, and
     * the second is the load-bearing one:
     *
     * A wrapped row costs a line of page, and on the sheet it costs a line of drawing.
     * But the sheet also reserves a band of its top padding for this strip, so the ruler
     * starts underneath it rather than behind it, and that band is a fixed height. A
     * strip that could wrap would grow back over the numbers it was moved off.
     *
     * The vertical padding is here because clipping one axis clips both, and the chips'
     * shadows and focus rings live in it; the negative margin hands the same amount back,
     * so the strip still sits where --sketch-bar-height says it does.
     */
    flex-wrap: nowrap;
    overflow-x: auto;
    overflow-y: hidden;
    overscroll-behavior-x: contain;
    /* Safe to pin down in a way it would not be on a row in the page: this strip sits on
       the canvas, which takes no scroll gesture of its own anyway. */
    touch-action: pan-x;
    padding-block: 6px;
    margin-block: -6px;
    scrollbar-width: none;
}

.sketch-bar::-webkit-scrollbar {
    display: none;
}

/*
 * ---- telling a row that slides from a row that just ends ----
 *
 * Cut off by the edge of its box, a sliding row looks exactly like a row that stops
 * there, and on a phone that is the difference between finding Clear and never knowing
 * it was there. A mobile browser is no help: its scrollbar only appears while a scroll is
 * already happening, which is after the moment that needed the hint.
 *
 * So the end that has something behind it fades out. The planner sets the two lengths as
 * the row is scrolled, so only the side with more beyond it fades; at 0 both stops
 * collapse onto the ends and the gradient is a flat opaque fill, which is to say the mask
 * costs nothing at all on a row that fits.
 *
 * Deliberately not on .stage-bar: the dropdowns hang off that one, they are positioned
 * against the viewport, and a mask is the kind of property that has been known to make an
 * element a containing block for them. Its overflow is a few pixels anyway.
 */
.sketch-bar,
.mode-bar {
    --fade-left: 0px;
    --fade-right: 0px;
    -webkit-mask-image: linear-gradient(to right,
        transparent 0, #000 var(--fade-left),
        #000 calc(100% - var(--fade-right)), transparent 100%);
    mask-image: linear-gradient(to right,
        transparent 0, #000 var(--fade-left),
        #000 calc(100% - var(--fade-right)), transparent 100%);
}

/* Reads as one of the utilities, not as another thing to draw with. */
.chip--warn {
    color: var(--paper-muted);
}

.sketch-bar > * {
    flex: 0 0 auto;
}

/* Shapes, then the two history buttons, then the grid size: each set stays together
   as the strip slides. */
.sketch-bar__group {
    display: flex;
    align-items: center;
    gap: 4px;
}

/* A chip on the paper. Same shape as the ones in the panel, but drawn in the sketch's
   own colours and lifted off the grid it is sitting on. */
.chip--paper {
    min-height: 34px;
    padding: 0 12px;
    font-size: 0.8rem;
    border-color: var(--paper-line);
    background: rgba(255, 255, 255, 0.94);
    color: var(--paper-ink);
    box-shadow: 0 1px 3px rgba(34, 32, 28, 0.14);
}

.chip--paper:hover {
    border-color: var(--paper-muted);
}

.chip--paper.is-selected {
    background: var(--accent);
    border-color: var(--accent);
    color: var(--on-accent);
}

/* Square, like the zoom buttons in the opposite corner, because they are the same kind
   of thing: one tap, no state to read. */
.sketch-btn {
    width: 34px;
    height: 34px;
    border-radius: 9px;
    border: 1px solid var(--paper-line);
    background: rgba(255, 255, 255, 0.94);
    color: var(--paper-ink);
    font: inherit;
    font-size: 1.05rem;
    line-height: 1;
    cursor: pointer;
    box-shadow: 0 1px 3px rgba(34, 32, 28, 0.14);
}

.sketch-btn:hover:not(:disabled) {
    border-color: var(--paper-muted);
}

.sketch-btn:disabled {
    opacity: 0.4;
    cursor: default;
}

/* How finely the yard is measured. A setting rather than an action, so it is the one
   thing here that is not a button, and it is last. */
.sketch-field {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    min-height: 34px;
    padding: 0 10px;
    border-radius: 999px;
    border: 1px solid var(--paper-line);
    background: rgba(255, 255, 255, 0.94);
    box-shadow: 0 1px 3px rgba(34, 32, 28, 0.14);
}

.sketch-field__label,
.sketch-field__unit {
    font-size: 0.78rem;
    color: var(--paper-muted);
}

.sketch-field__label {
    font-weight: 550;
}

/* Narrower than the page's number boxes, nobody types four digits into a grid size,
   and in the paper's ink rather than the page's. */
.sketch-field input[type="number"] {
    width: 3.2em;
    color: var(--paper-ink);
    text-align: right;
}

/* ---- the blank sheet ---------------------------------------------------- */

/*
 * What a first-time visitor is offered instead of empty graph paper.
 *
 * Centred over the sheet, but deliberately transparent to the pointer: only the buttons
 * catch it, so a drag that starts on open paper still draws a rectangle underneath this.
 * It takes the paper's palette rather than the page's, for the same reason the zoom
 * buttons do: it is sitting on the drawing, and the drawing does not change theme.
 */
.empty-start {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    z-index: 4;
    width: min(340px, calc(100% - 32px));
    padding: 16px;
    border-radius: 14px;
    border: 1px solid var(--paper-line);
    background: rgba(255, 255, 255, 0.94);
    box-shadow: var(--shadow-float);
    text-align: center;
    pointer-events: none;
}

.empty-start__lead {
    margin: 0 0 10px;
    font-size: 0.72rem;
    font-weight: 650;
    text-transform: uppercase;
    letter-spacing: 0.07em;
    color: var(--paper-muted);
}

.empty-start__list {
    display: grid;
    gap: 6px;
}

.empty-start__item {
    display: block;
    width: 100%;
    padding: 9px 12px;
    border: 1px solid var(--paper-line);
    border-radius: var(--radius);
    background: var(--paper-surface);
    font: inherit;
    text-align: left;
    cursor: pointer;
    /* The one thing here that does take the pointer. */
    pointer-events: auto;
}

.empty-start__item:hover {
    border-color: var(--accent);
    background: var(--accent-soft);
}

.empty-start__name {
    display: block;
    font-size: 0.9rem;
    font-weight: 600;
    color: var(--paper-ink);
}

.empty-start__note {
    display: block;
    margin-top: 1px;
    font-size: 0.75rem;
    line-height: 1.35;
    color: var(--paper-muted);
}

.empty-start__or {
    margin: 10px 0 0;
    font-size: 0.75rem;
    color: var(--paper-muted);
}

.canvas-btn {
    min-height: 36px;
    padding: 0 14px;
    border-radius: 999px;
    border: 1px solid var(--accent);
    background: var(--accent);
    color: #fff;
    font: inherit;
    font-size: 0.82rem;
    font-weight: 550;
    cursor: pointer;
    box-shadow: var(--shadow-chip);
}

.canvas-btn--quiet {
    background: var(--paper-surface);
    border-color: var(--paper-line);
    color: var(--paper-muted);
}

/* Sits at the tapped wall, like the reference sketch's context menu. */
.wall-menu {
    position: absolute;
    z-index: 6;
    display: flex;
    flex-direction: column;
    min-width: 132px;
    padding: 4px;
    border-radius: 10px;
    border: 1px solid var(--paper-line);
    background: var(--paper-surface);
    box-shadow: var(--shadow-float);
    transform: translate(-50%, -50%);
}

.wall-menu__item {
    appearance: none;
    border: none;
    background: none;
    font: inherit;
    font-size: 0.85rem;
    text-align: left;
    padding: 9px 12px;
    border-radius: 7px;
    color: var(--paper-ink);
    cursor: pointer;
    min-height: 40px;
}

.wall-menu__item:hover {
    background: var(--accent-soft);
    color: var(--accent);
}

/* Something under the pointer can be dragged. */
#plan-canvas.is-grabbable {
    cursor: grab;
}

#plan-canvas.is-grabbable:active {
    cursor: grabbing;
}

/*
 * The corner column: the one-time tip, then the zoom buttons under it. They share a
 * wrapper so the tip lands directly above the Full button without anyone having to know
 * how tall the button stack is, which differs between a mouse and a finger.
 *
 * Transparent to the pointer, like the strip in the other corner: the tip is wider than
 * the buttons, and the paper beside them stays paper.
 */
.zoom-stack {
    position: absolute;
    right: 10px;
    bottom: 10px;
    z-index: 5;
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    gap: 8px;
    pointer-events: none;
}

.zoom-stack > * {
    pointer-events: auto;
}

.zoom-bar {
    display: flex;
    flex-direction: column;
    gap: 4px;
}

/*
 * Said once, on the sheet, next to the thing it is about, rather than as another line
 * of help under the sketch that nobody reads on a phone. It takes the paper's palette
 * for the same reason the buttons below it do: it is sitting on the drawing.
 */
.fs-tip {
    width: min(230px, calc(100vw - 60px));
    padding: 10px 12px 8px;
    border-radius: 12px;
    border: 1px solid var(--paper-line);
    background: rgba(255, 255, 255, 0.97);
    box-shadow: var(--shadow-float);
    /* The pointer at the Full button underneath. Drawn as a rotated corner of the bubble
       so it carries the same border and background without a second element. */
    position: relative;
}

.fs-tip::after {
    content: "";
    position: absolute;
    right: 14px;
    bottom: -5px;
    width: 9px;
    height: 9px;
    transform: rotate(45deg);
    border-right: 1px solid var(--paper-line);
    border-bottom: 1px solid var(--paper-line);
    background: rgba(255, 255, 255, 0.97);
}

.fs-tip__text {
    margin: 0;
    font-size: 0.78rem;
    line-height: 1.4;
    color: var(--paper-muted);
}

.fs-tip__text strong {
    color: var(--paper-ink);
}

.fs-tip__dismiss {
    display: block;
    margin: 8px 0 0 auto;
    padding: 4px 10px;
    border: 1px solid var(--paper-line);
    border-radius: 999px;
    background: var(--paper-surface);
    font: inherit;
    font-size: 0.75rem;
    font-weight: 550;
    color: var(--paper-ink);
    cursor: pointer;
}

.fs-tip__dismiss:hover {
    border-color: var(--accent);
    color: var(--accent);
}

.zoom-btn {
    width: 38px;
    height: 38px;
    border-radius: 9px;
    border: 1px solid var(--paper-line);
    background: rgba(255, 255, 255, 0.94);
    color: var(--paper-ink);
    font: inherit;
    font-size: 1rem;
    line-height: 1;
    cursor: pointer;
    box-shadow: 0 1px 3px rgba(34, 32, 28, 0.14);
}

.zoom-btn--fit,
.zoom-btn--full {
    font-size: 0.72rem;
}

/* On, and the way back off. It is the only button in the corner that latches, so it
   says so rather than looking like the three beside it. */
.zoom-btn--full[aria-pressed="true"] {
    border-color: var(--accent);
    background: var(--accent);
    color: #fff;
}

.zoom-btn:hover {
    border-color: var(--paper-muted);
}

#plan-canvas.is-panning {
    cursor: grabbing;
}

/* In shape-editing mode the sheet itself can be dragged around. */
#plan-canvas.is-editing {
    cursor: grab;
}

.wave-fields {
    display: grid;
    gap: 4px;
    margin-bottom: 10px;
}

.wave-field {
    display: flex;
    align-items: center;
    gap: 8px;
    font-size: 0.8rem;
    color: var(--muted);
}

.wave-field > span:first-child {
    min-width: 3.6em;
}

.wave-field input[type="range"] {
    flex: 1;
    min-width: 0;
    accent-color: var(--accent);
}

.wave-field__value {
    min-width: 3.2em;
    text-align: right;
    font-variant-numeric: tabular-nums;
    color: var(--ink);
    font-weight: 550;
}

/* ---- grouped material picker ------------------------------------------ */

.tool-group {
    border: 1px solid var(--line);
    border-radius: var(--radius);
    background: var(--surface);
}

.tool-group__head {
    border-radius: var(--radius);
}

.tool-group.holds-selection {
    border-color: var(--accent);
}

.tool-group__head {
    display: flex;
    align-items: center;
    gap: 10px;
    width: 100%;
    min-height: 52px;
    padding: 8px 10px;
    border: none;
    background: none;
    font: inherit;
    color: var(--ink);
    text-align: left;
    cursor: pointer;
}

.tool-group__head:hover {
    background: var(--accent-soft);
}

.tool-group__swatches {
    display: flex;
    flex: none;
}

.tool-group__chip {
    width: 18px;
    height: 30px;
    border: 1px solid var(--swatch-line);
    margin-right: -6px;
    border-radius: 5px;
}

.tool-group__chip:first-child {
    border-radius: 7px 5px 5px 7px;
}

.tool-group__chip:last-child {
    margin-right: 0;
    border-radius: 5px 7px 7px 5px;
}

.tool-group__label {
    display: flex;
    flex: 1;
    min-width: 0;
    flex-direction: column;
}

.tool-group__name {
    font-weight: 550;
    font-size: 0.9rem;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.tool-group__pick {
    font-size: 0.72rem;
    color: var(--accent);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.tool-group__count {
    flex: none;
    font-size: 0.72rem;
    color: var(--muted);
    background: var(--bg);
    border-radius: 999px;
    padding: 1px 7px;
}

.tool-group.is-open .tool-group__head,
.tool-group__head[aria-expanded="true"] {
    background: var(--accent-soft);
}

.tool-group__head[aria-expanded="true"] .tool-group__count {
    background: var(--accent-soft);
    color: var(--accent);
}

.tool-group__items {
    position: fixed;
    z-index: 40;
    display: grid;
    gap: 6px;
    padding: 8px;
    max-height: min(52vh, 420px);
    max-height: min(52dvh, 420px);
    overflow-y: auto;
    overscroll-behavior: contain;
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: var(--radius);
    box-shadow: var(--shadow-pop);
}

/* Inside a group the border would double up with the group's own. */
.tool-group__items .tool {
    border-color: transparent;
    background: var(--bg);
}

.tool-group__items .tool.is-selected {
    background: var(--surface);
}

.mode-bar__label {
    align-self: center;
    font-size: 0.72rem;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--muted);
    margin-right: 2px;
}

/* ---- phones ----------------------------------------------------------- */

@media (max-width: 899px) {
    /* The sketch is what someone came for, so it goes directly under the shape
       buttons and the paragraph explaining them moves below it. */
    .planner__stage {
        display: flex;
        flex-direction: column;
    }

    .canvas-wrap {
        flex: none;
    }

    /* The base rule already puts it under the sketch; this keeps it below the material
       controls that move up here on a phone. */
    .shape-help {
        order: 1;
    }

    /* The photo's own controls follow the help text below the sketch, and for the same
       reason: 200px of sliders above it puts the sketch itself under the fold. */
    .map-bar {
        order: 1;
        margin: 10px 2px 0;
    }

    /* Every pixel above the sketch is a pixel of sketch below the fold. The heading is
       the only thing that sits above it, and it says so rather than relying on the
       default: an unnumbered child sorts to the front, not the back. */
    .intro {
        order: 0;
        padding-top: 20px;
    }

    /* The planner is what the page is for, so on a phone it comes before the
       paragraph describing it. The DOM order is unchanged. */
    main {
        display: flex;
        flex-direction: column;
    }

    .planner {
        order: 1;
        padding-top: 14px;
    }

    .ad-slot[data-ad-placement="planner-bottom"] {
        order: 2;
    }

    .intro-lede {
        order: 3;
        margin-top: 24px;
    }

    noscript,
    .reference {
        order: 4;
    }

    /* Left out of this list, the questions defaulted to order 0 and sorted above
       everything numbered, which landed them between the heading and the sketch. */
    .faq {
        order: 5;
    }

    /* Last, after the content, exactly as it falls on a wide screen. */
    .ad-slot[data-ad-placement="content-bottom"] {
        order: 6;
    }

    /*
     * ---- rows that slide instead of wrapping ----
     *
     * A row of buttons that wraps costs a whole extra line of page, and on a phone
     * every one of those lines is a line of sketch pushed below the fold. It is worse
     * on the sheet itself, where the second row of shape buttons sat on the drawing.
     *
     * So none of these wrap. Each is one line that slides sideways, which is what the
     * material picker underneath has always done. The vertical padding is there because
     * clipping one axis clips both, and a chip's shadow and focus ring live in it; the
     * negative margin hands the same amount back, so every row still sits where it did.
     */
    .stage-bar,
    .stage-bar__actions,
    .mode-bar {
        flex-wrap: nowrap;
    }

    .stage-bar,
    .mode-bar {
        overflow-x: auto;
        overflow-y: hidden;
        /* A flick past the end of the row should not become the browser's back gesture,
           or the page moving under it. */
        overscroll-behavior-x: contain;
        padding-block: 6px;
        margin-block: -6px 4px;
    }

    /* Nothing may shrink to fit here: squeezing a chip is how a row that cannot wrap
       hides the word written on it. */
    .stage-bar > *,
    .stage-bar__actions > *,
    .mode-bar > * {
        flex: 0 0 auto;
    }

    /* The strip on the paper gets this at every width, see .sketch-bar, because the
       sheet reserves a fixed band of padding for it. */

    /* A scrollbar under four buttons is most of a row spent on the bar. These rows are
       short, and the half-shown chip at the edge says the same thing for nothing. */
    .stage-bar,
    .mode-bar {
        scrollbar-width: none;
    }

    .stage-bar::-webkit-scrollbar,
    .mode-bar::-webkit-scrollbar {
        display: none;
    }
}

/* A phone held sideways has very little height, and the sketch was getting the
   worst of it. */
@media (max-width: 899px) and (orientation: landscape) {
    .intro {
        padding-top: 14px;
    }

    .canvas-wrap {
        height: calc(min(72vh, 420px) + var(--sheet-chrome));
        height: calc(min(72dvh, 420px) + var(--sheet-chrome));
    }

    .tool-scroll {
        max-height: 62vh;
        max-height: 62dvh;
    }
}

/* ---- touch targets ---------------------------------------------------- */

/* A finger is about 44px wide. These controls were sized for a cursor. */
@media (pointer: coarse) {
    .chip,
    .mode-bar .chip,
    .canvas-btn,
    .wall-menu__item,
    .depth-field,
    .fs-tip__dismiss {
        min-height: 44px;
    }

    .zoom-btn,
    .sketch-btn {
        width: 44px;
        height: 44px;
    }

    .wave-field input[type="range"] {
        height: 44px;
    }

    .brand {
        min-height: 44px;
    }

    .site-footer a {
        display: inline-block;
        padding: 10px 0;
    }

    /* The box was 44px but the input inside it was 29px, so most of the
       control was not actually tappable. */
    .sketch-field {
        padding-block: 0;
        min-height: 44px;
    }

    .sketch-field input[type="number"] {
        align-self: stretch;
    }
}

@media (max-width: 560px) {
    /* Sharing a row with the chips, this label pushed them onto a fourth line.
       On its own line it costs 18px and saves about 90. */
    .shape-bar__label {
        flex-basis: 100%;
        margin-bottom: -2px;
    }

    /* Nothing sits in the far corner on a sheet this narrow until a shape is half
       drawn, and the corner actions are stacked above this anyway. */
    .sketch-rail {
        max-width: calc(100% - 20px);
    }
}

/* Ad units. Kept well away from the sketch and the tool panel: an ad next to a
   control someone is dragging is both an AdSense placement violation and a way
   to lose the click they meant to make. */
.ad-slot {
    display: block;
    max-width: 970px;
    margin: 32px auto 0;
    text-align: center;
}

.ad-slot__label {
    display: block;
    margin-bottom: 6px;
    font-size: 0.7rem;
    letter-spacing: 0.09em;
    text-transform: uppercase;
    color: var(--muted);
}

/* Reserving the height stops a late-arriving ad from shoving the page down
   under someone's finger. */
.ad-slot .adsbygoogle {
    display: block;
    min-height: 100px;
}

/* Google reports an unsold unit by stamping the <ins>; collapse the label with
   it rather than leaving a labelled blank. */
.ad-slot:has(.adsbygoogle[data-ad-status="unfilled"]) {
    display: none;
}

/* ---- material strip (phones) ------------------------------------------ */

/* Empty and out of the way on a wide screen: the picker only moves in here when the
   layout goes single column. */
.material-bar {
    display: none;
}

@media (max-width: 899px) {
    /* Picker first, then how the armed material goes down: one cluster under the sketch
       instead of the paint modes sitting a paragraph of help further down the page. */
    .material-bar {
        display: flex;
        flex-direction: column;
        gap: 10px;
        min-width: 0;
        margin-top: 10px;
    }

    /* The column's gap spaces these; their own margin would double it. The mode bars
       keep the -6px that pays for the padding holding their focus rings. */
    .material-bar .wave-fields {
        margin-bottom: 0;
    }

    .material-bar .mode-bar {
        margin-block: -6px;
    }

    /* One row that scrolls sideways, sitting right under the sketch. Down the page in
       the tools panel it was a scroll away, and every pick meant scrolling back up to
       see what it did. */
    .material-bar .tool-grid {
        display: flex;
        min-width: 0;
        max-width: 100%;
        gap: 8px;
        overflow-x: auto;
        padding-bottom: 4px;
        overscroll-behavior-x: contain;
        scrollbar-width: thin;
    }

    .material-bar .tool-group,
    .material-bar .tool {
        flex: 0 0 auto;
        max-width: 60vw;
    }

    .material-bar .tool-group__head,
    .material-bar .tool {
        min-height: 52px;
        white-space: nowrap;
    }

    /* Prices belong in the dropdown and the reference table, not in a row that has to
       stay narrow enough to fit several materials on screen at once. */
    .material-bar > .tool-grid > .tool .tool__meta {
        display: none;
    }

    /* The panel keeps the paint modes and the help text, but its heading would now sit
       above an empty space where the picker used to be. Moved off screen rather than
       removed, so the section still announces itself to a screen reader. */
    .planner__tools .panel__title {
        position: absolute;
        left: -9999px;
    }

    .tool-scroll {
        max-height: none;
        overflow-y: visible;
    }
}

/* ---- full screen ------------------------------------------------------- */

/*
 * The sketch is the whole point of the page and it was getting 58vh of it, with a
 * heading, three bars and an ad taking the rest. Full screen hands the viewport over to
 * the planner: same markup, same controls, no page around it.
 *
 * Fixed rather than the Fullscreen API alone, because iOS Safari will not put a plain
 * element into real fullscreen at all. The planner asks for the native one too where it
 * exists, since that is what folds the browser's own chrome away, but this is what actually
 * does the resizing, so both paths land in the same place.
 */
.planner.is-fullscreen {
    position: fixed;
    inset: 0;
    z-index: 60;
    margin: 0;
    max-width: none;
    /* A phone on its side puts the notch beside the sheet, and the home indicator
       under it. The 8px is the floor, not the answer. */
    padding: 8px max(8px, env(safe-area-inset-right)) max(8px, env(safe-area-inset-bottom))
             max(8px, env(safe-area-inset-left));
    gap: 8px;
    background: var(--bg);
    overflow: hidden;
}

.planner.is-fullscreen .planner__stage {
    display: flex;
    flex-direction: column;
    /* Without this the sketch below cannot give the column back any height it asks
       for, and a tall yard pushes the bottom of the sheet off the screen. */
    min-height: 0;
}

/* The whole reason for the mode: the sheet takes every pixel the bars leave. */
.planner.is-fullscreen .canvas-wrap {
    flex: 1 1 auto;
    height: auto;
    min-height: 0;
}

/*
 * Which plan is open, what it is drawn on, and the paragraph explaining the buttons are
 * all things you read before you start. The map bar is deliberately not in this list:
 * Google's terms require the imagery credit to stay visible, and the fade and rotate
 * sliders are wanted at exactly the moment you are tracing at full size.
 */
.planner.is-fullscreen .stage-bar,
.planner.is-fullscreen .view-bar,
.planner.is-fullscreen .shape-help,
.planner.is-fullscreen .panel__hint {
    display: none;
}

/* Nothing behind the sheet may scroll under it. */
body.has-fullscreen-planner {
    overflow: hidden;
}

@media (max-width: 899px) {
    /* On a phone the picker has already moved onto the stage, so the panel below it is
       help text and the totals, both worth a scroll, neither worth the height here. */
    .planner.is-fullscreen {
        grid-template-areas: "stage";
        grid-template-rows: minmax(0, 1fr);
    }

    .planner.is-fullscreen .planner__tools,
    .planner.is-fullscreen .planner__totals {
        display: none;
    }
}

@media (min-width: 900px) {
    /*
     * There is room for the picker and the totals beside a full-height sketch. The caps
     * that share the right-hand column between them go, and the two rows split it
     * evenly instead. The column is the viewport now, so a cap measured off the
     * viewport would be measuring the same thing twice.
     *
     * align-items has to be reset with them: start is what lets each panel stop at its
     * content, and here they are meant to fill the row and scroll inside it.
     */
    .planner.is-fullscreen {
        grid-template-rows: minmax(0, 1fr) minmax(0, 1fr);
        align-items: stretch;
    }

    .planner.is-fullscreen .planner__tools,
    .planner.is-fullscreen .planner__totals {
        max-height: none;
        min-height: 0;
    }
}

/* ---- guide articles ---------------------------------------------------- */

.guide-crumb {
    margin: 0 0 6px;
    font-size: 0.8rem;
    text-transform: uppercase;
    letter-spacing: 0.08em;
}

/* A trail, not a list: it runs along one line and wraps like text. The separator is drawn
   rather than written so it is never read out as a word. */
.guide-crumb ol {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 0 8px;
    margin: 0;
    padding: 0;
    list-style: none;
    color: var(--muted);
}

.guide-crumb li {
    margin: 0;
}

.guide-crumb li + li::before {
    content: "/";
    margin-right: 8px;
    opacity: 0.5;
}

/* Where you already are. It carries no link, so it is dimmed rather than left looking like
   one that stopped working. */
.guide-crumb [aria-current="page"] {
    color: var(--muted);
}

/* The opening paragraph carries the whole promise of the page, so it reads a step up
   from the body without shouting. */
.guide-lede {
    font-size: 1.05rem;
    line-height: 1.6;
}

.prose ul,
.prose ol {
    color: var(--muted);
    padding-left: 20px;
    margin: 14px 0;
}

.prose li {
    margin-bottom: 8px;
}

.prose li strong,
.prose p strong {
    color: var(--ink);
}

.prose .table-scroll {
    margin: 18px 0;
}

/* The one line of arithmetic each guide is really about. */
.formula {
    margin: 18px 0;
    padding: 14px 16px;
    background: var(--surface);
    border: 1px solid var(--line);
    border-left: 3px solid var(--accent);
    border-radius: var(--radius);
    line-height: 1.9;
}

.formula code {
    font-size: 0.98rem;
    font-weight: 600;
    color: var(--ink);
}

.guide-cta {
    margin: 26px 0 18px;
}

.guide-list h2 a {
    text-decoration: none;
}

.guide-list h2 a:hover {
    text-decoration: underline;
}

/* A key on the keyboard, in the help text under the sketch. */
kbd {
    display: inline-block;
    padding: 1px 5px;
    border: 1px solid var(--line);
    border-bottom-width: 2px;
    border-radius: 4px;
    background: var(--surface);
    font-family: inherit;
    font-size: 0.85em;
    font-weight: 600;
    line-height: 1.4;
    color: var(--ink);
    white-space: nowrap;
}

/* ---- FAQ ---------------------------------------------------------------- */

.faq__list {
    margin: 0;
}

.faq__list dt {
    font-weight: 650;
    color: var(--ink);
    margin-top: 20px;
}

.faq__list dd {
    margin: 6px 0 0;
    color: var(--muted);
}


/* ---- printed sheet ------------------------------------------------------ */

/* Built by the planner only while a print is in flight, so it never shows on screen.
   Printing the page itself would print the sketch cropped to the current pan and zoom,
   wrapped in the header, the tool panel and an ad; this is the sketch on its own. */
.print-sheet {
    display: none;
}

.print-sheet__head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    border-bottom: 1px solid #ddd;
    padding-bottom: 6px;
}

.print-sheet__brand {
    display: inline-flex;
    align-items: center;
}

.print-sheet__mark {
    display: block;
    height: 22px;
    width: auto;
}

.print-sheet__site,
.print-sheet__foot {
    color: #666;
    font-size: 0.78rem;
}

.print-sheet__meta {
    margin: 8px 0 10px;
    color: #444;
    font-size: 0.85rem;
}

.print-sheet__plan {
    display: block;
    margin: 0 auto;
    max-width: 100%;
    /* A tall yard is taller than the page it is printed on unless something stops it, and
       break-inside then splits it across two sheets. This ceiling is the thing that stops
       it, so it is set here rather than only in the orientation query below: a phone whose
       print path never resolves that query still gets a sketch that fits. 13cm clears the
       shortest page the sheet can land on, landscape Letter, about 19cm between the
       margins, with the brand line, the size line and the date taking the rest. */
    max-height: 13cm;
    width: auto;
    height: auto;
    border: 1px solid #bbb;
}

/* A portrait page has 25cm rather than 19cm, so the sketch can be half again as tall on
   the browsers that say which way up the paper is. */
@media print and (orientation: portrait) {
    .print-sheet__plan {
        max-height: 16cm;
    }
}

/* The material list under the drawing: what to buy, and the key to what is on the sheet. */
.print-sheet__list {
    margin: 12px 0 0;
    /* The list may run onto a second page; the drawing above it must not be split, and
       neither must a row of the table. */
    break-inside: auto;
}

.print-sheet__list table {
    width: 100%;
    border-collapse: collapse;
    font-size: 0.78rem;
}

.print-sheet__list th,
.print-sheet__list td {
    text-align: left;
    vertical-align: top;
    padding: 4px 8px 4px 0;
    border-bottom: 1px solid #ddd;
    break-inside: avoid;
}

.print-sheet__list thead th {
    font-size: 0.68rem;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: #666;
    border-bottom: 1px solid #999;
}

.print-sheet__list tfoot th,
.print-sheet__list tfoot td {
    border-bottom: none;
    border-top: 1px solid #999;
    padding-top: 6px;
    font-weight: 700;
}

.print-sheet__cost {
    text-align: right;
    white-space: nowrap;
}

/* The row's own colour, so the list doubles as the key to the drawing. Printers drop
   backgrounds by default, and this is the one background on the sheet that carries
   meaning rather than decoration, so it asks to be kept. */
.print-sheet__swatch {
    display: inline-block;
    width: 9px;
    height: 9px;
    margin-right: 6px;
    border: 1px solid rgba(0, 0, 0, 0.35);
    border-radius: 2px;
    vertical-align: baseline;
    print-color-adjust: exact;
    -webkit-print-color-adjust: exact;
}

.print-sheet__note {
    margin: 8px 0 0;
    color: #666;
    font-size: 0.7rem;
}

.print-sheet__foot {
    margin: 8px 0 0;
    text-align: right;
}

@media print {
    /* Everything except the sheet, including the header, the ads and the planner itself.
       Hiding by class would mean revisiting this list every time the page grows a section. */
    body > *:not(#print-sheet) {
        display: none !important;
    }

    .print-sheet {
        display: block;
        color: #000;
        background: #fff;
    }

    /* A page break through the drawing makes both halves useless. */
    .print-sheet__plan {
        break-inside: avoid;
        page-break-inside: avoid;
    }

    /* A long list is allowed onto a second page, but its heading row goes with it, so a
       column of numbers on page two still says which column it is. */
    .print-sheet__list thead {
        display: table-header-group;
    }
}

@page {
    margin: 14mm;
}

/* ---- guide calculators -------------------------------------------------- */

/* The answer to the question in the page's own headline, above the prose that explains it.
   Someone who came for the number gets the number; someone who wants the reasoning reads on. */
.calc {
    margin: 24px 0 28px;
    padding: 18px 18px 14px;
    border: 1px solid var(--line);
    border-radius: var(--radius);
    background: var(--surface);
}

.calc__heading {
    margin: 0 0 14px;
    font-size: 1.05rem;
}

.calc__form {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    gap: 10px;
}

.calc__row {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    gap: 10px;
}

.calc__field {
    display: flex;
    flex-direction: column;
    gap: 4px;
}

.calc__field label {
    font-size: 0.72rem;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--muted);
}

/* Page chrome, not part of a sketch: it takes the page's surface and ink. It asked for
   --paper before that token existed, which resolved to nothing and left the card's own
   white showing through, correct by accident in light, and a near-white box under pale
   text once the token was real and the page could go dark. */
.calc__field input {
    width: 6rem;
    min-height: 42px;
    padding: 0 10px;
    border: 1px solid var(--line);
    border-radius: var(--radius);
    background: var(--surface);
    font: inherit;
    color: var(--ink);
}

.calc__field input:focus {
    outline: 2px solid var(--accent);
    outline-offset: 1px;
}

/* Sits on the input's baseline rather than the label's, so a row of fields lines up. */
.calc__times {
    align-self: center;
    padding-top: 18px;
    color: var(--muted);
}

/* Under the field it belongs to, so a row of boxes does not need a legend explaining
   which of them is in feet and which is in inches. */
.calc__unit {
    font-size: 0.72rem;
    color: var(--muted);
}

.calc__out {
    display: block;
    margin-top: 14px;
    padding-top: 12px;
    border-top: 1px solid var(--line);
    font-size: 0.95rem;
    line-height: 1.55;
    color: var(--ink);
}

.calc__out:empty {
    display: none;
}

.calc__link {
    margin: 12px 0 0;
    font-size: 0.85rem;
    color: var(--muted);
}

@media (max-width: 599px) {
    /* Two fields to a row on a phone rather than one long scroll of them. */
    .calc__field input {
        width: 5rem;
    }
}

/* ---- where the material comes from -------------------------------------- */

/* Prices are quoted for somewhere, and this says where. Above the totals rather than
   buried under them: it changes every number below it. */
.region-field {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-bottom: 12px;
}

.region-field__label {
    font-size: 0.72rem;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--muted);
    white-space: nowrap;
}

.region-field select {
    flex: 1;
    min-width: 0;
    min-height: 40px;
    padding: 0 8px;
    border: 1px solid var(--line);
    border-radius: var(--radius);
    background: var(--surface);
    font: inherit;
    color: var(--ink);
}

.region-field select:focus {
    outline: 2px solid var(--accent);
    outline-offset: 1px;
}

/* The two ways the same pile is bought, under the material it belongs to. Bagged first
   because that is what people picture, then the number that changes their mind. */
.total-row__buying {
    margin-top: 6px;
    padding-top: 6px;
    border-top: 1px dashed var(--line);
}

.total-row__route {
    font-size: 0.76rem;
    line-height: 1.45;
    color: var(--muted);
}

/* Marked rather than merely listed: the whole point of showing both is that one of them
   is often half the price, and that is easy to skim past in two grey lines. */
.total-row__route.is-better {
    font-weight: 600;
    color: var(--accent);
}

.total-row__advice {
    margin-top: 2px;
    font-size: 0.72rem;
    line-height: 1.4;
    color: var(--muted);
}

/* The size of a placed item, which belongs to the item rather than to the grid: a mature
   oak and a rose bush are one item and one price each, and nothing like the same size. */
#item-size-field {
    align-items: center;
}

#item-delete {
    margin-left: auto;
}

/* ---- address suggestions ------------------------------------------------ */

/* The list hangs under the address box rather than pushing the bar around, so the sketch
   below it does not jump every time somebody types a letter. */
.suggest {
    position: relative;
    flex: 1;
    min-width: 0;
}

.suggest__list {
    position: absolute;
    z-index: 45;
    top: calc(100% + 4px);
    left: 0;
    right: 0;
    margin: 0;
    padding: 4px;
    list-style: none;
    border: 1px solid var(--line);
    border-radius: var(--radius);
    background: var(--surface);
    box-shadow: var(--shadow-pop);
}

.suggest__option {
    padding: 10px 12px;
    border-radius: 7px;
    font-size: 0.9rem;
    line-height: 1.35;
    color: var(--ink);
    cursor: pointer;
}

/* Hover and the keyboard highlight are the same state deliberately: with both a mouse and
   arrow keys in play, two different highlights on one list is two answers to "what does
   Enter do now". */
.suggest__option:hover,
.suggest__option.is-active {
    background: var(--accent-soft);
}

/* Fill sits beside Replace and Add layer but is not one of them: those two are a choice of
   what happens to what is already there, and this is a choice of drag versus tap. The gap
   says so without a second label. */
.mode-bar__fill {
    margin-left: 8px;
}

/* A bucket cursor, so it is obvious before the tap that a tap is about to do rather a lot. */
#plan-canvas.is-filling {
    cursor: cell;
}

/* Privacy and Contact sit on one line with room between them, rather than running together
   as one long string of underlined words. */
.site-footer__links {
    display: flex;
    flex-wrap: wrap;
    gap: 16px;
}
