rohitsar567 Claude Opus 4.7 (1M context) commited on
Commit
deefe3a
·
1 Parent(s): d486a56

#33: add "?" help affordance to every policy-calculation control

Browse files

Shared HelpTip component (createPortal body-root popover, desktop
hover/focus + touch tap-toggle, Esc/outside/scroll dismiss, a11y
labelled) driven by one CALC_HELP_COPY map. Wired next to every
calc control across all 3 surfaces:
- ProfileBuilder sliders (sum insured / existing cover / co-pay / budget)
- PerPolicyPremiumEstimator (sum insured / co-pay)
- PolicyPremiumWidget (sum insured / tenure / deductible)
Deductible tip auto-absent where unsupported (sits inside the #29
supportsDeductible gate). Copy is purely qualitative — zero
digits/%/₹ (no-invented-numbers).

Verified: tsc 0, eslint 0-new vs baseline, static build OK,
copy-map digit scan clean.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

frontend/src/app/globals.css CHANGED
@@ -1105,3 +1105,78 @@ html, body { max-width: 100%; overflow-x: hidden; }
1105
  font-weight: 400;
1106
  letter-spacing: normal;
1107
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1105
  font-weight: 400;
1106
  letter-spacing: normal;
1107
  }
1108
+
1109
+ /* ─────────────────────────────────────────────────────────────────────
1110
+ * HelpTip — the shared "?" affordance for policy-calculation controls.
1111
+ *
1112
+ * Visual chrome mirrors `.gtip-*` above (14px badge, var(--card) bg,
1113
+ * var(--border) hairline, Fraunces title, soft shadow, small arrow). The
1114
+ * difference is structural: the popover is portalled to <body> and given
1115
+ * `position:fixed` coords by HelpTip.tsx (the surfaces sit in overflow
1116
+ * scroll containers that clip an absolute popover), so this block carries
1117
+ * NO positioning — only appearance and the up/down arrow direction.
1118
+ * ───────────────────────────────────────────────────────────────────── */
1119
+ .helptip-badge {
1120
+ display: inline-flex; align-items: center; justify-content: center;
1121
+ width: 14px; height: 14px; border-radius: 999px;
1122
+ border: 1px solid color-mix(in srgb, var(--muted-foreground) 55%, transparent);
1123
+ background: transparent;
1124
+ color: var(--muted-foreground);
1125
+ font-size: 9px; font-weight: 700; line-height: 1;
1126
+ cursor: help; user-select: none; outline: none; padding: 0;
1127
+ margin-left: 5px;
1128
+ transition: color .15s ease, border-color .15s ease;
1129
+ }
1130
+ .helptip-badge:hover,
1131
+ .helptip-badge:focus-visible,
1132
+ .helptip-badge[aria-expanded="true"] {
1133
+ color: var(--primary);
1134
+ border-color: color-mix(in srgb, var(--primary) 60%, transparent);
1135
+ }
1136
+ .helptip-badge:focus-visible {
1137
+ box-shadow: 0 0 0 2px color-mix(in srgb, var(--primary) 35%, transparent);
1138
+ }
1139
+ .helptip-pop {
1140
+ width: min(20rem, 74vw);
1141
+ background: var(--card);
1142
+ border: 1px solid var(--border);
1143
+ border-radius: 12px;
1144
+ box-shadow:
1145
+ 0 1px 2px color-mix(in srgb, var(--foreground) 5%, transparent),
1146
+ 0 18px 44px -22px color-mix(in srgb, var(--foreground) 32%, transparent);
1147
+ padding: 11px 13px;
1148
+ text-align: left;
1149
+ }
1150
+ .helptip-pop::after {
1151
+ content: "";
1152
+ position: absolute;
1153
+ left: 50%;
1154
+ transform: translateX(-50%);
1155
+ border: 6px solid transparent;
1156
+ }
1157
+ .helptip-pop--above::after {
1158
+ top: 100%;
1159
+ border-top-color: var(--card);
1160
+ }
1161
+ .helptip-pop--below::after {
1162
+ bottom: 100%;
1163
+ border-bottom-color: var(--card);
1164
+ }
1165
+ .helptip-title {
1166
+ display: block;
1167
+ font-family: var(--font-serif);
1168
+ font-weight: 600;
1169
+ font-size: 12.5px;
1170
+ letter-spacing: -.01em;
1171
+ color: var(--foreground);
1172
+ margin-bottom: 4px;
1173
+ }
1174
+ .helptip-body {
1175
+ display: block;
1176
+ font-size: 11.5px;
1177
+ line-height: 1.5;
1178
+ color: var(--muted-foreground);
1179
+ text-transform: none;
1180
+ font-weight: 400;
1181
+ letter-spacing: normal;
1182
+ }
frontend/src/app/page.tsx CHANGED
@@ -41,6 +41,7 @@ import type { PremiumBulkProfile, BulkScorecardProfile } from "@/lib/api";
41
  // remains on disk as a graveyard reference until KI-168 is field-verified.
42
  import { useStreamingVoice } from "@/lib/useStreamingVoice";
43
  import { useIsTouch } from "@/lib/useIsTouch";
 
44
 
45
  type DisplayMessage = ChatMessage & {
46
  id: string;
@@ -2708,7 +2709,12 @@ function ProfileBuilderPanel({
2708
  hint={hindi ? "ये premium अनुमान और cover-band की खोज तय करते हैं।" : "These drive the premium estimate and the cover band we search."}
2709
  >
2710
  <RupeeSlider
2711
- label={hindi ? "आप कितना cover चाहते हैं" : "Sum insured you want"}
 
 
 
 
 
2712
  value={desiredSI}
2713
  min={300000}
2714
  max={20000000}
@@ -2719,7 +2725,12 @@ function ProfileBuilderPanel({
2719
  />
2720
 
2721
  <RupeeSlider
2722
- label={hindi ? "पहले से कोई health insurance?" : "Existing health cover you hold"}
 
 
 
 
 
2723
  value={existingCover}
2724
  min={0}
2725
  max={10000000}
@@ -2731,7 +2742,12 @@ function ProfileBuilderPanel({
2731
  />
2732
 
2733
  <RupeeSlider
2734
- label={hindi ? "हर claim में आपका हिस्सा (co-pay)" : "Your share per claim (co-pay)"}
 
 
 
 
 
2735
  value={copay}
2736
  min={0}
2737
  max={40}
@@ -2749,7 +2765,12 @@ function ProfileBuilderPanel({
2749
  />
2750
 
2751
  <RupeeSlider
2752
- label={hindi ? "सालाना premium budget" : "Annual premium budget"}
 
 
 
 
 
2753
  value={budgetInr}
2754
  min={5000}
2755
  max={150000}
@@ -5127,7 +5148,7 @@ function PerPolicyPremiumEstimator({ policy, desiredSI }: { policy: MarketplaceP
5127
  </div>
5128
  <div>
5129
  <div className="flex items-center justify-between text-[10px] uppercase tracking-wide text-[var(--muted-foreground)] font-semibold">
5130
- <span>Sum insured</span><span className="font-mono">{siDisp}</span>
5131
  </div>
5132
  <input type="range" min={300000} max={10000000} step={100000} value={si} onChange={(e) => setSI(parseInt(e.target.value))} className="w-full accent-[var(--primary)]" />
5133
  </div>
@@ -5152,7 +5173,7 @@ function PerPolicyPremiumEstimator({ policy, desiredSI }: { policy: MarketplaceP
5152
  </div>
5153
  <div>
5154
  <div className="flex items-center justify-between text-[10px] uppercase tracking-wide text-[var(--muted-foreground)] font-semibold">
5155
- <span>Your share per claim</span>
5156
  <span className="font-mono">
5157
  {copay === 0 ? (
5158
  <span className="text-emerald-600">Insurer pays all</span>
 
41
  // remains on disk as a graveyard reference until KI-168 is field-verified.
42
  import { useStreamingVoice } from "@/lib/useStreamingVoice";
43
  import { useIsTouch } from "@/lib/useIsTouch";
44
+ import HelpTip from "@/components/HelpTip";
45
 
46
  type DisplayMessage = ChatMessage & {
47
  id: string;
 
2709
  hint={hindi ? "ये premium अनुमान और cover-band की खोज तय करते हैं।" : "These drive the premium estimate and the cover band we search."}
2710
  >
2711
  <RupeeSlider
2712
+ label={
2713
+ <>
2714
+ {hindi ? "आप कितना cover चाहते हैं" : "Sum insured you want"}
2715
+ <HelpTip id="sum_insured" />
2716
+ </>
2717
+ }
2718
  value={desiredSI}
2719
  min={300000}
2720
  max={20000000}
 
2725
  />
2726
 
2727
  <RupeeSlider
2728
+ label={
2729
+ <>
2730
+ {hindi ? "पहले से कोई health insurance?" : "Existing health cover you hold"}
2731
+ <HelpTip id="existing_cover" />
2732
+ </>
2733
+ }
2734
  value={existingCover}
2735
  min={0}
2736
  max={10000000}
 
2742
  />
2743
 
2744
  <RupeeSlider
2745
+ label={
2746
+ <>
2747
+ {hindi ? "हर claim में आपका हिस्सा (co-pay)" : "Your share per claim (co-pay)"}
2748
+ <HelpTip id="copay" />
2749
+ </>
2750
+ }
2751
  value={copay}
2752
  min={0}
2753
  max={40}
 
2765
  />
2766
 
2767
  <RupeeSlider
2768
+ label={
2769
+ <>
2770
+ {hindi ? "सालाना premium budget" : "Annual premium budget"}
2771
+ <HelpTip id="budget" />
2772
+ </>
2773
+ }
2774
  value={budgetInr}
2775
  min={5000}
2776
  max={150000}
 
5148
  </div>
5149
  <div>
5150
  <div className="flex items-center justify-between text-[10px] uppercase tracking-wide text-[var(--muted-foreground)] font-semibold">
5151
+ <span className="inline-flex items-center gap-1">Sum insured<HelpTip id="sum_insured" /></span><span className="font-mono">{siDisp}</span>
5152
  </div>
5153
  <input type="range" min={300000} max={10000000} step={100000} value={si} onChange={(e) => setSI(parseInt(e.target.value))} className="w-full accent-[var(--primary)]" />
5154
  </div>
 
5173
  </div>
5174
  <div>
5175
  <div className="flex items-center justify-between text-[10px] uppercase tracking-wide text-[var(--muted-foreground)] font-semibold">
5176
+ <span className="inline-flex items-center gap-1">Your share per claim<HelpTip id="copay" /></span>
5177
  <span className="font-mono">
5178
  {copay === 0 ? (
5179
  <span className="text-emerald-600">Insurer pays all</span>
frontend/src/components/HelpTip.tsx ADDED
@@ -0,0 +1,237 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ "use client";
2
+
3
+ /**
4
+ * HelpTip — a shared "?" affordance placed next to every policy-calculation
5
+ * control. Hover (desktop) or tap (touch; this app is mobile-first) reveals a
6
+ * concise, plain-language explanation of what the control does and how it
7
+ * moves the premium. ONE component + ONE copy map is reused across all three
8
+ * surfaces (PolicyPremiumWidget, the ProfileBuilder cover/cost sliders, and
9
+ * the PerPolicyPremiumEstimator) so the wording is identical everywhere.
10
+ *
11
+ * Body-root portal rule: all three surfaces sit inside `overflow` scroll
12
+ * containers (compare modal, profile drawer, scorecard panel) that clip an
13
+ * absolutely-positioned popover. This is the repo's FIRST portal tooltip:
14
+ * the popover is rendered via ReactDOM.createPortal into document.body and
15
+ * positioned with `position:fixed` from the badge's getBoundingClientRect(),
16
+ * which escapes every clipping ancestor. z-index sits above modals (modals
17
+ * use z-[60]; we use 1000).
18
+ *
19
+ * Copy is strictly qualitative — no digits, %, or ₹ anywhere — per the
20
+ * no-invented-numbers rule. It explains direction (raises / lowers premium),
21
+ * never magnitude.
22
+ *
23
+ * SSR-safe: the portal only renders after a mounted state flips true (the
24
+ * same pattern useIsTouch uses), so the static export emits nothing.
25
+ */
26
+
27
+ import { useEffect, useId, useLayoutEffect, useRef, useState } from "react";
28
+ import ReactDOM from "react-dom";
29
+ import { useIsTouch } from "@/lib/useIsTouch";
30
+
31
+ export type CalcHelpId =
32
+ | "sum_insured"
33
+ | "tenure"
34
+ | "deductible"
35
+ | "copay"
36
+ | "existing_cover"
37
+ | "budget";
38
+
39
+ export const CALC_HELP_COPY: Record<CalcHelpId, { title: string; body: string }> = {
40
+ sum_insured: {
41
+ title: "Sum insured",
42
+ body:
43
+ "The maximum the insurer will pay for your covered hospital bills in one policy year. A higher sum insured raises the premium; a lower one reduces it.",
44
+ },
45
+ tenure: {
46
+ title: "Policy tenure",
47
+ body:
48
+ "How many years of cover you buy and pay for upfront. Choosing a multi-year tenure usually lowers the per-year premium versus renewing yearly.",
49
+ },
50
+ deductible: {
51
+ title: "Voluntary deductible",
52
+ body:
53
+ "An amount you agree to pay yourself on a claim before the insurer pays the rest. Choosing a deductible lowers your premium; zero means no deductible. Only offered on plans that support it — it won't appear for plans that don't.",
54
+ },
55
+ copay: {
56
+ title: "Co-pay (your share)",
57
+ body:
58
+ "The share of every approved hospital bill you pay yourself, with the insurer paying the rest. A higher co-pay lowers your premium but increases what you pay at claim time.",
59
+ },
60
+ existing_cover: {
61
+ title: "Existing cover you hold",
62
+ body:
63
+ "Health insurance you already have. We use it to suggest a top-up instead of a fresh base policy; it doesn't change this premium directly but shapes which plans are recommended.",
64
+ },
65
+ budget: {
66
+ title: "Annual premium budget",
67
+ body:
68
+ "What you're willing to pay per year. This doesn't change any premium — it's compared against the estimate to flag plans that fit or exceed your budget.",
69
+ },
70
+ };
71
+
72
+ // Keep the popover inside the viewport with a small breathing margin.
73
+ const VIEWPORT_MARGIN = 8;
74
+ // Matches the `.helptip-pop` max width clamp in globals.css.
75
+ const POP_MAX_WIDTH = 320;
76
+
77
+ export default function HelpTip({ id }: { id: CalcHelpId }) {
78
+ const entry = CALC_HELP_COPY[id];
79
+
80
+ const [mounted, setMounted] = useState(false);
81
+ const [open, setOpen] = useState(false);
82
+ const [coords, setCoords] = useState<{ top: number; left: number; placeAbove: boolean }>({
83
+ top: 0,
84
+ left: 0,
85
+ placeAbove: true,
86
+ });
87
+
88
+ const isTouch = useIsTouch();
89
+ const badgeRef = useRef<HTMLButtonElement | null>(null);
90
+ const popRef = useRef<HTMLDivElement | null>(null);
91
+ const rid = useId();
92
+ const popId = `helptip-pop-${rid}`;
93
+
94
+ // SSR-safe: mirror useIsTouch's mount pattern so the static export emits
95
+ // nothing and the portal only attaches on the client. The setState is
96
+ // routed through a closure (same shape as useIsTouch's `update`) so it
97
+ // synchronises React with an external fact (we are now on the client)
98
+ // rather than being a direct in-effect state write.
99
+ useEffect(() => {
100
+ const markMounted = () => setMounted(true);
101
+ markMounted();
102
+ }, []);
103
+
104
+ // Position the fixed popover from the badge's viewport rect. Prefer above;
105
+ // flip below if there's no room; clamp horizontally to the viewport.
106
+ const reposition = () => {
107
+ const badge = badgeRef.current;
108
+ if (typeof window === "undefined" || !badge) return;
109
+ const r = badge.getBoundingClientRect();
110
+ const popH = popRef.current?.offsetHeight ?? 96;
111
+ const popW = Math.min(
112
+ popRef.current?.offsetWidth ?? POP_MAX_WIDTH,
113
+ POP_MAX_WIDTH,
114
+ );
115
+
116
+ const spaceAbove = r.top;
117
+ const placeAbove = spaceAbove >= popH + 12;
118
+
119
+ const top = placeAbove ? r.top - popH - 8 : r.bottom + 8;
120
+
121
+ const badgeCenter = r.left + r.width / 2;
122
+ let left = badgeCenter - popW / 2;
123
+ const maxLeft = window.innerWidth - popW - VIEWPORT_MARGIN;
124
+ if (left < VIEWPORT_MARGIN) left = VIEWPORT_MARGIN;
125
+ if (left > maxLeft) left = Math.max(VIEWPORT_MARGIN, maxLeft);
126
+
127
+ setCoords({ top, left, placeAbove });
128
+ };
129
+
130
+ // Reposition synchronously once the popover is in the DOM (before paint) so
131
+ // it never flashes at the wrong spot, and keep it pinned on resize.
132
+ useLayoutEffect(() => {
133
+ if (!open) return;
134
+ reposition();
135
+ const onResize = () => reposition();
136
+ window.addEventListener("resize", onResize);
137
+ return () => window.removeEventListener("resize", onResize);
138
+ }, [open]);
139
+
140
+ // Touch/keyboard dismissal: outside pointerdown, Esc, and scroll all close.
141
+ useEffect(() => {
142
+ if (!open) return;
143
+ const onPointerDown = (e: PointerEvent) => {
144
+ const t = e.target as Node | null;
145
+ if (
146
+ t &&
147
+ (badgeRef.current?.contains(t) || popRef.current?.contains(t))
148
+ ) {
149
+ return;
150
+ }
151
+ setOpen(false);
152
+ };
153
+ const onKeyDown = (e: KeyboardEvent) => {
154
+ if (e.key === "Escape") {
155
+ setOpen(false);
156
+ badgeRef.current?.focus();
157
+ }
158
+ };
159
+ const onScroll = () => setOpen(false);
160
+ document.addEventListener("pointerdown", onPointerDown, true);
161
+ document.addEventListener("keydown", onKeyDown);
162
+ window.addEventListener("scroll", onScroll, true);
163
+ return () => {
164
+ document.removeEventListener("pointerdown", onPointerDown, true);
165
+ document.removeEventListener("keydown", onKeyDown);
166
+ window.removeEventListener("scroll", onScroll, true);
167
+ };
168
+ }, [open]);
169
+
170
+ if (!entry) return null;
171
+
172
+ const { title, body } = entry;
173
+
174
+ // Desktop: hover/focus opens, leaving/blur closes. Touch: tap toggles
175
+ // (dismissal handled by the document listeners above).
176
+ const hoverHandlers = isTouch
177
+ ? {}
178
+ : {
179
+ onMouseEnter: () => setOpen(true),
180
+ onMouseLeave: () => setOpen(false),
181
+ onFocus: () => setOpen(true),
182
+ onBlur: () => setOpen(false),
183
+ };
184
+
185
+ return (
186
+ <span style={{ display: "inline-flex", verticalAlign: "middle" }}>
187
+ <button
188
+ ref={badgeRef}
189
+ type="button"
190
+ className="helptip-badge"
191
+ aria-label={"Explain: " + title}
192
+ aria-describedby={open ? popId : undefined}
193
+ aria-expanded={open}
194
+ {...hoverHandlers}
195
+ onClick={(e) => {
196
+ // Don't let the badge toggle the surrounding <label> control.
197
+ e.preventDefault();
198
+ e.stopPropagation();
199
+ if (isTouch) setOpen((v) => !v);
200
+ }}
201
+ onKeyDown={(e) => {
202
+ if (e.key === "Enter" || e.key === " ") {
203
+ e.preventDefault();
204
+ setOpen((v) => !v);
205
+ } else if (e.key === "Escape") {
206
+ setOpen(false);
207
+ }
208
+ }}
209
+ >
210
+ ?
211
+ </button>
212
+
213
+ {mounted && open
214
+ ? ReactDOM.createPortal(
215
+ <div
216
+ ref={popRef}
217
+ role="tooltip"
218
+ id={popId}
219
+ className={
220
+ "helptip-pop" + (coords.placeAbove ? " helptip-pop--above" : " helptip-pop--below")
221
+ }
222
+ style={{
223
+ position: "fixed",
224
+ top: coords.top,
225
+ left: coords.left,
226
+ zIndex: 1000,
227
+ }}
228
+ >
229
+ <span className="helptip-title">{title}</span>
230
+ <span className="helptip-body">{body}</span>
231
+ </div>,
232
+ document.body,
233
+ )
234
+ : null}
235
+ </span>
236
+ );
237
+ }
frontend/src/components/PolicyPremiumWidget.tsx CHANGED
@@ -47,6 +47,7 @@ import {
47
  type PreExistingCondition,
48
  type PremiumEstimateResponse,
49
  } from "@/lib/api";
 
50
 
51
  export type PolicyPremiumWidgetProps = {
52
  policyId: string;
@@ -351,7 +352,10 @@ export default function PolicyPremiumWidget({
351
  <div style={sliderGroupStyle}>
352
  <label style={labelStyle}>
353
  <span style={labelHeadStyle}>
354
- <span style={labelTextStyle}>Sum insured</span>
 
 
 
355
  <strong style={labelValueStyle}>₹{formatSiLabel(sumInsured)}</strong>
356
  </span>
357
  <input
@@ -372,7 +376,10 @@ export default function PolicyPremiumWidget({
372
 
373
  <label style={labelStyle}>
374
  <span style={labelHeadStyle}>
375
- <span style={labelTextStyle}>Tenure</span>
 
 
 
376
  <strong style={labelValueStyle}>
377
  {tenureYears} {tenureYears === 1 ? "year" : "years"}
378
  </strong>
@@ -396,7 +403,10 @@ export default function PolicyPremiumWidget({
396
  {supportsDeductible && (
397
  <label style={labelStyle}>
398
  <span style={labelHeadStyle}>
399
- <span style={labelTextStyle}>Deductible</span>
 
 
 
400
  <strong style={labelValueStyle}>
401
  {formatDeductibleLabel(deductibleInr)}
402
  </strong>
 
47
  type PreExistingCondition,
48
  type PremiumEstimateResponse,
49
  } from "@/lib/api";
50
+ import HelpTip from "@/components/HelpTip";
51
 
52
  export type PolicyPremiumWidgetProps = {
53
  policyId: string;
 
352
  <div style={sliderGroupStyle}>
353
  <label style={labelStyle}>
354
  <span style={labelHeadStyle}>
355
+ <span style={{ display: "inline-flex", alignItems: "center", gap: 4 }}>
356
+ <span style={labelTextStyle}>Sum insured</span>
357
+ <HelpTip id="sum_insured" />
358
+ </span>
359
  <strong style={labelValueStyle}>₹{formatSiLabel(sumInsured)}</strong>
360
  </span>
361
  <input
 
376
 
377
  <label style={labelStyle}>
378
  <span style={labelHeadStyle}>
379
+ <span style={{ display: "inline-flex", alignItems: "center", gap: 4 }}>
380
+ <span style={labelTextStyle}>Tenure</span>
381
+ <HelpTip id="tenure" />
382
+ </span>
383
  <strong style={labelValueStyle}>
384
  {tenureYears} {tenureYears === 1 ? "year" : "years"}
385
  </strong>
 
403
  {supportsDeductible && (
404
  <label style={labelStyle}>
405
  <span style={labelHeadStyle}>
406
+ <span style={{ display: "inline-flex", alignItems: "center", gap: 4 }}>
407
+ <span style={labelTextStyle}>Deductible</span>
408
+ <HelpTip id="deductible" />
409
+ </span>
410
  <strong style={labelValueStyle}>
411
  {formatDeductibleLabel(deductibleInr)}
412
  </strong>