create-issflow 1.9.0 → 1.9.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-issflow",
3
- "version": "1.9.0",
3
+ "version": "1.9.1",
4
4
  "description": "Scaffold the iStartSoftFlow AI-coding workflow into a project. Stack-agnostic, tool-agnostic (Claude Code, Codex, Cursor, Gemini, Aider), non-destructive.",
5
5
  "bin": {
6
6
  "create-issflow": "bin/cli.js"
@@ -77,7 +77,8 @@ Show me CR-<n> (impact + price delta + new total — no rate). **STOP for approv
77
77
  (commercial gate — always interactive).
78
78
  - **Approved** -> set CR status `approved`; bump PROPOSAL.md to a new version (vN+1)
79
79
  with the delta folded in (**totals only**); re-render `docs/proposal.html` from it
80
- (same template + language; no contingency note / rate); then dispatch `/replan` to
80
+ (same `/propose` package rows + screen appendix — do not dump every PLAN phase
81
+ onto the sign table; same template + language; no contingency note / rate); then dispatch `/replan` to
81
82
  apply the phase changes to PLAN.md (done phases stay frozen). Update STATE.md.
82
83
  NOTE: `/replan` reverts PLAN.md to `> Approval: PENDING` and re-runs the
83
84
  PLAN-APPROVAL gate (hard rule 13) — the commercial CR sign-off is SEPARATE from
@@ -1,17 +1,18 @@
1
1
  ---
2
- description: Turn approved requirements + tech stack into a client proposal — scope, phase breakdown, effort + cost estimate, timeline, assumptions, and a sign-off gate. Run after /overview, before building.
2
+ description: Turn approved requirements + tech stack into a client proposal — scope, packages, effort + cost estimate, timeline, assumptions, screen appendix, and a sign-off gate. Run after /overview, before building.
3
3
  argument-hint: [optional: rate / budget / constraints · "dry-run" to preview]
4
4
  ---
5
5
 
6
6
  Caveman ULTRA mode. You are the ORCHESTRATOR.
7
7
 
8
- Purpose: produce `docs/PROPOSAL.md` — WHAT we build, in what phases, how long, how
8
+ Purpose: produce `docs/PROPOSAL.md` — WHAT we build, in what packages, how long, how
9
9
  much, and on what assumptions — for the client to approve BEFORE any build starts.
10
10
  A proposal is a commercial gate: always interactive (both AUTO and GUIDED).
11
11
 
12
12
  DRY-RUN: if `$ARGUMENTS` contains `dry-run`/`--dry-run`, do the full analysis but
13
- EXECUTE NOTHING — print the ACTION PLAN (scope, phase breakdown, rough estimate)
14
- and STOP. No PROPOSAL.md / proposal.html is written. (METHODOLOGY → Dry-run.)
13
+ EXECUTE NOTHING — print the ACTION PLAN (scope, phase breakdown, package collapse,
14
+ rough estimate) and STOP. No PROPOSAL.md / proposal.html is written.
15
+ (METHODOLOGY → Dry-run.)
15
16
 
16
17
  ## PRE-FLIGHT
17
18
  Read `docs/OVERVIEW.md` (scope, stack, success criteria) and `docs/PRD.md` if
@@ -28,12 +29,15 @@ List the deliverables (features / epics) from OVERVIEW / PRD. Mark each
28
29
  **in-scope** or **out-of-scope** explicitly — naming out-of-scope items now is what
29
30
  prevents silent scope creep (and grounds change-order re-pricing later).
30
31
 
31
- ## STEP 2 — PHASE BREAKDOWN
32
+ ## STEP 2 — PHASE BREAKDOWN (internal)
32
33
  Derive the vertical-slice phases (or read `docs/PLAN.md` if it exists). Size each:
33
34
  - complexity: **S | M | L | XL**
34
35
  - effort: an ideal-days RANGE (e.g. 2–3d), + story points if your team uses them
35
36
  - risk / unknowns: what could move the estimate
36
37
 
38
+ Keep this sizing for the **chat math**. Do **not** dump every PLAN phase onto the
39
+ client table — collapse into packages in STEP 5.
40
+
37
41
  ## STEP 3 — ESTIMATE (ask rate · never invent a kit default)
38
42
  Estimation config is **project-private**. The public kit ships **no** default rate
39
43
  card and **no** sample salary/rate numbers — rates are confidential.
@@ -46,22 +50,35 @@ card and **no** sample salary/rate numbers — rates are confidential.
46
50
  3. Optional: store the answered rate/contingency in a **project-local** file the
47
51
  team keeps private (e.g. `docs/ESTIMATE.local.md` gitignored, or OVERVIEW fields
48
52
  that never get published). Never commit personal rate/salary into a public kit
49
- or template.
53
+ or template. If you create `docs/ESTIMATE.local.md`, add it to the project's
54
+ `.gitignore` when it is not already listed.
50
55
  4. Configurable fields (ask or read — no invented kit defaults for money):
51
56
  - **unit:** ideal-days | hours | story-points | both
52
57
  - **rate card:** blended OR per-role (senior / mid / junior…)
53
58
  - **currency:** as declared (ask if unset; THB is common for Thai clients)
54
59
  - **contingency:** % buffer for unknowns (ask if unset)
55
- - **payment milestones:** by-phase, split (e.g. 30/40/30), or none
60
+ - **payment split:** e.g. 30/40/30 — **ASK once; do not guess** a ratio
56
61
  - **language:** rendered doc language (default = project language)
57
62
 
63
+ Ask these **once each** if unset (commercial input — do not invent kit defaults):
64
+
65
+ - **Hours columns:** does the client table show estimated hours next to billed
66
+ hours? If yes → columns ประเมิน / คิดเงิน / ยอด. If no / unset → ชุดงาน + ยอด
67
+ only. Hours are effort, not a rate — still never print the rate.
68
+ - **Managed hosting / database:** is platform hosting+database **in** the quoted
69
+ total? If **not included**, write clearly on page 1 (out of scope + exclusions)
70
+ that the client pays the provider directly. A one-line exclusion is enough —
71
+ do **not** paste vendor SKU/price tables into the kit or invent list prices.
72
+ - **Bank:** include a bank block **only if the human provides** account details
73
+ in this project. No kit default. If none given, omit the column.
74
+
58
75
  Compute cost per phase, then a **Total as a RANGE (low–high)** that already folds
59
76
  in contingency. Show the math **in chat to the human** (rate × effort + contingency).
60
77
  **Timeline:** phases in dependency order → calendar estimate (note parallelism).
61
78
 
62
79
  ### CLIENT-DOC RULE (hard — commercial privacy)
63
80
  Client-facing artifacts (`docs/PROPOSAL.md` client sections, `docs/proposal.html`,
64
- and any PDF/print) MUST show **totals and phase costs only**.
81
+ and any PDF/print) MUST show **totals and package costs only**.
65
82
  **Never** print: hourly/day rates, rate cards, contingency %, “incl. X% buffer”,
66
83
  salary, or the estimate math. Contingency is already inside the numbers — do not
67
84
  label it on the client page.
@@ -71,38 +88,83 @@ List every assumption the estimate rests on (infra provided, third-party/licence
71
88
  costs excluded, content/design provided, etc.). These are the baseline that
72
89
  change-orders re-price against.
73
90
 
91
+ If hosting/database is not in the quote, the exclusion **must** say the client
92
+ pays the provider directly.
93
+
74
94
  ## STEP 5 — WRITE + RENDER
95
+ Collapse the internal PLAN phases into **3–6 client packages / sprints** that a
96
+ non-engineer can read. PLAN may have any number of phases; the sign page does not
97
+ list them all.
98
+
99
+ Payment copy = short **software delivery events** tied to those packages, e.g.
100
+ deposit on sign-off then work starts · when the main package is usable · when
101
+ production is up within the scope on this quote. **Never** construction wording
102
+ (% structure, house handover, site prep / equipment staging).
103
+
75
104
  1. Write `docs/PROPOSAL.md` — the SOURCE OF TRUTH (versioned v1 + date). This is
76
105
  what `CHANGES.md` re-prices against. **Client-safe** body (no rate / no
77
106
  contingency %):
78
107
  ```
79
108
  # Proposal — <project> (v1, <date>)
80
109
  ## Scope — in-scope: … | out-of-scope: …
81
- ## Phases — table: phase | complexity | effort (range) | cost
110
+ ## Packages — table: package | cost
111
+ — or package | estimated | billed | cost (only if hours columns requested)
82
112
  ## Total — <low>–<high> ← totals only; no “incl. X% contingency”
83
113
  ## Timeline — <estimate>, dependency order
84
114
  ## Assumptions — …
85
- ## Exclusions — …
86
- ## Payment — milestones (if any)
115
+ ## Exclusions — … (hosting/database: client pays provider, if that was the answer)
116
+ ## Payment — software delivery events + the asked split (if any)
117
+ ## Screens — docs/proposal.html pages 2–N (or “none — no UI in scope”)
118
+ — not pixel-binding; sign page 1 only; page count must match the HTML
87
119
  ## Sign-off — approved by: ___ date: ___ version: v1
88
120
  ```
121
+ Point the Screens section at the **real** HTML page range after render
122
+ (page 1 = sign · remaining sheets = screen appendix). Keep PROPOSAL.md and
123
+ `docs/proposal.html` in sync.
89
124
  If you keep an internal rate memo, put it in a **separate private** file (not
90
125
  the client PROPOSAL.md / HTML). PROPOSAL.md itself stays client-safe so it can
91
126
  be shared.
92
127
 
93
- 2. RENDER a client-facing `docs/proposal.html` from `.issflow/templates/proposal.html`:
94
- copy it, replace every `{{PLACEHOLDER}}`, and fill the CONTENT in the declared
95
- language (the section labels are already bilingual TH / EN). It must fit ONE A4
96
- page — be terse (≈ 3–6 phase rows, ≈ 4 assumptions, short scope items); trim before
97
- it spills to a second page. Fill `{{COMPANY}}` / `{{COMPANY_TAGLINE}}` / `{{LOGO}}`
98
- from the ISSUING company's brand declared in OVERVIEW (or ask once) — white-label,
99
- never hardcode the kit's name. Leave `{{TOTAL_NOTE}}` empty or a non-rate line
128
+ 2. RENDER a client-facing `docs/proposal.html` from `.issflow/templates/proposal.html`
129
+ (Claude Code also mirrors this under `.claude/templates/` — same file). Copy it,
130
+ replace every `{{PLACEHOLDER}}`, and fill the CONTENT in the declared language
131
+ (the section labels are already bilingual TH / EN).
132
+
133
+ **Page 1 = the only signable A4 sheet.** Be terse (≈ 3–6 package rows, ≈ 4
134
+ assumptions, short scope items). If page 1 overflows A4, **trim the sign-page
135
+ copy first** — never spill the sign block onto page 2. The screen appendix may
136
+ grow extra `.sheet` pages.
137
+
138
+ Fill `{{PACKAGE_TABLE}}` with the matching header:
139
+ - default: ชุดงาน / Packages + Cost
140
+ - if hours columns requested: ประเมิน / คิดเงิน / ยอด (and EN equivalents)
141
+ Fill `{{BANK_COL}}` only when the human gave bank details; otherwise leave
142
+ empty so payment takes the full width.
143
+ Fill `{{COMPANY}}` / `{{COMPANY_TAGLINE}}` / `{{LOGO}}` from the ISSUING
144
+ company's brand declared in OVERVIEW (or ask once) — white-label, never
145
+ hardcode the kit's name. Leave `{{TOTAL_NOTE}}` empty or a non-rate line
100
146
  (e.g. currency / “ราคารวมทั้งโครงการ”) — **never** a contingency % or rate.
147
+ Set `{{PAGE_FOOTER}}` to the real page count (e.g. sign page 1 of N).
148
+
149
+ **Screen appendix (required when UI is in scope)** — same `docs/proposal.html`,
150
+ not a second signable file. After page 1's page-break, emit `.sheet.screens`
151
+ into `{{SCREEN_SHEETS}}`:
152
+ - Build frames from **PLAN + OVERVIEW** modules/capabilities (empty chrome is
153
+ fine). Do **not** wait for UX-PACK (that gate is after sign-off).
154
+ - Cover **every** in-scope module and capability — not a 4–8 frame sampler.
155
+ - Group sheets by package; module bar on each sheet; numbered short captions
156
+ under frames.
157
+ - Label: not pixel-binding. Sign on page 1 only. **No emoji as icons.**
158
+ - Use the template's desk/phone/sidebar/card/table CSS. Do not invent a
159
+ parallel stylesheet.
160
+
101
161
  Print-ready (Ctrl/Cmd-P → A4 → Save as PDF). Keep PROPOSAL.md and proposal.html
102
162
  in sync.
103
163
 
104
164
  ## STEP 6 — SIGN-OFF GATE
105
165
  Show me the proposal. **STOP for approval** (commercial gate — always interactive).
166
+ Do **not** run `/design` or `/phase` yourself.
167
+
106
168
  On approval: record the approved version + date in PROPOSAL.md and STATE.md, and
107
169
  append a HISTORY line `proposal v<n> approved (<total>)`.
108
170
 
@@ -109,10 +109,12 @@ from idea to closeout:
109
109
  the proposal estimates *these* phases.
110
110
  5. **Proposal & estimate (OPTIONAL — depends on the job)** — for client / quoted
111
111
  work, `/propose` reads OVERVIEW + PLAN → `docs/PROPOSAL.md` + a rendered
112
- `docs/proposal.html`: scope, phase breakdown, effort + cost estimate, timeline,
113
- assumptions, with a **client sign-off gate** before build. **Ask rate +
114
- contingency in chat** when missing — the kit stores **no** default rate (rates
115
- are confidential). Client docs show **totals only** (never rate or contingency %).
112
+ `docs/proposal.html`: scope, **package** rows on the signable A4 page (not every
113
+ PLAN phase), effort + cost estimate, timeline, assumptions, and a screen
114
+ appendix in the **same HTML** after a page-break, with a **client sign-off gate**
115
+ before build. **Ask rate + contingency in chat** when missing — the kit stores
116
+ **no** default rate (rates are confidential). Client docs show **totals only**
117
+ (never rate or contingency %).
116
118
  Internal / personal projects skip straight from plan to build (and may set
117
119
  design/architecture gates to `n/a`).
118
120
  6. **Design + architecture gates (rule 15 — after proposal, before build)** —
@@ -620,10 +622,12 @@ the KB. The kit works normally without a KB.
620
622
  ## File contract
621
623
 
622
624
  - `docs/PRD.md` — crystallised product requirements (or your BMAD/iSSM stories).
623
- - `docs/PROPOSAL.md` — scope + phase breakdown + effort/cost totals + assumptions
624
- + sign-off. Versioned; client-safe commercial baseline (no rate / contingency %).
625
+ - `docs/PROPOSAL.md` — scope + package rows + effort/cost totals + assumptions
626
+ + screen-appendix page range + sign-off. Versioned; client-safe commercial
627
+ baseline (no rate / contingency %).
625
628
  - `docs/proposal.html` — the client-facing proposal, rendered from PROPOSAL.md via
626
- `.issflow/templates/proposal.html`, in the project language; print-ready (PDF).
629
+ `.issflow/templates/proposal.html`, in the project language; page 1 is the
630
+ signable A4 sheet, then screen frames in the same file (print A4).
627
631
  - `docs/UX-PACK.md` · `docs/ARCHITECTURE.md` — pre-build design/arch frames
628
632
  (rule 15); templates under `.issflow/templates/`.
629
633
  - `.issflow/templates/` — document templates (proposal.html, UX-PACK, ARCHITECTURE,
@@ -1,12 +1,51 @@
1
1
  <!doctype html>
2
2
  <!--
3
- Client-facing proposal — ONE A4 PAGE (rendered by /propose from docs/PROPOSAL.md).
4
- HOW TO USE (agent): copy to docs/proposal.html, replace every {{PLACEHOLDER}}, and
5
- keep it to a SINGLE A4 page — be terse (≈3–6 phases, ≈4 assumptions). Localise the
6
- CONTENT to the project language; the section labels are bilingual (TH / EN) already.
7
- WHITE-LABEL: fill {{COMPANY}} / {{LOGO}} with the ISSUING company's brand (not the
8
- kit's). {{LOGO}} optional: an <img src="…">, an SVG, or delete to keep the monogram.
9
- Print: Ctrl/Cmd-P → A4 → "Save as PDF" (fits one page).
3
+ Client-facing proposal (rendered by /propose from docs/PROPOSAL.md).
4
+
5
+ PAGE 1 = the only signable A4 sheet (packages 3–6 rows, short scope). Trim
6
+ sign-page copy before it overflows. Screen sheets after the first page-break
7
+ may grow extra A4 pages.
8
+
9
+ HOW TO USE (agent): copy to docs/proposal.html, replace every {{PLACEHOLDER}}.
10
+ Localise CONTENT to the project language; section labels are bilingual (TH / EN).
11
+ WHITE-LABEL: fill {{COMPANY}} / {{LOGO}} with the ISSUING company's brand (not
12
+ the kit's). {{LOGO}} optional: an <img src="…">, an SVG, or delete the monogram.
13
+ {{BANK_COL}}: omit unless the human gave bank details (no kit default).
14
+ {{PACKAGE_TABLE}}: default head = ชุดงาน / Packages + Cost; if hours columns
15
+ were requested = ประเมิน / คิดเงิน / ยอด. Never leave sample amounts in the file.
16
+ {{SCREEN_SHEETS}}: one .sheet.screens per appendix page; cover every in-scope
17
+ module from PLAN + OVERVIEW; numbered captions; no emoji icons; not pixel-binding.
18
+ {{PAGE_FOOTER}}: real page count (sign page 1 of N).
19
+ Print: Ctrl/Cmd-P → A4 → "Save as PDF".
20
+
21
+ Example screen frame (fill {{SCREEN_SHEETS}}; placeholders only — no domain copy):
22
+ <div class="sheet screens">
23
+ <div class="head">… {{COMPANY}} · ตัวอย่างจอ — ไม่ผูกพิกเซล / Screens — not pixel-binding</div>
24
+ <div class="modbar"><span class="here">{{MODULE}}</span></div>
25
+ <p class="note">{{SCREEN_NOTE}}</p>
26
+ <div class="figs">
27
+ <figure>
28
+ <div class="desk">
29
+ <div class="top"><span class="mark">{{MARK}}</span><span class="brand">{{APP_NAME}}</span></div>
30
+ <div class="body">
31
+ <div class="nav"><span class="on">{{NAV_ON}}</span></div>
32
+ <div class="main">
33
+ <div class="kpis"><div class="card">{{CARD}}</div></div>
34
+ <table class="ui">{{UI_ROWS}}</table>
35
+ </div>
36
+ </div>
37
+ </div>
38
+ <figcaption><b>{{FRAME_N}}. {{FRAME_TITLE}}</b> — {{FRAME_CAPTION}}</figcaption>
39
+ </figure>
40
+ <figure>
41
+ <div class="phone">
42
+ <div class="top"><span class="mark">{{MARK}}</span><span class="brand">{{APP_NAME}}</span></div>
43
+ <div class="screen">{{PHONE_BODY}}</div>
44
+ </div>
45
+ <figcaption><b>{{FRAME_N}}. {{FRAME_TITLE}}</b> — {{FRAME_CAPTION}}</figcaption>
46
+ </figure>
47
+ </div>
48
+ </div>
10
49
  -->
11
50
  <html lang="{{LANG}}">
12
51
  <head>
@@ -16,23 +55,21 @@
16
55
  @page { size: A4; margin: 0 }
17
56
  :root{
18
57
  --ink:#162033; --muted:#5d6a7d; --line:#dbe3ee; --soft:#f6f8fb;
19
- --violet:#635bff; --green:#15803d;
58
+ --violet:#635bff; --green:#15803d; --bad:#b42318;
20
59
  --sans:"Inter","Noto Sans Thai",-apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif;
21
60
  --mono:ui-monospace,Menlo,Consolas,monospace;
22
61
  }
23
62
  *{box-sizing:border-box}
24
- body{margin:0;background:#e9edf3;color:var(--ink);font-family:var(--sans);font-size:10.5px;line-height:1.45}
25
- .sheet{width:210mm;min-height:297mm;margin:10mm auto;background:#fff;padding:15mm 16mm;display:flex;flex-direction:column;gap:11px}
26
- .lbl{color:var(--muted);font-size:8.5px;font-weight:800;letter-spacing:.06em;text-transform:uppercase;margin:0 0 3px}
63
+ body{margin:0;background:#e9edf3;color:var(--ink);font-family:var(--sans);font-size:10.5px;line-height:1.4}
64
+ .sheet{width:210mm;min-height:297mm;margin:10mm auto;background:#fff;padding:13mm 15mm;display:flex;flex-direction:column;gap:8px}
65
+ .lbl{color:var(--muted);font-size:8px;font-weight:800;letter-spacing:.06em;text-transform:uppercase;margin:0 0 3px}
27
66
  .lbl em{font-style:normal;opacity:.6;font-weight:600}
28
- h1{font-size:21px;margin:0;letter-spacing:-.3px;line-height:1.1}
29
- .muted{color:var(--muted)} ul{margin:0;padding-left:15px} li{margin:1.5px 0}
30
- hr{border:none;border-top:1px solid var(--line);margin:0}
67
+ h1{font-size:19px;margin:0;letter-spacing:-.3px;line-height:1.15}
68
+ .muted{color:var(--muted)} ul{margin:0;padding-left:15px} li{margin:1px 0}
31
69
 
32
- /* header */
33
- .head{display:flex;justify-content:space-between;align-items:flex-start;border-bottom:2px solid var(--ink);padding-bottom:11px}
70
+ .head{display:flex;justify-content:space-between;align-items:flex-start;border-bottom:2px solid var(--ink);padding-bottom:9px}
34
71
  .co{display:flex;align-items:center;gap:10px}
35
- .logo{width:42px;height:42px;border-radius:9px;background:var(--ink);color:#fff;display:flex;align-items:center;justify-content:center;font-weight:800;font-size:13px;flex:0 0 auto;overflow:hidden}
72
+ .logo{width:40px;height:40px;border-radius:9px;background:var(--ink);color:#fff;display:flex;align-items:center;justify-content:center;font-weight:800;font-size:13px;flex:0 0 auto;overflow:hidden}
36
73
  .logo img{width:100%;height:100%;object-fit:contain}
37
74
  .co .name{font-weight:800;font-size:15px;line-height:1.15}
38
75
  .co .tag{color:var(--muted);font-size:9px}
@@ -40,19 +77,69 @@
40
77
  .head .meta .big{font:800 12px/1.2 var(--sans);letter-spacing:.12em;color:var(--violet)}
41
78
  .pill{display:inline-block;border:1px solid var(--line);border-radius:999px;padding:2px 8px;font:800 8px/1 var(--mono);color:var(--muted);margin-top:4px}
42
79
 
43
- .cols{display:flex;gap:18px} .cols>div{flex:1;min-width:0}
44
- table{width:100%;border-collapse:collapse;font-size:10px}
45
- th,td{text-align:left;padding:5px 7px;border-bottom:1px solid var(--line)}
46
- th{background:var(--soft);font-size:8px;text-transform:uppercase;letter-spacing:.04em;color:var(--muted)}
47
- td.n,th.n{text-align:right;font-family:var(--mono)}
48
- tfoot td{font-weight:800;border-top:1.5px solid var(--ink);border-bottom:none}
49
- .total{display:flex;align-items:baseline;justify-content:space-between;background:var(--soft);border-radius:9px;padding:9px 13px}
50
- .total .amt{font-size:19px;font-weight:800} .total .amt small{font-size:9px;color:var(--muted);font-weight:600}
51
-
52
- .sign{display:flex;gap:34px;margin-top:auto;padding-top:14px}
53
- .sign>div{flex:1} .line{border-bottom:1px solid var(--ink);height:30px} .sign .lbl{margin-top:5px}
54
- footer{border-top:1px solid var(--line);padding-top:8px;color:var(--muted);font-size:8.5px;display:flex;justify-content:space-between}
55
- @media print{ body{background:#fff} .sheet{margin:0;min-height:auto;box-shadow:none} }
80
+ .cols{display:flex;gap:16px} .cols>div{flex:1;min-width:0}
81
+ table.quote{width:100%;border-collapse:collapse;font-size:10px}
82
+ .quote th,.quote td{text-align:left;padding:4px 6px;border-bottom:1px solid var(--line)}
83
+ .quote th{background:var(--soft);font-size:8px;text-transform:uppercase;letter-spacing:.04em;color:var(--muted)}
84
+ .quote td.n,.quote th.n{text-align:right;font-family:var(--mono)}
85
+ .quote tfoot td{font-weight:800;border-top:1.5px solid var(--ink);border-bottom:none}
86
+ .total{display:flex;align-items:flex-end;justify-content:space-between;background:var(--soft);border-radius:9px;padding:8px 12px;gap:12px}
87
+ .total .amt{font-size:18px;font-weight:800;text-align:right}
88
+ .total .amt small{display:block;font-size:9px;color:var(--muted);font-weight:600}
89
+
90
+ .sign{display:flex;gap:34px;margin-top:auto;padding-top:10px}
91
+ .sign>div{flex:1} .line{border-bottom:1px solid var(--ink);height:26px} .sign .lbl{margin-top:4px}
92
+ footer{border-top:1px solid var(--line);padding-top:7px;color:var(--muted);font-size:8px;display:flex;justify-content:space-between}
93
+
94
+ /* screen appendix — empty chrome; fill from PLAN + OVERVIEW */
95
+ .sheet.screens{padding:10mm 12mm;gap:6px}
96
+ .screens .head{padding-bottom:6px}
97
+ .screens .note{font-size:9px;margin:0;color:var(--muted)}
98
+ .modbar{display:flex;flex-wrap:wrap;gap:4px}
99
+ .modbar span{border:1px solid var(--line);border-radius:999px;padding:2px 7px;font-size:8px;font-weight:700;color:var(--muted)}
100
+ .modbar .here{background:#ecebff;border-color:#d4d1ff;color:var(--violet)}
101
+ .figs{display:grid;grid-template-columns:1fr 1fr;gap:8px 10px;flex:1}
102
+ figure{margin:0;display:flex;flex-direction:column;min-width:0}
103
+ figcaption{margin-top:3px;font-size:8px;color:var(--muted);line-height:1.35}
104
+ figcaption b{color:var(--ink);font-weight:700}
105
+ .desk,.phone{background:#fff;border:1px solid var(--line);border-radius:10px;overflow:hidden;flex:1;min-height:0}
106
+ .top{display:flex;align-items:center;gap:6px;padding:5px 8px;border-bottom:1px solid var(--line);background:var(--soft)}
107
+ .mark{width:16px;height:16px;border-radius:4px;background:var(--violet);color:#fff;font-size:8px;font-weight:800;display:flex;align-items:center;justify-content:center}
108
+ .brand{font-weight:800;font-size:10px;color:var(--violet)}
109
+ .sub{font-size:8px;color:var(--muted)}
110
+ .body{display:flex;min-height:148px}
111
+ .nav{width:64px;border-right:1px solid var(--line);padding:5px;font-size:8px}
112
+ .nav span{display:block;padding:2px 4px;border-radius:4px;margin-bottom:1px;color:#334155}
113
+ .nav .on{background:#ecebff;color:var(--violet);font-weight:700}
114
+ .nav .tail{margin-top:6px;padding-top:4px;border-top:1px solid var(--line)}
115
+ .main{flex:1;padding:6px;min-width:0}
116
+ .kpis{display:grid;grid-template-columns:1fr 1fr 1fr;gap:4px}
117
+ .kpis.two{grid-template-columns:1fr 1fr}
118
+ .card{border:1px solid var(--line);border-radius:6px;padding:4px 5px;font-size:8px;background:#fff}
119
+ .card .n{font-size:12px;font-weight:800}
120
+ .red{border-color:#f0c4c0;background:#fff7f6}
121
+ .red .n{color:var(--bad)}
122
+ .ok{border-color:#b7d4c2;background:#f4faf6}
123
+ .ok .n{color:var(--green)}
124
+ .warn{border-color:#ead8a4;background:#fffbeb}
125
+ .ui{width:100%;border-collapse:collapse;font-size:8px;margin-top:4px}
126
+ .ui th,.ui td{text-align:left;padding:2px 3px;border-bottom:1px solid var(--line)}
127
+ .ui th{color:var(--muted);font-weight:600}
128
+ .btn{display:inline-block;background:var(--violet);color:#fff;border-radius:4px;padding:3px 7px;font-size:8px;font-weight:700;margin-top:5px}
129
+ .btn.ghost{background:#fff;color:var(--violet);border:1px solid var(--violet)}
130
+ .field{display:flex;justify-content:space-between;gap:8px;border-bottom:1px dashed var(--line);padding:3px 0;font-size:8px}
131
+ .crumbs{font-size:8px;color:var(--muted);margin-bottom:3px}
132
+ .login{padding:12px;min-height:148px;display:flex;flex-direction:column;justify-content:center;align-items:flex-start;gap:6px}
133
+ .login h3{margin:0;font-size:12px}
134
+ .phone{max-width:168px;margin:0 auto;width:100%}
135
+ .screen{padding:7px}
136
+ .tiny{font-size:7px;color:var(--muted)}
137
+
138
+ @media print{
139
+ body{background:#fff}
140
+ .sheet{margin:0;min-height:297mm;page-break-after:always;box-shadow:none}
141
+ .sheet:last-child{page-break-after:auto}
142
+ }
56
143
  </style>
57
144
  </head>
58
145
  <body>
@@ -81,12 +168,8 @@
81
168
  </div>
82
169
 
83
170
  <div>
84
- <p class="lbl">เฟส &amp; ค่าใช้จ่าย <em>Phases &amp; cost</em></p>
85
- <table>
86
- <thead><tr><th>เฟส <em style="font-style:normal;opacity:.5">Phase</em></th><th>Complexity</th><th class="n">Effort</th><th class="n">Cost</th></tr></thead>
87
- <tbody>{{PHASE_ROWS}}<!-- <tr><td>1. Auth</td><td>M</td><td class="n">2–3d</td><td class="n">฿16k–24k</td></tr> --></tbody>
88
- <tfoot><tr><td colspan="2">รวม <em style="font-style:normal;opacity:.5">Total</em></td><td class="n">{{TOTAL_EFFORT}}</td><td class="n">{{TOTAL_COST}}</td></tr></tfoot>
89
- </table>
171
+ <p class="lbl">ชุดงาน &amp; ค่าใช้จ่าย <em>Packages &amp; cost</em></p>
172
+ <table class="quote">{{PACKAGE_TABLE}}</table>
90
173
  </div>
91
174
 
92
175
  <div class="total">
@@ -100,14 +183,22 @@
100
183
  <div><p class="lbl">ข้อยกเว้น <em>Exclusions</em></p><ul>{{EXCLUSION_ITEMS}}</ul></div>
101
184
  </div>
102
185
 
103
- <div><p class="lbl">เงื่อนไขการชำระเงิน <em>Payment</em></p><p class="muted" style="margin:0">{{PAYMENT_ITEMS}}</p></div>
186
+ <div class="cols">
187
+ <div>
188
+ <p class="lbl">เงื่อนไขการชำระเงิน <em>Payment</em></p>
189
+ <ul>{{PAYMENT_ITEMS}}</ul>
190
+ </div>
191
+ {{BANK_COL}}
192
+ </div>
104
193
 
105
194
  <div class="sign">
106
195
  <div><div class="line"></div><p class="lbl">ลงนามลูกค้า <em>Client sign-off</em></p></div>
107
196
  <div><div class="line"></div><p class="lbl">วันที่ <em>Date</em></p></div>
108
197
  </div>
109
198
 
110
- <footer><span>{{COMPANY}} · {{FOOTER}}</span><span>{{VERSION}}</span></footer>
199
+ <footer><span>{{COMPANY}} · {{PAGE_FOOTER}}</span><span>{{VERSION}}</span></footer>
111
200
  </div>
201
+
202
+ {{SCREEN_SHEETS}}
112
203
  </body>
113
204
  </html>