<!doctype html>
<html lang="en">
<head><base href="about:srcdoc"><script>(function(){function n(){parent.postMessage({t:'share:hash',h:location.hash},'*')}addEventListener('hashchange',n);addEventListener('message',function(e){if(e.source!==parent)return;var d=e.data||{};if(d.t==='share:setHash'&&typeof d.h==='string'&&d.h!==location.hash){location.hash=d.h}});addEventListener('DOMContentLoaded',function(){parent.postMessage({t:'share:ready',h:location.hash},'*')});})();</script>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>ePhyto Hub — Decisions for BAFRA</title>
<style>
:root{--bg:#f7f9fc;--paper:#fff;--ink:#122033;--muted:#536173;--line:#d9e1ea;--accent:#0b5cab;--soft:#eef5fc;--ok:#0f7a3a;--warn:#a45c00;--ok-bg:#e8f5ee;--warn-bg:#fff8ee;--ok-line:#b7d9c2;--defer:#5e4b8b;--defer-bg:#f1eefa;--defer-line:#d5cce8}
*{box-sizing:border-box} body{margin:0;background:linear-gradient(180deg,#f3f7fb,#eef4f9 35%,#f7f9fc);color:var(--ink);font:17px/1.55 "Segoe UI",Arial,sans-serif}
.wrap{max-width:920px;margin:0 auto;padding:32px 24px 56px}
.hero,.card{background:var(--paper);border:1px solid var(--line);border-radius:20px;box-shadow:0 14px 42px rgba(18,32,51,.06)}
.hero{padding:28px 30px 22px;margin-bottom:18px}
.eyebrow{margin:0 0 8px;color:var(--accent);font:700 12px/1.2 Arial,sans-serif;letter-spacing:.12em;text-transform:uppercase}
h1,h2,h3{font-family:Georgia,"Times New Roman",serif}
h1{margin:0 0 12px;font-size:34px;line-height:1.1} h2{margin:0 0 12px;font-size:22px} h3{margin:16px 0 6px;font-size:17px}
.lede{margin:0;color:var(--muted)}
.card{padding:22px 26px;margin-bottom:14px}
.card summary{cursor:pointer;list-style:none;display:flex;align-items:baseline;gap:14px;padding:4px 0}
.card summary::-webkit-details-marker{display:none}
.num{display:inline-block;min-width:34px;height:34px;line-height:34px;text-align:center;border-radius:50%;background:var(--soft);color:var(--accent);font-weight:700;font-size:14px;border:1px solid #d7e5f4}
.title{font-family:Georgia,serif;font-size:20px;font-weight:400;flex:1}
.badge{display:inline-block;padding:3px 10px;border-radius:999px;font-size:11px;font-weight:700;letter-spacing:.06em;text-transform:uppercase;background:#eef5fc;color:var(--accent);border:1px solid #d7e5f4}
.badge.q{background:#fff4e5;color:var(--warn);border-color:#f0d9b5}
details[open] summary .title{color:var(--accent)}
.body{padding:14px 0 4px 48px}
.body p{margin:0 0 10px}
.body a{color:var(--accent)} .body a:hover{text-decoration:underline}
.body ul{margin:0 0 10px 0;padding-left:20px} .body li+li{margin-top:4px}
.reflist{margin:10px 0;padding:12px 14px;background:var(--soft);border-radius:10px;border:1px solid #d7e5f4;font-size:14px}
.reflist strong{color:var(--accent);font-size:11px;letter-spacing:.08em;text-transform:uppercase;display:block;margin-bottom:6px}
.reflist ul{margin:0;padding-left:16px;list-style:none}
.reflist li{padding:3px 0}
.reflist code{font:12px/1.4 ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;background:#fff;padding:1px 5px;border-radius:4px;border:1px solid #d7e5f4;color:#15314f}
.reply{margin-top:16px;padding:14px 16px;background:#fafbfd;border:1px dashed #cfd8e3;border-radius:10px;position:relative}
.reply.filled{background:var(--ok-bg);border-color:#b7d9c2;border-style:solid}
.reply-head{display:flex;justify-content:space-between;align-items:center;margin-bottom:8px}
.reply-label{font-size:12px;font-weight:700;color:var(--accent);letter-spacing:.06em;text-transform:uppercase}
.clearOne{background:none;border:none;color:var(--muted);font-size:12px;cursor:pointer;padding:2px 6px;border-radius:5px}
.clearOne:hover{color:var(--warn);background:#fff4e5}
.reply-opts{display:flex;flex-wrap:wrap;gap:8px;margin-bottom:10px}
.reply-opts label{display:inline-flex;align-items:center;gap:6px;padding:7px 12px;border-radius:999px;border:1px solid var(--line);background:#fff;cursor:pointer;font-size:14px;transition:all .15s}
.reply-opts label:hover{border-color:var(--accent);background:var(--soft)}
.reply-opts input[type=radio]{margin:0}
.reply-opts input[type=radio]:checked + span{color:var(--accent);font-weight:600}
.reply-opts label:has(input:checked){background:var(--soft);border-color:var(--accent)}
.reply textarea{width:100%;min-height:60px;padding:10px 12px;border:1px solid var(--line);border-radius:8px;font:14px/1.45 "Segoe UI",Arial,sans-serif;resize:vertical;color:var(--ink);background:#fff}
.reply textarea:focus{outline:none;border-color:var(--accent)}
.statusbar{position:sticky;top:0;z-index:10;background:var(--paper);border:1px solid var(--line);border-radius:14px;padding:10px 14px;margin-bottom:14px;display:flex;justify-content:space-between;align-items:center;font-size:14px;box-shadow:0 6px 20px rgba(18,32,51,.08)}
.statusbar .progress{color:var(--accent);font-weight:600}
.statusbar .saveMark{color:var(--ok);font-size:12px}
.submit{background:var(--paper);border:1px solid var(--line);border-radius:20px;padding:22px 26px;margin-top:24px;text-align:center;box-shadow:0 14px 42px rgba(18,32,51,.06)}
.submit h2{margin-top:0}
.submit p{margin:0 0 14px;color:var(--muted);font-size:15px}
.btnrow{display:flex;gap:10px;justify-content:center;flex-wrap:wrap;margin-bottom:10px}
.btn{display:inline-flex;align-items:center;gap:6px;padding:11px 20px;border-radius:10px;border:1px solid var(--accent);background:var(--accent);color:#fff;font:600 14px "Segoe UI",Arial,sans-serif;cursor:pointer;text-decoration:none;transition:all .15s}
.btn:hover{background:#094a8a;border-color:#094a8a}
.btn.secondary{background:#fff;color:var(--accent)} .btn.secondary:hover{background:var(--soft);color:#094a8a}
.btn.ghost{background:#fff;color:var(--muted);border-color:var(--line)} .btn.ghost:hover{background:#fff4e5;color:var(--warn);border-color:#f0d9b5}
.status{min-height:22px;color:var(--ok);font-weight:600;font-size:14px;margin-top:6px}
.preview{margin-top:14px;text-align:left;max-height:280px;overflow:auto;padding:14px;background:#f8faff;border:1px solid var(--line);border-radius:10px;font:13px/1.5 ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;white-space:pre-wrap;color:#2a3b52;display:none}
.preview.show{display:block}
.q{font-weight:600;color:var(--ink);border-left:3px solid var(--accent);padding:4px 0 4px 12px;background:var(--soft);border-radius:0 6px 6px 0;margin:10px 0 !important}
.status-banner{background:var(--ok-bg);border:1px solid var(--ok-line);border-radius:14px;padding:16px 20px;margin:16px 0 4px}
.status-banner h3{margin:0 0 6px;font-family:Georgia,serif;font-size:18px;color:var(--ok)}
.status-banner p{margin:0 0 6px;font-size:14px;color:#1a4a2e}
.status-banner code{font:12px/1.4 ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;background:#fff;padding:1px 5px;border-radius:4px;border:1px solid var(--ok-line);color:#1a4a2e}
.status-pill{display:inline-block;padding:3px 10px;border-radius:999px;font-size:11px;font-weight:700;letter-spacing:.06em;text-transform:uppercase;background:var(--ok-bg);color:var(--ok);border:1px solid var(--ok-line);margin-left:6px}
.status-pill.partial{background:var(--warn-bg);color:var(--warn);border-color:#f0d9b5}
.status-pill.defer{background:var(--defer-bg);color:var(--defer);border-color:var(--defer-line)}
.done-box{background:var(--ok-bg);border:1px solid var(--ok-line);border-left:3px solid var(--ok);border-radius:0 8px 8px 0;padding:10px 14px;margin:0 0 14px;font-size:14px}
.done-box.partial{background:var(--warn-bg);border-color:#f0d9b5;border-left-color:var(--warn)}
.done-box.defer{background:var(--defer-bg);border-color:var(--defer-line);border-left-color:var(--defer)}
.done-box strong{display:block;margin-bottom:4px;font-size:12px;letter-spacing:.06em;text-transform:uppercase;color:var(--ok)}
.done-box.partial strong{color:var(--warn)}
.done-box.defer strong{color:var(--defer)}
.done-box ul{margin:4px 0 0;padding-left:18px}
.done-box li+li{margin-top:2px}
@media(max-width:720px){.wrap{padding:18px 14px 40px}.hero,.card,.submit{border-radius:16px;padding:18px}.body{padding-left:0}.reply-opts label{font-size:13px;padding:6px 10px}.statusbar{flex-direction:column;align-items:flex-start;gap:4px}}
</style>
</head>
<body>
<div class="wrap">
<div class="statusbar">
<span class="progress" id="progress">0 of 8 items answered</span>
<span class="saveMark" id="saveMark">Replies are saved in your browser as you type</span>
</div>
<section class="hero">
<p class="eyebrow">For Tshering & Pramod • Please share with BAFRA</p>
<h1>Changes to the Phytosanitary Certificate service</h1>
<p class="lede">
To send Bhutan’s phytosanitary certificates to the IPPC ePhyto Hub, six changes are needed to the service, plus two open questions. Pick your decision on each item and add any comments. Your answers are saved in this browser as you type — you can come back later and continue. When you’re done, use the buttons at the bottom to send them to us.
</p>
<p class="lede" style="margin-top:12px">
<strong>“We’ll do it”</strong> means BAFRA will make the change. <strong>“Please do it”</strong> means you’d like us to set it up on the staging instance for your review. <strong>“Skip”</strong> means BAFRA does not agree.
</p>
<div class="status-banner">
<h3>Status update — 21 May 2026</h3>
<p>All six proposed changes have now been prototyped on the staging service “Phytosanitary certificate (export) — Hub integration WIP”, published as version 12. Items 1–4 and 6 are live on the form; item 5 is partially complete (countries and modes of conveyance done, purpose/end use deferred).</p>
<p>This form is kept open for BAFRA’s review. Your decisions remain useful — the staging build can be adjusted or rolled back per item.</p>
<p style="margin-top:8px"><strong>Staging service:</strong> <code>522c7dc1-d862-4c55-a608-4d1709c32f4a</code> · <strong>Last publish:</strong> 2026-05-21 10:58 UTC · <strong>GDB schema:</strong> <code>export 5.8</code></p>
</div>
</section>
<details class="card" open>
<summary><span class="num">1</span><span class="title">Split the “Unit” dropdown into two: “Unit of measure” and “Package type”</span><span class="badge">Form change</span><span class="status-pill">Done on staging</span></summary>
<div class="body">
<div class="done-box">
<strong>Status — done on staging</strong>
The commodity grid now has two separate dropdowns. Both are wired to the official IPPC code lists.
<ul>
<li>Unit of measure — 49 IPPC entries</li>
<li>Package type — 92 IPPC entries</li>
<li>The legacy “Quantity unit” column is kept alongside during the transition so existing print readers don’t break.</li>
</ul>
</div>
<p><strong>What changes:</strong> Today the single “Unit” dropdown in the commodity grid mixes two different things: units of measure (KG, CBM, cft, Sqft…) and package types (Boxes, Bags, Nos.…). We propose two side-by-side dropdowns on each commodity row:</p>
<ul>
<li><strong>Unit of measure</strong> — KG, tonnes, m³ …</li>
<li><strong>Package type</strong> — boxes, bags, drums, pallets …</li>
</ul>
<p>We would also remove the separate “No. and description of packages” text area, because the same information is now carried by the commodity rows.</p>
<p><strong>Why:</strong> The Hub treats “how much” and “in what packaging” as two separate fields with different code lists.</p>
<p><strong>Officer experience:</strong> Two small dropdowns instead of one. No more free-text packages textbox.</p>
<div class="reflist">
<strong>International code lists</strong>
<ul>
<li>Units of measure — <a href="https://www.ephytoexchange.org/doc/mapping/IPPC_Specific_Unit_of_Measure_Codes.pdf" target="_blank">IPPC UOM codes (PDF)</a></li>
<li>Package types — <a href="https://www.ephytoexchange.org/doc/mapping/IPPC_Specific_Package_Codes.pdf" target="_blank">IPPC package codes (PDF)</a></li>
</ul>
</div>
<p class="q">Please send the shortlists of units of measure and package types BAFRA wants (or say “please do it” and we prune the IPPC lists to what Bhutan uses).</p>
<div class="reply" data-item="p1" data-title="1. Split the Unit dropdown into Unit of measure + Package type">
<div class="reply-head">
<span class="reply-label">Your decision</span>
<button type="button" class="clearOne">Clear this answer</button>
</div>
<div class="reply-opts">
<label><input type="radio" name="p1" value="we-do"><span>We’ll do it</span></label>
<label><input type="radio" name="p1" value="please-do"><span>Please do it</span></label>
<label><input type="radio" name="p1" value="skip"><span>Skip</span></label>
</div>
<textarea placeholder="Comments, shortlists of units + package types, or questions"></textarea>
</div>
</div>
</details>
<details class="card">
<summary><span class="num">2</span><span class="title">Add an “Import permit number” field</span><span class="badge">New field</span><span class="status-pill">Done on staging</span></summary>
<div class="body">
<div class="done-box">
<strong>Status — done on staging</strong>
One optional text field added next to <em>Importing country</em>. It is distinct from the existing “Phytosanitary certificate number issued from place of origin” (which is for re-exports).
</div>
<p><strong>What changes:</strong> One new optional text field for the destination country’s import permit number, placed next to <em>Importing country</em> and <em>Declared point of entry</em>.</p>
<p><strong>Why:</strong> The existing “Phytosanitary certificate number issued from place of origin” is for re-exports (it’s the origin-country PC). The Hub separately asks for the <em>importing</em> country’s import permit number — a different thing.</p>
<p><strong>Officer experience:</strong> One new optional field.</p>
<p class="q">Does BAFRA already collect the destination country’s import permit number in practice? If yes, we keep the field optional. If no, we may skip.</p>
<div class="reply" data-item="p2" data-title="2. Add an Import permit number field">
<div class="reply-head">
<span class="reply-label">Your decision</span>
<button type="button" class="clearOne">Clear this answer</button>
</div>
<div class="reply-opts">
<label><input type="radio" name="p2" value="we-do"><span>We’ll do it</span></label>
<label><input type="radio" name="p2" value="please-do"><span>Please do it</span></label>
<label><input type="radio" name="p2" value="skip"><span>Skip</span></label>
</div>
<textarea placeholder="Comments or clarification"></textarea>
</div>
</div>
</details>
<details class="card">
<summary><span class="num">3</span><span class="title">Replace the “Additional declarations” textbox with coded rows</span><span class="badge">Form change</span><span class="status-pill">Done on staging</span></summary>
<div class="body">
<div class="done-box">
<strong>Status — done on staging</strong>
The textbox is replaced by an editable grid on the inspector’s form. Each row has three fields, kept deliberately simple:
<ul>
<li><strong>Scope</strong> — whole consignment, or per commodity row</li>
<li><strong>Declaration code</strong> — from the 20-entry IPPC SAD list (ISPM 12 Appendix 2)</li>
<li><strong>Declaration text</strong> — auto-fills from the chosen code’s template, then the inspector edits the wording inline (e.g. fills in pest name / parameters)</li>
</ul>
All rows are concatenated and printed on the certificate. The 5-field variant we initially considered (with separate Pest / Parameters substitution) was dropped in favour of this simpler shape, which matches the Hub <code>IncludedSPSNote</code> structure 1:1.
</div>
<p><strong>What changes:</strong> Today there is a textbox on the inspector’s form for “Additional declaration required by importing country”. We propose replacing it with a small grid where each row has: a declaration code from a fixed list (e.g. <code>ADEDL</code>) and the declaration text.</p>
<p><strong>Why:</strong> The Hub needs one coded declaration per row, not one paragraph.</p>
<p><strong>Officer experience:</strong> Inspectors click “+ add row” for each declaration, choose a code, type the text.</p>
<div class="reflist">
<strong>Code list</strong>
<ul>
<li>IPPC additional-declaration codes — <a href="https://www.ephytoexchange.org/doc/mapping/IPPC_Codes_for_additional_declarations.pdf" target="_blank">AD codes (PDF)</a></li>
</ul>
</div>
<p class="q">Does BAFRA accept using the IPPC declaration code list?</p>
<div class="reply" data-item="p3" data-title="3. Replace Additional declarations textbox with coded rows">
<div class="reply-head">
<span class="reply-label">Your decision</span>
<button type="button" class="clearOne">Clear this answer</button>
</div>
<div class="reply-opts">
<label><input type="radio" name="p3" value="we-do"><span>We’ll do it</span></label>
<label><input type="radio" name="p3" value="please-do"><span>Please do it</span></label>
<label><input type="radio" name="p3" value="skip"><span>Skip</span></label>
</div>
<textarea placeholder="Comments or clarification"></textarea>
</div>
</div>
</details>
<details class="card">
<summary><span class="num">4</span><span class="title">Split the “Treatment” textbox into separate fields</span><span class="badge">Form change</span><span class="status-pill">Done on staging</span></summary>
<div class="body">
<div class="done-box">
<strong>Status — done on staging</strong>
Treatment is now structured and lives <em>inside each commodity row</em>, so different commodities in the same shipment can carry different treatments:
<ul>
<li><strong>Treatment type L1</strong> — 4 IPPC categories (fumigation, heat, cold, irradiation)</li>
<li><strong>Treatment type L2</strong> — 18 IPPC methods</li>
<li><strong>Chemical</strong>, <strong>Concentration</strong>, <strong>Duration (hours)</strong> and <strong>Temperature (°C)</strong> as separate fields (Duration and Temperature were previously merged)</li>
</ul>
Cascading filter L1 → L2 is not yet enforced on the form; the bridge to the Hub will validate the combination at submission time.
</div>
<p><strong>What changes:</strong> Today the inspector types the full treatment into one textbox (e.g. <em>“Methyl bromide fumigation 48 g/m³ for 24 h at 25°C”</em>). We propose breaking it into:</p>
<ul>
<li>Treatment category (dropdown: fumigation, heat, cold, irradiation…)</li>
<li>Treatment method (dropdown, depends on category)</li>
<li>Chemical (text)</li>
<li>Duration in hours (number)</li>
<li>Temperature in °C (number)</li>
<li>Concentration in g/m³ (number)</li>
</ul>
<p><strong>Why:</strong> The Hub wants each piece separately, with units.</p>
<p><strong>Officer experience:</strong> More clicks, but clearer data. If inspectors prefer the current textbox, we can keep it — the software will try to split the text automatically (less reliable).</p>
<div class="reflist">
<strong>Code lists</strong>
<ul>
<li>Treatment categories + methods — <a href="https://www.ephytoexchange.org/doc/mapping/IPPC_Specific_Treatment_Types.pdf" target="_blank">IPPC treatment types (PDF)</a></li>
<li>Units of measure — <a href="https://www.ephytoexchange.org/doc/mapping/IPPC_Specific_Unit_of_Measure_Codes.pdf" target="_blank">IPPC UOM codes (PDF)</a></li>
</ul>
</div>
<p class="q">Structured fields or keep the textbox?</p>
<div class="reply" data-item="p4" data-title="4. Split Treatment textbox into structured fields">
<div class="reply-head">
<span class="reply-label">Your decision</span>
<button type="button" class="clearOne">Clear this answer</button>
</div>
<div class="reply-opts">
<label><input type="radio" name="p4" value="we-do"><span>We’ll do it</span></label>
<label><input type="radio" name="p4" value="please-do"><span>Please do it</span></label>
<label><input type="radio" name="p4" value="keep-textbox"><span>Keep textbox</span></label>
<label><input type="radio" name="p4" value="skip"><span>Skip</span></label>
</div>
<textarea placeholder="Comments or clarification"></textarea>
</div>
</div>
</details>
<details class="card">
<summary><span class="num">5</span><span class="title">Match Bhutan catalogs with international code lists</span><span class="badge">Catalog change</span><span class="status-pill partial">Partly done</span></summary>
<div class="body">
<div class="done-box partial">
<strong>Status — partly done</strong>
<ul>
<li><strong>Countries</strong> — re-keyed to ISO 3166-1 alpha-2 (248 of 249 entries; Sark skipped, no official ISO code)</li>
<li><strong>Mode of conveyance</strong> — re-keyed to UN/CEFACT Rec 19</li>
<li><strong>Unit of measure</strong> and <strong>Package type</strong> — new IPPC catalogs (item 1)</li>
<li><strong>Treatment types L1 / L2</strong> — new IPPC catalogs (item 4)</li>
<li><strong>Additional declaration codes</strong> — new IPPC SAD catalog (item 3)</li>
</ul>
<p style="margin:8px 0 0"><strong>Still to do:</strong> “Purpose / end use” was deferred — the existing entries had garbled keys (e.g. label “Packaging” bound to key “Dunnage (wooden packing material)”) and need a deliberate IPPC <em>Intended Use</em> mapping. Commodity type / BFDA office / Exit point are not yet IPPC-aligned either; those will follow.</p>
</div>
<p><strong>What changes:</strong> Nothing on the form. The dropdowns for <em>Importing country</em>, <em>Country of origin</em>, <em>Country of nationality</em>, <em>Commodity type</em>, <em>Mode of conveyance</em>, <em>Purpose / end use</em>, <em>BFDA office</em>, <em>Exit point</em>, and <em>Unit</em> all use Bhutan’s own codes today. We propose attaching the matching international code to each entry.</p>
<p><strong>Why:</strong> The Hub only accepts these international codes. Without the attachment, every submission is rejected.</p>
<p><strong>Officer experience:</strong> No change. Same dropdowns, same labels. Only the data sent to the Hub changes.</p>
<div class="reflist">
<strong>Where to get the international codes</strong>
<ul>
<li>Countries — <a href="https://www.iso.org/obp/ui/#search/code/" target="_blank">ISO 3166-1 alpha-2</a> (two-letter country codes)</li>
<li>Exit point / points of entry — <a href="https://unece.org/trade/cefact/UNLOCODE-Download" target="_blank">UN/LOCODE download</a></li>
<li>Commodity type / common name — <a href="https://www.ephytoexchange.org/doc/mapping/IPPC_Specific_Product_Description.pdf" target="_blank">IPPC product description (PDF)</a></li>
<li>Mode of conveyance — <a href="https://www.ephytoexchange.org/doc/mapping/IPPC_Specific_Modes_of_Transport_Codes.pdf" target="_blank">IPPC modes of transport (PDF)</a></li>
<li>Purpose / end use — <a href="https://www.ephytoexchange.org/doc/mapping/IPPC_Specific_Intend_Use.pdf" target="_blank">IPPC intended use (PDF)</a></li>
<li>Unit of measure — <a href="https://www.ephytoexchange.org/doc/mapping/IPPC_Specific_Unit_of_Measure_Codes.pdf" target="_blank">IPPC UOM codes (PDF)</a></li>
<li>Package type — <a href="https://www.ephytoexchange.org/doc/mapping/IPPC_Specific_Package_Codes.pdf" target="_blank">IPPC package codes (PDF)</a></li>
<li>Index of all IPPC mapping lists — <a href="https://www.ephytoexchange.org/mapping/" target="_blank">ePhyto Exchange mapping page</a></li>
</ul>
</div>
<p>There are around 200–300 entries across the nine catalogs. We recommend letting us do the mapping in bulk from the published lists, then BAFRA reviews on staging.</p>
<p class="q">Does BAFRA accept the bulk international-code attachment?</p>
<div class="reply" data-item="p5" data-title="5. Match Bhutan catalogs with international code lists">
<div class="reply-head">
<span class="reply-label">Your decision</span>
<button type="button" class="clearOne">Clear this answer</button>
</div>
<div class="reply-opts">
<label><input type="radio" name="p5" value="we-do"><span>We’ll do it</span></label>
<label><input type="radio" name="p5" value="please-do"><span>Please do it</span></label>
<label><input type="radio" name="p5" value="skip"><span>Skip</span></label>
</div>
<textarea placeholder="Comments or clarification"></textarea>
</div>
</div>
</details>
<details class="card">
<summary><span class="num">6</span><span class="title">Transit country field — skip for now?</span><span class="badge">Optional</span><span class="status-pill">Done on staging</span></summary>
<div class="body">
<div class="done-box">
<strong>Status — done on staging</strong>
A multi-select <em>Transit country</em> field has been added to the inspector form, drawing from the existing country catalog (now ISO 3166-1 alpha-2 keyed). Optional — leave empty if there are no transit countries.
</div>
<p><strong>What changes:</strong> The Hub allows listing transit countries (countries a shipment passes through) on the certificate. Bhutan’s current form has no such field.</p>
<p><strong>Why:</strong> Only needed if Bhutan exports through one or more transit countries that must appear on the certificate.</p>
<p><strong>Officer experience:</strong> One optional multi-select dropdown using the existing country catalog.</p>
<p class="q">Is this ever required for Bhutan’s exports?</p>
<div class="reply" data-item="p6" data-title="6. Transit country field">
<div class="reply-head">
<span class="reply-label">Your decision</span>
<button type="button" class="clearOne">Clear this answer</button>
</div>
<div class="reply-opts">
<label><input type="radio" name="p6" value="we-do"><span>We’ll do it</span></label>
<label><input type="radio" name="p6" value="please-do"><span>Please do it</span></label>
<label><input type="radio" name="p6" value="skip"><span>Skip</span></label>
</div>
<textarea placeholder="Comments or clarification"></textarea>
</div>
</div>
</details>
<section class="hero" style="margin-top:24px">
<p class="eyebrow">Two open questions</p>
<h2>Questions for BAFRA</h2>
<p class="lede">These shape how the data is sent to the Hub. Please answer before we start.</p>
<details class="card" open style="margin-top:14px;box-shadow:none;border-color:#f0d9b5;background:var(--warn-bg)">
<summary><span class="num" style="background:#fff4e5;color:var(--warn);border-color:#f0d9b5">A</span><span class="title">Who signs the certificate — Inspector or OIC?</span><span class="badge q">Question</span><span class="status-pill defer">Awaiting answer</span></summary>
<div class="body">
<p>The certificate sent to the Hub carries one “authorised officer” name. The service has two candidate fields: the <em>Inspector</em> name and the <em>OIC (Officer in Charge)</em> name. Please tell us which name should appear as the signatory on the Hub certificate.</p>
<div class="reply" data-item="qA" data-title="Question A: Who signs — Inspector or OIC?">
<div class="reply-head">
<span class="reply-label">Answer</span>
<button type="button" class="clearOne">Clear this answer</button>
</div>
<div class="reply-opts">
<label><input type="radio" name="qA" value="inspector"><span>Inspector</span></label>
<label><input type="radio" name="qA" value="oic"><span>OIC</span></label>
<label><input type="radio" name="qA" value="other"><span>Other (see comment)</span></label>
</div>
<textarea placeholder="Optional comment"></textarea>
</div>
</div>
</details>
<details class="card" style="box-shadow:none;border-color:#f0d9b5;background:var(--warn-bg)">
<summary><span class="num" style="background:#fff4e5;color:var(--warn);border-color:#f0d9b5">B</span><span class="title">Point of entry — one port or two?</span><span class="badge q">Question</span><span class="status-pill defer">Awaiting answer</span></summary>
<div class="body">
<p>The form has two location fields: <em>Exit point</em> (Bhutan side, e.g. Phuentsholing) and <em>Declared point of entry</em> (destination side). The Hub expects a destination port, and optionally the origin port.</p>
<p>We plan to send only the destination in version 1. Is that acceptable, or should both be sent?</p>
<div class="reply" data-item="qB" data-title="Question B: Point of entry — one port or two?">
<div class="reply-head">
<span class="reply-label">Answer</span>
<button type="button" class="clearOne">Clear this answer</button>
</div>
<div class="reply-opts">
<label><input type="radio" name="qB" value="destination"><span>Destination only (v1)</span></label>
<label><input type="radio" name="qB" value="both"><span>Both ports</span></label>
<label><input type="radio" name="qB" value="other"><span>Other (see comment)</span></label>
</div>
<textarea placeholder="Optional comment"></textarea>
</div>
</div>
</details>
</section>
<section class="submit">
<h2>Send or save your replies</h2>
<p>
Your answers are already saved in this browser — close the tab and come back later if you like.
To share them with us, pick one:
</p>
<div class="btnrow">
<button class="btn" type="button" id="downloadBtn">Download replies (JSON)</button>
<a class="btn secondary" id="mailBtn" href="#">Open email with my replies</a>
<button class="btn secondary" type="button" id="copyBtn">Copy to clipboard</button>
</div>
<div class="btnrow" style="margin-top:4px">
<label class="btn ghost" for="uploadInput" style="cursor:pointer">Upload previous replies (JSON)</label>
<input type="file" id="uploadInput" accept="application/json,.json" style="display:none">
<button class="btn ghost" type="button" id="previewBtn">Preview the text</button>
<button class="btn ghost" type="button" id="clearAllBtn">Clear all answers</button>
</div>
<div class="status" id="status"></div>
<div class="preview" id="preview"></div>
<p class="lede" style="font-size:13px;margin-top:14px">
The JSON file is the easiest way to send replies back: click Download, then attach the file to an email or chat message. If you ever want to resume editing on another computer, click Upload and pick the file.
</p>
</section>
</div>
<script>
const STORAGE_KEY = 'bafra-ephyto-replies-v1';
const decisionLabels = {
'we-do': "We'll do it",
'please-do': "Please do it",
'skip': "Skip",
'keep-textbox': "Keep textbox",
'inspector': "Inspector",
'oic': "OIC",
'destination': "Destination only (v1)",
'both': "Both ports",
'other': "Other (see comment)"
};
const statusEl = document.getElementById('status');
const previewEl = document.getElementById('preview');
const progressEl = document.getElementById('progress');
const saveMarkEl = document.getElementById('saveMark');
function replyWidgets() { return document.querySelectorAll('.reply'); }
function readState() {
const state = {};
replyWidgets().forEach(b => {
const name = b.dataset.item;
const checked = b.querySelector(`input[name="${name}"]:checked`);
const comment = b.querySelector('textarea').value;
state[name] = { decision: checked ? checked.value : null, comment };
});
return state;
}
function applyState(state) {
for (const [name, r] of Object.entries(state || {})) {
const widget = document.querySelector(`.reply[data-item="${name}"]`);
if (!widget) continue;
widget.querySelectorAll(`input[name="${name}"]`).forEach(x => x.checked = false);
if (r && r.decision) {
const radio = widget.querySelector(`input[name="${name}"][value="${r.decision}"]`);
if (radio) radio.checked = true;
}
const ta = widget.querySelector('textarea');
if (ta) ta.value = (r && r.comment) || '';
}
refresh();
}
function refresh() {
let answered = 0;
const total = replyWidgets().length;
replyWidgets().forEach(b => {
const name = b.dataset.item;
const checked = b.querySelector(`input[name="${name}"]:checked`);
const comment = b.querySelector('textarea').value.trim();
if (checked || comment) { answered++; b.classList.add('filled'); }
else { b.classList.remove('filled'); }
});
progressEl.textContent = `${answered} of ${total} items answered`;
}
function save() {
localStorage.setItem(STORAGE_KEY, JSON.stringify(readState()));
saveMarkEl.textContent = 'Saved ✓';
setTimeout(() => { saveMarkEl.textContent = 'Replies are saved in your browser as you type'; }, 1500);
refresh();
}
function load() {
try {
const raw = localStorage.getItem(STORAGE_KEY);
if (raw) applyState(JSON.parse(raw));
} catch (e) {}
refresh();
}
function composeText() {
const now = new Date().toISOString().slice(0,10);
let text = `ePhyto Hub — BAFRA replies\nDate: ${now}\nService: Phytosanitary certificate (export of plants and plant products)\n\n`;
let answered = 0;
replyWidgets().forEach(b => {
const title = b.dataset.title;
const name = b.dataset.item;
const checked = b.querySelector(`input[name="${name}"]:checked`);
const comment = b.querySelector('textarea').value.trim();
const decision = checked ? (decisionLabels[checked.value] || checked.value) : '(no decision)';
if (checked || comment) answered++;
text += `--- ${title} ---\nDecision: ${decision}\n`;
if (comment) text += `Comment: ${comment}\n`;
text += '\n';
});
return { text, answered, total: replyWidgets().length };
}
function composeJson() {
const now = new Date().toISOString().slice(0,10);
const replies = {};
replyWidgets().forEach(b => {
const name = b.dataset.item;
const checked = b.querySelector(`input[name="${name}"]:checked`);
const comment = b.querySelector('textarea').value.trim();
replies[name] = {
title: b.dataset.title,
decision: checked ? checked.value : null,
decision_label: checked ? (decisionLabels[checked.value] || checked.value) : null,
comment
};
});
return {
schema: 'bafra-ephyto-replies-v1',
service: 'Phytosanitary certificate (export of plants and plant products) — Bhutan',
date: now,
replies
};
}
function clearOne(widget) {
const name = widget.dataset.item;
widget.querySelectorAll(`input[name="${name}"]`).forEach(r => r.checked = false);
widget.querySelector('textarea').value = '';
save();
statusEl.textContent = `Cleared "${widget.dataset.title}".`;
}
function clearAll() {
if (!confirm('Clear all answers? This cannot be undone.')) return;
replyWidgets().forEach(b => {
const name = b.dataset.item;
b.querySelectorAll(`input[name="${name}"]`).forEach(r => r.checked = false);
b.querySelector('textarea').value = '';
});
save();
statusEl.textContent = 'All answers cleared.';
}
// Event wiring
document.addEventListener('input', save);
document.addEventListener('change', save);
document.addEventListener('click', e => {
if (e.target.matches('.clearOne')) clearOne(e.target.closest('.reply'));
});
document.getElementById('downloadBtn').addEventListener('click', () => {
const data = composeJson();
const blob = new Blob([JSON.stringify(data, null, 2)], { type: 'application/json' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = `bafra-ephyto-replies-${data.date}.json`;
a.click();
URL.revokeObjectURL(url);
statusEl.textContent = 'Downloaded — attach this file to your email or chat.';
});
document.getElementById('uploadInput').addEventListener('change', e => {
const file = e.target.files[0];
if (!file) return;
const reader = new FileReader();
reader.onload = ev => {
try {
const data = JSON.parse(ev.target.result);
if (data && data.replies) {
applyState(data.replies);
save();
statusEl.textContent = `Loaded replies from ${file.name}.`;
} else {
statusEl.textContent = 'File does not look like a replies JSON.';
}
} catch (err) {
statusEl.textContent = 'Could not read the file (not valid JSON).';
}
e.target.value = '';
};
reader.readAsText(file);
});
document.getElementById('copyBtn').addEventListener('click', async () => {
const { text, answered, total } = composeText();
try {
await navigator.clipboard.writeText(text);
statusEl.textContent = `Copied to clipboard (${answered}/${total} items answered).`;
} catch (e) {
statusEl.textContent = 'Could not copy — use "Preview the text" and copy manually.';
}
});
document.getElementById('mailBtn').addEventListener('click', e => {
e.preventDefault();
const { text } = composeText();
const subject = encodeURIComponent('ePhyto Hub — BAFRA replies');
const body = encodeURIComponent(text);
window.location.href = `mailto:?subject=${subject}&body=${body}`;
});
document.getElementById('previewBtn').addEventListener('click', () => {
const { text, answered, total } = composeText();
previewEl.textContent = text;
previewEl.classList.add('show');
statusEl.textContent = `${answered}/${total} items answered.`;
});
document.getElementById('clearAllBtn').addEventListener('click', clearAll);
load();
</script>
</body>
</html>