calcsuite-react 1.1.0 → 1.1.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/CHANGELOG.md CHANGED
@@ -3,6 +3,14 @@
3
3
  All notable changes to **CalcSuite** are documented here. This project adheres to
4
4
  [Semantic Versioning](https://semver.org/).
5
5
 
6
+ ## [1.1.1] — 2026-09-04
7
+
8
+ ### Fixed
9
+ - **Dialog layers above host UI.** Raised the dialog / command-palette / toast z-index so CalcSuite renders above app chrome (e.g. MUI app bars & drawers) when embedded in another app.
10
+
11
+ ### Changed
12
+ - **`<FinCalcProvider settings={…}>` now applies.** The provider accepts a deep-partial `settings` prop as *defaults* (region, currency, theme, …). The user's in-app choices still persist in `localStorage` and take precedence, so region stays user-driven.
13
+
6
14
  ## [1.1.0] — 2026-09-04
7
15
 
8
16
  ### Added
package/README.md CHANGED
@@ -3,6 +3,9 @@
3
3
  [![CI](https://github.com/ashish13377/calcsuite/actions/workflows/ci.yml/badge.svg)](https://github.com/ashish13377/calcsuite/actions/workflows/ci.yml)
4
4
  [![npm version](https://img.shields.io/npm/v/calcsuite-react.svg)](https://www.npmjs.com/package/calcsuite-react)
5
5
  [![license: MIT](https://img.shields.io/npm/l/calcsuite-react.svg)](LICENSE)
6
+ [![live demo](https://img.shields.io/badge/demo-live-brightgreen)](https://ashish13377.github.io/calcsuite/)
7
+
8
+ **▶ Live demo:** https://ashish13377.github.io/calcsuite/
6
9
 
7
10
  **Decimal-exact, offline-first financial calculator library for React** — ~55 calculators for **🇮🇳 India (₹)** and **🇺🇸 United States ($)**, a scientific calculator, live currency conversion, export, and a keyboard-first launcher/dialog. All money math runs on `decimal.js` — no floating-point in any money path.
8
11
 
package/dist/calcsuite.js CHANGED
@@ -3,7 +3,7 @@ var pa = (e, t, n) => t in e ? ma(e, t, { enumerable: !0, configurable: !0, writ
3
3
  var ge = (e, t, n) => pa(e, typeof t != "symbol" ? t + "" : t, n);
4
4
  import { jsx as o, jsxs as b, Fragment as re } from "react/jsx-runtime";
5
5
  import { useState as M, useCallback as ke, useMemo as ne, useContext as ha, createContext as fa, useRef as de, useEffect as X, Fragment as xn, useSyncExternalStore as ya } from "react";
6
- import ut from "decimal.js";
6
+ import dt from "decimal.js";
7
7
  const ba = {
8
8
  money: 2,
9
9
  rate: 6,
@@ -29,7 +29,7 @@ const ba = {
29
29
  persistence: { driver: "localStorage", namespace: "calcsuite", historyLimit: 100 },
30
30
  features: { integrationPanel: !1, beta: !1 }
31
31
  };
32
- function Nt(e) {
32
+ function xt(e) {
33
33
  return e === "US" ? {
34
34
  ...qt,
35
35
  region: "US",
@@ -68,12 +68,12 @@ function Nt(e) {
68
68
  defaults: { tenureUnit: "both", rateType: "floating", maxRatePercent: 50, sipReturnPercent: "12", inflationPercent: "6" }
69
69
  };
70
70
  }
71
- const Ze = Nt("IN"), H = ut.clone({
71
+ const Ze = xt("IN"), H = dt.clone({
72
72
  precision: 40,
73
- rounding: ut.ROUND_HALF_UP,
73
+ rounding: dt.ROUND_HALF_UP,
74
74
  toExpPos: 60,
75
75
  toExpNeg: -60,
76
- modulo: ut.ROUND_DOWN
76
+ modulo: dt.ROUND_DOWN
77
77
  }), g = (e) => new H(e), cs = (e, t) => g(e).eq(t), us = (e, t) => g(e).gt(t), ds = (e, t) => g(e).lt(t), ce = (e, t = "1e-9") => e.abs().lt(t), ga = {
78
78
  HALF_UP: H.ROUND_HALF_UP,
79
79
  HALF_EVEN: H.ROUND_HALF_EVEN,
@@ -122,66 +122,70 @@ function Sn(e) {
122
122
  };
123
123
  return { settings: e, money: m, moneyParts: d, num: i, pct: (l, p = e.numberFormat.percentPlaces) => `${i(l, p)}%`, compact: u, round: n };
124
124
  }
125
- function dt(e) {
125
+ function mt(e) {
126
126
  const t = Math.floor(e / 12), n = e % 12, a = [];
127
127
  return t && a.push(`${t} yr`), n && a.push(`${n} mo`), a.join(" ") || "0 mo";
128
128
  }
129
129
  const Cn = fa(null), Pn = "calcsuite:settings";
130
- function $t(e, t) {
130
+ function Xe(e, t) {
131
131
  if (t == null) return e;
132
132
  const n = Array.isArray(e) ? [...e] : { ...e };
133
133
  for (const a of Object.keys(t)) {
134
134
  const r = t[a], s = e[a];
135
- n[a] = r && typeof r == "object" && !Array.isArray(r) && s && typeof s == "object" ? $t(s, r) : r;
135
+ n[a] = r && typeof r == "object" && !Array.isArray(r) && s && typeof s == "object" ? Xe(s, r) : r;
136
136
  }
137
137
  return n;
138
138
  }
139
- function ka() {
139
+ function ka(e) {
140
+ const t = e ? Xe(Ze, e) : Ze;
140
141
  try {
141
- const e = localStorage.getItem(Pn);
142
- if (e) return $t(Ze, JSON.parse(e));
142
+ const n = localStorage.getItem(Pn);
143
+ if (n) return Xe(t, JSON.parse(n));
143
144
  } catch {
144
145
  }
145
- return Ze;
146
+ return t;
146
147
  }
147
- function mt(e) {
148
+ function pt(e) {
148
149
  try {
149
150
  e.persistence.driver === "localStorage" && localStorage.setItem(Pn, JSON.stringify(e));
150
151
  } catch {
151
152
  }
152
153
  }
153
- function ms({ children: e }) {
154
- const [t, n] = M(ka), a = ke((l) => {
155
- n(l), mt(l);
156
- }, []), r = ke((l) => n((p) => {
157
- const h = $t(p, l);
158
- return mt(h), h;
159
- }), []), s = ke((l) => {
160
- n((p) => {
161
- const f = { ...Nt(l), ui: p.ui, compliance: p.compliance, persistence: p.persistence, features: p.features };
162
- return mt(f), f;
154
+ function ms({
155
+ children: e,
156
+ settings: t
157
+ }) {
158
+ const [n, a] = M(() => ka(t)), r = ke((p) => {
159
+ a(p), pt(p);
160
+ }, []), s = ke((p) => a((h) => {
161
+ const f = Xe(h, p);
162
+ return pt(f), f;
163
+ }), []), u = ke((p) => {
164
+ a((h) => {
165
+ const y = { ...xt(p), ui: h.ui, compliance: h.compliance, persistence: h.persistence, features: h.features };
166
+ return pt(y), y;
163
167
  });
164
- }, []), u = ke(() => a(Nt(t.region)), [a, t.region]), m = ke((l) => a(l), [a]), d = ne(() => Sn(t), [t]), i = ne(() => {
165
- var p;
166
- const l = t.ui.theme;
167
- return l === "system" ? (p = window.matchMedia) != null && p.call(window, "(prefers-color-scheme: dark)").matches ? "dark" : "light" : l;
168
- }, [t.ui.theme]), c = ne(
169
- () => ({ settings: t, fmt: d, update: r, setRegion: s, reset: u, replace: m, resolvedTheme: i }),
170
- [t, d, r, s, u, m, i]
168
+ }, []), m = ke(() => r(xt(n.region)), [r, n.region]), d = ke((p) => r(p), [r]), i = ne(() => Sn(n), [n]), c = ne(() => {
169
+ var h;
170
+ const p = n.ui.theme;
171
+ return p === "system" ? (h = window.matchMedia) != null && h.call(window, "(prefers-color-scheme: dark)").matches ? "dark" : "light" : p;
172
+ }, [n.ui.theme]), l = ne(
173
+ () => ({ settings: n, fmt: i, update: s, setRegion: u, reset: m, replace: d, resolvedTheme: c }),
174
+ [n, i, s, u, m, d, c]
171
175
  );
172
- return /* @__PURE__ */ o(Cn.Provider, { value: c, children: e });
176
+ return /* @__PURE__ */ o(Cn.Provider, { value: l, children: e });
173
177
  }
174
178
  function ue() {
175
179
  const e = ha(Cn);
176
180
  if (!e) throw new Error("useSettings must be used within SettingsProvider");
177
181
  return e;
178
182
  }
179
- let Xe = 0;
183
+ let Qe = 0;
180
184
  const wa = () => {
181
- Xe += 1;
185
+ Qe += 1;
182
186
  }, Na = () => {
183
- Xe = Math.max(0, Xe - 1);
184
- }, xa = () => Xe > 0, Sa = 'a[href],button:not([disabled]),textarea:not([disabled]),input:not([disabled]),select:not([disabled]),[tabindex]:not([tabindex="-1"])';
187
+ Qe = Math.max(0, Qe - 1);
188
+ }, xa = () => Qe > 0, Sa = 'a[href],button:not([disabled]),textarea:not([disabled]),input:not([disabled]),select:not([disabled]),[tabindex]:not([tabindex="-1"])';
185
189
  function Ca({
186
190
  open: e,
187
191
  onClose: t,
@@ -261,7 +265,7 @@ function be(e, t, n, a = !1) {
261
265
  let m = s.times(u.minus(1)).div(r);
262
266
  return a && (m = m.times(r.plus(1))), m;
263
267
  }
264
- function Qe(e, t, n) {
268
+ function et(e, t, n) {
265
269
  return g(e).times(g(t).plus(1).pow(n));
266
270
  }
267
271
  function Tn(e, t, n, a = !1) {
@@ -285,7 +289,7 @@ function Ta(e, t, n) {
285
289
  const a = g(n), r = g(e), s = g(t);
286
290
  return ce(a) ? r.div(s) : H.ln(s.div(s.minus(r.times(a)))).div(H.ln(a.plus(1)));
287
291
  }
288
- function at(e, t = -0.9999, n = 100, a = 200) {
292
+ function rt(e, t = -0.9999, n = 100, a = 200) {
289
293
  let r = g(t), s = g(n), u = e(r), m = e(s);
290
294
  if (u.times(m).gt(0)) return null;
291
295
  for (let d = 0; d < a; d++) {
@@ -303,7 +307,7 @@ function At(e, t) {
303
307
  return a;
304
308
  }
305
309
  function Fn(e) {
306
- return at((t) => At(t, e));
310
+ return rt((t) => At(t, e));
307
311
  }
308
312
  const Fa = (e, t) => (Date.parse(t) - Date.parse(e)) / 864e5;
309
313
  function In(e, t) {
@@ -318,17 +322,17 @@ function In(e, t) {
318
322
  function Rn(e) {
319
323
  if (e.length < 2) return null;
320
324
  const t = [...e].sort((n, a) => Date.parse(n.date) - Date.parse(a.date));
321
- return at((n) => In(n, t), -0.9999, 100);
325
+ return rt((n) => In(n, t), -0.9999, 100);
322
326
  }
323
- function rt(e, t, n) {
327
+ function ot(e, t, n) {
324
328
  return g(t).div(e).pow(g(1).div(n)).minus(1);
325
329
  }
326
330
  const ps = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
327
331
  __proto__: null,
328
- bisectRate: at,
329
- cagr: rt,
332
+ bisectRate: rt,
333
+ cagr: ot,
330
334
  fvAnnuity: be,
331
- fvLump: Qe,
335
+ fvLump: et,
332
336
  irr: Fn,
333
337
  nper: Ta,
334
338
  npv: At,
@@ -374,8 +378,8 @@ class se extends Error {
374
378
  this.name = "FinCalcError", this.code = n, this.field = r;
375
379
  }
376
380
  }
377
- const Ia = 2, ee = (e) => e.toDecimalPlaces(Ia, H.ROUND_HALF_UP), xt = (e) => e.div(100).div(12);
378
- function St(e, t, n) {
381
+ const Ia = 2, ee = (e) => e.toDecimalPlaces(Ia, H.ROUND_HALF_UP), St = (e) => e.div(100).div(12);
382
+ function Ct(e, t, n) {
379
383
  if (ce(t)) return e.div(n);
380
384
  const a = t.plus(1).pow(n);
381
385
  return e.times(t).times(a).div(a.minus(1));
@@ -402,7 +406,7 @@ function Gt(e, t, n, a) {
402
406
  throw new se("RATE_OUT_OF_RANGE", "Payment is too low to repay this amount.", "payment");
403
407
  let r = g(0), s = g(a);
404
408
  for (let m = 0; m < 200; m++) {
405
- const d = r.plus(s).div(2), i = St(e, xt(d), t);
409
+ const d = r.plus(s).div(2), i = Ct(e, St(d), t);
406
410
  if (ce(i.minus(n), "1e-8")) return d;
407
411
  i.lt(n) ? r = d : s = d;
408
412
  }
@@ -466,10 +470,10 @@ function Ie(e) {
466
470
  else throw s === "tenure" ? new se("MISSING_SOLVE_TARGET", "Flat-rate loans need an explicit tenure.", "tenureMonths") : new se("MISSING_SOLVE_TARGET", "Flat-rate loans need an explicit rate.", "annualRatePct");
467
471
  c = Gt(u, d, i, t.maxRatePct), l = "Flat: interest = P × rate × years; EMI = (P + interest) / n";
468
472
  } else {
469
- const k = () => xt(m);
473
+ const k = () => St(m);
470
474
  switch (s) {
471
475
  case "payment":
472
- i = ee(St(u, k(), d)), l = "PMT = P·r·(1+r)^n / ((1+r)^n − 1)";
476
+ i = ee(Ct(u, k(), d)), l = "PMT = P·r·(1+r)^n / ((1+r)^n − 1)";
473
477
  break;
474
478
  case "principal":
475
479
  u = Ra(i, k(), d), l = "P = PMT·((1+r)^n − 1) / (r·(1+r)^n)";
@@ -482,7 +486,7 @@ function Ie(e) {
482
486
  break;
483
487
  }
484
488
  }
485
- const p = xt(m), h = n === "flat" ? i : ee(St(u, p, d)), f = Ma(u, p, d, h);
489
+ const p = St(m), h = n === "flat" ? i : ee(Ct(u, p, d)), f = Ma(u, p, d, h);
486
490
  d = f.length;
487
491
  const y = f.reduce((k, S) => k.plus(S.interest), g(0)), w = f.reduce((k, S) => k.plus(S.payment), g(0));
488
492
  return {
@@ -794,7 +798,7 @@ const Aa = {
794
798
  let S = a;
795
799
  for (let F = 1; F <= s; F++) S = S.plus(S.times(m)).minus(k.times(d(F)));
796
800
  return S;
797
- }, c = U(at((k) => i(k), 0, a.toNumber(), 200) ?? we(a, m, s)), l = [];
801
+ }, c = U(rt((k) => i(k), 0, a.toNumber(), 200) ?? we(a, m, s)), l = [];
798
802
  let p = a, h = g(0), f = c;
799
803
  for (let k = 1; k <= s && p.gt("0.005"); k++) {
800
804
  const S = U(p.times(m));
@@ -969,7 +973,7 @@ const Aa = {
969
973
  Ba,
970
974
  _a,
971
975
  Ha
972
- ], ot = Ze.defaults.sipReturnPercent, Ga = Ze.defaults.inflationPercent, it = (e, t) => ({
976
+ ], it = Ze.defaults.sipReturnPercent, Ga = Ze.defaults.inflationPercent, st = (e, t) => ({
973
977
  labels: e,
974
978
  series: [{ name: "Value", tone: "accent", points: t, area: !0 }]
975
979
  }), Dt = (e) => ({
@@ -987,7 +991,7 @@ const Aa = {
987
991
  keywords: ["sip", "systematic investment plan", "mutual fund", "monthly investment", "future value"],
988
992
  inputs: [
989
993
  { key: "monthlyAmount", label: "Monthly investment", kind: "money", prefix: "currency", default: "10000" },
990
- { key: "expectedReturnPct", label: "Expected return", kind: "percent", suffix: "% p.a.", default: ot },
994
+ { key: "expectedReturnPct", label: "Expected return", kind: "percent", suffix: "% p.a.", default: it },
991
995
  { key: "tenure", label: "Investment period", kind: "tenure", default: 120 }
992
996
  ],
993
997
  compute(e, t) {
@@ -1005,7 +1009,7 @@ const Aa = {
1005
1009
  ],
1006
1010
  split: Lt(i.toFixed(2), c.toFixed(2)),
1007
1011
  schedule: Dt(p),
1008
- chart: it(p.map((f) => f.label), h),
1012
+ chart: st(p.map((f) => f.label), h),
1009
1013
  formula: "FV = P·[((1+i)^n − 1) / i]·(1+i), i = r/12 (invested at the start of each month)",
1010
1014
  notes: ["Returns are assumed constant; actual market returns vary year to year."],
1011
1015
  raw: {
@@ -1025,7 +1029,7 @@ const Aa = {
1025
1029
  inputs: [
1026
1030
  { key: "monthlyAmount", label: "Initial monthly investment", kind: "money", prefix: "currency", default: "10000" },
1027
1031
  { key: "annualStepPct", label: "Annual step-up", kind: "percent", suffix: "%", default: "10" },
1028
- { key: "returnPct", label: "Expected return", kind: "percent", suffix: "% p.a.", default: ot },
1032
+ { key: "returnPct", label: "Expected return", kind: "percent", suffix: "% p.a.", default: it },
1029
1033
  { key: "tenure", label: "Investment period", kind: "tenure", default: 120 }
1030
1034
  ],
1031
1035
  compute(e, t) {
@@ -1044,7 +1048,7 @@ const Aa = {
1044
1048
  ],
1045
1049
  split: Lt(c.toFixed(2), f.toFixed(2)),
1046
1050
  schedule: Dt(p),
1047
- chart: it(p.map((y) => y.label), h),
1051
+ chart: st(p.map((y) => y.label), h),
1048
1052
  formula: "Monthly simulation; the SIP amount is increased by the step-up % every 12 months",
1049
1053
  notes: ["The monthly amount steps up on each yearly anniversary; returns are assumed constant."],
1050
1054
  raw: { maturity: i.toFixed(2), invested: c.toFixed(2), gains: f.toFixed(2), finalMonthly: l.toFixed(2) }
@@ -1058,7 +1062,7 @@ const Aa = {
1058
1062
  keywords: ["lump sum", "lumpsum", "one time investment", "compound interest", "maturity"],
1059
1063
  inputs: [
1060
1064
  { key: "principal", label: "Investment amount", kind: "money", prefix: "currency", default: "100000" },
1061
- { key: "ratePct", label: "Expected return", kind: "percent", suffix: "% p.a.", default: ot },
1065
+ { key: "ratePct", label: "Expected return", kind: "percent", suffix: "% p.a.", default: it },
1062
1066
  { key: "years", label: "Investment period", kind: "years", suffix: "years", default: 10 },
1063
1067
  {
1064
1068
  key: "compounding",
@@ -1074,7 +1078,7 @@ const Aa = {
1074
1078
  }
1075
1079
  ],
1076
1080
  compute(e, t) {
1077
- const { D: n, fmt: a } = t, r = D(e.principal, "100000"), s = n(C(e.ratePct, Number(t.settings.defaults.sipReturnPercent))), u = Math.max(1, Math.round(C(e.years, 10))), m = Ya[_(e.compounding, "annual")] ?? 1, d = s.div(100).div(m), i = r.times(d.plus(1).pow(m * u)), c = i.minus(r), l = r.isZero() ? n(0) : rt(r, i, u), p = [], h = [];
1081
+ const { D: n, fmt: a } = t, r = D(e.principal, "100000"), s = n(C(e.ratePct, Number(t.settings.defaults.sipReturnPercent))), u = Math.max(1, Math.round(C(e.years, 10))), m = Ya[_(e.compounding, "annual")] ?? 1, d = s.div(100).div(m), i = r.times(d.plus(1).pow(m * u)), c = i.minus(r), l = r.isZero() ? n(0) : ot(r, i, u), p = [], h = [];
1078
1082
  for (let f = 1; f <= u; f++) {
1079
1083
  const y = r.times(d.plus(1).pow(m * f));
1080
1084
  p.push({ label: String(f), cells: [a.money(r), a.money(y.minus(r)), a.money(y)] }), h.push(Number(y.toFixed(2)));
@@ -1088,7 +1092,7 @@ const Aa = {
1088
1092
  ],
1089
1093
  split: Lt(r.toFixed(2), c.toFixed(2)),
1090
1094
  schedule: Dt(p),
1091
- chart: it(p.map((f) => f.label), h),
1095
+ chart: st(p.map((f) => f.label), h),
1092
1096
  formula: "A = P·(1 + r/f)^(f·t)",
1093
1097
  notes: ["Returns are assumed constant across the whole period."],
1094
1098
  raw: { maturity: i.toFixed(2), invested: r.toFixed(2), gains: c.toFixed(2), cagr: l.times(100).toFixed(4) }
@@ -1133,7 +1137,7 @@ const Aa = {
1133
1137
  rows: h,
1134
1138
  toneCols: { 2: "interest", 3: "principal" }
1135
1139
  },
1136
- chart: it(h.map((N) => N.label), f),
1140
+ chart: st(h.map((N) => N.label), f),
1137
1141
  formula: "Each month: balance = balance·(1 + r/12) − withdrawal",
1138
1142
  notes: [
1139
1143
  S ? `The corpus is exhausted in month ${p}; the final withdrawal may be partial.` : "The corpus survives the whole withdrawal period; the remaining balance is shown.",
@@ -1155,12 +1159,12 @@ const Aa = {
1155
1159
  inputs: [
1156
1160
  { key: "targetCorpus", label: "Today's cost of goal", kind: "money", prefix: "currency", default: "10000000" },
1157
1161
  { key: "years", label: "Years to goal", kind: "years", suffix: "years", default: 15 },
1158
- { key: "expectedReturnPct", label: "Expected return", kind: "percent", suffix: "% p.a.", default: ot },
1162
+ { key: "expectedReturnPct", label: "Expected return", kind: "percent", suffix: "% p.a.", default: it },
1159
1163
  { key: "inflationPct", label: "Inflation", kind: "percent", suffix: "% p.a.", default: Ga },
1160
1164
  { key: "existingSavings", label: "Existing savings", kind: "money", prefix: "currency", default: "0", optional: !0 }
1161
1165
  ],
1162
1166
  compute(e, t) {
1163
- const { D: n, fmt: a } = t, r = D(e.targetCorpus, "10000000"), s = Math.max(1, Math.round(C(e.years, 15))), u = C(e.expectedReturnPct, Number(t.settings.defaults.sipReturnPercent)), m = n(C(e.inflationPct, Number(t.settings.defaults.inflationPercent))).div(100), d = D(e.existingSavings, "0"), i = s * 12, c = J(u, 12), l = r.times(m.plus(1).pow(s)), p = Qe(d, c, i), h = l.minus(p), f = be(1, c, i, !0), y = h.gt(0) ? h.div(f) : n(0), w = y.times(i), k = h.gt(0) ? h.minus(w) : n(0), S = [
1167
+ const { D: n, fmt: a } = t, r = D(e.targetCorpus, "10000000"), s = Math.max(1, Math.round(C(e.years, 15))), u = C(e.expectedReturnPct, Number(t.settings.defaults.sipReturnPercent)), m = n(C(e.inflationPct, Number(t.settings.defaults.inflationPercent))).div(100), d = D(e.existingSavings, "0"), i = s * 12, c = J(u, 12), l = r.times(m.plus(1).pow(s)), p = et(d, c, i), h = l.minus(p), f = be(1, c, i, !0), y = h.gt(0) ? h.div(f) : n(0), w = y.times(i), k = h.gt(0) ? h.minus(w) : n(0), S = [
1164
1168
  `Target grows with ${a.pct(m.times(100))} inflation to ${a.money(l)} in ${s} years.`
1165
1169
  ];
1166
1170
  d.gt(0) && S.push(`Existing savings grow to ${a.money(p)}, reducing what the SIP must fund.`);
@@ -1636,7 +1640,7 @@ const Aa = {
1636
1640
  { key: "collegeCostInflationPct", label: "College cost inflation", kind: "percent", suffix: "%", default: 5, advanced: !0 }
1637
1641
  ],
1638
1642
  compute(e, t) {
1639
- const { fmt: n } = t, a = g(C(e.currentSavings)), r = g(C(e.monthlyContribution)), s = Math.max(0, Math.round(C(e.yearsUntilCollege))), u = s * 12, m = J(C(e.expectedReturnPct), 12), d = Qe(a, m, u), i = be(r, m, u), c = d.plus(i), l = a.plus(r.times(u)), p = c.minus(l), h = [
1643
+ const { fmt: n } = t, a = g(C(e.currentSavings)), r = g(C(e.monthlyContribution)), s = Math.max(0, Math.round(C(e.yearsUntilCollege))), u = s * 12, m = J(C(e.expectedReturnPct), 12), d = et(a, m, u), i = be(r, m, u), c = d.plus(i), l = a.plus(r.times(u)), p = c.minus(l), h = [
1640
1644
  v("Total invested", n.money(l), "principal"),
1641
1645
  v("Investment growth", n.money(p), "interest")
1642
1646
  ], f = {
@@ -1650,7 +1654,7 @@ const Aa = {
1650
1654
  const k = g(C(e.currentAnnualCost)), S = g(C(e.collegeCostInflationPct)).div(100);
1651
1655
  let F = g(0);
1652
1656
  for (let x = 0; x < 4; x++)
1653
- F = F.plus(Qe(k, S, s + x));
1657
+ F = F.plus(et(k, S, s + x));
1654
1658
  const N = c.minus(F), P = N.gte(0);
1655
1659
  h.push(v("4-year college cost", n.money(F), "default", "inflation-adjusted")), h.push(
1656
1660
  v(
@@ -1675,7 +1679,7 @@ const Aa = {
1675
1679
  raw: f
1676
1680
  };
1677
1681
  }
1678
- }, lr = [or, ir, sr], cr = (e) => e === "annual" ? 1 : e === "semiannual" ? 2 : e === "quarterly" ? 4 : 12, st = (e) => _(e).split(/[, ]+/).map((t) => t.trim()).filter(Boolean).map(Number).filter((t) => Number.isFinite(t)), ur = {
1682
+ }, lr = [or, ir, sr], cr = (e) => e === "annual" ? 1 : e === "semiannual" ? 2 : e === "quarterly" ? 4 : 12, lt = (e) => _(e).split(/[, ]+/).map((t) => t.trim()).filter(Boolean).map(Number).filter((t) => Number.isFinite(t)), ur = {
1679
1683
  id: "returns.tvm",
1680
1684
  group: "returns",
1681
1685
  title: "Time value of money (TVM)",
@@ -1755,7 +1759,7 @@ const Aa = {
1755
1759
  { key: "years", label: "Period", kind: "years", default: "10" }
1756
1760
  ],
1757
1761
  compute(e, t) {
1758
- const n = t.D(C(e.begin)), a = t.D(C(e.end)), r = C(e.years) || 1, s = rt(n, a, r).times(100), u = a.minus(n).div(n).times(100);
1762
+ const n = t.D(C(e.begin)), a = t.D(C(e.end)), r = C(e.years) || 1, s = ot(n, a, r).times(100), u = a.minus(n).div(n).times(100);
1759
1763
  return {
1760
1764
  primary: v("CAGR", `${t.fmt.num(s, 2)}%`, "accent"),
1761
1765
  secondary: [
@@ -1779,7 +1783,7 @@ const Aa = {
1779
1783
  ],
1780
1784
  compute(e, t) {
1781
1785
  const n = t.D(C(e.invested)), a = t.D(C(e.current)), r = a.minus(n).div(n).times(100), s = C(e.years), u = [v("Total gain", t.fmt.money(a.minus(n)), a.gte(n) ? "positive" : "negative")];
1782
- return s > 0 && u.push(v("Annualised (CAGR)", `${t.fmt.num(rt(n, a, s).times(100), 2)}%`)), {
1786
+ return s > 0 && u.push(v("Annualised (CAGR)", `${t.fmt.num(ot(n, a, s).times(100), 2)}%`)), {
1783
1787
  primary: v("Absolute return", `${t.fmt.num(r, 2)}%`, "accent"),
1784
1788
  secondary: u,
1785
1789
  formula: "Absolute return = (Current − Invested) / Invested",
@@ -1819,7 +1823,7 @@ const Aa = {
1819
1823
  keywords: ["irr", "internal rate of return"],
1820
1824
  inputs: [{ key: "series", label: "Cashflows (comma-separated, period 0 first)", kind: "text", default: "-100000, 30000, 40000, 50000, 40000", help: "-100000, 30000, ..." }],
1821
1825
  compute(e, t) {
1822
- const n = st(_(e.series));
1826
+ const n = lt(_(e.series));
1823
1827
  if (n.length < 2) return { primary: v("IRR", "—"), warnings: ["Enter at least two cashflows."] };
1824
1828
  const a = Fn(n);
1825
1829
  return a ? { primary: v("IRR", `${t.fmt.num(a.times(100), 2)}%`, "accent"), formula: "IRR: rate where NPV = 0", raw: { irr: a.times(100).toNumber() } } : { primary: v("IRR", "—"), warnings: ["No sign change — IRR is undefined for these flows."] };
@@ -1835,7 +1839,7 @@ const Aa = {
1835
1839
  { key: "series", label: "Cashflows (comma-separated, period 0 first)", kind: "text", default: "-100000, 30000, 40000, 50000, 40000" }
1836
1840
  ],
1837
1841
  compute(e, t) {
1838
- const n = st(_(e.series)), a = At(g(C(e.ratePct)).div(100), n);
1842
+ const n = lt(_(e.series)), a = At(g(C(e.ratePct)).div(100), n);
1839
1843
  return {
1840
1844
  primary: v("NPV", t.fmt.money(a), a.gte(0) ? "positive" : "negative"),
1841
1845
  secondary: [v(a.gte(0) ? "Value-creating" : "Value-destroying", a.gte(0) ? "NPV ≥ 0" : "NPV < 0")],
@@ -1855,7 +1859,7 @@ const Aa = {
1855
1859
  { key: "reinvestPct", label: "Reinvestment rate", kind: "percent", default: "12" }
1856
1860
  ],
1857
1861
  compute(e, t) {
1858
- const n = st(_(e.series)), a = n.length - 1;
1862
+ const n = lt(_(e.series)), a = n.length - 1;
1859
1863
  if (a < 1) return { primary: v("MIRR", "—"), warnings: ["Enter at least two cashflows."] };
1860
1864
  const r = g(C(e.financePct)).div(100), s = g(C(e.reinvestPct)).div(100);
1861
1865
  let u = g(0), m = g(0);
@@ -1877,7 +1881,7 @@ const Aa = {
1877
1881
  { key: "discountPct", label: "Discount rate (for discounted payback)", kind: "percent", default: "0", optional: !0, advanced: !0 }
1878
1882
  ],
1879
1883
  compute(e, t) {
1880
- const n = t.D(C(e.investment)), a = st(_(e.series)), r = g(C(e.discountPct)).div(100), s = r.gt(0);
1884
+ const n = t.D(C(e.investment)), a = lt(_(e.series)), r = g(C(e.discountPct)).div(100), s = r.gt(0);
1881
1885
  let u = g(0), m = 0, d = null;
1882
1886
  for (let i = 0; i < a.length; i++) {
1883
1887
  const c = s ? g(a[i]).div(r.plus(1).pow(i + 1)) : g(a[i]), l = u;
@@ -1962,7 +1966,7 @@ function Ut(e, t, n) {
1962
1966
  }
1963
1967
  return { tax: a, rows: s };
1964
1968
  }
1965
- const wr = (e, t) => Ut(e, t, Nr).tax, Nr = { money: (e) => String(e) }, jt = (e, t) => e.gt(t) ? g(t) : e, lt = (e, t) => v(e, t, "positive"), xr = {
1969
+ const wr = (e, t) => Ut(e, t, Nr).tax, Nr = { money: (e) => String(e) }, jt = (e, t) => e.gt(t) ? g(t) : e, ct = (e, t) => v(e, t, "positive"), xr = {
1966
1970
  id: "tax.gst",
1967
1971
  group: "tax",
1968
1972
  title: "GST Calculator",
@@ -2077,7 +2081,7 @@ const wr = (e, t) => Ut(e, t, Nr).tax, Nr = { money: (e) => String(e) }, jt = (e
2077
2081
  ), {
2078
2082
  primary: v("TDS deducted", n.money(p), p.gt(0) ? "negative" : "positive"),
2079
2083
  secondary: [
2080
- lt("Net interest received", n.money(h)),
2084
+ ct("Net interest received", n.money(h)),
2081
2085
  v("Effective TDS rate", n.pct(f), "accent"),
2082
2086
  v("Applicable threshold", n.money(d), "default")
2083
2087
  ],
@@ -2244,7 +2248,7 @@ const Tr = {
2244
2248
  l.lt(h) && (h = l), p.lt(h) && (h = p);
2245
2249
  const f = s.minus(h);
2246
2250
  return {
2247
- primary: lt("HRA exempt", n.money(h)),
2251
+ primary: ct("HRA exempt", n.money(h)),
2248
2252
  secondary: [
2249
2253
  v("Taxable HRA", n.money(f), "negative"),
2250
2254
  v("HRA received", n.money(s), "principal"),
@@ -2405,7 +2409,7 @@ const Tr = {
2405
2409
  v("Taxable income", n.money(i), "principal", `after ${n.money(m)} deduction`),
2406
2410
  v("Effective rate", n.pct(p), "accent"),
2407
2411
  v("Marginal rate", `${f}%`, "default"),
2408
- lt("After-tax income", n.money(y))
2412
+ ct("After-tax income", n.money(y))
2409
2413
  ],
2410
2414
  schedule: {
2411
2415
  title: "Bracket breakdown",
@@ -2445,7 +2449,7 @@ const Tr = {
2445
2449
  "Acquisition-debt limit is $750,000 ($375,000 if married filing separately) for loans after 15 Dec 2017. " + Ne
2446
2450
  ];
2447
2451
  return s.gt(u) && i.unshift(`Loan balance exceeds $750k: only ${n.pct(g(u).div(s).times(100))} of the interest is deductible.`), {
2448
- primary: lt("Estimated tax savings", n.money(d)),
2452
+ primary: ct("Estimated tax savings", n.money(d)),
2449
2453
  secondary: [
2450
2454
  v("Deductible interest", n.money(m), "principal"),
2451
2455
  v("Marginal tax rate", n.pct(g(C(e.marginalTaxRatePct, 24))), "accent")
@@ -2470,7 +2474,7 @@ const Tr = {
2470
2474
  area: { sqm: 1, sqft: 0.092903, sqyd: 0.836127, acre: 4046.8564224, hectare: 1e4, bigha: 1337.8, gunta: 101.17, cent: 40.4686 },
2471
2475
  weight: { kg: 1, g: 1e-3, mg: 1e-6, lb: 0.45359237, oz: 0.0283495, tonne: 1e3, quintal: 100 },
2472
2476
  volume: { l: 1, ml: 1e-3, m3: 1e3, gal_us: 3.785411784, gal_uk: 4.54609, cup: 0.24, pint: 0.473176 }
2473
- }, Ct = {
2477
+ }, Pt = {
2474
2478
  m: "Meters (m)",
2475
2479
  km: "Kilometers (km)",
2476
2480
  cm: "Centimeters (cm)",
@@ -2504,7 +2508,7 @@ const Tr = {
2504
2508
  C: "Celsius (°C)",
2505
2509
  F: "Fahrenheit (°F)",
2506
2510
  K: "Kelvin (K)"
2507
- }, Lr = ["C", "F", "K"], Wt = (e) => e.map((t) => ({ value: t, label: Ct[t] ?? t })), Ae = (e, t, n, a) => [
2511
+ }, Lr = ["C", "F", "K"], Wt = (e) => e.map((t) => ({ value: t, label: Pt[t] ?? t })), Ae = (e, t, n, a) => [
2508
2512
  { key: `${e}From`, label: "From", kind: "select", default: n, options: Wt(t), showIf: (r) => r.category === e },
2509
2513
  { key: `${e}To`, label: "To", kind: "select", default: a, options: Wt(t), showIf: (r) => r.category === e }
2510
2514
  ], Ur = {
@@ -2544,21 +2548,21 @@ const Tr = {
2544
2548
  const p = $e[s];
2545
2549
  i = r.times(p[u] ?? 1).div(p[m] ?? 1), (u === "bigha" || m === "bigha") && d.push("Bigha is not standardised — its size varies by state; this uses a common ~1337.8 m² value.");
2546
2550
  }
2547
- const c = Ct[u] ?? u, l = Ct[m] ?? m;
2551
+ const c = Pt[u] ?? u, l = Pt[m] ?? m;
2548
2552
  return {
2549
2553
  primary: v(`${r.toString()} ${c} =`, `${a.num(i, 4)} ${l}`, "accent"),
2550
2554
  notes: d,
2551
2555
  raw: { result: i.toFixed(6), from: u, to: m, category: s }
2552
2556
  };
2553
2557
  }
2554
- }, je = 864e5, pt = (e) => {
2558
+ }, je = 864e5, ht = (e) => {
2555
2559
  if (!e) {
2556
2560
  const r = /* @__PURE__ */ new Date();
2557
2561
  return new Date(Date.UTC(r.getUTCFullYear(), r.getUTCMonth(), r.getUTCDate()));
2558
2562
  }
2559
2563
  const [t, n, a] = e.split("-").map(Number);
2560
2564
  return new Date(Date.UTC(t, (n || 1) - 1, a || 1));
2561
- }, ht = (e, t) => new Date(Date.UTC(e, t, 0)).getUTCDate(), Ve = (e) => e.toISOString().slice(0, 10), Or = {
2565
+ }, ft = (e, t) => new Date(Date.UTC(e, t, 0)).getUTCDate(), Ve = (e) => e.toISOString().slice(0, 10), Or = {
2562
2566
  id: "tools.dateCalc",
2563
2567
  group: "tools",
2564
2568
  title: "Date Calculator",
@@ -2605,15 +2609,15 @@ const Tr = {
2605
2609
  ],
2606
2610
  compute(e) {
2607
2611
  if (_(e.mode, "difference") === "addSubtract") {
2608
- const l = pt(_(e.startDate, "")), p = Math.round(C(e.count, 0)), h = _(e.unit, "days"), f = _(e.direction, "add") === "subtract" ? -1 : 1, y = f * p;
2612
+ const l = ht(_(e.startDate, "")), p = Math.round(C(e.count, 0)), h = _(e.unit, "days"), f = _(e.direction, "add") === "subtract" ? -1 : 1, y = f * p;
2609
2613
  let w;
2610
2614
  if (h === "days" || h === "weeks")
2611
2615
  w = new Date(l.getTime() + y * (h === "weeks" ? 7 : 1) * je);
2612
2616
  else if (h === "months") {
2613
- const S = l.getUTCMonth() + y, F = l.getUTCFullYear() + Math.floor(S / 12), N = (S % 12 + 12) % 12, P = Math.min(l.getUTCDate(), ht(F, N + 1));
2617
+ const S = l.getUTCMonth() + y, F = l.getUTCFullYear() + Math.floor(S / 12), N = (S % 12 + 12) % 12, P = Math.min(l.getUTCDate(), ft(F, N + 1));
2614
2618
  w = new Date(Date.UTC(F, N, P));
2615
2619
  } else {
2616
- const S = l.getUTCFullYear() + y, F = Math.min(l.getUTCDate(), ht(S, l.getUTCMonth() + 1));
2620
+ const S = l.getUTCFullYear() + y, F = Math.min(l.getUTCDate(), ft(S, l.getUTCMonth() + 1));
2617
2621
  w = new Date(Date.UTC(S, l.getUTCMonth(), F));
2618
2622
  }
2619
2623
  const k = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"][w.getUTCDay()];
@@ -2623,10 +2627,10 @@ const Tr = {
2623
2627
  raw: { resultDate: Ve(w), weekday: k, from: Ve(l) }
2624
2628
  };
2625
2629
  }
2626
- let n = pt(_(e.startDate, "")), a = pt(_(e.endDate, "")), r = !1;
2630
+ let n = ht(_(e.startDate, "")), a = ht(_(e.endDate, "")), r = !1;
2627
2631
  a.getTime() < n.getTime() && ([n, a] = [a, n], r = !0);
2628
2632
  let s = a.getUTCFullYear() - n.getUTCFullYear(), u = a.getUTCMonth() - n.getUTCMonth(), m = a.getUTCDate() - n.getUTCDate();
2629
- m < 0 && (u -= 1, m += ht(a.getUTCFullYear(), a.getUTCMonth())), u < 0 && (s -= 1, u += 12);
2633
+ m < 0 && (u -= 1, m += ft(a.getUTCFullYear(), a.getUTCMonth())), u < 0 && (s -= 1, u += 12);
2630
2634
  const d = Math.round((a.getTime() - n.getTime()) / je);
2631
2635
  let i = 0;
2632
2636
  for (let l = n.getTime() + je; l <= a.getTime(); l += je) {
@@ -2645,22 +2649,22 @@ const Tr = {
2645
2649
  raw: { years: s, months: u, days: m, totalDays: d, weeks: Number((d / 7).toFixed(2)), businessDays: i }
2646
2650
  };
2647
2651
  }
2648
- }, Pt = ["Zero", "One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight", "Nine", "Ten", "Eleven", "Twelve", "Thirteen", "Fourteen", "Fifteen", "Sixteen", "Seventeen", "Eighteen", "Nineteen"], Br = ["", "", "Twenty", "Thirty", "Forty", "Fifty", "Sixty", "Seventy", "Eighty", "Ninety"], et = (e) => e < 20 ? Pt[e] : Br[Math.floor(e / 10)] + (e % 10 ? " " + Pt[e % 10] : ""), Tt = (e) => {
2652
+ }, Tt = ["Zero", "One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight", "Nine", "Ten", "Eleven", "Twelve", "Thirteen", "Fourteen", "Fifteen", "Sixteen", "Seventeen", "Eighteen", "Nineteen"], Br = ["", "", "Twenty", "Thirty", "Forty", "Fifty", "Sixty", "Seventy", "Eighty", "Ninety"], tt = (e) => e < 20 ? Tt[e] : Br[Math.floor(e / 10)] + (e % 10 ? " " + Tt[e % 10] : ""), Ft = (e) => {
2649
2653
  const t = Math.floor(e / 100), n = e % 100, a = [];
2650
- return t && a.push(Pt[t] + " Hundred"), n && a.push(et(n)), a.join(" ");
2654
+ return t && a.push(Tt[t] + " Hundred"), n && a.push(tt(n)), a.join(" ");
2651
2655
  }, An = (e) => {
2652
2656
  if (e === 0) return "Zero";
2653
2657
  const t = ["", " Thousand", " Million", " Billion", " Trillion"], n = [];
2654
2658
  let a = 0;
2655
2659
  for (; e > 0 && a < t.length; ) {
2656
2660
  const r = e % 1e3;
2657
- r && n.unshift(Tt(r) + t[a]), e = Math.floor(e / 1e3), a++;
2661
+ r && n.unshift(Ft(r) + t[a]), e = Math.floor(e / 1e3), a++;
2658
2662
  }
2659
2663
  return n.length ? n.join(" ") : "Zero";
2660
2664
  }, _r = (e) => {
2661
2665
  if (e === 0) return "Zero";
2662
2666
  const t = Math.floor(e / 1e7), n = Math.floor(e / 1e5) % 100, a = Math.floor(e / 1e3) % 100, r = e % 1e3, s = [];
2663
- return t && s.push((t <= 999 ? Tt(t) : An(t)) + " Crore"), n && s.push(et(n) + " Lakh"), a && s.push(et(a) + " Thousand"), r && s.push(Tt(r)), s.join(" ");
2667
+ return t && s.push((t <= 999 ? Ft(t) : An(t)) + " Crore"), n && s.push(tt(n) + " Lakh"), a && s.push(tt(a) + " Thousand"), r && s.push(Ft(r)), s.join(" ");
2664
2668
  }, Hr = {
2665
2669
  id: "tools.numToWords",
2666
2670
  group: "tools",
@@ -2684,7 +2688,7 @@ const Tr = {
2684
2688
  compute(e, t) {
2685
2689
  const { D: n, fmt: a } = t, r = _(e.scale, "indian"), s = ye(e.cheque, !1), u = n(_(e.amount, "0").replace(/[, ]/g, "") || "0"), m = u.isNegative(), d = u.abs(), i = d.floor(), c = Number(d.minus(i).times(100).toDecimalPlaces(0).toString()), l = Number(i.toString()), p = t.settings.currency.code, h = p === "INR" ? "Rupees" : p === "USD" ? "Dollars" : p, f = p === "INR" ? "Paise" : "Cents";
2686
2690
  let y = r === "western" ? An(l) : _r(l);
2687
- return c > 0 && (y += ` and ${et(c)} ${f}`), s && (y = `${h} ${y} Only`), m && (y = `Minus ${y}`), {
2691
+ return c > 0 && (y += ` and ${tt(c)} ${f}`), s && (y = `${h} ${y} Only`), m && (y = `Minus ${y}`), {
2688
2692
  primary: v("In words", y, "accent"),
2689
2693
  secondary: [v("In figures", a.num(u, c > 0 ? 2 : 0))],
2690
2694
  notes: ['Words are Title Case with the chosen number scale; the cheque format adds the currency name and "Only".'],
@@ -2731,17 +2735,17 @@ const Tr = {
2731
2735
  ...Dr,
2732
2736
  ...qr,
2733
2737
  ...Gr
2734
- ], Ft = [];
2738
+ ], It = [];
2735
2739
  function hs(e) {
2736
- Ft.some((t) => t.id === e.id) || Ft.push(e);
2740
+ It.some((t) => t.id === e.id) || It.push(e);
2737
2741
  }
2738
2742
  function Dn() {
2739
- return [...Yr, ...Ft];
2743
+ return [...Yr, ...It];
2740
2744
  }
2741
2745
  function Kr(e) {
2742
2746
  return Dn().filter((t) => !t.regions || t.regions.includes(e));
2743
2747
  }
2744
- function It(e) {
2748
+ function Rt(e) {
2745
2749
  return Dn().find((t) => t.id === e);
2746
2750
  }
2747
2751
  const Wr = [
@@ -3042,19 +3046,19 @@ function oo(e) {
3042
3046
  var t;
3043
3047
  return e ? e.groups ? e.groups.reduce((n, a) => n + a.rows.length, 0) : ((t = e.rows) == null ? void 0 : t.length) ?? 0 : 0;
3044
3048
  }
3045
- function Rt(e) {
3049
+ function Et(e) {
3046
3050
  return String(e ?? "").replace(/[/\\]/g, "-").replace(/[-<>:"|?*]/g, "").trim().replace(/^\.+/, "") || "export";
3047
3051
  }
3048
3052
  function ve(e, t) {
3049
3053
  var m;
3050
- const n = new Date(((m = e.meta) == null ? void 0 : m.computedAt) || Date.now()), a = n.getFullYear(), r = String(n.getMonth() + 1).padStart(2, "0"), s = String(n.getDate()).padStart(2, "0"), u = Rt(e.calculatorId || e.title || "export");
3051
- return Rt(`${u}-${a}${r}${s}.${t}`);
3054
+ const n = new Date(((m = e.meta) == null ? void 0 : m.computedAt) || Date.now()), a = n.getFullYear(), r = String(n.getMonth() + 1).padStart(2, "0"), s = String(n.getDate()).padStart(2, "0"), u = Et(e.calculatorId || e.title || "export");
3055
+ return Et(`${u}-${a}${r}${s}.${t}`);
3052
3056
  }
3053
3057
  function Se(e, t, n = "application/octet-stream") {
3054
3058
  if (!Ot() || typeof URL > "u" || !URL.createObjectURL)
3055
3059
  throw new Error("Download is only available in the browser.");
3056
3060
  const a = t instanceof Blob ? t : new Blob([t], { type: n }), r = URL.createObjectURL(a), s = document.createElement("a");
3057
- s.href = r, s.download = Rt(e), s.style.display = "none", document.body.appendChild(s), s.click(), setTimeout(() => {
3061
+ s.href = r, s.download = Et(e), s.style.display = "none", document.body.appendChild(s), s.click(), setTimeout(() => {
3058
3062
  URL.revokeObjectURL(r), s.remove();
3059
3063
  }, 0);
3060
3064
  }
@@ -3482,7 +3486,7 @@ function Wn() {
3482
3486
  payment: T ? t.money(T.payment) : "—",
3483
3487
  principal: T ? t.money(T.principal) : "—",
3484
3488
  rate: T ? `${t.num(T.annualRatePct, 3)} %` : "—",
3485
- tenure: T ? dt(T.tenureMonths) : "—"
3489
+ tenure: T ? mt(T.tenureMonths) : "—"
3486
3490
  }, G = T ? t.moneyParts(T.payment) : { symbol: "", digits: "—" }, q = e.currency.symbol, A = {
3487
3491
  region: n,
3488
3492
  basis: u,
@@ -3523,7 +3527,7 @@ function Wn() {
3523
3527
  { label: "Principal", value: t.money(R.principal) },
3524
3528
  { label: "Total interest", value: t.money(R.totalInterest), tone: "interest" },
3525
3529
  { label: "Total payment", value: t.money(R.totalPayment) },
3526
- { label: a.tenureWord, value: dt(R.tenureMonths) }
3530
+ { label: a.tenureWord, value: mt(R.tenureMonths) }
3527
3531
  ],
3528
3532
  schedule: j,
3529
3533
  formula: R.formula,
@@ -3559,8 +3563,8 @@ function Wn() {
3559
3563
  ] })
3560
3564
  ] }),
3561
3565
  /* @__PURE__ */ b("div", { className: "grid two", children: [
3562
- /* @__PURE__ */ o(ft, { label: "Loan amount", solved: L("principal"), solvedText: B.principal, affix: q, children: /* @__PURE__ */ o("input", { className: "num", inputMode: "decimal", value: d, onChange: (R) => i(R.target.value), "aria-label": "Loan amount" }) }),
3563
- /* @__PURE__ */ o(ft, { label: "Interest rate", solved: L("rate"), solvedText: B.rate, suffix: "% p.a.", children: /* @__PURE__ */ o("input", { className: "num", inputMode: "decimal", value: c, onChange: (R) => l(R.target.value), "aria-label": "Interest rate" }) }),
3566
+ /* @__PURE__ */ o(yt, { label: "Loan amount", solved: L("principal"), solvedText: B.principal, affix: q, children: /* @__PURE__ */ o("input", { className: "num", inputMode: "decimal", value: d, onChange: (R) => i(R.target.value), "aria-label": "Loan amount" }) }),
3567
+ /* @__PURE__ */ o(yt, { label: "Interest rate", solved: L("rate"), solvedText: B.rate, suffix: "% p.a.", children: /* @__PURE__ */ o("input", { className: "num", inputMode: "decimal", value: c, onChange: (R) => l(R.target.value), "aria-label": "Interest rate" }) }),
3564
3568
  /* @__PURE__ */ b("div", { className: "field", children: [
3565
3569
  /* @__PURE__ */ o("span", { className: "lbl", children: a.tenureWord }),
3566
3570
  L("tenure") ? /* @__PURE__ */ b(re, { children: [
@@ -3577,7 +3581,7 @@ function Wn() {
3577
3581
  ] })
3578
3582
  ] })
3579
3583
  ] }),
3580
- /* @__PURE__ */ o(ft, { label: a.paymentLabel, solved: L("payment"), solvedText: B.payment, affix: q, children: /* @__PURE__ */ o("input", { className: "num", inputMode: "decimal", value: w, onChange: (R) => k(R.target.value), "aria-label": a.paymentLabel }) })
3584
+ /* @__PURE__ */ o(yt, { label: a.paymentLabel, solved: L("payment"), solvedText: B.payment, affix: q, children: /* @__PURE__ */ o("input", { className: "num", inputMode: "decimal", value: w, onChange: (R) => k(R.target.value), "aria-label": a.paymentLabel }) })
3581
3585
  ] }),
3582
3586
  $ && /* @__PURE__ */ o("div", { className: "error", role: "alert", style: { marginTop: 16 }, children: $ })
3583
3587
  ] }),
@@ -3610,7 +3614,7 @@ function Wn() {
3610
3614
  ] }),
3611
3615
  /* @__PURE__ */ b("div", { className: "kv", children: [
3612
3616
  /* @__PURE__ */ o("div", { className: "k", children: a.tenureWord }),
3613
- /* @__PURE__ */ o("div", { className: "v num", children: dt(T.tenureMonths) })
3617
+ /* @__PURE__ */ o("div", { className: "v num", children: mt(T.tenureMonths) })
3614
3618
  ] })
3615
3619
  ] }),
3616
3620
  /* @__PURE__ */ b("div", { className: "actions-row", children: [
@@ -3679,7 +3683,7 @@ function Wn() {
3679
3683
  ] })
3680
3684
  ] });
3681
3685
  }
3682
- function ft({
3686
+ function yt({
3683
3687
  label: e,
3684
3688
  solved: t,
3685
3689
  solvedText: n,
@@ -4113,10 +4117,10 @@ function Vo(e) {
4113
4117
  return m;
4114
4118
  }
4115
4119
  const Yo = new H("3.141592653589793238462643383279502884197"), Ko = new H("2.718281828459045235360287471352662497757"), Wo = new H("1.618033988749894848204586834365638117720");
4116
- function yt(e, t) {
4120
+ function bt(e, t) {
4117
4121
  return t === "deg" ? e * Math.PI / 180 : t === "grad" ? e * Math.PI / 200 : e;
4118
4122
  }
4119
- function bt(e, t) {
4123
+ function gt(e, t) {
4120
4124
  return t === "deg" ? e * 180 / Math.PI : t === "grad" ? e * 200 / Math.PI : e;
4121
4125
  }
4122
4126
  function an(e) {
@@ -4147,7 +4151,7 @@ function rn(e, t) {
4147
4151
  }
4148
4152
  return n;
4149
4153
  }
4150
- function gt(e, t) {
4154
+ function vt(e, t) {
4151
4155
  if (e.isNegative()) {
4152
4156
  if (t.isInteger() && !t.mod(2).isZero()) return e.abs().pow(g(1).div(t)).neg();
4153
4157
  throw new Error("root of negative");
@@ -4167,22 +4171,22 @@ function Zo(e, t = {}) {
4167
4171
  let p;
4168
4172
  switch (i) {
4169
4173
  case "sin":
4170
- p = Math.sin(yt(l, n));
4174
+ p = Math.sin(bt(l, n));
4171
4175
  break;
4172
4176
  case "cos":
4173
- p = Math.cos(yt(l, n));
4177
+ p = Math.cos(bt(l, n));
4174
4178
  break;
4175
4179
  case "tan":
4176
- p = Math.tan(yt(l, n));
4180
+ p = Math.tan(bt(l, n));
4177
4181
  break;
4178
4182
  case "asin":
4179
- p = bt(Math.asin(l), n);
4183
+ p = gt(Math.asin(l), n);
4180
4184
  break;
4181
4185
  case "acos":
4182
- p = bt(Math.acos(l), n);
4186
+ p = gt(Math.acos(l), n);
4183
4187
  break;
4184
4188
  case "atan":
4185
- p = bt(Math.atan(l), n);
4189
+ p = gt(Math.atan(l), n);
4186
4190
  break;
4187
4191
  case "sinh":
4188
4192
  p = Math.sinh(l);
@@ -4216,11 +4220,11 @@ function Zo(e, t = {}) {
4216
4220
  case "sqrt":
4217
4221
  return p(1), l.sqrt();
4218
4222
  case "cbrt":
4219
- return p(1), gt(l, g(3));
4223
+ return p(1), vt(l, g(3));
4220
4224
  case "qdrt":
4221
- return p(1), gt(l, g(4));
4225
+ return p(1), vt(l, g(4));
4222
4226
  case "root":
4223
- return p(2), gt(l, c[1]);
4227
+ return p(2), vt(l, c[1]);
4224
4228
  case "pow":
4225
4229
  return p(2), l.pow(c[1]);
4226
4230
  case "ln":
@@ -4536,7 +4540,7 @@ function Jn({ def: e }) {
4536
4540
  ] })
4537
4541
  ] });
4538
4542
  }
4539
- const tt = [
4543
+ const nt = [
4540
4544
  { code: "USD", name: "US Dollar", symbol: "$" },
4541
4545
  { code: "EUR", name: "Euro", symbol: "€" },
4542
4546
  { code: "GBP", name: "British Pound", symbol: "£" },
@@ -4581,11 +4585,11 @@ const tt = [
4581
4585
  { code: "BDT", name: "Bangladeshi Taka", symbol: "৳" },
4582
4586
  { code: "LKR", name: "Sri Lankan Rupee", symbol: "Rs" },
4583
4587
  { code: "NPR", name: "Nepalese Rupee", symbol: "रू" }
4584
- ], Xo = (e) => tt.find((t) => t.code === e), Qo = (e) => e === "INR" ? "en-IN" : "en-US", Zn = (e, t) => g(e).times(t), Xn = (e) => {
4588
+ ], Xo = (e) => nt.find((t) => t.code === e), Qo = (e) => e === "INR" ? "en-IN" : "en-US", Zn = (e, t) => g(e).times(t), Xn = (e) => {
4585
4589
  const t = g(e);
4586
4590
  return t.gt(0) ? g(1).div(t) : g(0);
4587
4591
  };
4588
- function Et(e, t) {
4592
+ function Mt(e, t) {
4589
4593
  const n = g(e);
4590
4594
  try {
4591
4595
  return new Intl.NumberFormat(Qo(t), { style: "currency", currency: t }).format(
@@ -4616,11 +4620,11 @@ function Je(e, t) {
4616
4620
  }
4617
4621
  const ea = (e, t) => t - e > 864e5, fs = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
4618
4622
  __proto__: null,
4619
- CURRENCIES: tt,
4623
+ CURRENCIES: nt,
4620
4624
  convert: Zn,
4621
4625
  currencyByCode: Xo,
4622
4626
  currencyDecimals: Qn,
4623
- formatCurrency: Et,
4627
+ formatCurrency: Mt,
4624
4628
  inverseRate: Xn,
4625
4629
  isStale: ea,
4626
4630
  stalenessLabel: Je
@@ -4642,7 +4646,7 @@ function ln(e, t) {
4642
4646
  const n = Date.parse(e);
4643
4647
  return Number.isFinite(n) ? n : t;
4644
4648
  }
4645
- const ta = "calcsuite:fxrates", na = "calcsuite:fxmode", vt = () => {
4649
+ const ta = "calcsuite:fxrates", na = "calcsuite:fxmode", kt = () => {
4646
4650
  try {
4647
4651
  return JSON.parse(localStorage.getItem(ta) || "{}");
4648
4652
  } catch {
@@ -4662,7 +4666,7 @@ const ta = "calcsuite:fxrates", na = "calcsuite:fxmode", vt = () => {
4662
4666
  }, Ke = (e, t) => `${e}_${t}`;
4663
4667
  function aa() {
4664
4668
  var _t;
4665
- const [e, t] = M("USD"), [n, a] = M("INR"), [r, s] = M(""), [u, m] = M(""), [d, i] = M("none"), [c, l] = M(""), [p, h] = M("idle"), [f, y] = M(""), [w, k] = M(() => ai()), [S, F] = M(() => vt()), [N, P] = M(() => Date.now()), x = de(null);
4669
+ const [e, t] = M("USD"), [n, a] = M("INR"), [r, s] = M(""), [u, m] = M(""), [d, i] = M("none"), [c, l] = M(""), [p, h] = M("idle"), [f, y] = M(""), [w, k] = M(() => ai()), [S, F] = M(() => kt()), [N, P] = M(() => Date.now()), x = de(null);
4666
4670
  X(() => {
4667
4671
  const O = setInterval(() => P(Date.now()), 3e4);
4668
4672
  return () => clearInterval(O);
@@ -4684,7 +4688,7 @@ function aa() {
4684
4688
  ae.signal.aborted || (m(xe.rate), i("live"), l(xe.asOf), h("idle"), T(xe.rate, ln(xe.asOf, Date.now())));
4685
4689
  }).catch((xe) => {
4686
4690
  if (ae.signal.aborted) return;
4687
- const Ht = vt()[Ke(O, Z)];
4691
+ const Ht = kt()[Ke(O, Z)];
4688
4692
  Ht ? (m(Ht.rate), i("saved"), h("error"), y("Offline — showing your last saved rate. Refresh when back online.")) : (i("none"), h("error"), y(`Couldn’t fetch a live rate (${xe instanceof Error ? xe.message : "offline"}). Enter one manually.`));
4689
4693
  });
4690
4694
  }, L = (O, Z) => {
@@ -4693,7 +4697,7 @@ function aa() {
4693
4697
  m("1"), i("saved");
4694
4698
  return;
4695
4699
  }
4696
- const ae = vt()[Ke(O, Z)];
4700
+ const ae = kt()[Ke(O, Z)];
4697
4701
  ae ? (m(ae.rate), i("saved")) : (m(""), i("none"));
4698
4702
  };
4699
4703
  X(() => (w === "online" ? $(e, n) : L(e, n), () => {
@@ -4752,12 +4756,12 @@ function aa() {
4752
4756
  ] }),
4753
4757
  /* @__PURE__ */ b("label", { className: "field cc-cur", children: [
4754
4758
  /* @__PURE__ */ o("span", { className: "lbl", children: "From" }),
4755
- /* @__PURE__ */ o("div", { className: "input-wrap", children: /* @__PURE__ */ o("select", { value: e, onChange: (O) => t(O.target.value), "aria-label": "From currency", children: tt.map(pe) }) })
4759
+ /* @__PURE__ */ o("div", { className: "input-wrap", children: /* @__PURE__ */ o("select", { value: e, onChange: (O) => t(O.target.value), "aria-label": "From currency", children: nt.map(pe) }) })
4756
4760
  ] }),
4757
4761
  /* @__PURE__ */ o("button", { type: "button", className: "cc-swap", onClick: Q, "aria-label": "Swap currencies", title: "Swap", children: "⇄" }),
4758
4762
  /* @__PURE__ */ b("label", { className: "field cc-cur", children: [
4759
4763
  /* @__PURE__ */ o("span", { className: "lbl", children: "To" }),
4760
- /* @__PURE__ */ o("div", { className: "input-wrap", children: /* @__PURE__ */ o("select", { value: n, onChange: (O) => a(O.target.value), "aria-label": "To currency", children: tt.map(pe) }) })
4764
+ /* @__PURE__ */ o("div", { className: "input-wrap", children: /* @__PURE__ */ o("select", { value: n, onChange: (O) => a(O.target.value), "aria-label": "To currency", children: nt.map(pe) }) })
4761
4765
  ] })
4762
4766
  ] }),
4763
4767
  /* @__PURE__ */ b("label", { className: "field", style: { marginTop: 16 }, children: [
@@ -4798,10 +4802,10 @@ function aa() {
4798
4802
  /* @__PURE__ */ b("section", { className: "card", children: [
4799
4803
  j ? /* @__PURE__ */ b("div", { className: "result", "aria-live": "polite", children: [
4800
4804
  /* @__PURE__ */ b("div", { className: "label", children: [
4801
- Et(q, e),
4805
+ Mt(q, e),
4802
4806
  " ="
4803
4807
  ] }),
4804
- /* @__PURE__ */ o("div", { className: "value num accent-txt", children: Et(j, n) }),
4808
+ /* @__PURE__ */ o("div", { className: "value num accent-txt", children: Mt(j, n) }),
4805
4809
  /* @__PURE__ */ b("div", { className: "secondary", children: [
4806
4810
  /* @__PURE__ */ b("div", { className: "kv", children: [
4807
4811
  /* @__PURE__ */ o("div", { className: "k", children: "Rate" }),
@@ -4894,7 +4898,7 @@ function ii({
4894
4898
  actions: s
4895
4899
  }) {
4896
4900
  var L, B, G, q;
4897
- const u = e ?? (t ? It(t) : void 0), m = u ?? ri, d = { ...oi, ...a }, { settings: i, fmt: c } = ue(), [l, p] = M(() => cn(m, n)), [h, f] = M("schedule"), [y, w] = M(!1);
4901
+ const u = e ?? (t ? Rt(t) : void 0), m = u ?? ri, d = { ...oi, ...a }, { settings: i, fmt: c } = ue(), [l, p] = M(() => cn(m, n)), [h, f] = M("schedule"), [y, w] = M(!1);
4898
4902
  X(() => p(cn(m, n)), [m.id, n]);
4899
4903
  const k = i.region, S = (A, I) => p((R) => ({ ...R, [A]: I })), F = m.inputs.filter((A) => A.showIf ? A.showIf(l, k) : !0), N = F.filter((A) => !A.advanced), P = F.filter((A) => A.advanced), { result: x, error: T } = ne(() => {
4900
4904
  const A = { settings: i, region: k, fmt: c, D: g };
@@ -4976,10 +4980,10 @@ const si = [
4976
4980
  { id: "blue", label: "Blue", main: "#2065D1", light: "#76B0F1", dark: "#103996", ink: "#FFFFFF" },
4977
4981
  { id: "orange", label: "Orange", main: "#FDA92D", light: "#FED680", dark: "#B66816", ink: "#212B36" },
4978
4982
  { id: "gray", label: "Gray", main: "#A4AAB3", light: "#CED1D7", dark: "#63686C", ink: "#FFFFFF" }
4979
- ], kt = "-apple-system, 'Segoe UI', system-ui, sans-serif", li = [
4980
- { id: "Inter Tight", label: "Inter Tight", stack: `'Inter Tight', ${kt}` },
4981
- { id: "Public Sans", label: "Public Sans", stack: `'Public Sans', ${kt}` },
4982
- { id: "system-ui", label: "System UI", stack: `system-ui, ${kt}` },
4983
+ ], wt = "-apple-system, 'Segoe UI', system-ui, sans-serif", li = [
4984
+ { id: "Inter Tight", label: "Inter Tight", stack: `'Inter Tight', ${wt}` },
4985
+ { id: "Public Sans", label: "Public Sans", stack: `'Public Sans', ${wt}` },
4986
+ { id: "system-ui", label: "System UI", stack: `system-ui, ${wt}` },
4983
4987
  { id: "Georgia", label: "Georgia (serif)", stack: "Georgia, 'Times New Roman', serif" }
4984
4988
  ];
4985
4989
  class z extends Error {
@@ -5031,7 +5035,7 @@ function oa(e, t) {
5031
5035
  const n = /* @__PURE__ */ new Date(), a = (d) => String(d).padStart(2, "0"), r = (((m = t.filename) == null ? void 0 : m.split(".").pop()) || t.kind || "bin").toLowerCase(), s = (t.inputsHash || "").replace(/^sha256:/, "").slice(0, 8) || "00000000", u = e.replace(/\{calculator\}/g, t.calculator || "calc").replace(/\{yyyy\}/g, String(n.getFullYear())).replace(/\{MM\}/g, a(n.getMonth() + 1)).replace(/\{dd\}/g, a(n.getDate())).replace(/\{hash8\}/g, s).replace(/\{ext\}/g, r).replace(/\{kind\}/g, t.kind || "file");
5032
5036
  return pi(u);
5033
5037
  }
5034
- function Mt(e, t = []) {
5038
+ function $t(e, t = []) {
5035
5039
  const n = /* @__PURE__ */ new Set([...ci, ...t.map((r) => r.toLowerCase())]), a = {};
5036
5040
  for (const [r, s] of Object.entries(e)) a[r] = n.has(r.toLowerCase()) ? "***" : s;
5037
5041
  return a;
@@ -5146,7 +5150,7 @@ function fi(e) {
5146
5150
  ...R.headers
5147
5151
  };
5148
5152
  $ && (j[a.headerName] = $);
5149
- const Y = Mt(j, R.keys);
5153
+ const Y = $t(j, R.keys);
5150
5154
  let V = P.body;
5151
5155
  const Q = { endpoint: String(N), method: x, url: T, headers: Y, body: V, attempt: I };
5152
5156
  e.transformRequest && V !== void 0 && (V = e.transformRequest(V, Q)), (B = e.onRequest) == null || B.call(e, Q);
@@ -5443,13 +5447,13 @@ function Ci(e, t, n) {
5443
5447
  return String(e);
5444
5448
  }
5445
5449
  }
5446
- function nt(e, t) {
5450
+ function at(e, t) {
5447
5451
  if (t === "number") return e;
5448
5452
  if (typeof e == "number") return String(e);
5449
- if (Array.isArray(e)) return e.map((n) => nt(n, t));
5453
+ if (Array.isArray(e)) return e.map((n) => at(n, t));
5450
5454
  if (e && typeof e == "object") {
5451
5455
  const n = {};
5452
- for (const [a, r] of Object.entries(e)) n[a] = nt(r, t);
5456
+ for (const [a, r] of Object.entries(e)) n[a] = at(r, t);
5453
5457
  return n;
5454
5458
  }
5455
5459
  return e;
@@ -5490,7 +5494,7 @@ function Ti(e, t, n) {
5490
5494
  u.transform && u.transform !== "none" && (m = xi(m, u.transform)), bn(a, i, Ci(m, u.type, t));
5491
5495
  }
5492
5496
  const r = t.include, s = (u, m) => {
5493
- m !== void 0 && (a[gn(u, t.keyCase)] = nt(m, t.numberEncoding));
5497
+ m !== void 0 && (a[gn(u, t.keyCase)] = at(m, t.numberEncoding));
5494
5498
  };
5495
5499
  return r != null && r.inputs && s("inputs", n.inputs), r != null && r.outputs && s("outputs", n.outputs), r != null && r.schedule && s("schedule", n.schedule), r != null && r.settingsSnapshot && s("settingsSnapshot", n.settings), r != null && r.meta && s("meta", n.context), t.numberEncoding === "number" && console.warn('[fincalc] numberEncoding="number" reintroduces float error; prefer "string".'), t.mode === "wrapped" && t.wrapperKey ? { [t.wrapperKey]: a } : a;
5496
5500
  }
@@ -5503,7 +5507,7 @@ const ys = {
5503
5507
  include: { inputs: !0, outputs: !0, schedule: !1, settingsSnapshot: !0, meta: !0 }
5504
5508
  };
5505
5509
  function vn(e) {
5506
- return nt(e, "string");
5510
+ return at(e, "string");
5507
5511
  }
5508
5512
  function bs(e) {
5509
5513
  const t = e.settings;
@@ -6001,9 +6005,9 @@ function Gi({ cfg: e, getToken: t }) {
6001
6005
  const c = performance.now();
6002
6006
  try {
6003
6007
  const l = await fetch(d, { method: m.method, headers: i, credentials: e.credentials }), p = await l.text(), h = {};
6004
- l.headers.forEach((f, y) => h[y] = f), a({ loading: !1, ok: l.ok, status: l.status, ms: Math.round(performance.now() - c), headers: h, body: Ki(p), sent: { url: d, method: m.method, headers: Mt(i) } });
6008
+ l.headers.forEach((f, y) => h[y] = f), a({ loading: !1, ok: l.ok, status: l.status, ms: Math.round(performance.now() - c), headers: h, body: Ki(p), sent: { url: d, method: m.method, headers: $t(i) } });
6005
6009
  } catch (l) {
6006
- a({ loading: !1, ok: !1, ms: Math.round(performance.now() - c), error: l instanceof Error ? l.message : "request failed", sent: { url: d, method: m.method, headers: Mt(i) } });
6010
+ a({ loading: !1, ok: !1, ms: Math.round(performance.now() - c), error: l instanceof Error ? l.message : "request failed", sent: { url: d, method: m.method, headers: $t(i) } });
6007
6011
  }
6008
6012
  }, disabled: n.loading, children: n.loading ? "Testing…" : "Test connection" }) })
6009
6013
  ] }),
@@ -6373,7 +6377,7 @@ function Zi({
6373
6377
  ] })
6374
6378
  ] }) });
6375
6379
  }
6376
- const ct = (e) => ({
6380
+ const ut = (e) => ({
6377
6381
  width: e,
6378
6382
  height: e,
6379
6383
  viewBox: "0 0 24 24",
@@ -6385,22 +6389,22 @@ const ct = (e) => ({
6385
6389
  "aria-hidden": !0
6386
6390
  });
6387
6391
  function Xi({ size: e = 17 }) {
6388
- return /* @__PURE__ */ b("svg", { ...ct(e), children: [
6392
+ return /* @__PURE__ */ b("svg", { ...ut(e), children: [
6389
6393
  /* @__PURE__ */ o("circle", { cx: "12", cy: "12", r: "3" }),
6390
6394
  /* @__PURE__ */ o("path", { d: "M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 1 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-4 0v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 1 1-2.83-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1 0-4h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 1 1 2.83-2.83l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 1 1 2.83 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1Z" })
6391
6395
  ] });
6392
6396
  }
6393
6397
  function Qi({ size: e = 17 }) {
6394
- return /* @__PURE__ */ b("svg", { ...ct(e), children: [
6398
+ return /* @__PURE__ */ b("svg", { ...ut(e), children: [
6395
6399
  /* @__PURE__ */ o("circle", { cx: "12", cy: "12", r: "4" }),
6396
6400
  /* @__PURE__ */ o("path", { d: "M12 2v2M12 20v2M4.93 4.93l1.41 1.41M17.66 17.66l1.41 1.41M2 12h2M20 12h2M6.34 17.66l-1.41 1.41M19.07 4.93l-1.41 1.41" })
6397
6401
  ] });
6398
6402
  }
6399
6403
  function es({ size: e = 17 }) {
6400
- return /* @__PURE__ */ o("svg", { ...ct(e), children: /* @__PURE__ */ o("path", { d: "M12 3a6 6 0 0 0 9 9 9 9 0 1 1-9-9Z" }) });
6404
+ return /* @__PURE__ */ o("svg", { ...ut(e), children: /* @__PURE__ */ o("path", { d: "M12 3a6 6 0 0 0 9 9 9 9 0 1 1-9-9Z" }) });
6401
6405
  }
6402
6406
  function ts({ size: e = 17 }) {
6403
- return /* @__PURE__ */ b("svg", { ...ct(e), children: [
6407
+ return /* @__PURE__ */ b("svg", { ...ut(e), children: [
6404
6408
  /* @__PURE__ */ o("path", { d: "M3 3v5h5" }),
6405
6409
  /* @__PURE__ */ o("path", { d: "M3.05 13A9 9 0 1 0 6 5.3L3 8" }),
6406
6410
  /* @__PURE__ */ o("path", { d: "M12 7v5l4 2" })
@@ -6412,7 +6416,7 @@ function as({ onClose: e }) {
6412
6416
  X(() => {
6413
6417
  const x = () => {
6414
6418
  const T = new URLSearchParams(location.hash.replace(/^#/, "") || location.search), $ = T.get("fincalc");
6415
- if ($ && It($)) {
6419
+ if ($ && Rt($)) {
6416
6420
  d($), c("calc");
6417
6421
  const L = T.get("s");
6418
6422
  if (L)
@@ -6428,7 +6432,7 @@ function as({ onClose: e }) {
6428
6432
  (x.metaKey || x.ctrlKey) && x.key.toLowerCase() === "k" && (x.preventDefault(), f(!0));
6429
6433
  }, S = (x) => {
6430
6434
  d(x), c("calc"), p(void 0), f(!1);
6431
- }, F = It(m) ?? u[0], N = [
6435
+ }, F = Rt(m) ?? u[0], N = [
6432
6436
  { id: "settings", label: "Open settings", run: () => {
6433
6437
  c("settings"), f(!1);
6434
6438
  } },
@@ -6590,7 +6594,7 @@ function gs({
6590
6594
  /* @__PURE__ */ o(Ca, { open: k, onClose: F.close, title: h, size: p, children: /* @__PURE__ */ o(as, { onClose: F.close }) })
6591
6595
  ] });
6592
6596
  }
6593
- const rs = 60 * 60 * 1e3, wt = (e, t) => `${e}|${[...t].sort().join(",")}`;
6597
+ const rs = 60 * 60 * 1e3, Nt = (e, t) => `${e}|${[...t].sort().join(",")}`;
6594
6598
  function vs(e, t = {}) {
6595
6599
  const n = t.ttlMs ?? rs, a = t.now ?? Date.now, r = /* @__PURE__ */ new Map();
6596
6600
  let s = null;
@@ -6604,7 +6608,7 @@ function vs(e, t = {}) {
6604
6608
  return a() - i.lastUpdated < n;
6605
6609
  }
6606
6610
  async function d(i, c) {
6607
- const l = wt(i, c), p = r.get(l);
6611
+ const l = Nt(i, c), p = r.get(l);
6608
6612
  if (p && m(p)) return { ...p, stale: !1 };
6609
6613
  if (e)
6610
6614
  try {
@@ -6627,12 +6631,12 @@ function vs(e, t = {}) {
6627
6631
  return {
6628
6632
  getRates: d,
6629
6633
  /** Non-throwing peek at whatever is cached, if anything. */
6630
- peek: (i, c) => r.get(wt(i, c)),
6634
+ peek: (i, c) => r.get(Nt(i, c)),
6631
6635
  get lastUpdated() {
6632
6636
  return s == null ? null : new Date(s);
6633
6637
  },
6634
6638
  isStale(i, c) {
6635
- const l = r.get(wt(i, c));
6639
+ const l = r.get(Nt(i, c));
6636
6640
  return !l || !m(l);
6637
6641
  },
6638
6642
  clear: () => r.clear()
@@ -6675,7 +6679,7 @@ export {
6675
6679
  oa as buildFilename,
6676
6680
  Ti as buildPayload,
6677
6681
  bs as buildSavePayload,
6678
- It as calculatorById,
6682
+ Rt as calculatorById,
6679
6683
  Kr as calculatorsForRegion,
6680
6684
  Eo as clearHistory,
6681
6685
  To as createExporter,
@@ -6696,7 +6700,7 @@ export {
6696
6700
  v as metric,
6697
6701
  C as numval,
6698
6702
  Vo as parseExpression,
6699
- Nt as regionDefaults,
6703
+ xt as regionDefaults,
6700
6704
  hs as registerCalculator,
6701
6705
  pi as sanitizeFilename,
6702
6706
  Yn as saveHistory,
@@ -13,8 +13,10 @@ interface SettingsCtx {
13
13
  replace: (s: Settings) => void;
14
14
  resolvedTheme: 'light' | 'dark' | 'highContrast';
15
15
  }
16
- export declare function SettingsProvider({ children }: {
16
+ export declare function SettingsProvider({ children, settings: initial, }: {
17
17
  children: ReactNode;
18
+ /** Default settings (deep-partial). The user's in-app choices still persist and win. */
19
+ settings?: DeepPartial<Settings>;
18
20
  }): import("react").JSX.Element;
19
21
  export declare function useSettings(): SettingsCtx;
20
22
  export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "calcsuite-react",
3
- "version": "1.1.0",
3
+ "version": "1.1.1",
4
4
  "description": "Decimal-exact, offline-first financial calculator library for React — India (₹) & US ($). ~55 calculators, scientific calculator, live FX, export, launcher/dialog. The financial-calculator module of AceCBM (Ace Cloud Business Management).",
5
5
  "keywords": [
6
6
  "finance",
package/src/theme.css CHANGED
@@ -461,7 +461,7 @@ td .in-txt { color: var(--fc-interest); }
461
461
 
462
462
  /* FAB */
463
463
  .fc-fab {
464
- position: fixed; z-index: 40; width: 56px; height: 56px; border-radius: 50%;
464
+ position: fixed; z-index: 9000; width: 56px; height: 56px; border-radius: 50%;
465
465
  border: 0; background: var(--fc-accent); color: #fff; cursor: pointer;
466
466
  box-shadow: var(--fc-shadow);
467
467
  display: flex; align-items: center; justify-content: center;
@@ -477,7 +477,7 @@ td .in-txt { color: var(--fc-interest); }
477
477
  /* Dialog */
478
478
  .dialog-backdrop {
479
479
  position: fixed; inset: 0; background: rgba(10, 16, 20, 0.5);
480
- display: flex; align-items: center; justify-content: center; z-index: 50; padding: 20px;
480
+ display: flex; align-items: center; justify-content: center; z-index: 2147483000; padding: 20px;
481
481
  animation: fc-fade 0.12s ease;
482
482
  }
483
483
  .dialog {
@@ -501,7 +501,7 @@ td .in-txt { color: var(--fc-interest); }
501
501
  }
502
502
 
503
503
  /* Command palette */
504
- .palette-backdrop { position: fixed; inset: 0; background: rgba(10, 16, 20, 0.4); z-index: 60; display: flex; justify-content: center; align-items: flex-start; padding-top: 12vh; }
504
+ .palette-backdrop { position: fixed; inset: 0; background: rgba(10, 16, 20, 0.4); z-index: 2147483010; display: flex; justify-content: center; align-items: flex-start; padding-top: 12vh; }
505
505
  .palette { background: var(--fc-surface); border: 1px solid var(--fc-line); border-radius: 14px; width: min(560px, 92vw); box-shadow: var(--fc-shadow); overflow: hidden; }
506
506
  .palette-input { width: 100%; border: 0; border-bottom: 1px solid var(--fc-line); outline: 0; background: transparent; color: var(--fc-ink); font: inherit; font-size: 16px; padding: 16px; }
507
507
  .palette-list { list-style: none; margin: 0; padding: 6px; max-height: 50vh; overflow-y: auto; }
@@ -577,7 +577,7 @@ td .in-txt { color: var(--fc-interest); }
577
577
  bottom: 20px;
578
578
  left: 50%;
579
579
  transform: translateX(-50%);
580
- z-index: 50;
580
+ z-index: 2147483020;
581
581
  padding: 10px 16px;
582
582
  border-radius: 999px;
583
583
  font-size: 13px;