- Header: remove initials box, match timesheet style (org name left,
REIMBURSEMENT right, same size, muted subtitles below each)
- Replace thin hairline after header with thick accent-colour divider (2.5pt)
- Info strip (Staff/Period/Currency): fix unequal vertical padding — labels
were crowded to top border; now symmetric using cap-height maths
- Item section header: replace bare left stripe with full-width surface-2 strip,
equal visual padding above and below text, accent bar full height of strip
- Reduce excessive whitespace after receipt refs and before grand total divider
- Apply same equal-padding fix to continuation header (page 2+)
https://claude.ai/code/session_01JyuActqTJG5tuRQNLmT7fZ
- Increased row label gaps and inter-item spacing throughout PDF layout
- Changed all figure/number fonts from Courier (monospace) to Helvetica body
- Download filename now uses FULL_NAME_YYYY-MM-DD_Reimbursement.pdf convention
https://claude.ai/code/session_01JyuActqTJG5tuRQNLmT7fZ
- Save (20%) and Validate (20%) as ghost buttons, Download (60%) as primary
- Validate runs full validation and shows error list or a green success note
- Save retains existing onSave behaviour (soft validation + persist)
https://claude.ai/code/session_01JyuActqTJG5tuRQNLmT7fZ
Matches the timesheet app: the blue squircle reimburse icon appears
next to the org name instead of the initials fallback. Uses var(--accent)
fill so it adapts to dark mode. Also used as fallback if logo image fails.
https://claude.ai/code/session_01JyuActqTJG5tuRQNLmT7fZ
- Language select moves to toolbar left, unstyled (CSS via .kb-toolbar select)
- Moon/sun and about SVGs updated to match timesheet icon set (stroke style)
- kb-doctitle h1 is now inline-flex with icon left of text, mirroring timesheet
- Icon uses var(--accent) fill so it adapts to dark mode
- Toolbar gap 8px to match
https://claude.ai/code/session_01JyuActqTJG5tuRQNLmT7fZ
- 'New claim' button below the claimant fields fills period from/to
using defaultPeriod() (previous month, or current if today is the
last day of the month)
- Period meta in the doctitle now shows '1 June – 30 June' format
instead of ISO dates
https://claude.ai/code/session_01JyuActqTJG5tuRQNLmT7fZ
- Remove app-wordmark from toolbar; place it in kb-doctitle where
the h1 "Reimbursement" was, at the same font size (--fs-h1)
- Glyph now appears to the right of "reimburse"
- Replace "Claim · today's date" with the user's selected period
(from – to), updated live as dates are changed
https://claude.ai/code/session_01JyuActqTJG5tuRQNLmT7fZ
- Replace plain <select> for FX direction with the same makeCDD custom
dropdown used for currency selection throughout the form
- Add padding-right:2px to .kb-toolbar so the theme icon button border
is not clipped on the right edge
https://claude.ai/code/session_01JyuActqTJG5tuRQNLmT7fZ
Users can now enter the exchange rate from either direction:
- "35 THB per USD" (foreign per base, the canonical form)
- "0.02857 USD per THB" (base per foreign, inverted display)
A compact inline select next to the rate field lets the user choose
which currency is in the numerator; the "per X" label updates to show
the denominator. Switching direction re-displays the current rate
inverted — the stored canonical (foreign/base) is unchanged, so
recalc(), fxRateMemory, and PDF output are unaffected.
Persists fxDir alongside fxRate in localStorage/IndexedDB.
https://claude.ai/code/session_01JyuActqTJG5tuRQNLmT7fZ
- Remove static app-bar header element
- Add glyph + "reimburse" wordmark to toolbar left
- Add optional language <select> (shown only when CFG.languages > 1)
- Replace 3-way Auto/Light/Dark segmented with single moon/sun icon toggle
- Theme toggle persists to localStorage and respects OS preference
https://claude.ai/code/session_01JyuActqTJG5tuRQNLmT7fZ
Thin 34px strip at the top of the page — the reimburse icon (card/
banknote outline glyph from dev/design_assets/reimburse-glyph.svg)
at 16px, 50% opacity, in var(--text-muted). One hairline border below.
aria-hidden so it is invisible to screen readers.
https://claude.ai/code/session_01JyuActqTJG5tuRQNLmT7fZ
Replaces the ad-hoc CSS and DOM structure with the full kBenestad
forms design language from dev/mockups/kbenestad-forms.css and the
dev/mockups/reimburse.html reference mockup. Surface-only change —
all PDF engine, state, validation, and persistence logic is intact.
Key changes:
- Schibsted Grotesk + JetBrains Mono (bunny.net, system fallback)
- Semantic CSS tokens with light/dark auto + manual override
- Toolbar: font-size A−/A/A+, theme Auto/Light/Dark, about button
- Document header: logo tile + org name left, title + date right
- kb-card sections for claimant and expenses
- kb-block item containers; kb-line line rows with kb-field/kb-label
- kb-btn variants (primary, ghost, soft, dashed, danger)
- kb-note for validation errors and modal feedback
- kb-totals grand total panel (mono tabular figures)
- kb-footer with kBenestad attribution
- Favicons from dev/design_assets/favicons/
https://claude.ai/code/session_01JyuActqTJG5tuRQNLmT7fZ
Adds a footer bar at the bottom of the page with copyright, a link to
docs.benestad.net/invoice, a repo link, and an About link that opens a
modal. Modal title, Markdown content, and button label are configurable
via config.yml (about-title, about-content, about-button).
https://claude.ai/code/session_01MNy1ymwx9URLgXSgHc9W3T
Green button next to the Staff Name field. Clicking shows a confirmation
modal; on confirm it removes all localStorage and IndexedDB data, resets
state using defaultPeriod() for the period dates, and re-renders.
Also fixes period date pickers to set .value directly (same fix applied
earlier to expense line date inputs) so they open to the right month.
https://claude.ai/code/session_01MbwfxnjLA9KdFTrfzB55HM
Text state (items, lines, programs, amounts, etc.) is saved to localStorage
and receipts/images are saved to IndexedDB. Data is restored automatically
on the next visit in the same browser.
Auto-save runs 1 s after the last input event. A green Save button triggers
an explicit save with a confirmation modal. Receipt validation is skipped on
save and only enforced at PDF generation time.
An entry modal on every load explains the save behaviour and (if IndexedDB
is unavailable) warns that receipts cannot be persisted.
https://claude.ai/code/session_01MbwfxnjLA9KdFTrfzB55HM
Selecting a non-base currency now shows a modal explaining the exchange
rate convention, using the actual currency names. Selecting Other shows
a variant asking the user to enter the ISO code first. Both messages
are configurable via fx-rate-message and fx-rate-message-other in
config.yml using {foreign} and {base} placeholders.
The Other option in the currency dropdown no longer shows __OTHER__.
https://claude.ai/code/session_01MbwfxnjLA9KdFTrfzB55HM
Tooltip now appears below the FX rate field, wraps across multiple lines,
and explains the rate convention using the actual currency names from config.
Currency dropdown gains an Other option: selecting it swaps to a three-letter
ISO input with its own tooltip. A × button cancels back to the dropdown.
The FX rate field responds to the custom code once three letters are entered.
https://claude.ai/code/session_01MbwfxnjLA9KdFTrfzB55HM
state.periodFrom was set inside render(), after newItem() was called,
so the first line always got an empty date. Setting the period before
pushing the first item ensures the default date is the period start.
https://claude.ai/code/session_01MbwfxnjLA9KdFTrfzB55HM
When a user enters a date outside the selected period, a modal warning
appears explaining they can continue but the date will be flagged. The
date input gets an amber border/background as a persistent visual cue.
The PDF marks out-of-period dates in orange with a trailing (!) marker.
https://claude.ai/code/session_01MbwfxnjLA9KdFTrfzB55HM
When multiple programmes are allocated on a line, each row now displays
the pro-rated amount in the base currency next to the percentage
(e.g. "10.00% – USD 12.34"). The figure updates live as the line amount,
FX rate, or currency changes, as well as when the percentage is edited.
The PDF receipt renders the same information as a right-aligned suffix
on each programme row.
https://claude.ai/code/session_01MbwfxnjLA9KdFTrfzB55HM
Replaces single program field with a dynamic multi-program UI. A single
program shows the select inline with an "+ Add program" button and no
percentages. Adding a second program switches the layout to show a percent
input per row, a colour-coded total (yellow <100%, green =100%, red >100%),
and a × button to remove individual rows. Returning to one program reverts
to the simple layout. PDF renders programmes stacked with (XX.XX%) suffix
when multiple are present. Validation requires each selection, all percents
positive, and total = 100% when multiple programmes are allocated.
https://claude.ai/code/session_01MbwfxnjLA9KdFTrfzB55HM
Creates docs/ with three audience-specific guides:
- docs/user-guide.md: step-by-step form-filling instructions, field
descriptions, FX rate explanation, receipt handling, troubleshooting
- docs/admin-guide.md: deployment instructions and exhaustive config.yml
key/value reference with types, defaults, and constraints
- docs/developer-guide.md: architecture overview, full state model, all
CFG key mappings, PDF engine internals, column positions, four-pass build
process, common modification checklists, known limitations
Rewrites CLAUDE.md as a dense agent reference covering the same ground
in a compact format: code section line ranges, full config key table with
JS access patterns, validation rules, PDF coordinate system, design
decisions, and modification checklists.
https://claude.ai/code/session_01Dad69NPna53u4hucCYnVNs
Logo is now pinned to an absolute position (10mm from top, 10mm from
left) independent of the content cursor, so it can never overlap any
form elements. The cursor y is pushed below the logo bottom before
the title and remaining header elements are drawn.
https://claude.ai/code/session_016aNBqHpiQciTr1DvNvE7nk
The logo was placed with a fixed +10pt offset that didn't account for
actual logo height. Content below always advanced by a fixed 28pt, so
any logo taller than ~18pt bled into the intro text and form fields.
Now the logo is anchored with its top at the cursor position (bottom at
y - lhh), the title baseline aligns to the same top edge, and y advances
by max(logoHeight, titleSize) + 8pt gap before the next element.
https://claude.ai/code/session_016aNBqHpiQciTr1DvNvE7nk