QA01 • virtual assistant time-block quote — Quote a defined block of assistant time with task categories, authorization boundaries and over-capacity handling, instead of promising…
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>QA01 • virtual assistant time-block quote</title><style>*{box-sizing:border-box}body{margin:0;background:var(--bg,#f3f7fa);color:var(--ink,#203342);font:16px/1.55 system-ui,Segoe UI,sans-serif}main{max-width:1100px;margin:auto;padding:28px 30px 50px}h1{font-size:clamp(27px,3.5vw,40px);line-height:1.18;letter-spacing:-.035em;margin:8px 0 12px}h2{font-size:21px;line-height:1.35;margin:0 0 16px}h3{font-size:18px}.eyebrow{color:var(--accent,#176783);font-size:12px;letter-spacing:.12em;font-weight:800;text-transform:uppercase}.intro,.muted,small{color:#516272}.intro{margin:0 0 24px}.panel{padding:24px;border:1px solid var(--line,#d6e0e7);border-radius:12px;background:white;margin:18px 0}.grid{display:grid;grid-template-columns:1fr 1fr;gap:22px}.grid>*{min-width:0}.controls{display:flex;gap:10px;flex-wrap:wrap;align-items:center;margin:16px 0}button,input,textarea,select{font:inherit}button{border:1px solid var(--accent,#176783);background:var(--accent,#176783);color:white;padding:10px 16px;min-height:44px;border-radius:7px;font-weight:700;cursor:pointer}button.secondary{background:white;color:var(--accent,#176783)}button[aria-pressed=true]{background:var(--tint,#e3f2f8);color:var(--ink,#203342);box-shadow:inset 0 0 0 2px var(--accent,#176783)}button:hover{filter:brightness(.96)}:focus-visible{outline:3px solid #d56b00;outline-offset:3px}label{display:block;margin:12px 0 5px;font-size:14px;font-weight:650}input:not([type=checkbox]),select,textarea{width:100%;padding:10px 12px;min-height:44px;border:1px solid #94a5b2;background:white;color:inherit;border-radius:7px}textarea{resize:vertical;min-height:120px}input[type=checkbox]{width:20px;height:20px;margin-right:9px}label.inline{display:flex;align-items:center;font-weight:500;gap:7px}.result{padding:24px;background:var(--tint,#e3f2f8);border:1px solid var(--line,#c8dce7);border-radius:12px}.big{font-size:clamp(30px,5vw,48px);font-weight:780;line-height:1.25;letter-spacing:-.035em;margin:10px 0}.trace{font:15px/1.7 ui-monospace,Consolas,monospace;white-space:pre-wrap;overflow-wrap:anywhere}.error{color:#a12820;font-weight:650;min-height:24px}.table-wrap{overflow-x:auto}table{border-collapse:collapse;width:100%;font-size:15px}th,td{text-align:left;border-bottom:1px solid var(--line,#d6e0e7);padding:12px 9px;vertical-align:top}th{font-size:12px;text-transform:uppercase;letter-spacing:.03em;color:#516272}code,pre,.code{font:14px/1.65 ui-monospace,Consolas,monospace}pre{white-space:pre-wrap;overflow-wrap:anywhere;background:var(--tint,#eef3f7);padding:16px;border-radius:6px}details{border-top:1px solid var(--line,#d6e0e7);margin:24px 0;padding-top:16px}summary{cursor:pointer;font-weight:700;min-height:44px}footer{border-top:1px solid var(--line,#d6e0e7);margin-top:26px;padding-top:16px;font-size:13px;color:#516272}.bar{height:16px;background:#dce4ea;border-radius:20px;overflow:hidden;margin:12px 0}.bar span{display:block;height:100%;background:var(--accent,#176783)}[hidden]{display:none!important}@media(max-width:720px){main{padding:20px}.grid{grid-template-columns:1fr;gap:12px}.panel,.result{padding:20px}}@media(max-width:400px){main{padding:16px}.panel,.result{padding:16px}button{padding:10px 13px}} .sheet{background:white;padding:28px;border:1px solid var(--line,#d6e0e7)}.note{padding:16px;border-left:4px solid var(--accent,#176783);background:var(--tint,#e3f3fa)}.badge{display:inline-block;padding:5px 11px;border-radius:22px;background:var(--tint,#e3f3fa);font-size:13px;font-weight:700}.preview{white-space:pre-wrap;overflow-wrap:anywhere}.schedule-row{display:grid;grid-template-columns:1fr 100px 100px;gap:14px;align-items:center;border-bottom:1px solid var(--line,#d6e0e7);padding:12px 0}.schedule-row label{margin:0}.schedule-row small{display:block}.export textarea{min-height:200px}h2,h3,p,td,button{overflow-wrap:anywhere}.grid>*{min-width:0}@media(max-width:720px){.sheet{padding:20px}.schedule-row{grid-template-columns:1fr 80px}.schedule-row .range{grid-column:1/3}}@media(max-width:400px){.sheet{padding:16px}}
body{--accent:#345f63;--tint:#edf5f1;--bg:#f5f6f2;--ink:#294247;--line:#cedbd5}h1{font-family:Georgia,serif}.quote-paper{padding:30px;background:white;border:1px solid #d2dcd6;box-shadow:0 8px 25px #263a3210}.quote-mast{display:flex;justify-content:space-between;gap:25px;border-bottom:2px solid #345f63;padding-bottom:20px}.quote-mast h2{font:28px Georgia,serif;margin:10px 0}.quote-price{text-align:right}.quote-price small,.quote-price strong,.quote-price span{display:block}.quote-price strong{font:43px Georgia,serif;color:#345f63;margin:8px 0}.quote-price span{font-size:13px}.allocation-preview{padding:20px 0}.allocation-row{display:grid;grid-template-columns:170px 1fr 60px;gap:15px;align-items:center;padding:8px 0;font-size:14px}.allocation-row b{text-align:right}.allocation-rail{height:13px;background:#edf2ef;border-radius:20px;overflow:hidden}.allocation-rail span{display:block;height:100%}.capacity-result{padding:17px;background:#f1f5f1;display:flex;justify-content:space-between;gap:15px;flex-wrap:wrap}.capacity-result span{font-size:14px}.permission-line{font-size:13px;margin-bottom:0;color:#52665e}.path-grid{display:grid;grid-template-columns:1fr 1fr;gap:18px;margin:22px 0}.path{padding:23px;border:1px solid #cbd9d1;background:#fff}.path h2{font:29px Georgia,serif;margin:10px 0}.path p{min-height:60px;font-size:14px}.path[data-selected=true]{border:2px solid #345f63;background:#edf5f1;padding:22px}@media(max-width:720px){.quote-mast{display:block}.quote-price{text-align:left;margin-top:12px}.quote-price strong{font-size:38px}.allocation-row{grid-template-columns:125px 1fr 45px;gap:8px;font-size:12px}.path-grid{grid-template-columns:1fr}.path p{min-height:0}.quote-paper{padding:21px}}</style></head><body><main>
<header><span class="eyebrow">QA01 / fictional service quote</span><h1>Make the extra-time decision visible.</h1><p class="intro">Compare a proposed time block with its task budgets before changing the scope.</p></header>
<section class="quote-paper"><div class="quote-mast"><div><span class="eyebrow">Draft quote / October 19–23, 2026</span><h2>Administrative support</h2><p id="quote-revision">QA01 / Draft 01</p></div><div class="quote-price"><small>Original block · assumed price</small><strong id="base-price"></strong><span id="base-basis"></span></div></div><div id="allocation-preview" class="allocation-preview"></div><div class="capacity-result"><b id="capacity" aria-live="polite"></b><span id="capacity-note"></span></div><p class="permission-line">Drafts and preparation only within confirmed scope. Access does not grant permission to send, cancel, pay or delete.</p></section>
<section class="path-grid"><article id="extra-path" class="path"><span class="eyebrow">Path 1 / add time</span><h2 id="extra-price"></h2><p id="extra-detail"></p><button type="button" id="choose-extra" class="secondary">Review add-time path</button></article><article id="fixed-path" class="path"><span class="eyebrow">Path 2 / keep the cap</span><h2 id="fixed-price"></h2><p id="fixed-detail"></p><button type="button" id="choose-fixed" class="secondary">Review fixed-cap path</button></article></section>
<p id="decision-state" class="note" aria-live="polite"></p>
<div class="grid"><section class="panel"><h2>Edit the planning assumptions</h2><div class="grid"><div><label for="cap">Original block hours</label><input id="cap" type="text" value="10"></div><div><label for="rate">Assumed $ per hour</label><input id="rate" type="text" value="30"></div></div><div class="grid"><div><label for="inbox">Inbox classification hours</label><input id="inbox" type="text" value="4"></div><div><label for="calendar">Calendar-draft coordination hours</label><input id="calendar" type="text" value="3"></div><div><label for="research">Original research-summary hours</label><input id="research" type="text" value="3"></div><div><label for="extra">New research-request hours</label><input id="extra" type="text" value="2"></div></div><div class="controls"><button type="button" id="calculate">Recalculate comparison</button><button type="button" id="tradeoff" class="secondary">Load 10-hour tradeoff illustration</button><button type="button" id="reset" class="secondary">Reset QA01</button></div><p id="error" class="error" role="alert"></p><small>Up to two decimals for hours/rate. Each block total rounds to cents; the added amount is the revised total minus the original total. These are planning budgets, not work performed or task-throughput promises.</small></section><section class="panel"><h2>Quote and change references</h2><label for="revision">Linked quote revision</label><input id="revision" type="text" value="QA01 / Draft 01"><label for="request-ref">Actual extra-request reference (to confirm)</label><input id="request-ref" type="text" value=""><label for="client">Actual client (to confirm)</label><input id="client" type="text" value=""><label for="provider">Actual provider (to confirm)</label><input id="provider" type="text" value=""><label for="priority-note">Proposed priority note / owner decision still needed</label><textarea id="priority-note"></textarea><p>Actual approver and decision: <b>not supplied</b>. A comparison or local edit does not approve a change.</p></section></div>
<section class="sheet"><h2>Authorization matrix</h2><div class="table-wrap"><table><thead><tr><th>Task</th><th>Preparation boundary</th><th>Actual authority to confirm</th></tr></thead><tbody><tr><td>Inbox</td><td>Classify supplied items; prepare draft responses.</td><td>Access level, handling rules, permitted items.</td></tr><tr><td>Calendar</td><td>Draft timing options and coordination messages.</td><td>Any actual booking or change needs separate authority.</td></tr><tr><td>Research</td><td>Summarize the supplied question and sources.</td><td>Source access and information boundaries.</td></tr><tr><td>Sending, cancellation, payment, deletion</td><td>Outside this example’s granted scope.</td><td>Separate actual authorization and process required.</td></tr></tbody></table></div><p>Working windows, time zone, reply expectations, unused-hours treatment, taxes, licenses and actual currency: TO CONFIRM. The $ sign is illustrative; no final all-in charge or SLA is established.</p></section>
<section class="panel"><h2>Actual time log / unfilled</h2><div class="table-wrap"><table><thead><tr><th>Task / date</th><th>Work performed</th><th>Actual hours</th><th>Authorization/change reference</th><th>Remaining agreed hours</th></tr></thead><tbody><tr><td>Not recorded</td><td>Not recorded</td><td>Not recorded</td><td>Not recorded</td><td>Agreement not supplied</td></tr></tbody></table></div><p>Proposed 4/3/3 budgets never populate this log.</p></section>
<section class="panel export"><h2>Manual-copy quote and change request</h2><div class="controls"><button type="button" id="prepare">Prepare text</button><button type="button" id="select-text" class="secondary">Select text</button></div><p id="export-error" class="error" role="alert"></p><label for="export-text">Generated plain text</label><textarea id="export-text" readonly></textarea><small>Select text, then copy manually. Nothing is saved or sent.</small></section>
<footer>This sanitized HTML companion prepares proposed scope text, not a booked service, signed quote, native PDF/Word/workbook, invoice, time tracker or account connection. No approval, message, booking, cancellation, payment or deletion occurs. Local edits do not persist; actual terms, permissions and records stay in the business workflow.</footer>
</main><script>const $=id=>document.getElementById(id);const on=(id,e,fn)=>$(id).addEventListener(e,fn);const txt=(id,v)=>$(id).textContent=v;const esc=s=>String(s).replace(/[&<>"']/g,c=>({'&':'&','<':'<','>':'>','"':'"',"'":'''}[c]));const positive=x=>String(x).trim()!==''&&Number.isFinite(Number(x))&&Number(x)>0;const num=x=>Number(x.toPrecision(10)).toString();function enter(id,fn){on(id,'keydown',e=>{if(e.key==='Enter'&&!e.isComposing&&e.keyCode!==229){e.preventDefault();fn()}})}function selectText(id){$(id).focus();$(id).select()}
function isoDay(s){if(!/^\d{4}-\d{2}-\d{2}$/.test(s))throw Error('Use a real calendar date as YYYY-MM-DD.');const d=new Date(s+'T00:00:00Z');if(!Number.isFinite(d.getTime())||d.toISOString().slice(0,10)!==s)throw Error('Use a real calendar date as YYYY-MM-DD.');return d.getTime()/86400000}
let path='extra',comparison=null;
function scaled(s,label,max,allowZero){if(!/^\d+(?:\.\d{1,2})?$/.test(s))throw Error(label+' must use a nonnegative decimal with at most two decimal places.');const [a,b='']=s.split('.'),v=Number(a)*100+Number((b+'00').slice(0,2));if(!Number.isSafeInteger(v)||v>max||(!allowZero&&v===0))throw Error(label+' is outside the allowed range.');return v}
function dollars(cents){return '$'+(cents/100).toFixed(2)}
function hours(hundredths){return String(hundredths/100)}
function price(h,r){return Math.floor((h*r+50)/100)}
function quoteMath(cap,rate,allocations){const demand=allocations.reduce((a,b)=>a+b,0),over=Math.max(0,demand-cap),proposed=Math.max(cap,demand);return {cap,rate,allocations,demand,over,proposed,base:price(cap,rate),added:price(proposed,rate)-price(cap,rate),revised:price(proposed,rate)}}
function pending(){comparison=null;for(const n of ['base-price','extra-price','fixed-price'])txt(n,'Pending');for(const n of ['base-basis','extra-detail','fixed-detail','capacity-note'])txt(n,'');txt('capacity','Recalculate current inputs');$('allocation-preview').innerHTML='';txt('decision-state','No accepted comparison for edited inputs.');txt('error','');$('export-text').value='';txt('export-error','')}
function decision(){if(!comparison)return;const r=comparison;txt('decision-state',path==='extra'?(r.over?'Proposed add-time path: '+hours(r.over)+' extra hours require the owner’s decision. No extra time is approved.':'Current allocations fit the original block; no extra hours are required. Actual terms and priorities still need agreement.'):(r.over?'Fixed-cap path needs reprioritization: reduce or defer '+hours(r.over)+' hours before this plan fits. No tradeoff has been agreed.':'Fixed-cap arithmetic fits '+hours(r.cap)+' hours. This is an illustration, not an agreed priority decision.'));for(const n of ['extra','fixed']){$('choose-'+n).setAttribute('aria-pressed',String(path===n));$(n+'-path').setAttribute('data-selected',String(path===n))}}
function calculate(){pending();try{const cap=scaled($('cap').value,'Block hours',100000,false),rate=scaled($('rate').value,'Hourly rate',1000000,false),allocations=['inbox','calendar','research','extra'].map(n=>scaled($(n).value,n+' hours',100000,true));comparison=quoteMath(cap,rate,allocations);const r=comparison;txt('base-price',dollars(r.base));txt('base-basis',hours(r.cap)+' hours × '+dollars(r.rate)+'/hour');txt('extra-price',dollars(r.revised)+' proposed');txt('extra-detail',hours(r.proposed)+' total block hours · '+hours(r.over)+' extra hours · '+dollars(r.added)+' added at the same assumed rate. Only if accepted on that basis.');txt('fixed-price',dollars(r.base)+' proposed');txt('fixed-detail',r.over?'Keep '+hours(r.cap)+' hours; identify '+hours(r.over)+' hours to reduce, defer or replace.':'Keep '+hours(r.cap)+' hours; '+hours(r.cap-r.demand)+' hours remain unallocated in this plan.');txt('capacity',hours(r.demand)+' planned hours / '+hours(r.cap)+'-hour cap');txt('capacity-note',r.over?hours(r.over)+' hours over the original cap':'Within the arithmetic cap; priorities not agreed');const labels=['Inbox classification','Calendar drafts','Original research','New research'];$('allocation-preview').innerHTML=allocations.map((h,i)=>'<div class="allocation-row"><span>'+labels[i]+'</span><div class="allocation-rail"><span style="width:'+(r.demand?h/r.demand*100:0)+'%;background:'+['#345f63','#688d91','#a6bcb4','#b76b42'][i]+'"></span></div><b>'+hours(h)+' h</b></div>').join('');txt('error','');decision();return true}catch(e){txt('capacity','No accepted comparison');txt('error',e.message);return false}}
for(const n of ['cap','rate','inbox','calendar','research','extra']){on(n,'input',pending);enter(n,calculate)}on('calculate','click',calculate);
for(const n of ['extra','fixed'])on('choose-'+n,'click',()=>{path=n;$('export-text').value='';txt('export-error','Path changed; prepare the current proposal.');decision()});
function sourceDefaults(){const values={cap:'10',rate:'30',inbox:'4',calendar:'3',research:'3',extra:'2'};for(const [n,v] of Object.entries(values))$(n).value=v}
on('tradeoff','click',()=>{sourceDefaults();$('inbox').value='2';path='fixed';$('priority-note').value='Arithmetic illustration only: reduce inbox from 4 to 2 hours; retain calendar 3, original research 3, new research 2. Actual owner decision not supplied.';calculate()});
on('reset','click',()=>{sourceDefaults();path='extra';$('revision').value='QA01 / Draft 01';for(const n of ['request-ref','client','provider','priority-note'])$(n).value='';txt('quote-revision','QA01 / Draft 01');calculate()});
for(const n of ['revision','request-ref','client','provider','priority-note'])on(n,'input',()=>{$('export-text').value='';txt('export-error','Document inputs changed; prepare the current text.');if(n==='revision')txt('quote-revision',$('revision').value||'Revision to confirm')});
on('prepare','click',()=>{$('export-text').value='';if(!comparison){txt('export-error','Recalculate valid planning inputs before preparing text.');return}if(!$('revision').value.trim()){txt('export-error','Supply the linked quote revision.');return}const r=comparison;if(path==='fixed'&&r.over){txt('export-error','The fixed-cap plan still exceeds capacity. Record a proposed tradeoff or review the add-time path.');return}const labels=['Inbox classification','Calendar-draft coordination','Original research summary','New research request'];$('export-text').value='PROPOSED VIRTUAL ASSISTANT QUOTE / '+$('revision').value+'\nFictional QA01 period: October 19–23, 2026.\nActual client: '+($('client').value||'TO CONFIRM')+'\nActual provider: '+($('provider').value||'TO CONFIRM')+'\nIllustrative $ rate: '+dollars(r.rate)+'/hour; actual currency TO CONFIRM.\nOriginal block: '+hours(r.cap)+' hours = '+dollars(r.base)+'.\nProposed allocations:\n'+labels.map((l,i)=>l+': '+hours(r.allocations[i])+' hours').join('\n')+'\nTotal planned demand: '+hours(r.demand)+' hours.\nReviewed path: '+(path==='extra'?'ADD TIME, ONLY IF ACCEPTED: '+hours(r.over)+' extra hours / '+dollars(r.added)+' added; revised proposed '+hours(r.proposed)+'-hour block '+dollars(r.revised)+'.':'KEEP CAP: '+hours(r.cap)+'-hour block '+dollars(r.base)+'. Priority proposal is not an actual agreement.')+'\nActual change-request reference: '+($('request-ref').value||'TO CONFIRM')+'\nProposed priority note: '+($('priority-note').value||'TO CONFIRM')+'\nActual approver: ______\nActual decision / date / accepted revision: ______\nDraft request, not sent: Please confirm the additional hours at the supplied same rate, or which original allocation should be reduced or deferred. No extra time or changed priority is assumed approved.\n\nAUTHORIZATION: Inbox classification and draft responses; calendar timing options and draft messages; research summary, all within confirmed scope. Access level, handling rules and source permissions TO CONFIRM. Access is not authority to send/cancel/pay/delete. No sensitive-account access granted by this quote.\nWorking windows, time zone, reply expectations, unused-hours treatment, taxes and licenses: TO CONFIRM. No final all-in charge or SLA supplied.\n\nACTUAL TIME LOG BLANK\nTask ID ___ / date ___ / work description ___ / actual time ___ / authorization or change reference ___ / remaining agreed hours ___\nPlanning budgets are not time worked or task-completion guarantees.';txt('export-error','Proposed quote text prepared. No extra time, changed priority or action authority was approved.')});on('select-text','click',()=>selectText('export-text'));calculate();
</script></body></html>