/* Self-hosted fonts (BUILDS-16): Saira Condensed, IBM Plex Sans, IBM Plex Mono,
   vendored under ./fonts/ so the page has no runtime dependency on Google Fonts.
   Subsetted to latin + latin-ext; the unicode-range values below are copied
   verbatim from fonts.googleapis.com's own stylesheet, so a browser still only
   fetches whichever subset a page actually needs.
   IBM Plex Sans ships upstream as a variable font: Google serves the SAME file
   for weights 400/500/600, so the three rules below (per subset) point at the
   same two local files and let font-weight select within them, matching
   upstream exactly. Saira Condensed and IBM Plex Mono are static per weight, so
   each weight has its own pair of files.
   SIL Open Font License 1.1 for both families; text travels with the files at
   fonts/OFL-IBM-Plex.txt and fonts/OFL-Saira-Condensed.txt. */
@font-face{font-family:'Saira Condensed';font-style:normal;font-weight:500;font-display:swap;src:url(./fonts/saira-condensed-500-latin-ext.woff2) format('woff2');unicode-range:U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;}
@font-face{font-family:'Saira Condensed';font-style:normal;font-weight:500;font-display:swap;src:url(./fonts/saira-condensed-500-latin.woff2) format('woff2');unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;}
@font-face{font-family:'Saira Condensed';font-style:normal;font-weight:700;font-display:swap;src:url(./fonts/saira-condensed-700-latin-ext.woff2) format('woff2');unicode-range:U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;}
@font-face{font-family:'Saira Condensed';font-style:normal;font-weight:700;font-display:swap;src:url(./fonts/saira-condensed-700-latin.woff2) format('woff2');unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;}
@font-face{font-family:'Saira Condensed';font-style:normal;font-weight:800;font-display:swap;src:url(./fonts/saira-condensed-800-latin-ext.woff2) format('woff2');unicode-range:U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;}
@font-face{font-family:'Saira Condensed';font-style:normal;font-weight:800;font-display:swap;src:url(./fonts/saira-condensed-800-latin.woff2) format('woff2');unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;}
@font-face{font-family:'IBM Plex Sans';font-style:normal;font-weight:400;font-stretch:100%;font-display:swap;src:url(./fonts/ibm-plex-sans-latin-ext.woff2) format('woff2');unicode-range:U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;}
@font-face{font-family:'IBM Plex Sans';font-style:normal;font-weight:400;font-stretch:100%;font-display:swap;src:url(./fonts/ibm-plex-sans-latin.woff2) format('woff2');unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;}
@font-face{font-family:'IBM Plex Sans';font-style:normal;font-weight:500;font-stretch:100%;font-display:swap;src:url(./fonts/ibm-plex-sans-latin-ext.woff2) format('woff2');unicode-range:U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;}
@font-face{font-family:'IBM Plex Sans';font-style:normal;font-weight:500;font-stretch:100%;font-display:swap;src:url(./fonts/ibm-plex-sans-latin.woff2) format('woff2');unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;}
@font-face{font-family:'IBM Plex Sans';font-style:normal;font-weight:600;font-stretch:100%;font-display:swap;src:url(./fonts/ibm-plex-sans-latin-ext.woff2) format('woff2');unicode-range:U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;}
@font-face{font-family:'IBM Plex Sans';font-style:normal;font-weight:600;font-stretch:100%;font-display:swap;src:url(./fonts/ibm-plex-sans-latin.woff2) format('woff2');unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;}
@font-face{font-family:'IBM Plex Mono';font-style:normal;font-weight:400;font-display:swap;src:url(./fonts/ibm-plex-mono-400-latin-ext.woff2) format('woff2');unicode-range:U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;}
@font-face{font-family:'IBM Plex Mono';font-style:normal;font-weight:400;font-display:swap;src:url(./fonts/ibm-plex-mono-400-latin.woff2) format('woff2');unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;}
@font-face{font-family:'IBM Plex Mono';font-style:normal;font-weight:500;font-display:swap;src:url(./fonts/ibm-plex-mono-500-latin-ext.woff2) format('woff2');unicode-range:U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;}
@font-face{font-family:'IBM Plex Mono';font-style:normal;font-weight:500;font-display:swap;src:url(./fonts/ibm-plex-mono-500-latin.woff2) format('woff2');unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;}
@font-face{font-family:'IBM Plex Mono';font-style:normal;font-weight:600;font-display:swap;src:url(./fonts/ibm-plex-mono-600-latin-ext.woff2) format('woff2');unicode-range:U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;}
@font-face{font-family:'IBM Plex Mono';font-style:normal;font-weight:600;font-display:swap;src:url(./fonts/ibm-plex-mono-600-latin.woff2) format('woff2');unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;}

/* Palette from the yard: copper-treated pine, raw softwood, grade-stamp ink,
   galvanized steel. Shared with price-sheet.html so the two read as one tool. */
:root{
  --treated:#dfe6dc;
  --treated-deep:#cdd8c9;
  --board:#f2ecdd;
  --board-edge:#c8b895;
  --ink:#16221c;
  --ink-soft:#4b5b52;
  /* Darkened from #5c6b62 to clear WCAG AA (4.5:1) on the pale --treated body,
     where the old value came out at 4.42 for the footer and bed-line captions.
     Still lighter than --ink-soft, so the quiet-text tier survives. */
  --ink-faint:#526056;
  --copper:#1d6b58;
  --copper-lift:#25876f;
  --stamp:#a8322a;
  --amber:#8a6d1f;
  --rule:#b6c2b3;
  --paper:#fff;
}
*{box-sizing:border-box}
html,body{margin:0}
body{
  background:var(--treated);
  color:var(--ink);
  font-family:"IBM Plex Sans",system-ui,sans-serif;
  font-size:17.2px;
  line-height:1.5;
}
/* Wide on purpose. The sheets are drawn on an 816px page and rendered to fit the
   output pane, so the pane's width IS the sheet's zoom level, at 1320px the pane
   came out around 890px and 9px sheet labels rendered at 9px, which Brad could
   not read on a 4K monitor. At 1800 the pane is ~1370 and the same label lands
   near 16px. Widening the container beats enlarging the SVG type, which would
   reflow every sheet. */
.wrap{max-width:min(1800px,96vw);margin:0 auto;padding:0 20px}
/* Prose still wants a readable measure at that width. */
.lede,.foot p{max-width:70ch}

/* Soft-launch notice: the plans are usable and for sale, but the latest revisions are not
   build-verified yet, so the page says so without blocking a purchase. A quiet banded note,
   not an alarm. */
.wip-note{
  max-width:none;margin:14px 0 0;padding:10px 14px;
  background:var(--treated-deep);border-left:3px solid var(--stamp);border-radius:3px;
  font-size:14.5px;line-height:1.5;color:var(--ink-soft);
}
.wip-note strong{color:var(--stamp)}

/* ---------- masthead ---------- */
.masthead{border-bottom:2px solid var(--ink);background:var(--treated)}
.mast-inner{padding:30px 20px 20px}
h1{
  font-family:"Saira Condensed",sans-serif;
  font-weight:800;
  font-size:clamp(38px,7vw,64px);
  text-transform:uppercase;
  letter-spacing:-.015em;
  line-height:.92;
  margin:0;
}
h1 span{color:var(--copper)}
.lede{max-width:60ch;margin:10px 0 0;color:var(--ink-soft)}

/* ---------- layout ---------- */
.layout{display:grid;grid-template-columns:334px 1fr;gap:22px;padding:22px 20px 10px;align-items:start}
/* A grid track refuses to shrink below its content's min-content width, so a
   zoomed drawing widened the whole page instead of scrolling inside its pane. */
.layout>.output{min-width:0}
.panel{background:var(--paper);border:1px solid var(--rule);border-radius:3px;padding:18px}
/* Controls sit in the normal page flow, so the page's own scrollbar is the only
   one. This used to be a sticky, inner-scrolling column, which on a shorter
   viewport put the Build list and Prices below its own fold behind a second
   scrollbar, a scroll within a scroll (BUILDS-12). The output pane brings its own
   scroll for a zoomed drawing, so a big sheet is still reachable without pinning
   the controls. */
.controls{align-self:start}

h2{
  font-family:"Saira Condensed",sans-serif;
  font-weight:700;
  font-size:19.5px;
  text-transform:uppercase;
  letter-spacing:.08em;
  margin:0 0 12px;
  padding-bottom:6px;
  border-bottom:1px solid var(--rule);
}
.controls h2:not(:first-child){margin-top:26px}

.ctl{margin-bottom:16px}
.ctl label,.controls .stack legend{
  display:block;
  font-family:"Saira Condensed",sans-serif;
  font-weight:700;
  font-size:13.2px;
  letter-spacing:.1em;
  text-transform:uppercase;
  color:var(--ink-soft);
  margin-bottom:6px;
}
.seg{display:flex;flex-wrap:wrap;gap:5px}
.seg button{
  flex:1 1 auto;
  min-width:44px;
  font-family:"IBM Plex Mono",monospace;
  font-size:14.9px;
  padding:7px 4px;
  border:1px solid var(--rule);
  background:var(--paper);
  color:var(--ink-soft);
  border-radius:2px;
  cursor:pointer;
}
.seg button:hover{border-color:var(--copper);color:var(--ink)}
.seg button[aria-pressed=true]{background:var(--copper);border-color:var(--copper);color:#fff;font-weight:600}
/* The recommendation marker. Deliberately just an asterisk keyed to a footnote -
   a "best" badge claimed more than the footnote can support. */
.seg button .rec{
  display:inline;font-size:15px;line-height:0;vertical-align:baseline;
  color:var(--copper);font-weight:700;margin-left:1px;
}
.seg button[aria-pressed=true] .rec{color:#fff}

select,textarea{
  width:100%;
  font-family:"IBM Plex Sans",sans-serif;
  font-size:16.1px;
  color:var(--ink);
  background:var(--paper);
  border:1px solid var(--rule);
  border-radius:2px;
  padding:8px 9px;
}
textarea{font-family:"IBM Plex Mono",monospace;font-size:13.8px;min-height:120px;resize:vertical}
:focus-visible{outline:2px solid var(--copper);outline-offset:2px}

.ctl.check{display:flex;gap:9px;align-items:flex-start}
.ctl.check input{margin-top:3px;flex:0 0 auto;accent-color:var(--copper)}
.ctl.check label{margin:0;text-transform:none;letter-spacing:0;font-size:15.5px;font-family:"IBM Plex Sans",sans-serif;font-weight:500;color:var(--ink)}
.ctl.check label span{display:block;font-weight:400;font-size:13.8px;color:var(--ink-faint);margin-top:2px}

.stack{display:flex;flex-direction:column;gap:5px}
.stack label{
  display:flex;align-items:center;gap:8px;
  font-family:"IBM Plex Mono",monospace;font-size:14.9px;
  text-transform:none;letter-spacing:0;color:var(--ink);margin:0;font-weight:400;
}
.stack input{accent-color:var(--copper)}

.note{font-size:14.4px;color:var(--ink-faint);margin:0 0 10px}
.beds{list-style:none;margin:0 0 10px;padding:0}
.beds li{
  display:flex;align-items:center;gap:8px;
  font-family:"IBM Plex Mono",monospace;font-size:14.4px;
  padding:6px 8px;background:var(--treated);border-radius:2px;margin-bottom:4px;
}
.beds li{flex-wrap:wrap}
.beds li .qty{color:var(--copper);font-weight:600}
/* Matches the letter tag on the order sheet, so the list and the sheet agree. */
.beds li .tag{
  font-weight:700;color:var(--stamp);border:1px solid var(--rule);
  border-radius:2px;padding:0 4px;background:var(--paper);
}
/* Options that differ from the default, what makes two same-size beds distinct. */
.beds li small{
  flex-basis:100%;font-size:12.6px;color:var(--ink-faint);
  font-family:inherit;padding-left:2px;
}
/* The size itself is the button that loads that bed back into the controls. */
.beds li button.pick{
  flex:1;border:none;background:none;padding:0;cursor:pointer;text-align:left;
  font-family:inherit;font-size:inherit;color:var(--ink);
}
.beds li button.pick:hover{color:var(--copper)}
.beds li button.drop{
  margin-left:auto;border:none;background:none;color:var(--stamp);
  cursor:pointer;font-size:18.4px;line-height:1;padding:0 2px;
}
/* The bed the rest of the tabs are currently drawing. Filled, not a hairline,
   so it is unmistakable which bed the plans are for. */
.beds li.live{background:var(--copper)}
.beds li.live .qty,
.beds li.live button.pick,
.beds li.live button.pick:hover,
.beds li.live button.drop{color:#fff}
.beds li.live small{color:rgba(255,255,255,.82)}
.beds li.live .tag{color:var(--copper);background:#fff;border-color:#fff}
.beds li.live button.pick{font-weight:700}

.row-btns{display:flex;gap:8px;flex-wrap:wrap}
.btn{
  font-family:"Saira Condensed",sans-serif;
  font-weight:700;font-size:14.9px;letter-spacing:.08em;text-transform:uppercase;
  padding:9px 14px;border-radius:2px;cursor:pointer;
  border:1px solid var(--copper);background:var(--copper);color:#fff;
  text-decoration:none;display:inline-block;text-align:center;
}
.btn:hover{background:var(--copper-lift);border-color:var(--copper-lift)}
.btn.ghost{background:transparent;color:var(--copper)}
.btn.ghost:hover{background:var(--treated);color:var(--copper)}
.btn.block{display:block;margin-top:8px}
.btn.small{padding:6px 11px;font-size:13.8px;margin-top:8px}
details.paste{margin-top:10px}
details.paste summary{font-size:14.4px;color:var(--copper);cursor:pointer}

/* ---------- readout ----------
   A heading and one line of actual dimensions. It used to be seven boxed
   figures, which shouted numbers you read once; the rest are on the notes tab. */
.readout{border-bottom:1px solid var(--rule);padding-bottom:10px}
/* Output header: bed dimensions on the left, the Buy PDF call to action on the
   right. The rule underneath spans the whole header, not just the readout.
   BUILDS-48. */
.output-head{display:flex;justify-content:space-between;align-items:flex-start;gap:20px;
  border-bottom:1px solid var(--rule);padding-bottom:10px}
.output-head .readout{border-bottom:0;padding-bottom:0}
.buy{flex:none;text-align:right}
.buy-pdf{background:#8a6d1f;border-color:#8a6d1f;padding:11px 20px}
.buy-pdf:hover{background:#a5842a;border-color:#a5842a}
.buy-note{margin:7px 0 0;font-size:13.2px;color:var(--ink-soft);max-width:24ch}

/* Cold-start notice: a dismissable centered modal shown while checkout is being
   set up, since the first request can take a moment. Temporary, for the
   soft-launch window (see showColdModal in planner.js). */
.cold-modal{position:fixed;inset:0;z-index:1000;display:flex;align-items:center;justify-content:center;padding:20px}
.cold-backdrop{position:absolute;inset:0;background:rgba(22,34,28,.55)}
.cold-card{
  position:relative;max-width:400px;width:100%;background:var(--paper);
  border:1px solid var(--rule);border-radius:4px;padding:24px 26px;
  box-shadow:0 20px 50px -12px rgba(22,34,28,.45);
}
.cold-card h3{
  font-family:"Saira Condensed",sans-serif;font-weight:800;font-size:22px;
  text-transform:uppercase;letter-spacing:.02em;margin:0 0 8px;color:var(--ink);
}
.cold-card p{margin:0;line-height:1.5;color:var(--ink-soft)}
.cold-x{
  position:absolute;top:6px;right:10px;background:none;border:none;
  font-size:26px;line-height:1;color:var(--ink-soft);cursor:pointer;padding:2px 6px;
}
.cold-x:hover{color:var(--ink)}

/* ---------- Buy PDF button animations ----------
   A quiet SVG flourish that mounts behind the button, plays once, and is removed
   (see BUY_ANIM in planner.js). The mount never takes pointer events, so the
   button stays a normal control; it is absolutely positioned so it never shifts
   layout. Set from the buy-button-animations design mockup. */
.buy-anim-wrap{position:relative;display:inline-block}
.buy-anim-wrap > .btn{position:relative;z-index:1}
.buy-anim-mount{
  position:absolute;left:50%;top:50%;width:300px;height:200px;
  transform:translate(-50%,-50%);pointer-events:none;z-index:0;
}
.buy-anim-mount svg{position:absolute;inset:0;width:100%;height:100%;overflow:visible;pointer-events:none}
.leaf{transform-box:fill-box;transform-origin:4% 50%}
@media (prefers-reduced-motion:reduce){ .buy-anim-mount{display:none!important} }

@keyframes vine-draw{
  0%   { stroke-dashoffset:515; opacity:1; }
  52%  { stroke-dashoffset:0;   opacity:1; }
  88%  { stroke-dashoffset:0;   opacity:1; }
  97%  { stroke-dashoffset:0;   opacity:0; }
  97.1%{ stroke-dashoffset:515; opacity:0; }
  100% { stroke-dashoffset:515; opacity:0; }
}
@keyframes leaf-unfurl{
  0%, 6%   { transform:scale(0) rotate(-14deg); opacity:0; }
  16%      { transform:scale(1.12) rotate(3deg); opacity:1; }
  22%, 88% { transform:scale(1) rotate(0deg);   opacity:1; }
  97%,100% { transform:scale(1) rotate(0deg);   opacity:0; }
}
@keyframes tendril-curl{
  0%   { stroke-dashoffset:100; opacity:1; }
  18%  { stroke-dashoffset:0;  opacity:1; }
  88%  { stroke-dashoffset:0;  opacity:1; }
  97%  { stroke-dashoffset:0;  opacity:0; }
  97.1%{ stroke-dashoffset:100; opacity:0; }
  100% { stroke-dashoffset:100; opacity:0; }
}
@keyframes kerf-trace{ 0%{stroke-dashoffset:584;} 60%{stroke-dashoffset:0;} 100%{stroke-dashoffset:0;} }
@keyframes blade-ride{
  0%   { offset-distance:0%; opacity:0; }
  4%   { opacity:1; }
  60%  { offset-distance:100%; opacity:1; }
  70%,100% { offset-distance:100%; opacity:0; }
}
@keyframes blade-spin{ to { transform:rotate(360deg); } }
@keyframes dust{
  0%, 8%  { transform:translate(0,0) scale(1); opacity:0; }
  12%     { opacity:.9; }
  100%    { transform:translate(-14px, 20px) scale(.4); opacity:0; }
}
@keyframes hammer-swing{
  0%      { transform:rotate(28deg); }
  9%      { transform:rotate(0deg); }
  14%     { transform:rotate(24deg); }
  26%     { transform:rotate(0deg); }
  31%     { transform:rotate(24deg); }
  43%     { transform:rotate(0deg); }
  48%     { transform:rotate(24deg); }
  60%     { transform:rotate(0deg); }
  72%,100%{ transform:rotate(28deg); }
}
@keyframes nail-sink{
  0%, 8%   { transform:translateY(0); }
  10%, 25% { transform:translateY(6px); }
  27%, 42% { transform:translateY(12px); }
  44%, 59% { transform:translateY(17px); }
  61%, 88% { transform:translateY(21px); }
  97%,100% { transform:translateY(0); }
}
@keyframes strike-ring{
  0%, 8%  { transform:scale(.2); opacity:0; }
  10%     { opacity:.9; }
  20%     { transform:scale(1.6); opacity:0; }
  100%    { opacity:0; }
}
@keyframes drill-push{
  0%      { transform:translate(56px, 0); }
  16%     { transform:translate(8px, 0); }
  22%     { transform:translate(4px, 1px); }
  28%     { transform:translate(6px, -1px); }
  42%     { transform:translate(-8px, 1px); }
  48%     { transform:translate(-6px, -1px); }
  62%     { transform:translate(-20px, 1px); }
  68%     { transform:translate(-18px, -1px); }
  80%     { transform:translate(-30px, 0); }
  88%     { transform:translate(-30px, 0); }
  100%    { transform:translate(56px, 0); }
}
@keyframes thread-spin{ to { stroke-dashoffset:-36; } }
@keyframes swarf{
  0%, 22% { transform:translate(0,0); opacity:0; }
  26%     { opacity:.9; }
  100%    { transform:translate(9px, 20px); opacity:0; }
}
.readout h2{
  font-family:"Saira Condensed",sans-serif;font-weight:800;font-size:34.5px;
  letter-spacing:.01em;margin:0;line-height:1.05;
  /* Not uppercased like the other panel headings, this is a dimension, and
     "8' X 30"" reads as an unknown rather than a size. */
  text-transform:none;color:var(--ink);
}
.readout p{
  margin:3px 0 0;font-family:"IBM Plex Mono",monospace;font-size:14.4px;
  color:var(--ink-faint);
}

/* The figures, in their new home on the notes page. */
dl.dims{
  display:grid;grid-template-columns:max-content 1fr;gap:3px 16px;
  margin:0 0 18px;font-size:15.5px;
}
dl.dims dt{
  font-family:"Saira Condensed",sans-serif;font-weight:700;font-size:12.1px;
  letter-spacing:.1em;text-transform:uppercase;color:var(--ink-faint);
  align-self:baseline;padding-top:2px;
}
dl.dims dd{margin:0;font-family:"IBM Plex Mono",monospace}

/* ---------- cart tab ---------- */

/* The tool checklist. Icons make it scannable; it carries no links, which is
   why it looks nothing like the lists below it. */
ul.toolgrid{
  list-style:none;margin:0 0 22px;padding:0;
  display:grid;grid-template-columns:repeat(auto-fill,minmax(150px,1fr));gap:14px;
}
ul.toolgrid li{
  display:grid;grid-template-columns:44px 1fr;grid-template-rows:auto auto;
  column-gap:10px;align-items:center;
  padding:9px 10px;border:1px solid var(--treated-deep);border-radius:5px;
}
ul.toolgrid li img.toolimg{grid-row:1/3;width:44px;height:44px;display:block}
ul.toolgrid li span{font-size:14.5px;color:var(--ink);font-weight:600;align-self:end}
ul.toolgrid li small{font-size:12.5px;color:var(--ink-faint);align-self:start}
ul.toolgrid li:has(small:empty) span{grid-row:1/3;align-self:center}
/* A tool we sell turns its whole tile into a jump to its buy row. The link
   covers the card with no visible text, so a tile that looks like a button now
   behaves like one; its aria-label names the tool for a screen reader. Only
   these tiles get the hover, so the affordance is honest. */
ul.toolgrid li.shop{position:relative}
ul.toolgrid li.shop:hover,ul.toolgrid li.shop:focus-within{border-color:var(--copper)}
ul.toolgrid li.shop .tilelink{position:absolute;inset:0}

ul.links{list-style:none;margin:0 0 20px;padding:0}
/* Each row is one flex line: the part name (and derived qty) on the left, the store
   links grouped and right-aligned on the right; a longer description wraps to its own
   full-width line beneath. Matches the box/marble/torch Shopping treatment. */
ul.links li{
  display:flex;flex-wrap:wrap;align-items:baseline;gap:4px 12px;
  padding:7px 0;border-bottom:1px solid var(--treated-deep);font-size:15.5px;
}
ul.links li .name{font-weight:600;color:var(--ink)}
/* Description text keeps its place, dropping to its own line under the row. It stays a
   full-width flex item (so it always breaks to its own line), but a percentage padding on
   the right wraps the text by ~mid-page so a long note never runs the full width under the
   right-aligned store links. (A max-width here would be clamped into the flex basis and
   the note would stop taking its own line.) */
ul.links li small{flex-basis:100%;order:5;display:block;padding-right:48%;font-size:13.5px;color:var(--ink-faint);margin:2px 0 0}
/* The store links: right-aligned as a group, full text size, underlined, spaced by a
   middot. The pack size is the lighter <em>. */
ul.links li .buy{margin-left:auto;display:flex;flex-wrap:wrap;align-items:baseline;gap:4px 10px}
/* The generic Amazon/Home Depot/Lowe's searches drop to their own line under the called-
   out products, still right-aligned. */
ul.links li .buy-search{flex-basis:100%;justify-content:flex-end;margin-top:3px}
ul.links li .buy a{
  color:var(--copper);font-size:15px;text-decoration:underline;text-underline-offset:2px;
  text-decoration-thickness:1px;
}
ul.links li .buy a em{font-style:normal;font-weight:400}
ul.links li .buy .sep{color:var(--treated-deep);user-select:none}
/* Derived count, next to the item name. */
ul.links li .qty{
  font-weight:600;color:var(--copper);font-variant-numeric:tabular-nums;
}

/* ---------- sheet tabs ---------- */
.tabs{display:flex;flex-wrap:wrap;gap:4px;margin:22px 0 0;border-bottom:1px solid var(--rule);padding-bottom:0}
.tabs button{
  font-family:"Saira Condensed",sans-serif;font-weight:700;font-size:14.4px;
  letter-spacing:.06em;text-transform:uppercase;
  padding:8px 12px;border:1px solid transparent;border-bottom:none;
  background:none;color:var(--ink-soft);cursor:pointer;border-radius:2px 2px 0 0;
}
.tabs button:hover{color:var(--ink);background:var(--treated)}
.tabs button[aria-selected=true]{background:var(--treated-deep);border-color:var(--rule);color:var(--ink);margin-bottom:-1px}
/* The Cross tie tab, held in place but disabled on a bed with no tie (BUILDS-12).
   Greyed and inert, and it does not take the hover treatment, so it reads as a
   tab that is not available at this size rather than one you can open. */
.tabs button:disabled{color:var(--ink-faint);opacity:.5;cursor:not-allowed}
.tabs button:disabled:hover{background:none;color:var(--ink-faint)}
/* ---------- zoom ---------- */
.zoombar{display:flex;align-items:center;gap:10px;margin-top:12px}
.zoombar>span{
  font-family:"Saira Condensed",sans-serif;font-weight:700;font-size:12.1px;
  letter-spacing:.1em;text-transform:uppercase;color:var(--ink-faint);
}
.seg.small button{font-size:12.6px;padding:3px 8px}

/* Upright controls, shown above the Uprights sheet. A boxed group so it reads as
   configuration for the drawing below it, not part of the drawing. */
.tab-panel{margin-top:12px;padding:14px 16px;border:1px solid var(--rule);
  border-radius:5px;background:var(--treated)}
.tab-panel .ctl{margin-bottom:14px}
.tab-panel .ctl:last-child{margin-bottom:0}
.tab-opts{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:14px 22px}
.tab-opts .ctl{margin-bottom:0}
.tab-panel select{width:100%;padding:8px 10px;border:1px solid var(--treated-deep);
  border-radius:5px;background:var(--paper);color:var(--ink);font-size:14.5px}
@media (max-width:620px){.tab-opts{grid-template-columns:1fr}}

.sheet{margin-top:10px;overflow-x:auto;background:var(--paper)}
/* width, not max-width. The sheets carry an explicit width="816" attribute, so
   max-width only ever shrank them, "Fit" rendered at 1:1 no matter how wide the
   pane was, and every 9px label on every sheet stayed 9px. */
.sheet svg{width:100%;height:auto;display:block}
/* Zoomed, the drawing is bigger than the pane on purpose, scroll it in place
   rather than pushing the rest of the page down a screen and a half.
   `contain` isolates the pane's paint so scrolling the large drawing does not
   invalidate anything outside it (BUILDS-11). */
.sheet.zoomed{overflow:auto;max-height:78vh;border:1px solid var(--rule);resize:vertical;cursor:grab;contain:layout paint}
.sheet.zoomed svg{max-width:none}
/* Dragging the drawing is the natural gesture for reading one. Scrollbars stay
   as a fallback, but nobody should have to use them. */
.sheet.dragging{cursor:grabbing}
.sheet.zoomed svg{user-select:none;-webkit-user-drag:none}
/* The Assembled view is a real 3D model, not an SVG drawing: give the viewer a
   pane to live in. It brings its own orbit and zoom, so it is outside the SVG
   zoom path entirely (applyZoom hides the zoombar when there is no <svg>). */
model-viewer.viewer3d{
  display:block;width:100%;height:min(70vh,600px);
  background:var(--paper);border:1px solid var(--rule);border-radius:5px;
  --poster-color:transparent;
}
/* The user-facing render-style toggle under the 3D view. */
.viewer-opts{display:flex;gap:16px;margin-top:10px;font-size:14px;color:var(--ink)}
.viewer-opts label{display:inline-flex;align-items:center;gap:6px;cursor:pointer}
/* Reset the 3D camera to the default framing. Pushed to the right of the row. */
.viewer-opts .reset-view{
  margin-left:auto;font-family:"Saira Condensed",sans-serif;font-weight:700;
  font-size:12.6px;letter-spacing:.06em;text-transform:uppercase;
  padding:5px 12px;border:1px solid var(--rule);background:var(--paper);
  color:var(--ink-soft);cursor:pointer;
}
.viewer-opts .reset-view:hover{border-color:var(--copper);color:var(--ink)}
/* Contextual deep-link into Musings, as a standard info "i". Quiet, sits inline in
   the finish row; the jump wiring in planner.js scrolls to the passage. The label
   lives on title/aria-label so the icon alone stays uncluttered. */
.viewer-opts .why-link{
  align-self:center;display:inline-flex;line-height:0;
  color:var(--copper);text-decoration:none;transition:transform .12s;
}
.viewer-opts .why-link:hover,.viewer-opts .why-link:focus-visible{transform:scale(1.12)}
.viewer-opts .why-link svg{width:19px;height:19px;display:block}
/* Dev-only (?dev=1) body and wireframe toggles under the 3D view, for isolating
   a member while troubleshooting geometry. */
.iso3d-dev{display:flex;flex-wrap:wrap;gap:6px 16px;margin-top:8px;font-size:13px;color:var(--ink-faint)}
.iso3d-dev label{display:inline-flex;align-items:center;gap:5px;cursor:pointer}
/* BUILDS-85 dev wood-material tuner: full-width row under the dev toggles. */
.mat-tune{flex-basis:100%;display:flex;flex-wrap:wrap;align-items:center;gap:6px 14px;margin-top:6px;padding-top:6px;border-top:1px dashed var(--rule,#b6c2b3)}
.mat-tune input[type=range]{width:96px}
.mat-tune code{font-size:12px;color:var(--ink,#16221c)}
/* The paid PDF plan set, built by the backend and wired to Buy PDF once a
   paywall lands, plus its cold-start spinner. */
.pdf-status{display:inline-flex;align-items:center;gap:8px;font-size:14px;color:var(--ink-soft);max-width:34ch}
.pdf-status .spin{flex:none;width:14px;height:14px;border:2px solid var(--rule);
  border-top-color:var(--copper);border-radius:50%;animation:spin .8s linear infinite}
@keyframes spin{to{transform:rotate(360deg)}}

/* ---------- warnings ---------- */
.warnings{margin-top:22px;border-top:1px solid var(--rule);padding-top:14px}
.warn-item{display:flex;gap:10px;padding:7px 0;font-size:15.5px;align-items:flex-start}
.warn-item b{
  flex:0 0 auto;font-family:"Saira Condensed",sans-serif;font-weight:700;font-size:12.1px;
  letter-spacing:.09em;text-transform:uppercase;padding:2px 6px;border-radius:2px;margin-top:2px;
}
.warn-item.required b{background:var(--stamp);color:#fff}
.warn-item.caution b{background:var(--amber);color:#fff}
.warn-item.info b{background:var(--treated-deep);color:var(--ink-soft)}
.warn-item p{margin:0;color:var(--ink-soft)}

/* Header on the per-sheet notes panel, with an escape hatch to the full list. */
.warn-head{
  font-family:"Saira Condensed",sans-serif;font-weight:700;font-size:13.8px;
  letter-spacing:.09em;text-transform:uppercase;color:var(--ink-faint);
  margin:0 0 6px;display:flex;align-items:baseline;gap:10px;
}
.warn-head a{margin-left:auto;color:var(--copper);text-transform:none;letter-spacing:0;font-size:13.8px;font-weight:600}

/* Which sheets a note belongs to, shown only on the All notes page. */
.warn-tags{
  display:block;margin-top:3px;font-family:"IBM Plex Mono",monospace;
  font-size:12.1px;color:var(--ink-faint);
}

/* ---------- all-notes page ---------- */
.notes-page{padding:4px 2px 8px;max-width:78ch}
/* The reference pages (Notes and Materials) are lists, not prose, so they drop
   the reading-measure cap and use the full width of the pane rather than leaving
   half of it empty on a wide screen (BUILDS-12). The checklist grid and the buy
   lists spread to fill it. The Journal is read top to bottom like an article, so
   it opts out and keeps its own narrow measure below. */
.notes-page:not(.musings){max-width:none}
.notes-page h2{
  font-family:"Saira Condensed",sans-serif;font-weight:700;font-size:23px;
  letter-spacing:.03em;margin:0 0 4px;color:var(--stamp);
}
.notes-page h3{
  font-family:"Saira Condensed",sans-serif;font-weight:700;font-size:14.9px;
  letter-spacing:.08em;text-transform:uppercase;color:var(--ink-faint);
  margin:22px 0 4px;padding-top:10px;border-top:1px solid var(--rule);
  display:flex;align-items:baseline;gap:8px;
}
.notes-page h3 .count{
  font-family:"IBM Plex Mono",monospace;font-size:12.6px;font-weight:500;
  background:var(--treated);padding:1px 6px;border-radius:2px;
}

/* ---------- musings ----------
   The one tab that is read rather than consulted, so it gets prose measure and
   prose leading instead of the reference-block treatment above. Section headings
   opt out of the uppercase grey rule shared with the notes page: these are titles
   someone wrote, not section labels. Each section carries an id for deep-links, so
   scroll-margin keeps a jumped-to heading clear of the pane's top edge. */
.musings{max-width:66ch}
.musings .entry{padding-top:22px;margin-top:22px;border-top:1px solid var(--rule);scroll-margin-top:16px}
.musings .entry:first-of-type{border-top:none;padding-top:8px;margin-top:8px}
.musings .entry h3{
  font-family:"Saira Condensed",sans-serif;font-weight:800;font-size:26px;
  letter-spacing:-.005em;text-transform:none;color:var(--ink);
  margin:0;padding-top:0;border-top:none;display:block;line-height:1.12;
}
.musings .standfirst{
  font-size:19px;line-height:1.4;color:var(--ink);font-weight:600;margin:12px 0 0;
}
.musings .entry p{margin:12px 0 0;line-height:1.62}
.musings .entry .subhead{
  font-family:"Saira Condensed",sans-serif;font-weight:700;font-size:19px;
  color:var(--ink);letter-spacing:-.005em;line-height:1.2;margin:26px 0 0;
}
.musings .entry a{color:var(--copper);text-decoration:underline;text-underline-offset:2px;overflow-wrap:anywhere}

.hint{margin:6px 0 0;font-size:13.2px;color:var(--ink-faint);line-height:1.45}
[hidden]{display:none!important}

.foot{padding:26px 20px 44px;color:var(--ink-faint);font-size:14.9px;max-width:70ch}
.foot p{margin:0 0 6px}
.tiny{font-size:13.2px}

@media (max-width:900px){
  .layout{grid-template-columns:1fr}
  .controls{position:static;max-height:none}
}

.blocked{padding:34px 24px;text-align:center;background:var(--treated)}
.blocked h3{font-family:"Saira Condensed",sans-serif;font-weight:700;font-size:21.8px;text-transform:uppercase;letter-spacing:.06em;margin:0 0 8px;color:var(--stamp)}
.blocked p{max-width:46ch;margin:0 auto 16px;color:var(--ink-soft);font-size:16.1px}

/* ============================================================================
   ENGINEERING-PAPER FRAME  (design/engineering-paper branch)

   The "shop drawing on green engineering paper" look from the Claude design
   system in Design/Garden planter design system/. Type is deliberately left
   alone (families and sizes above are unchanged) per Brad: the identity comes
   from the frame, not from smaller or denser text. Shared verbatim with
   boxes/boxes.css, which carries the same tokens and control classes.
   ========================================================================== */

:root{
  --paper:#FBFCF7;   /* panel + sheet interior: warm near-white drawing stock */
  --rule:#A7B6A9;    /* hairline, nudged toward the system's green-grey line */
  --eng-ink:#16241c; /* structural ink line */
}

/* Page ground: green engineering paper, two rules at 14px and 70px, fixed so
   the grid stays registered while scrolling. Panels are opaque over it, so the
   grid only reads in the margins, masthead and footer, keeping controls legible. */
body{
  background-color:#E7EDDD;
  background-image:
    linear-gradient(rgba(58,96,66,.07) 1px,transparent 1px),
    linear-gradient(90deg,rgba(58,96,66,.07) 1px,transparent 1px),
    linear-gradient(rgba(58,96,66,.14) 1px,transparent 1px),
    linear-gradient(90deg,rgba(58,96,66,.14) 1px,transparent 1px);
  background-size:14px 14px,14px 14px,70px 70px,70px 70px;
  background-attachment:fixed;
}

/* Rules, not cards: square every corner, structural borders go full ink. */
.panel{border-color:var(--eng-ink);border-radius:0}
select,textarea{border-color:var(--eng-ink);border-radius:0}
.seg button,.btn,.beds li,.beds li .tag,.tab-panel,.warn-item b,.blocked{border-radius:0}
.sheet.zoomed,model-viewer.viewer3d{border-radius:0;border-color:var(--eng-ink)}

/* Masthead: compass mark, faint watermark, double registration rule. */
.masthead{background:transparent;border-bottom:3px double var(--eng-ink);
  position:relative;overflow:hidden}
.mast-inner{position:relative}
.mast-watermark{position:absolute;right:-30px;top:auto;bottom:-46px;width:230px;height:230px;
  opacity:.13;pointer-events:none}
.mast-brand{display:flex;align-items:center;gap:16px}
.mast-brand svg{flex:none}

/* Section headers: a tool glyph sits before the label. */
.controls h2{display:flex;align-items:center;gap:9px}
.controls h2 svg{width:16px;height:16px;flex:none}

/* Choice chips: the pressed size reads as a stamp, unavailable is drawn dashed. */
.seg button[aria-pressed=true]{box-shadow:2px 2px 0 var(--eng-ink);border-color:var(--eng-ink)}
.seg button:disabled{border-style:dashed;color:var(--rule);background:var(--paper)}

/* Buttons: square + a hard ink offset for the stamped, sharper feel. */
.btn{border-radius:0}
.btn:not(.ghost){box-shadow:2px 2px 0 var(--eng-ink)}
.btn:not(.ghost):active{box-shadow:0 0 0 var(--eng-ink);transform:translate(2px,2px)}
.btn.ghost{border-color:var(--eng-ink);color:var(--copper)}

/* Folder tabs joined to the panel, saw blade on the active sheet. */
.tabs{gap:2px;border-bottom:1px solid var(--eng-ink)}
.tabs button{border:1px solid var(--rule);border-bottom:none;
  background:rgba(255,255,255,.5);border-radius:0}
.tabs button:hover{background:rgba(255,255,255,.8)}
.tabs button[aria-selected=true]{background:var(--eng-ink);color:var(--paper);
  border-color:var(--eng-ink);margin-bottom:-1px;display:inline-flex;align-items:center;gap:7px}
.tabs button[aria-selected=true]::before{content:"";width:13px;height:13px;flex:none;
  background:url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='%23A8C27E'%20stroke-width='1.8'%3E%3Ccircle%20cx='12'%20cy='12'%20r='9.6'%20stroke-dasharray='2.6%203.4'/%3E%3Ccircle%20cx='12'%20cy='12'%20r='5'/%3E%3C/svg%3E") no-repeat center/contain}
.tabs button:disabled::before{display:none}

/* Drawing sheet: near-white stock on a 16px grid. */
.sheet{background-color:var(--paper);
  background-image:
    linear-gradient(rgba(58,96,66,.075) 1px,transparent 1px),
    linear-gradient(90deg,rgba(58,96,66,.075) 1px,transparent 1px);
  background-size:16px 16px}
/* ---------- home button (upper-right of the masthead, to the landing hub) ---------- */
.mast-inner{position:relative}
.home-btn{
  position:absolute;top:14px;right:16px;z-index:3;
  display:inline-flex;align-items:center;gap:7px;
  padding:8px 15px;border:1px solid var(--copper,#1d6b58);border-radius:999px;
  background:var(--paper,#fff);color:var(--copper,#1d6b58);
  text-decoration:none;font-weight:700;font-size:13.5px;letter-spacing:.02em;line-height:1;
  box-shadow:0 1px 0 rgba(22,34,28,.05);
  transition:background .16s ease,color .16s ease,transform .16s ease,box-shadow .16s ease;
}
.home-btn:hover,.home-btn:focus-visible{
  background:var(--copper,#1d6b58);color:#fff;outline:none;
  transform:translateY(-1px);box-shadow:0 8px 18px -8px rgba(22,34,28,.4);
}
.home-btn svg{width:16px;height:16px;transition:transform .2s ease}
.home-btn:hover svg{transform:rotate(-12deg)}

/* Shared 3D control bar (BUILDS-117): identical rules to boxes.css so the bar reads
   the same across tools. The planter slots its wood Finish + the "why PT-wood" link
   in as extras; Edge lines / Auto-rotate / Exposure / Reset are the shared baseline. */
.viewbar{display:flex;align-items:center;gap:16px;margin-top:10px;flex-wrap:wrap}
.viewbar .vb-finish{display:inline-flex;align-items:center;gap:6px;font-size:13px;color:var(--ink-soft)}
.viewbar .vb-check{display:inline-flex;align-items:center;gap:6px;margin:0;font-size:13px;color:var(--ink-soft)}
.viewbar .vb-check input{accent-color:var(--copper)}
.viewbar .vb-range{display:inline-flex;align-items:center;gap:8px;font-size:13px;color:var(--ink-soft)}
.viewbar .vb-range input{width:110px;accent-color:var(--copper)}
.viewbar .vb-reset{font:inherit;font-size:12.6px;padding:3px 10px;border:1px solid var(--rule);background:var(--paper);color:var(--ink-soft);cursor:pointer}
.viewbar .vb-reset:hover{border-color:var(--copper);color:var(--ink)}
.viewbar .why-link{align-self:center;display:inline-flex;line-height:0;color:var(--copper);text-decoration:none;transition:transform .12s}
.viewbar .why-link:hover,.viewbar .why-link:focus-visible{transform:scale(1.12)}
.viewbar .why-link svg{width:19px;height:19px;display:block}
