@font-face { font-family: 'Big Shoulders'; font-style: normal; font-weight: 100 900; font-display: swap; src: url('assets/big-shoulders.woff2') format('woff2'); }
:root { color-scheme: light; --ink: #24362f; --paper: #faf9f4; --accent: #dfab51; }
* { box-sizing: border-box; }
body { margin: 0; background: #e6e7e1; color: var(--ink); font-family: 'Plan Sans', 'Avenir Next', sans-serif; }
.toolbar { min-height: 86px; padding: 18px 32px; display: flex; align-items: center; justify-content: space-between; gap: 20px; border-bottom: 1px solid #c4cbc1; background: #fafbf7; }
.identity { display: flex; align-items: center; gap: 13px; }
.mark { display: block; width: 38px; height: 38px; flex: none; object-fit: contain; }
.identity-label { display: block; margin-bottom: 3px; color: #5c6b60; font-family: 'Plan Mono', monospace; font-size: 10.5px; letter-spacing: .1em; line-height: 1.2; text-transform: uppercase; }
.identity strong { display: block; font-size: 20px; font-weight: 600; line-height: 1.15; }
/* Equal-width buttons: each auto-sized 1fr column takes the widest label's width. */
.actions { display: grid; grid-auto-flow: column; grid-auto-columns: 1fr; gap: 8px; }
button { display: inline-flex; align-items: center; justify-content: center; gap: 8px; min-height: 42px; padding: 10px 15px; border: 1px solid #bac3b8; border-radius: 3px; background: transparent; color: var(--ink); font: 600 13px 'Plan Sans', 'Avenir Next', sans-serif; cursor: pointer; white-space: nowrap; }
.actions button { font-family: 'Big Shoulders', 'Plan Display', sans-serif; font-size: 16px; font-weight: 700; letter-spacing: .08em; text-transform: uppercase; }
button:hover { background: #e8ece4; border-color: var(--ink); }
button:focus-visible { outline: 3px solid #bb8729; outline-offset: 3px; }
button:disabled { cursor: progress; opacity: .65; }
.primary { background: var(--ink); border-color: var(--ink); color: #fffdf4; }
.primary:hover { background: #365242; }
button svg { width: 16px; height: 16px; fill: none; stroke: currentColor; stroke-width: 1.5; }
.viewer { padding: 30px 32px 20px; overflow: auto; }
.sheet { width: min(100%, 1680px); margin: 0 auto; background: var(--paper); box-shadow: 0 8px 28px #20352817, 0 1px 3px #20352824; }
#plan { display: block; width: 100%; height: auto; }
.export-status { margin: 0; padding: 0 24px 20px; text-align: center; color: #5c6b60; font-size: 12px; }
.export-status:empty { padding: 0; }
dialog { width: min(1120px, calc(100vw - 32px)); max-height: calc(100dvh - 32px); padding: 0; border: 1px solid #000; border-radius: 0; background: #fff; color: #000; box-shadow: 0 24px 80px #0003; overscroll-behavior: contain; }
dialog::backdrop { background: #0009; backdrop-filter: blur(4px); }
.costs { --costs-muted: #666; font-family: 'Plan Sans', 'Avenir Next', sans-serif; }
.costs-head { display: grid; grid-template-columns: 1fr auto; gap: 32px; padding: 34px 38px 30px; border-bottom: 1px solid #000; }
.costs-kicker, .costs-label { font-family: 'Plan Mono', monospace; font-size: 10px; letter-spacing: .12em; text-transform: uppercase; }
.costs h2 { margin: 18px 0 8px; font: 600 clamp(38px, 6vw, 72px)/.92 'Plan Display', 'DIN Condensed', sans-serif; letter-spacing: -.025em; text-transform: uppercase; }
.costs-address { margin: 0; color: var(--costs-muted); font-size: 14px; line-height: 1.5; }
.proposal-status { align-self: start; min-width: 210px; padding: 12px 14px 13px; border: 1px solid #000; border-top: 3px solid #f5a623; background: #fafafa; }
.proposal-status span, .proposal-status small { display: block; color: #666; font: 9px 'Plan Mono', monospace; letter-spacing: .1em; text-transform: uppercase; }
.proposal-status strong { display: block; margin: 8px 0 5px; font-size: 14px; font-weight: 600; }
.costs-meta { display: grid; grid-template-columns: repeat(3, 1fr); border-bottom: 1px solid #000; }
.costs-meta > div { padding: 18px 38px; border-right: 1px solid #d8d8d8; }
.costs-meta > div:last-child { border-right: 0; }
.costs-meta strong { display: block; margin-top: 7px; font: 400 13px 'Plan Mono', monospace; }
.costs-body { padding: 4px 38px 32px; }
.costs-table { width: 100%; border-collapse: collapse; font-size: 13px; }
.costs-table th { padding: 18px 0 11px; border-bottom: 1px solid #000; color: var(--costs-muted); font: 10px 'Plan Mono', monospace; letter-spacing: .08em; text-align: left; text-transform: uppercase; }
.costs-table td { padding: 16px 0; border-bottom: 1px solid #e5e5e5; vertical-align: top; }
.costs-table th:nth-child(n+2), .costs-table td:nth-child(n+2) { padding-left: 18px; text-align: right; white-space: nowrap; }
.item-name { display: block; font-weight: 600; }
.item-note { display: block; margin-top: 4px; color: var(--costs-muted); font-size: 11px; line-height: 1.5; }
.costs-total { display: grid; grid-template-columns: 1fr auto; align-items: end; gap: 24px; padding: 24px 0 28px; border-bottom: 1px solid #000; }
.costs-total p { max-width: 520px; margin: 8px 0 0; color: var(--costs-muted); font-size: 11px; line-height: 1.55; }
.costs-total strong { font: 600 clamp(38px, 5vw, 64px)/1 'Plan Display', 'DIN Condensed', sans-serif; letter-spacing: -.02em; white-space: nowrap; }
.costs-deposit { display: grid; grid-template-columns: 1fr auto; gap: 28px; align-items: center; margin-top: 18px; padding: 20px 22px; background: #000; color: #fff; }
.costs-deposit .costs-label { color: #aaa; }
.costs-deposit h3 { margin: 7px 0 5px; font-size: 15px; font-weight: 600; }
.costs-deposit p { max-width: 670px; margin: 0; color: #bbb; font-size: 11px; line-height: 1.55; }
.deposit-amount { text-align: right; }
.deposit-amount strong { display: block; font: 600 clamp(30px, 4vw, 48px)/1 'Plan Display', 'DIN Condensed', sans-serif; letter-spacing: -.015em; white-space: nowrap; }
.deposit-amount small { display: block; margin-top: 6px; color: #aaa; font: 10px 'Plan Mono', monospace; letter-spacing: .06em; text-transform: uppercase; }
.costs-scope { padding: 28px 0 24px; border-bottom: 1px solid #000; }
.scope-list { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); column-gap: 34px; margin: 14px 0 0; padding: 0; list-style: none; }
.scope-list li { position: relative; padding: 9px 0 9px 20px; border-bottom: 1px solid #ececec; font-size: 12px; line-height: 1.4; }
.scope-list li::before { content: '+'; position: absolute; left: 0; font-family: 'Plan Mono', monospace; }
/* Scope of work: the phone's groups side by side, each a one-column list. */
.scope-note { margin: 8px 0 0; color: var(--costs-muted); font-size: 12px; line-height: 1.5; }
.scope-groups { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 18px; margin-top: 16px; }
.scope-groups h3 { margin: 0; padding-bottom: 7px; border-bottom: 1px solid #000; font-size: 13px; font-weight: 600; }
.scope-groups .scope-list { grid-template-columns: 1fr; margin-top: 0; }
.costs-spec { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); }
.costs-spec > div { padding: 18px 16px 18px 0; }
.costs-spec strong { display: block; margin-top: 7px; font-size: 15px; font-weight: 600; }
.costs-source { margin: 0; padding: 0 0 18px; border-bottom: 1px solid #000; color: var(--costs-muted); font-size: 11px; line-height: 1.5; }
.costs-excluded { padding: 24px 0 22px; border-bottom: 1px solid #000; }
.costs-excluded .scope-list { grid-template-columns: 1fr; }
.costs-excluded .scope-list li::before { content: '−'; }
.costs-contact { margin: 18px 0 0; font-size: 12px; line-height: 1.5; }
.costs-contact a { color: inherit; font-weight: 600; }
.costs-actions { position: sticky; bottom: 0; display: flex; justify-content: flex-end; gap: 8px; padding: 14px 38px; border-top: 1px solid #000; background: #fff; }
.costs-actions button { border-color: #000; border-radius: 0; color: #000; }
.costs-actions .costs-primary { background: #000; color: #fff; }
.costs-actions .costs-primary:hover { background: #222; }
.print-costs-document { display: none; }
html.map-open { overflow: hidden; overscroll-behavior: none; }
body.map-open { position: fixed; width: 100%; overflow: hidden; }
.map-dialog { position: fixed; inset: 0; width: 100%; height: 100dvh; max-width: none; max-height: none; margin: 0; padding: 0; border: 0; overflow: hidden; background: #17251e; box-shadow: none; overscroll-behavior: none; }
.map-dialog::backdrop { background: #17251e; backdrop-filter: none; }
.map-viewport { position: absolute; inset: 0; overflow: hidden; touch-action: none; overscroll-behavior: none; user-select: none; -webkit-user-select: none; -webkit-touch-callout: none; cursor: grab; }
.map-viewport.is-dragging { cursor: grabbing; }
.map-viewport:focus-visible { outline: 2px solid #f2cb7c; outline-offset: -4px; }
#map-art { position: absolute; left: 0; top: 0; display: block; max-width: none; transform-origin: 0 0; will-change: transform; pointer-events: none; }
.map-close { position: absolute; z-index: 1; top: max(16px, env(safe-area-inset-top)); right: max(16px, env(safe-area-inset-right)); width: 48px; height: 48px; min-height: 48px; padding: 0; border: 1px solid #ffffff40; border-radius: 50%; background: #1d3028e8; color: #fffdf4; box-shadow: 0 2px 14px #0003; backdrop-filter: blur(12px); -webkit-backdrop-filter: blur(12px); touch-action: manipulation; }
.map-close:hover { background: #243e31; border-color: #ffffff80; }
.map-close svg { width: 22px; height: 22px; }
.map-hint { position: absolute; bottom: max(24px, env(safe-area-inset-bottom)); left: 50%; transform: translateX(-50%); margin: 0; padding: 11px 16px; border: 1px solid #ffffff26; border-radius: 24px; background: #1d3028e8; color: #fffdf4; font-size: 13px; line-height: 1.4; white-space: nowrap; pointer-events: none; opacity: 1; transition: opacity .3s ease; }
.map-hint.is-hidden { opacity: 0; }
.map-help { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
@media (prefers-reduced-motion: reduce) { .map-hint { transition: none !important; } }
.mobile { display: none; }

/* Phones, upright or sideways, get the mobile view: the phone masthead (its own section below) over one panel
   at a time. Tablets, laptops, and print keep the plan sheet. */
@media screen and (max-width: 700px), screen and (max-height: 500px) and (pointer: coarse) {
  :root { --m-muted: #6a776c; --m-rule: #d3d8cf; --m-gutter: max(16px, calc((100% - 560px) / 2)); }
  /* Estimate panel colours. --m-estimate-muted passes 4.5:1 on paper and on the scope green. */
  :root {
    --m-estimate-muted: #5a685b;
    --m-scope-bg: #e2efd9; --m-scope-rule: #b4c8aa; --m-scope-on: #1e6e34;
    --m-outside-bg: #f3e6e2; --m-outside-ink: #713e36; --m-outside-line: #a96e60; --m-outside-rule: #cfa295;
  }
  body { padding-top: var(--masthead-height, 216px); background: var(--paper); }
  .viewer, .export-status, .actions { display: none; }
  .masthead { position: fixed; z-index: 5; top: 0; left: 0; right: 0; background: var(--paper); }
  .toolbar { display: none; }

  .mobile { display: block; padding: 0 max(var(--m-gutter), env(safe-area-inset-right)) calc(56px + env(safe-area-inset-bottom)) max(var(--m-gutter), env(safe-area-inset-left)); }
  .m-panel { padding-top: 4px; }
  /* A panel shown on its own is at least a screen tall, so even Contact can open under the compact masthead. */
  .mobile:has(> .m-panel[hidden]) > .m-panel { min-height: 100dvh; }
  .m-head { display: flex; justify-content: space-between; align-items: baseline; gap: 12px; margin: 22px 0 10px; }
  .m-head h2, .m-estimate-heading { margin: 0; font: 600 22px/1 'Plan Display', 'DIN Condensed', sans-serif; letter-spacing: .03em; text-transform: uppercase; }
  .m-tag { color: var(--m-muted); font: 13px 'Plan Mono', monospace; letter-spacing: .06em; text-transform: uppercase; }

  .m-aerial { position: relative; display: grid; border: 1.2px solid var(--ink); background: #2b3a30; cursor: zoom-in; }
  /* The aerial and Full size share one grid cell. Full size sticks just under the compact masthead while the tall aerial
     is on screen, so it stays reachable from anywhere in the lot. */
  .m-aerial > svg { grid-area: 1 / 1; display: block; width: 100%; height: auto; }
  .m-full-size { position: sticky; z-index: 1; top: calc(66px + max(4px, env(safe-area-inset-top))); grid-area: 1 / 1; align-self: start; justify-self: start; margin: 10px; gap: 7px; min-height: 0; padding: 8px 11px; border-color: #ffffff40; background: #1d3028e8; color: #fffdf4; font: 700 14px 'Big Shoulders', 'Plan Display', sans-serif; letter-spacing: .08em; text-transform: uppercase; }
  .m-full-size:hover { border-color: #ffffff80; background: #243e31; }
  .m-full-size svg { width: 14px; height: 14px; }
  .m-legend { margin-top: 12px; font-size: 13px; line-height: 1.45; }
  .m-legend-row { display: flex; flex-wrap: wrap; gap: 8px 18px; padding-bottom: 9px; border-bottom: 1px dashed #9aa597; }
  .m-legend-row span { display: inline-flex; align-items: center; gap: 8px; }
  .m-swatch { width: 24px; height: 14px; border: 1px solid #927243; background: #ead4a7; }
  .m-legend p { margin: 8px 0 0; }
  .m-legend .m-units { color: var(--m-muted); }

  .m-schedule { border-top: 1.5px solid var(--ink); }
  .m-schedule-row { display: grid; grid-template-columns: 34px 1fr auto; gap: 4px 12px; align-items: start; padding: 14px 0; border-bottom: 1px solid var(--m-rule); }
  .m-key { display: grid; place-items: center; width: 30px; height: 30px; background: #ead4a7; font: 14px 'Plan Mono', monospace; }
  .m-schedule-row strong { display: block; font-size: 18px; font-weight: 600; }
  .m-schedule-row small { display: block; margin-top: 3px; color: var(--m-muted); font-size: 13px; }
  .m-dims { display: block; margin-top: 6px; font-size: 15px; font-weight: 600; }
  .m-foundation-summary { grid-column: 1 / -1; margin: 8px 0 0; padding-top: 12px; border-top: 1px solid var(--m-rule); font-size: 14px; line-height: 1.45; }
  .m-foundation-summary b { display: block; margin-bottom: 4px; font-weight: 600; }
  .m-area { font: 600 30px/1 'Plan Display', 'DIN Condensed', sans-serif; text-align: right; }
  .m-area small { display: block; margin-top: 4px; color: var(--m-muted); font: 13px 'Plan Mono', monospace; letter-spacing: .06em; text-transform: uppercase; }
  /* At 13 px the two notes share a row only on wider phones; otherwise the total drops below. */
  .m-follows { display: flex; flex-wrap: wrap; justify-content: space-between; gap: 2px 12px; padding-top: 8px; color: #b3311f; font: 13px/1.35 'Plan Mono', monospace; letter-spacing: .04em; }
  .m-section { display: block; width: 100%; height: auto; }
  /* Keynotes: the numbered markers in the phone section, explained in words. The rebar keynote is in the outside red. */
  .m-keynotes { display: grid; gap: 0; margin: 12px 0 0; padding: 0; list-style: none; counter-reset: m-keynote; border-top: 1px solid var(--ink); }
  .m-keynotes li { display: grid; grid-template-columns: 34px minmax(0, 1fr); column-gap: 8px; padding: 11px 0; border-bottom: 1px solid var(--m-rule); counter-increment: m-keynote; font-size: 14px; line-height: 1.45; }
  .m-keynotes li::before { content: counter(m-keynote); grid-row: span 2; display: grid; place-items: center; width: 24px; height: 24px; margin-top: 1px; border-radius: 50%; background: var(--ink); color: #fffdf4; font: 13px/1 'Plan Mono', monospace; }
  .m-keynotes strong { font-size: 15px; font-weight: 600; }
  .m-footing-run { display: block; margin: 6px 0 3px; font: 600 26px/1.1 'Plan Display', 'DIN Condensed', sans-serif; }
  .m-footing-basis { display: block; margin-bottom: 8px; color: var(--m-muted); font-size: 13px; }
  .m-keynotes .m-keynote-outside { color: var(--m-outside-ink); }
  .m-keynotes .m-keynote-outside::before { background: var(--m-outside-ink); }
  /* The plans note ends the Site plan panel: pushed to the bottom of its scroll area, and quieter than the content. */
  #panel-site-plan:not([hidden]) { display: flex; flex-direction: column; }
  .m-source { margin: auto 0 0; padding-top: 28px; color: #8a958b; font-size: 13px; line-height: 1.45; }
  .mobile:has(> .m-panel[hidden]) > #panel-site-plan { margin-bottom: -36px; }

  /* Estimate panel: Scope of work on green, Outside this estimate on red, then the dock with the totals. */
  #panel-estimate { padding-top: 12px; }
  .m-scope { padding-top: 14px; }
  .m-scope-header { padding: 0 12px 12px; border-bottom: 1.5px solid var(--ink); }
  .m-scope-body { padding: 0 12px 4px; background: var(--m-scope-bg); }
  .m-phase { padding: 13px 0 14px; }
  .m-phase + .m-phase { border-top: 1px solid var(--m-scope-rule); }
  .m-phase-heading { display: flex; align-items: center; gap: 9px; min-height: 25px; margin-bottom: 9px; }
  .m-phase h3 { margin: 0; font: 600 20px/1 'Plan Display', 'DIN Condensed', sans-serif; letter-spacing: .015em; text-transform: uppercase; }
  /* Tasks fill two columns top to bottom, split by a dashed rule. */
  .m-phase-tasks { position: relative; display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); grid-template-rows: repeat(2, auto); grid-auto-flow: column; gap: 7px 18px; margin: 0; padding: 0; list-style: none; }
  .m-phase-tasks.m-single-row { grid-template-rows: auto; }
  .m-phase-tasks::before { content: ''; position: absolute; left: 50%; top: 1px; bottom: 1px; border-left: 1px dashed var(--m-scope-rule); }
  .m-phase-tasks li { position: relative; min-width: 0; padding-left: 12px; font-size: 13px; line-height: 1.4; }
  .m-phase-tasks li::before { content: '•'; position: absolute; left: 0; top: 0; }

  .m-exclusions { margin-top: 15px; padding-top: 14px; color: var(--m-outside-ink); }
  .m-exclusions .m-estimate-heading { padding: 0 12px 10px; border-bottom: 1.5px solid var(--m-outside-line); }
  .m-exclusions-body { padding: 14px 12px 13px; background: var(--m-outside-bg); }
  .m-exclusion-text { margin: 0; font-size: 14px; line-height: 1.45; }
  .m-exclusion-text + .m-exclusion-text { margin-top: 10px; }
  .m-outside-note { margin: 14px 0 0; padding-top: 12px; border-top: 1px solid var(--m-outside-rule); color: #b3311f; }
  .m-outside-note strong { display: block; font: 600 18px/1.25 'Plan Sans', 'Avenir Next', sans-serif; }
  .m-outside-note span { display: block; margin-top: 5px; font: 600 13px/1.4 'Plan Sans', 'Avenir Next', sans-serif; }

  /* The price dock: the approved 08 + 10 shrinking bar with payments, drawn as 03's title block, in ink.
     An ink band across the screen holds a block set in from its edges (12 px on a phone), framed at 1.5 px and ruled at
     1 px between rows and cells. With script, the band is fixed to the bottom of the screen above the home indicator and
     shows the bar; the rest rises from below when the bar is tapped or the panel is scrolled through its end
     (setupPriceDock in plan.js). The dock keeps its open layout throughout: the reveal only translates and scales parts.
     Without script it ends the panel fully open. At 600 px tall or less, script locks the bar collapsed. */
  .m-dock {
    --m-dock-bg: var(--ink); --m-dock-fg: #f4f1e6; --m-dock-muted: #aebbad; --m-dock-line: #f4f1e6;
    --m-dock-ease: cubic-bezier(.23, 1, .32, 1); --m-dock-duration: 240ms;
    --m-dock-bar-closed: 56px; --m-dock-fit: 1;
    margin: 24px calc(50% - 50vw) 0;
    color: var(--m-dock-fg);
  }
  .m-pricing { margin: 26px 0 8px; border-top: 1.5px solid var(--ink); }
  .m-pricing > h2 { padding: 14px 12px; border-bottom: 1px solid var(--ink); }
  .m-price-item { padding: 16px 12px; border-bottom: 1px solid var(--m-rule); }
  .m-price-item-head { display: flex; flex-wrap: wrap; justify-content: space-between; align-items: baseline; gap: 6px 16px; }
  .m-price-item h3 { margin: 0; font: 600 22px/1.1 'Plan Display', 'DIN Condensed', sans-serif; text-transform: uppercase; }
  .m-item-amount { font: 600 25px/1.1 'Plan Display', 'DIN Condensed', sans-serif; }
  .m-item-status { color: var(--m-muted); font: 600 13px/1.45 'Plan Sans', 'Avenir Next', sans-serif; }
  .m-price-item p { margin: 8px 0 0; font-size: 13px; line-height: 1.45; }
  .m-price-item .m-item-quantity { font-size: 14px; font-weight: 600; }
  .m-item-rate { color: var(--m-muted); }

  .m-dock-sheet { padding: 8px max(12px, calc(var(--m-gutter) - 4px), env(safe-area-inset-right)) 10px max(12px, calc(var(--m-gutter) - 4px), env(safe-area-inset-left)); background: var(--m-dock-bg); }
  /* The bar replaces the site's button styles. Unpinned, it is the open bar at its full height, and its lines may wrap. */
  .m-dock-bar, .m-dock-bar:hover { position: relative; display: grid; grid-template-columns: minmax(min-content, 1fr) auto; grid-template-rows: minmax(72px, auto); align-items: stretch; gap: 0; width: 100%; min-height: 0; padding: 0; border: 1.5px solid var(--m-dock-line); border-bottom: 0; border-radius: 0; background: none; color: inherit; text-align: left; white-space: normal; -webkit-tap-highlight-color: transparent; touch-action: manipulation; }
  .m-dock-cell { display: flex; align-items: center; min-width: 0; padding: 5px 9px 6px; color: var(--m-dock-muted); font: 600 14px 'Plan Sans', 'Avenir Next', sans-serif; }
  .m-dock-figure, .m-dock-label { display: inline-block; }
  /* Below 400 px the spelled-out labels stack in two lines beside their figures, leaving the figures room to stay large. */
  .m-dock-break { display: none; }
  @media (max-width: 399px) {
    .m-dock-break { display: block; }
    .m-dock-label { line-height: 1.1; }
  }
  .m-dock-figure { color: var(--m-dock-fg); font: 600 calc(var(--m-dock-open) * var(--m-dock-fit))/1 'Plan Display', 'DIN Condensed', sans-serif; font-variant-numeric: tabular-nums; }
  /* Script lowers --m-dock-fit only when the total and its label need more room. */
  .m-dock-total { --m-dock-open: 50px; --m-dock-closed: 30px; }
  .m-dock-chevron { display: none; align-self: center; justify-self: center; width: 20px; height: 20px; fill: none; stroke: var(--m-dock-fg); stroke-width: 2; transition: rotate 200ms var(--m-dock-ease); }
  /* The chevron points up until the dock is fully open, then down. */
  .m-dock.is-open .m-dock-chevron { rotate: 180deg; }

  /* Pinned, the dock stays in the panel as a spacer the open dock's height, so the panel's last lines clear it by 24 px.
     The band is fixed above the home indicator, and the dock's own band covers the indicator's strip. The bar keeps
     to one 72 px row, which the collapsed details cover to 56 px, with the chevron in a column of its own. */
    .m-dock.is-ready { height: calc(var(--m-dock-height, 0px) + env(safe-area-inset-bottom)); }
    .m-dock.is-ready .m-dock-sheet { position: fixed; z-index: 4; left: 0; right: 0; bottom: env(safe-area-inset-bottom); box-shadow: 0 -6px 16px #24362f1f; }
    .m-dock.is-ready::after { content: ''; position: fixed; z-index: 4; left: 0; right: 0; bottom: 0; height: env(safe-area-inset-bottom); background: var(--m-dock-bg); }
    .m-dock.is-ready .m-dock-bar { grid-template-columns: minmax(0, 1fr) 36px; grid-template-rows: 72px; }
    .m-dock.is-ready .m-dock-cell { white-space: nowrap; }
    .m-dock.is-ready .m-dock-chevron { display: block; }
    .m-dock[data-locked] .m-dock-chevron { visibility: hidden; }

  .m-dock-more { border: 1.5px solid var(--m-dock-line); border-top: 0; background: var(--m-dock-bg); }
  .m-dock-steps { margin: 0; padding: 0; list-style: none; }
  .m-dock-steps li { display: grid; grid-template-columns: minmax(0, 1fr) minmax(112px, max-content); border-top: 1px solid var(--m-dock-line); font: 600 15px/1.3 'Plan Sans', 'Avenir Next', sans-serif; }
  .m-dock-steps li > span { align-self: center; padding: 8px 9px; }
  .m-dock-steps small { display: block; color: var(--m-dock-muted); font-size: 13px; }
  .m-dock-amount { display: flex; align-self: stretch; align-items: center; justify-content: flex-end; padding: 8px 9px; border-left: 1px solid var(--m-dock-line); font: 600 28px/1 'Plan Display', 'DIN Condensed', sans-serif; font-variant-numeric: tabular-nums; }
  .m-dock-actions { display: grid; grid-template-columns: 1fr 1fr; border-top: 1px solid var(--m-dock-line); }
  .m-dock-actions a { display: flex; flex-wrap: wrap; align-items: center; align-content: center; justify-content: center; column-gap: .28em; min-height: 48px; padding: 6px 9px; color: var(--m-dock-fg); font: 600 16px 'Plan Sans', 'Avenir Next', sans-serif; text-align: center; text-decoration: none; }
  .m-dock-actions a:first-child { border-right: 1px solid var(--m-dock-line); background: var(--m-dock-fg); color: var(--m-dock-bg); }
  /* The number is its own flex item, so it wraps below "Call" whole; the gap stands in for the space before it. */
  .m-dock-actions span { white-space: nowrap; }

  /* The details cover the bottom of the bar, so its focus ring goes around the block. */
  .m-dock-bar:focus-visible { outline: none; }
  .m-dock-block:has(> .m-dock-bar:focus-visible) { outline: 3px solid #bb8729; outline-offset: 3px; }
  .m-dock-actions a:focus-visible { outline: 3px solid currentColor; outline-offset: -7px; }

  /* A tap animates; scrolling sets every value directly, frame by frame. */
  .m-dock[data-motion="tap"] :is(.m-dock-sheet, .m-dock-more, .m-dock-figure, .m-dock-label) { transition: translate var(--m-dock-duration) var(--m-dock-ease), scale var(--m-dock-duration) var(--m-dock-ease); }
  .m-dock[data-motion="tap"] .m-dock-chevron { transition: rotate 200ms var(--m-dock-ease), translate var(--m-dock-duration) var(--m-dock-ease); }
  @media (prefers-reduced-motion: reduce) { .m-dock * { transition: none !important; } }

  /* While one panel shows at a time, the Estimate panel ends at the dock: it absorbs the bottom padding of .mobile. */
  .mobile:has(> .m-panel[hidden]) > #panel-estimate { margin-bottom: calc(-56px - env(safe-area-inset-bottom)); }

  #panel-contact { padding-top: 22px; }
  .m-contact-name { display: block; margin-top: 8px; font: 600 34px/1 'Plan Display', 'DIN Condensed', sans-serif; text-transform: uppercase; }
  .m-contact-company { display: block; margin-top: 6px; color: var(--m-muted); font-size: 15px; }
  .m-contact-row { display: block; padding: 16px 0; border-bottom: 1px solid var(--m-rule); color: inherit; text-decoration: none; }
  .m-contact-company + .m-contact-row { margin-top: 18px; border-top: 1.5px solid var(--ink); }
  .m-contact-row b { display: block; margin-top: 6px; font-size: 22px; font-weight: 600; }
  .m-contact-actions { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; margin-top: 12px; }
  .m-contact-actions a { display: flex; align-items: center; justify-content: center; min-height: 48px; border: 1px solid var(--ink); border-radius: 3px; color: var(--ink); font: 700 17px 'Big Shoulders', 'Plan Display', sans-serif; letter-spacing: .08em; text-decoration: none; text-transform: uppercase; }
  .m-contact-actions a:first-child { background: var(--ink); color: #fffdf4; }
}

@media screen and (max-width: 360px) {
  .m-scope-header, .m-scope-body, .m-exclusions-body, .m-exclusions .m-estimate-heading { padding-inline: 10px; }
  .m-phase h3 { font-size: 19px; }
  .m-phase-tasks { column-gap: 14px; }
  .m-outside-note strong { font-size: 16px; }
}
@media screen and (max-width: 379px) {
  .m-full-size { gap: 5px; padding: 6px 8px; font-size: 13px; }
  .m-full-size svg { width: 12px; height: 12px; }
}

/* Phone masthead: the plate (emblem, project name, address) over the drum of panel titles. Scrolled down a
   panel, the drum folds up behind the plate and drops into its empty slot as a small lens; back at the top, the
   lens flips away and the drum unfolds. Design: header mockups round 8 (T20 + S22).
   Behaviour: setupPhoneMasthead in plan.js.

   The two @property rules must stay at the top level of a stylesheet; they do not work inside @media. */
@property --m-drum-height { syntax: '<length>'; inherits: true; initial-value: 96px; }
@property --m-strip-height { syntax: '<length>'; inherits: false; initial-value: 98px; }
.m-plate, .m-drum, .m-controls-measure { display: none; }

@media screen and (max-width: 700px), screen and (max-height: 500px) and (pointer: coarse) {
  .m-controls-measure { display: block; padding-bottom: env(safe-area-inset-bottom); visibility: hidden; pointer-events: none; }
  .m-controls-measure *, .m-controls-measure *::before, .m-controls-measure *::after { transition: none !important; }
  .m-panel[hidden][data-measuring] { display: block; position: fixed; inset: 0; visibility: hidden; pointer-events: none; }
  html[data-short-phone] body { padding-top: calc(56px + max(4px, env(safe-area-inset-top))); }
  .masthead { --m-ease-out: cubic-bezier(.23, 1, .32, 1); --m-collapse: 300ms; --m-plate-delay: 120ms; }
  /* Expanding, the plate waits for the lens to flip out of its slot before it opens. */
  .masthead.is-compact { --m-plate-delay: 0ms; }

  /* ---- Plate ------------------------------------------------------------------------------------------- */
  .m-plate { display: block; padding-left: max(10px, calc((100% - 560px) / 2), env(safe-area-inset-left)); padding-right: max(10px, calc((100% - 560px) / 2), env(safe-area-inset-right)); background: #fafbf7; }
  .m-plate::before, .m-plate::after, .m-plate-inset::before, .m-plate-inset::after { content: ''; display: block; transition: height var(--m-collapse) var(--m-ease-out) var(--m-plate-delay); }
  .m-plate::before { height: max(10px, env(safe-area-inset-top)); }
  .m-plate::after { height: 10px; }
  .is-compact .m-plate::before { height: max(4px, env(safe-area-inset-top)); }
  .is-compact .m-plate::after { height: 4px; }
  .m-plate-face { border: 1px solid #8d9b8d; background: #e6ebe2; clip-path: polygon(7px 0, calc(100% - 7px) 0, 100% 7px, 100% calc(100% - 7px), calc(100% - 7px) 100%, 7px 100%, 0 calc(100% - 7px), 0 7px); }
  .m-plate-inset { padding-inline: 11px; }
  .m-plate-inset::before, .m-plate-inset::after { height: 12px; }
  .is-compact .m-plate-inset::before, .is-compact .m-plate-inset::after { height: 6px; }
  .m-plate-row { display: grid; grid-template-columns: 36px minmax(0, 1fr); gap: 10px; align-items: center; }
  /* The 72 px emblem overhangs its 36 px column; the name sits past it at rest and moves in as it halves. */
  .m-plate-mark { position: relative; width: 36px; height: 72px; transition: height var(--m-collapse) var(--m-ease-out) var(--m-plate-delay); }
  .m-plate-mark img { position: absolute; top: 50%; left: 0; display: block; width: 72px; height: 72px; transform: translateY(-50%) scale(1); transform-origin: left center; transition: transform var(--m-collapse) var(--m-ease-out) var(--m-plate-delay); }
  .is-compact .m-plate-mark { height: 36px; }
  .is-compact .m-plate-mark img { transform: translateY(-50%) scale(.5); }
  .m-plate-bar { position: relative; display: flex; align-items: center; min-width: 0; }
  .m-plate-name { flex: none; font: 600 23px/1 'Plan Display', 'DIN Condensed', sans-serif; white-space: nowrap; transform: translate(36px, var(--m-name-y, 0px)); transition: transform var(--m-collapse) var(--m-ease-out) var(--m-plate-delay); }
  .is-compact .m-plate-name { transform: none; }
  /* A faint hairline divides the name from the address. Compact, it follows the name (masthead.js measures
     --m-divider-shift) and marks the lens's slot. */
  .m-plate-divider { flex: none; width: 1px; height: 34px; margin: 0 12px 0 auto; background: #bdc5ba; transition: opacity 180ms ease calc(60ms + var(--m-plate-delay)), transform var(--m-collapse) var(--m-ease-out) var(--m-plate-delay), height var(--m-collapse) var(--m-ease-out) var(--m-plate-delay); }
  .is-compact .m-plate-divider { opacity: 1; height: 24px; transform: translateX(var(--m-divider-shift, -36px)); transition: opacity 140ms ease 120ms, transform var(--m-collapse) var(--m-ease-out), height var(--m-collapse) var(--m-ease-out); }
  /* The address fades in once the plate has opened, and out before it closes. Its two lines stand 38 px tall;
     the negative margins keep it from making the compact row taller than the 36 px emblem. */
  .m-plate-address { flex: none; margin: -2px 0; text-align: right; transition: opacity 180ms ease calc(60ms + var(--m-plate-delay)), visibility 0s; }
  .is-compact .m-plate-address { opacity: 0; visibility: hidden; transition: opacity 80ms linear, visibility 0s 80ms; }
  .m-plate-street { display: block; font: 13px/1.2 'Plan Sans', 'Avenir Next', sans-serif; white-space: nowrap; }
  .m-plate-locality { display: block; margin-top: 3px; padding-top: 3px; border-top: 1px solid #bdc5ba; color: #526156; font: 600 13px/1.2 'Plan Sans', 'Avenir Next', sans-serif; white-space: nowrap; }
  /* Beside the name, only the short form of the address fits at 13 px. */
  .m-plate-address .long { display: none; }
  /* Narrower phones stack the full address under the name at rest; the compact bar is the same. */
  @media (max-width: 419px) {
    .m-plate-name { --m-name-y: -21.5px; }
    .m-plate-divider { margin: 0 0 0 11px; opacity: 0; }
    .m-plate-address { position: absolute; left: 36px; top: calc(50% - 5px); margin: 0; text-align: left; }
    .m-plate-address .long { display: inline; }
    .m-plate-address .short { display: none; }
  }

  /* ---- Drum -------------------------------------------------------------------------------------------- */
  /* The strip closes to its ink rule with the fold, and reopens only once the lens has flipped away. The drum
     hangs from the plate's lower edge and keeps its size while it folds. */
  .m-drum { --m-drum-height: 96px; --m-strip-height: 98px; position: relative; display: flex; align-items: flex-start; height: var(--m-strip-height); padding-left: max(16px, calc((100% - 560px) / 2 + 6px), calc(env(safe-area-inset-left) + 6px)); padding-right: max(16px, calc((100% - 560px) / 2 + 6px), calc(env(safe-area-inset-right) + 6px)); border-bottom: 2px solid var(--ink); background: #fafbf7; -webkit-tap-highlight-color: transparent; transition: --m-strip-height 210ms cubic-bezier(.2, .8, .3, 1) 120ms; }
  .is-compact .m-drum { --m-strip-height: 2px; transition: --m-strip-height 180ms cubic-bezier(.55, 0, .85, .35); }
  .m-drum[data-lens] { --m-drum-height: 36px; }
  /* One window, hinged in two places. It turns edge-on whenever the masthead and the lens disagree: folding up
     behind the plate at full size, or flipping out of the slot. Out of sight it changes place, size and shape
     at once (masthead.js sets data-lens), then turns back to face the reader. */
  .m-drum-window { position: relative; flex: none; width: 100%; border-radius: 4px; background-color: #f2f5ef00; box-shadow: inset 0 1px 3px #24362f00, inset 0 0 0 1px #8d9b8d00; transform-origin: 50% 0; transform: perspective(600px) rotateX(0deg); transition: transform 210ms cubic-bezier(.2, .8, .3, 1), opacity 120ms ease; }
  .is-compact .m-drum:not([data-lens]) .m-drum-window { transform: perspective(600px) rotateX(-90deg); opacity: 0; transition: transform 180ms cubic-bezier(.55, 0, .85, .35), opacity 90ms ease 90ms; }
  /* The lens drops in overshooting a little before it settles, centred on the plate's compact row 29 px
     above the strip; its recessed frame forms as it lands. */
  .m-drum[data-lens] .m-drum-window { width: var(--m-lens-width, 176px); translate: var(--m-lens-x, 181px) calc(-29px - 50%); background-color: #f2f5ef; box-shadow: inset 0 1px 3px #24362f38, inset 0 0 0 1px #8d9b8d; transition: transform 260ms cubic-bezier(.25, 1.5, .45, 1), opacity 50ms ease, background-color 140ms ease 150ms, box-shadow 140ms ease 150ms; }
  .masthead:not(.is-compact) .m-drum[data-lens] .m-drum-window { transform: perspective(600px) rotateX(-90deg); opacity: 0; background-color: #f2f5ef00; box-shadow: inset 0 1px 3px #24362f00, inset 0 0 0 1px #8d9b8d00; transition: transform 120ms cubic-bezier(.55, 0, .85, .35), opacity 50ms ease 70ms, background-color 80ms ease, box-shadow 80ms ease; }
  /* Reading rails mark the window to the right of the titles, so no title ever passes through them. */
  .m-drum-window::before, .m-drum-window::after { content: ''; position: absolute; left: var(--m-rail-left, 62%); right: 0; z-index: 1; height: 1px; background: #c4cbc1; pointer-events: none; }
  .m-drum-window::before { top: calc(50% - 25px); }
  .m-drum-window::after { top: calc(50% + 24px); }
  .m-drum[data-lens] .m-drum-window::before, .m-drum[data-lens] .m-drum-window::after { opacity: 0; }
  /* The reel is a native vertical scroller: wheel, trackpad and touch inertia come from the browser. */
  .m-drum-reel { position: relative; height: var(--m-drum-height); overflow-x: hidden; overflow-y: auto; overscroll-behavior: contain; overflow-anchor: none; scroll-snap-type: y mandatory; scrollbar-width: none; touch-action: pan-y; cursor: grab; user-select: none; -webkit-user-select: none; -webkit-mask-image: linear-gradient(transparent, #000 16%, #000 84%, transparent); mask-image: linear-gradient(transparent, #000 16%, #000 84%, transparent); }
  .m-drum-reel::-webkit-scrollbar { display: none; }
  .m-drum-reel[data-dragging] { scroll-snap-type: none; cursor: grabbing; }
  /* In the lens, a deeper fade top and bottom lets the neighbouring titles peek, so it still reads as a drum. */
  .m-drum[data-lens] .m-drum-reel { -webkit-mask-image: linear-gradient(transparent, #000 30%, #000 70%, transparent); mask-image: linear-gradient(transparent, #000 30%, #000 70%, transparent); }
  .m-drum-track { padding-block: calc((var(--m-drum-height) - 37px) / 2); }
  /* Titles are buttons, so every property the site's global button rules set is reset here. */
  .m-drum-item, .m-drum-item:hover { display: flex; align-items: center; justify-content: flex-start; gap: 0; width: 100%; height: 37px; min-height: 0; padding: 0; border: 0; border-radius: 0; background: none; color: var(--ink); font: 600 42px/44px 'Plan Display', 'DIN Condensed', sans-serif; letter-spacing: .01em; text-align: left; text-transform: uppercase; white-space: nowrap; scroll-snap-align: center; cursor: inherit; transition: opacity 160ms ease; }
  .m-drum[data-lens] .m-drum-item { padding-left: 10px; transition-duration: 80ms; }
  .m-drum-reel[data-moving] .m-drum-item { transition: none; }
  .m-drum-item:focus-visible { outline: 3px solid #bb8729; outline-offset: -3px; }
  .m-drum-label { display: block; width: 100%; transform-origin: 0 50%; pointer-events: none; backface-visibility: hidden; }
  .m-drum-type { display: inline-block; vertical-align: top; transform-origin: left center; }
  .m-drum[data-lens] .m-drum-type { transform: scale(var(--m-lens-scale, .6666667)); }
  /* Small stacked arrows sit at the plate's right end, only while compact, and arrive after the lens. */
  .m-drum-steps { position: absolute; top: -29px; right: max(22px, calc((100% - 560px) / 2 + 12px), calc(env(safe-area-inset-right) + 12px)); display: grid; gap: 2px; opacity: 0; visibility: hidden; pointer-events: none; transform: translateY(-50%) translateX(6px); transition: opacity 80ms ease, transform 120ms ease, visibility 0s 80ms; }
  .is-compact .m-drum-steps { opacity: 1; visibility: visible; pointer-events: auto; transform: translateY(-50%); transition: opacity 140ms ease 320ms, transform 220ms var(--m-ease-out) 280ms, visibility 0s; }
  .m-drum-steps button, .m-drum-steps button:hover { position: relative; display: grid; place-items: center; width: 26px; height: 16px; min-height: 0; padding: 0; border: 1px solid #9aa797; border-radius: 3px; background: #f3f5f0; cursor: pointer; }
  /* Each arrow draws at 26 × 16 px but takes taps across 42 × 25 px, reaching away from the other arrow. */
  .m-drum-steps button::before { content: ''; position: absolute; inset: -10px -9px -1px; }
  .m-drum-steps button + button::before { inset: -1px -9px -10px; }
  .m-drum-steps button:focus-visible { outline: 3px solid #bb8729; outline-offset: -3px; }
  .m-drum-steps svg { width: 14px; height: 14px; fill: none; stroke: var(--ink); stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }

  /* Keyboard navigation and reduced motion skip every transition, so focus and state change at once. */
  html:is([data-keyboard-nav], [data-short-phone]) :is(.m-plate, .m-drum), html:is([data-keyboard-nav], [data-short-phone]) :is(.m-plate, .m-drum) *, html:is([data-keyboard-nav], [data-short-phone]) :is(.m-plate, .m-drum)::before, html:is([data-keyboard-nav], [data-short-phone]) :is(.m-plate, .m-drum)::after, html:is([data-keyboard-nav], [data-short-phone]) :is(.m-plate, .m-drum) *::before, html:is([data-keyboard-nav], [data-short-phone]) :is(.m-plate, .m-drum) *::after { transition: none !important; }
  @media (prefers-reduced-motion: reduce) {
    :is(.m-plate, .m-drum), :is(.m-plate, .m-drum) *, :is(.m-plate, .m-drum)::before, :is(.m-plate, .m-drum)::after, :is(.m-plate, .m-drum) *::before, :is(.m-plate, .m-drum) *::after { transition: none !important; }
  }
}

/* The costs document still lays out for narrow windows if it is open. */
@media screen and (max-width: 700px) {
  dialog { width: 100vw; max-width: none; max-height: 100dvh; height: 100dvh; margin: 0; border: 0; }
  .costs-head { padding: 26px 22px; grid-template-columns: 1fr; gap: 20px; }
  .proposal-status { justify-self: start; }
  .costs-meta { grid-template-columns: 1fr; }
  .costs-meta > div { padding: 14px 22px; border-right: 0; border-bottom: 1px solid #e5e5e5; }
  .costs-body { padding: 4px 22px 26px; }
  .costs-table { table-layout: fixed; }
  .costs-table th:nth-child(2), .costs-table td:nth-child(2), .costs-table th:nth-child(3), .costs-table td:nth-child(3) { display: none; }
  .costs-table th:last-child, .costs-table td:last-child { width: 104px; }
  .scope-list { grid-template-columns: 1fr; }
  .scope-groups { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .costs-spec { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .costs-total, .costs-deposit { grid-template-columns: 1fr; }
  .deposit-amount { text-align: left; }
  .costs-actions { padding: 12px 22px; }
}
@page plan-sheet { size: 24in 18in; margin: 0; }
@page costs-sheet { size: letter portrait; margin: .5in; }
@media print {
  html, body { margin: 0; background: white; -webkit-print-color-adjust: exact; print-color-adjust: exact; }
  html.map-open, body.map-open { position: static; top: auto !important; width: auto; overflow: visible; }
  /* The masthead holds only screen controls; left in the flow, its empty box prints as a blank first page. */
  .masthead, .export-status, dialog { display: none !important; }
  .viewer { page: plan-sheet; padding: 0; overflow: visible; }
  .sheet { width: 24in; height: 18in; max-width: none; margin: 0; box-shadow: none; }
  #plan { width: 24in; height: 18in; }
  body.print-costs .viewer { display: none !important; }
  .print-costs-document { page: costs-sheet; display: block; color: #000; }
  .costs-head { gap: 16px; padding: 16px 0 22px; }
  .costs h2 { font-size: 50px; }
  .proposal-status { min-width: 175px; }
  .costs-meta > div { padding: 16px; }
  .costs-meta > div:first-child { padding-left: 0; }
  .costs-body { padding: 4px 0 0; }
  .costs-deposit { grid-template-columns: 1fr; gap: 16px; break-inside: avoid; }
  .deposit-amount { text-align: left; }
  .costs-actions { display: none; }
  .costs-table, .costs-total, .costs-excluded { break-inside: avoid; }
}
