QW01 · Woodworking quote review

HTML for this example

Select the code and use your copy shortcut. Changes in this preview are temporary.

<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>QW01 · Woodworking quote review</title>
<style>
:root{color-scheme:light;--ink:#30271f;--muted:#65594d;--paper:#fffdf7;--line:#d8cbb8;--walnut:#4a3527;--green:#d9edab}
*{box-sizing:border-box}body{margin:0;background:#e9e2d6;color:var(--ink);font:16px/1.6 system-ui,-apple-system,"Segoe UI",sans-serif}main{max-width:1000px;margin:32px auto;background:var(--paper);border:1px solid var(--line);box-shadow:0 12px 42px #382b1610}header{padding:28px 32px 24px;border-top:7px solid var(--walnut);border-bottom:1px solid var(--line)}.topline{display:flex;flex-wrap:wrap;justify-content:space-between;gap:10px;color:var(--muted)}.stamp{border:1px solid #87715a;border-radius:3px;padding:2px 12px;color:var(--walnut)}h1{font:500 clamp(30px,5.5vw,46px)/1.14 Georgia,serif;margin:20px 0 12px;letter-spacing:-.02em}header p{margin:0;max-width:700px}h2{font:500 26px/1.25 Georgia,serif;margin:0 0 18px}h3{font-size:18px;margin:0 0 10px}p{margin:0 0 16px}.lede{color:var(--muted)}.summary{padding:24px 32px;background:#f3efdf;display:grid;grid-template-columns:1fr 1.15fr;gap:24px;border-bottom:1px solid var(--line)}.big{font:500 42px/1.1 Georgia,serif;display:block;margin:6px 0 10px;font-variant-numeric:tabular-nums}.summary p{margin:0}.unpriced{border-left:2px solid #b09264;padding-left:22px}.content{padding:30px 32px}section+section{margin-top:36px;padding-top:30px;border-top:1px solid var(--line)}.specs{display:grid;grid-template-columns:1fr 1fr;gap:18px}.spec{padding:22px;border:1px solid var(--line);background:#faf7ee}.spec.proposed{border-color:#99a4a5;background-color:#f1f5f3;background-image:linear-gradient(#9eacaa17 1px,transparent 1px),linear-gradient(90deg,#9eacaa17 1px,transparent 1px);background-size:20px 20px}.tag{color:var(--muted);margin-bottom:10px}.dimensions{font-size:22px;font-weight:650;margin-bottom:12px}.spec dl{margin:0}.spec dt{font-weight:650}.spec dd{margin:0 0 12px;color:var(--muted)}.spec dd:last-child{margin-bottom:0}.note{padding:16px 18px;background:#f4eddc;border-left:3px solid #94733d;margin-top:18px}.inputs{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:18px}label{display:block;font-weight:650}input,textarea,button{font:inherit}input{display:block;width:100%;min-width:0;border:1px solid #968470;border-radius:4px;padding:12px;margin:8px 0;background:white;color:var(--ink)}.help{color:var(--muted);font-weight:400;display:block}button{border:1px solid var(--walnut);padding:13px 20px;background:var(--walnut);color:white;border-radius:4px;cursor:pointer;font-weight:650}button:hover{background:#654833}button:focus-visible,input:focus-visible,textarea:focus-visible{outline:3px solid #315e72;outline-offset:3px}.width-row{display:grid;grid-template-columns:minmax(0,250px) 1fr;gap:24px;align-items:center;margin:24px 0}.width-row p{margin:0}mark{background:var(--green);color:var(--ink);padding:0 3px}.result{padding:18px 0 0}.result p:last-child{margin-bottom:0}textarea{width:100%;min-width:0;resize:vertical;border:1px solid #968470;border-radius:4px;background:#fff;color:var(--ink);padding:18px;line-height:1.65;margin-top:12px}footer{padding:24px 32px;background:#f4f0e7;color:var(--muted);border-top:1px solid var(--line)}footer p:last-child{margin-bottom:0}.error{color:#8a231b;font-weight:650}.pending{color:#65521c}#status{margin:12px 0 0}.small-gap{margin-top:16px}noscript{display:block;padding:20px;color:#8a231b}a{color:inherit}input[aria-invalid="true"]{border:2px solid #8a231b}
@media(max-width:640px){main{margin:0;border-left:0;border-right:0;box-shadow:none}header,.content,footer{padding:24px 20px}.summary{padding:22px 20px;grid-template-columns:1fr;gap:18px}.unpriced{border-left:0;border-top:1px solid var(--line);padding:16px 0 0}.specs,.inputs,.width-row{grid-template-columns:1fr}.specs{gap:16px}.width-row{gap:8px}.spec{padding:18px}.dimensions{font-size:21px}button{width:100%}h1{font-size:34px}textarea{padding:12px}.topline{align-items:center}}
</style>
</head>
<body>
<main>
<header>
<div class="topline"><span>Custom piece / quote review</span><span class="stamp">QW01 · DRAFT</span></div>
<h1>Desktop organizer<br>quote review.</h1>
<p class="lede">Fictional QW01 · one freestanding organizer. DR01 Draft: W 18 × D 8 × H 10 in. Compare the original piece with a requested width.</p>
</header>
<div class="summary" aria-live="polite">
<div><span>DR01 known subtotal</span><strong class="big" id="subtotal">$200.00</strong><p id="arithmetic">$40.00 + $60.00 + $100.00</p></div>
<div class="unpriced"><strong>Complete final price: unavailable</strong><p>Finish · Delivery · Tax: <mark>To confirm</mark></p><p id="quickScope">Requested width: 24 in · DR02 Proposed</p><p id="revisedPrice">DR02 price: unavailable; new estimate required.</p></div>
</div>
<div class="content">
<section aria-labelledby="pieceHeading">
<h2 id="pieceHeading">The drawing sets the scope</h2>
<div class="specs">
<article class="spec"><p class="tag">Original · DR01 Draft</p><h3>Desktop organizer × 1</h3><p class="dimensions" id="originalDimensions">W 18 × D 8 × H 10 in</p><dl><dt>Material</dt><dd>Birch plywood, proposed</dd><dt>Finish</dt><dd>To confirm</dd><dt>Specification approval</dt><dd>Not supplied</dd></dl></article>
<article class="spec proposed"><p class="tag" id="proposalTag">Requested · DR02 Proposed</p><h3>Width request</h3><p class="dimensions" id="requestedDimensions">W 24 in · +6 in</p><dl><dt>Depth / height</dt><dd>Reconfirm; do not carry forward automatically</dd><dt>Material / finish</dt><dd>Reconfirm for proposed drawing</dd><dt>Revised estimate / acceptance</dt><dd>Not supplied</dd></dl></article>
</div>
<p class="note">Intended contents, critical dimensions, hardware, and technical requirements: to confirm. Overall dimensions do not establish internal fit or a load rating. This comparison is not a fabrication drawing.</p>
</section>
<section aria-labelledby="estimateHeading">
<h2 id="estimateHeading">Review the known costs</h2>
<p>Enter amounts for <strong>DR01 only</strong>. The material amount is an allowance. The three lines are illustrative assumptions, not market rates.</p>
<form id="quoteForm" novalidate>
<div class="inputs">
<label for="design">Design review · USD<input id="design" type="number" inputmode="decimal" min="0" step="0.01" value="40" aria-describedby="moneyHelp"></label>
<label for="material">Material allowance · USD<input id="material" type="number" inputmode="decimal" min="0" step="0.01" value="60" aria-describedby="moneyHelp"></label>
<label for="fabrication">Fabrication · USD<input id="fabrication" type="number" inputmode="decimal" min="0" step="0.01" value="100" aria-describedby="moneyHelp"></label>
</div>
<p class="help" id="moneyHelp">Use nonnegative amounts with up to two decimal places. Unknown finish, delivery, and tax are not zero or included.</p>
<div class="width-row"><label for="width">Requested width · inches<input id="width" type="number" inputmode="decimal" min="0.01" step="0.01" value="24" aria-describedby="widthHelp"></label><p class="help" id="widthHelp">Original width: 18 in. A different width needs a new estimate. Reconfirm the rest of the specification.</p></div>
<button type="button" id="updateQuote">Update quote review</button>
<p id="status" role="status">Sample loaded. Original and proposed pricing are separate.</p>
<p class="error" id="error" role="alert" hidden></p>
</form>
<div class="result" aria-live="polite"><p id="widthResult">24 in requested; increase of 6 in from DR01.</p><p id="pricingResult">$200.00 is the DR01 known subtotal. DR02 remains unpriced.</p></div>
</section>
<section aria-labelledby="requestHeading">
<h2 id="requestHeading">Ask for the missing estimate</h2>
<p>Select the draft text to copy into your own correspondence. Confirm the drawing and remaining specifications before issuing a revised quote.</p>
<label for="requestText">Clarification request · not sent<textarea id="requestText" rows="9" readonly>QW01 references DR01 Draft: W 18 in x D 8 in x H 10 in; birch plywood proposed; finish to confirm. Please review a width of 24 in under DR02 Proposed, reconfirm depth, height, material, finish, critical dimensions, hardware, and technical requirements, and supply a revised material/fabrication estimate. The DR01 known subtotal is $200.00. Please also confirm finish, delivery, and tax details. The complete final price is unavailable; no specification approval or price acceptance is recorded.</textarea></label>
<p class="help small-gap">Record the actual response with the revised drawing and quote version in your native project records.</p>
</section>
</div>
<footer><p><strong>Before issuing the quote:</strong> match its dimensions and estimate to the same drawing revision. Supply actual commercial terms, dates, and decisions in your Word document, PDF, or workbook.</p><p>This local comparison sends nothing and saves no changes. Reloading restores the fictional sample.</p></footer>
<noscript>JavaScript is required to recalculate the comparison. The displayed amounts are the original fictional sample.</noscript>
</main>
<script>
(() => {
  'use strict';
  const find = selector => document.querySelector(selector);
  const fields = ['design', 'material', 'fabrication', 'width'].map(id => find('#' + id));
  const money = cents => new Intl.NumberFormat('en-US', {style:'currency', currency:'USD'}).format(cents / 100);
  const number = value => new Intl.NumberFormat('en-US', {maximumFractionDigits:2}).format(value);
  function clearResults(message) {
    find('#subtotal').textContent = 'Unavailable';
    find('#arithmetic').textContent = message;
    find('#requestedDimensions').textContent = 'Awaiting update';
    find('#proposalTag').textContent = 'Requested specification · pending';
    find('#quickScope').textContent = 'Requested width: awaiting update';
    find('#widthResult').textContent = 'Update valid inputs to compare widths.';
    find('#pricingResult').textContent = 'No current subtotal. Revised pricing remains unavailable.';
    find('#revisedPrice').textContent = 'Revised price: unavailable.';
    find('#requestText').value = '';
  }
  fields.forEach(field => field.addEventListener('keydown', event => { if (event.key === 'Enter') { event.preventDefault(); find('#updateQuote').click(); } }));
  fields.forEach(field => field.addEventListener('input', () => {
    field.removeAttribute('aria-invalid');
    find('#error').hidden = true;
    find('#status').textContent = 'Inputs changed. Update quote review to recalculate.';
    clearResults('Inputs changed; recalculate the known lines.');
  }));
  find('#updateQuote').addEventListener('click', event => {
    event.preventDefault();
    const labels = ['Design review', 'Material allowance', 'Fabrication', 'Requested width'];
    const invalid = fields.findIndex((field, index) => {
      const raw = field.value.trim();
      const value = Number(raw);
      const bad = !/^\d+(?:\.\d{1,2})?$/.test(raw) || !Number.isFinite(value) || (index === 3 ? value <= 0 : value < 0) || value > 1000000;
      field.setAttribute('aria-invalid', String(bad));
      return bad;
    });
    if (invalid !== -1) {
      const message = labels[invalid] + (invalid === 3 ? ': enter a positive width up to 1,000,000 inches with at most two decimal places.' : ': enter an amount from 0 to 1,000,000 with at most two decimal places.');
      clearResults('Correct the highlighted input.');
      find('#error').textContent = message;
      find('#error').hidden = false;
      find('#status').textContent = 'Review not updated.';
      fields[invalid].focus();
      return;
    }
    const costs = fields.slice(0,3).map(field => Math.round(Number(field.value) * 100));
    const total = costs.reduce((sum, cost) => sum + cost, 0);
    const requested = Number(fields[3].value);
    const difference = Math.round((requested - 18) * 100) / 100;
    const changed = difference !== 0;
    find('#error').hidden = true;
    find('#subtotal').textContent = money(total);
    find('#arithmetic').textContent = costs.map(money).join(' + ');
    find('#requestedDimensions').textContent = 'W ' + number(requested) + ' in · ' + (difference > 0 ? '+' : '') + number(difference) + ' in';
    find('#proposalTag').textContent = changed ? 'Requested · DR02 Proposed' : 'Requested · matches DR01 width';
    find('#quickScope').textContent = 'Requested width: ' + number(requested) + ' in · ' + (changed ? 'DR02 Proposed' : 'matches DR01');
    find('#widthResult').textContent = changed ? number(requested) + ' in requested; ' + (difference > 0 ? 'increase' : 'decrease') + ' of ' + number(Math.abs(difference)) + ' in from DR01.' : '18 in requested; no width change from DR01.';
    find('#pricingResult').textContent = money(total) + ' is the DR01 known subtotal. ' + (changed ? 'DR02 remains unpriced.' : 'Finish, delivery, and tax remain unpriced.');
    find('#revisedPrice').textContent = changed ? 'DR02 price: unavailable; new estimate required.' : 'Complete pricing still requires finish, delivery, and tax details.';
    find('#requestText').value = 'QW01 references DR01 Draft: W 18 in x D 8 in x H 10 in; birch plywood proposed; finish to confirm. ' + (changed ? 'Please review a width of ' + number(requested) + ' in under DR02 Proposed, reconfirm depth, height, material, finish, critical dimensions, hardware, and technical requirements, and supply a revised material/fabrication estimate.' : 'No width change is requested. Please confirm the intended contents, critical dimensions, hardware, material, finish, and technical requirements against DR01.') + ' The DR01 known subtotal is ' + money(total) + '. Please also confirm finish, delivery, and tax details. The complete final price is unavailable; no specification approval or price acceptance is recorded.';
    find('#status').textContent = 'Quote review updated. No changes saved or sent.';
  });
})();
</script>
</body>
</html>