@hjmds/react 1.46.0 → 1.47.0

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.
Files changed (90) hide show
  1. package/dist/actions.d.ts +2 -2
  2. package/dist/activity-chip.d.ts +1 -1
  3. package/dist/advanced-display.d.ts +6 -0
  4. package/dist/advanced-display.d.ts.map +1 -1
  5. package/dist/advanced-display.js +4 -2
  6. package/dist/advanced-display.js.map +1 -1
  7. package/dist/advanced-forms.d.ts +2 -2
  8. package/dist/auth-screen.d.ts +1 -1
  9. package/dist/bottom-navigation.d.ts.map +1 -1
  10. package/dist/bottom-navigation.js +1 -1
  11. package/dist/bottom-navigation.js.map +1 -1
  12. package/dist/calendar.d.ts.map +1 -1
  13. package/dist/calendar.js +31 -24
  14. package/dist/calendar.js.map +1 -1
  15. package/dist/carousel.d.ts +5 -1
  16. package/dist/carousel.d.ts.map +1 -1
  17. package/dist/carousel.js +2 -2
  18. package/dist/carousel.js.map +1 -1
  19. package/dist/clipboard.d.ts +2 -2
  20. package/dist/color-picker.d.ts +33 -3
  21. package/dist/color-picker.d.ts.map +1 -1
  22. package/dist/color-picker.js +73 -10
  23. package/dist/color-picker.js.map +1 -1
  24. package/dist/communication.d.ts +6 -1
  25. package/dist/communication.d.ts.map +1 -1
  26. package/dist/communication.js +2 -2
  27. package/dist/communication.js.map +1 -1
  28. package/dist/conversation-row.d.ts +7 -1
  29. package/dist/conversation-row.d.ts.map +1 -1
  30. package/dist/conversation-row.js +4 -2
  31. package/dist/conversation-row.js.map +1 -1
  32. package/dist/date-range.d.ts +24 -3
  33. package/dist/date-range.d.ts.map +1 -1
  34. package/dist/date-range.js +38 -17
  35. package/dist/date-range.js.map +1 -1
  36. package/dist/display.d.ts +28 -0
  37. package/dist/display.d.ts.map +1 -1
  38. package/dist/display.js +11 -9
  39. package/dist/display.js.map +1 -1
  40. package/dist/evidence.d.ts +1 -1
  41. package/dist/evidence.js +1 -1
  42. package/dist/evidence.js.map +1 -1
  43. package/dist/feedback.d.ts +1 -1
  44. package/dist/floating-action-button.d.ts +1 -1
  45. package/dist/follow-list.d.ts +58 -0
  46. package/dist/follow-list.d.ts.map +1 -0
  47. package/dist/follow-list.js +25 -0
  48. package/dist/follow-list.js.map +1 -0
  49. package/dist/forms.d.ts +3 -3
  50. package/dist/image-viewer.d.ts +1 -1
  51. package/dist/index.d.ts +1 -1
  52. package/dist/index.d.ts.map +1 -1
  53. package/dist/index.js.map +1 -1
  54. package/dist/internal/calendar-paint.d.ts +12 -0
  55. package/dist/internal/calendar-paint.d.ts.map +1 -0
  56. package/dist/internal/calendar-paint.js +3 -0
  57. package/dist/internal/calendar-paint.js.map +1 -0
  58. package/dist/internal/identity-action.d.ts +12 -0
  59. package/dist/internal/identity-action.d.ts.map +1 -0
  60. package/dist/internal/identity-action.js +10 -0
  61. package/dist/internal/identity-action.js.map +1 -0
  62. package/dist/internal.d.ts +1 -1
  63. package/dist/layout.d.ts +1 -1
  64. package/dist/overlays.d.ts +4 -0
  65. package/dist/overlays.d.ts.map +1 -1
  66. package/dist/overlays.js +3 -3
  67. package/dist/overlays.js.map +1 -1
  68. package/dist/provider-button.d.ts +1 -1
  69. package/dist/public-exports.generated.d.ts +3 -0
  70. package/dist/public-exports.generated.d.ts.map +1 -1
  71. package/dist/public-exports.generated.js +9 -0
  72. package/dist/public-exports.generated.js.map +1 -1
  73. package/dist/screen-flows.d.ts +33 -4
  74. package/dist/screen-flows.d.ts.map +1 -1
  75. package/dist/screen-flows.js +25 -10
  76. package/dist/screen-flows.js.map +1 -1
  77. package/dist/screens.d.ts +38 -6
  78. package/dist/screens.d.ts.map +1 -1
  79. package/dist/screens.js +26 -12
  80. package/dist/screens.js.map +1 -1
  81. package/dist/selection.d.ts +1 -1
  82. package/dist/social-compositions.d.ts +10 -0
  83. package/dist/social-compositions.d.ts.map +1 -1
  84. package/dist/social-compositions.js +3 -2
  85. package/dist/social-compositions.js.map +1 -1
  86. package/dist/styles.css +108 -46
  87. package/dist/styles.layered.css +108 -46
  88. package/dist/toast.d.ts +1 -1
  89. package/dist/top-bar.d.ts +1 -1
  90. package/package.json +8 -3
@@ -1 +1 @@
1
- {"version":3,"file":"social-compositions.js","sourceRoot":"","sources":["../src/social-compositions.tsx"],"names":[],"mappings":"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","sourcesContent":["\"use client\";\nimport { useState, type ReactNode } from \"react\";\nimport { resolveFollowProposal, resolveAttendanceProposal, type FollowProfileState, type AttendanceChoice, type EventAttendanceState } from \"@hjmds/design-contracts/social-compositions\";\nimport { Button } from \"./actions.js\";\nimport { AnimatedStatistic } from \"./statistic-motion.js\";\nimport { Avatar } from \"./advanced-display.js\";\nimport { Card } from \"./display.js\";\nimport { Stack, Text } from \"./layout.js\";\nimport { RadioGroup } from \"./selection.js\";\nimport { useCompositionAction } from \"./internal/use-composition-action.js\";\n\ntype Person = Readonly<{ id: string; name: string; avatar?: ReactNode }>;\nfunction Failure({ failed, label }: Readonly<{ failed: boolean; label: string }>) {\n return failed ? <Text role=\"alert\" style={{ textAlign: \"center\" }} tone=\"danger\">{label}</Text> : null;\n}\nexport type FollowProfileCardProps = Readonly<{\n /** Changing entities remounts the action scope and detaches old responses. */\n profileId: string; name: string; description?: ReactNode; avatar?: ReactNode;\n state: FollowProfileState; locale: string;\n labels: Readonly<{ follow: string; following: string; pending: string; count: string; error: string }>;\n /** Resolve only after the real mutation; update state with the server's confirmed snapshot. */\n onFollowChange: (following: boolean) => void | Promise<void>; disabled?: boolean;\n}>;\nexport function FollowProfileCard(props: FollowProfileCardProps) {\n if (!props.profileId.trim()) throw new TypeError(\"Follow profile requires a stable id\");\n return <FollowProfileBody key={props.profileId} {...props} />;\n}\nfunction FollowProfileBody(props: FollowProfileCardProps) {\n resolveFollowProposal(props.state, props.state.following);\n const action = useCompositionAction<FollowProfileState>(props.disabled);\n // Capture the proposal once; changing server counts during the request must not add the delta twice.\n const displayed: FollowProfileState = action.active ?? props.state;\n return <Card title={props.name} description={props.description} leading={props.avatar ?? <Avatar name={props.name} aria-hidden />}>\n <Stack gap=\"md\"><AnimatedStatistic descriptor={{ id: \"social-count\", label: props.labels.count }} value={displayed.count} locale={props.locale} />\n <Button selected={displayed.following} loading={action.pending} aria-label={action.pending ? props.labels.pending : undefined} disabled={props.disabled === true}\n onClick={() => { const proposal = resolveFollowProposal(props.state, !props.state.following); void action.run(proposal, () => props.onFollowChange(proposal.following)); }}>\n {displayed.following ? props.labels.following : props.labels.follow}\n </Button><Failure failed={action.failed} label={props.labels.error} />\n </Stack>\n </Card>;\n}\n\nexport type EventAttendanceCardProps = Readonly<{\n eventId: string; title: string; description?: ReactNode; dateLabel: string;\n state: EventAttendanceState; choices: readonly AttendanceChoice[]; participants: readonly Person[]; locale: string;\n labels: Readonly<{ response: string; pending: string; count: string; calendar: string; calendarAdded: string; error: string }>;\n onResponseChange: (responseId: string) => void | Promise<void>;\n /** Actual calendar adapter, including platform permissions; rejection stays retryable. */\n onAddToCalendar: () => void | Promise<void>; disabled?: boolean;\n}>;\nexport function EventAttendanceCard(props: EventAttendanceCardProps) {\n if (!props.eventId.trim()) throw new TypeError(\"Event attendance requires a stable id\");\n return <EventAttendanceBody key={props.eventId} {...props} />;\n}\nfunction EventAttendanceBody(props: EventAttendanceCardProps) {\n resolveAttendanceProposal(props.state, props.choices, props.state.responseId);\n const action = useCompositionAction<EventAttendanceState | \"calendar\">(props.disabled), [calendarAdded, setCalendarAdded] = useState(false);\n const displayed: EventAttendanceState = action.active === null || action.active === \"calendar\" ? props.state : action.active;\n const locked = props.disabled === true || action.pending;\n return <Card title={props.title} description={props.description}><Stack gap=\"md\">\n <Text>{props.dateLabel}</Text>\n <AnimatedStatistic descriptor={{ id: \"social-count\", label: props.labels.count }} value={displayed.count} locale={props.locale} />\n <Stack axis=\"inline\" gap=\"xs\" wrap>{props.participants.map(person => <Stack key={person.id} axis=\"inline\" gap=\"xs\" align=\"center\">{person.avatar ?? <Avatar name={person.name} aria-hidden />}<Text>{person.name}</Text></Stack>)}</Stack>\n {/* One answer out of several is a radio choice; selected primary Buttons gave the card three primaries.\n RadioGroup (not SegmentedControl) keeps the \"no answer yet\" state that responseId=null needs; plain keeps\n three short answers on one line inside the card. */}\n <RadioGroup label={props.labels.response} orientation=\"horizontal\" presentation=\"plain\" value={displayed.responseId}\n items={props.choices.map(choice => ({ value: choice.id, label: choice.label, ...(choice.disabled ? { disabled: true } : {}) }))}\n disabled={locked} {...(action.pending && action.active !== \"calendar\" ? { description: props.labels.pending } : {})}\n onValueChange={id => { const choice = props.choices.find(item => item.id === id); if (!choice || choice.disabled || choice.id === props.state.responseId || locked) return; const proposal = resolveAttendanceProposal(props.state, props.choices, choice.id); void action.run(proposal, () => props.onResponseChange(choice.id)); }} />\n <Button tone=\"secondary\" disabled={locked || calendarAdded} loading={action.active === \"calendar\"} aria-label={action.pending ? props.labels.pending : undefined}\n onClick={() => { if (calendarAdded) return; void action.run(\"calendar\", props.onAddToCalendar).then(outcome => { if (outcome.status === \"success\") setCalendarAdded(true); }); }}>{calendarAdded ? props.labels.calendarAdded : props.labels.calendar}</Button>\n <Failure failed={action.failed} label={props.labels.error} />\n </Stack></Card>;\n}\n"]}
1
+ {"version":3,"file":"social-compositions.js","sourceRoot":"","sources":["../src/social-compositions.tsx"],"names":[],"mappings":"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","sourcesContent":["\"use client\";\nimport { IdentityAction } from \"./internal/identity-action.js\";\nimport { useState, type ReactNode } from \"react\";\nimport { resolveFollowProposal, resolveAttendanceProposal, type FollowProfileState, type AttendanceChoice, type EventAttendanceState } from \"@hjmds/design-contracts/social-compositions\";\nimport { Button } from \"./actions.js\";\nimport { AnimatedStatistic } from \"./statistic-motion.js\";\nimport { Avatar } from \"./advanced-display.js\";\nimport { Card } from \"./display.js\";\nimport { Stack, Text } from \"./layout.js\";\nimport { RadioGroup } from \"./selection.js\";\nimport { useCompositionAction } from \"./internal/use-composition-action.js\";\n\ntype Person = Readonly<{ id: string; name: string; avatar?: ReactNode; avatarAction?: Readonly<{label:string;onPress():void; disabled?: boolean }> }>;\nfunction Failure({ failed, label }: Readonly<{ failed: boolean; label: string }>) {\n return failed ? <Text role=\"alert\" style={{ textAlign: \"center\" }} tone=\"danger\">{label}</Text> : null;\n}\nexport type FollowProfileCardProps = Readonly<{\n /** Changing entities remounts the action scope and detaches old responses. */\n profileId: string; name: string; description?: ReactNode; avatar?: ReactNode; avatarAction?: Readonly<{label:string;onPress():void; disabled?: boolean }>;\n state: FollowProfileState; locale: string;\n labels: Readonly<{ follow: string; following: string; pending: string; count: string; error: string }>;\n /** Resolve only after the real mutation; update state with the server's confirmed snapshot. */\n onFollowChange: (following: boolean) => void | Promise<void>; disabled?: boolean;\n}>;\nexport function FollowProfileCard(props: FollowProfileCardProps) {\n if (!props.profileId.trim()) throw new TypeError(\"Follow profile requires a stable id\");\n return <FollowProfileBody key={props.profileId} {...props} />;\n}\nfunction FollowProfileBody(props: FollowProfileCardProps) {\n resolveFollowProposal(props.state, props.state.following);\n const action = useCompositionAction<FollowProfileState>(props.disabled);\n // Capture the proposal once; changing server counts during the request must not add the delta twice.\n const displayed: FollowProfileState = action.active ?? props.state;\n return <Card title={props.name} description={props.description} leading={props.avatarAction?<IdentityAction action={props.avatarAction}>{props.avatar ?? <Avatar name={props.name} aria-hidden />}</IdentityAction>:props.avatar ?? <Avatar name={props.name} aria-hidden />}>\n <Stack gap=\"md\"><AnimatedStatistic descriptor={{ id: \"social-count\", label: props.labels.count }} value={displayed.count} locale={props.locale} />\n <Button selected={displayed.following} loading={action.pending} aria-label={action.pending ? props.labels.pending : undefined} disabled={props.disabled === true}\n onClick={() => { const proposal = resolveFollowProposal(props.state, !props.state.following); void action.run(proposal, () => props.onFollowChange(proposal.following)); }}>\n {displayed.following ? props.labels.following : props.labels.follow}\n </Button><Failure failed={action.failed} label={props.labels.error} />\n </Stack>\n </Card>;\n}\n\nexport type EventAttendanceCardProps = Readonly<{\n eventId: string; title: string; description?: ReactNode; dateLabel: string;\n state: EventAttendanceState; choices: readonly AttendanceChoice[]; participants: readonly Person[]; locale: string;\n labels: Readonly<{ response: string; pending: string; count: string; calendar: string; calendarAdded: string; error: string }>;\n onResponseChange: (responseId: string) => void | Promise<void>;\n /** Actual calendar adapter, including platform permissions; rejection stays retryable. */\n onAddToCalendar: () => void | Promise<void>; disabled?: boolean;\n}>;\nexport function EventAttendanceCard(props: EventAttendanceCardProps) {\n if (!props.eventId.trim()) throw new TypeError(\"Event attendance requires a stable id\");\n return <EventAttendanceBody key={props.eventId} {...props} />;\n}\nfunction EventAttendanceBody(props: EventAttendanceCardProps) {\n resolveAttendanceProposal(props.state, props.choices, props.state.responseId);\n const action = useCompositionAction<EventAttendanceState | \"calendar\">(props.disabled), [calendarAdded, setCalendarAdded] = useState(false);\n const displayed: EventAttendanceState = action.active === null || action.active === \"calendar\" ? props.state : action.active;\n const locked = props.disabled === true || action.pending;\n return <Card title={props.title} description={props.description}><Stack gap=\"md\">\n <Text>{props.dateLabel}</Text>\n <AnimatedStatistic descriptor={{ id: \"social-count\", label: props.labels.count }} value={displayed.count} locale={props.locale} />\n <Stack axis=\"inline\" gap=\"xs\" wrap>{props.participants.map(person => <Stack key={person.id} axis=\"inline\" gap=\"xs\" align=\"center\">{person.avatarAction?<IdentityAction action={person.avatarAction}>{person.avatar ?? <Avatar name={person.name} aria-hidden />}</IdentityAction>:person.avatar ?? <Avatar name={person.name} aria-hidden />}<Text>{person.name}</Text></Stack>)}</Stack>\n {/* One answer out of several is a radio choice; selected primary Buttons gave the card three primaries.\n RadioGroup (not SegmentedControl) keeps the \"no answer yet\" state that responseId=null needs; plain keeps\n three short answers on one line inside the card. */}\n <RadioGroup label={props.labels.response} orientation=\"horizontal\" presentation=\"plain\" value={displayed.responseId}\n items={props.choices.map(choice => ({ value: choice.id, label: choice.label, ...(choice.disabled ? { disabled: true } : {}) }))}\n disabled={locked} {...(action.pending && action.active !== \"calendar\" ? { description: props.labels.pending } : {})}\n onValueChange={id => { const choice = props.choices.find(item => item.id === id); if (!choice || choice.disabled || choice.id === props.state.responseId || locked) return; const proposal = resolveAttendanceProposal(props.state, props.choices, choice.id); void action.run(proposal, () => props.onResponseChange(choice.id)); }} />\n <Button tone=\"secondary\" disabled={locked || calendarAdded} loading={action.active === \"calendar\"} aria-label={action.pending ? props.labels.pending : undefined}\n onClick={() => { if (calendarAdded) return; void action.run(\"calendar\", props.onAddToCalendar).then(outcome => { if (outcome.status === \"success\") setCalendarAdded(true); }); }}>{calendarAdded ? props.labels.calendarAdded : props.labels.calendar}</Button>\n <Failure failed={action.failed} label={props.labels.error} />\n </Stack></Card>;\n}\n"]}
package/dist/styles.css CHANGED
@@ -1051,8 +1051,8 @@
1051
1051
  .hjm-card__header-actions { position: relative; z-index: 1; display: flex; flex: 0 0 auto; align-items: center; gap: var(--hjm-space-xs); }
1052
1052
  .hjm-card__leading { flex: 0 0 auto; display: inline-grid; place-items: center; line-height: 1; }
1053
1053
  .hjm-card__copy { flex: 1 1 auto; min-inline-size: 0; display: grid; gap: var(--hjm-space-xs); }
1054
- /* cardRecipe.title.emphasis "strong": without a weight the h2–h6 element fell back to the UA bold (700). */
1055
- .hjm-card__title { margin: 0; color: var(--hjm-color-text); font-size: var(--hjm-type-title-size); line-height: var(--hjm-type-title-line-height); font-weight: var(--hjm-text-emphasis-strong); overflow-wrap: anywhere; }
1054
+ /* Follow cardRecipe.title: native headings must not fall back to the UA bold weight. */
1055
+ .hjm-card__title { margin: 0; color: var(--hjm-color-text); font-size: var(--hjm-type-body-large-size); line-height: var(--hjm-type-body-large-line-height); font-weight: var(--hjm-text-emphasis-medium); overflow-wrap: anywhere; }
1056
1056
  .hjm-card__description { margin: 0; overflow-wrap: anywhere; }
1057
1057
  .hjm-card__actions { display: flex; flex-wrap: wrap; gap: var(--hjm-space-xs); padding: 0 var(--hjm-space-md) var(--hjm-space-md); }
1058
1058
  /* Row rhythm reads the recipe density variables so the stylesheet does not
@@ -1118,7 +1118,7 @@ button.hjm-list-row, a.hjm-list-row { cursor: pointer; }
1118
1118
  .hjm-section__copy { display: grid; flex: 1 1 auto; gap: var(--hjm-space-xxs); min-inline-size: 0; }
1119
1119
  /* sectionRecipe.title is the `title` variant (18/26 bold) and description the `caption` variant (11/16), as Native draws them.
1120
1120
  Until 2026-10-06 Web inherited body (14) for both, so the same Section header was smaller on Web. */
1121
- .hjm-section__title { margin: 0; color: var(--hjm-color-text-body); font-size: var(--hjm-type-title-size); line-height: var(--hjm-type-title-line-height); font-weight: var(--hjm-type-title-weight); overflow-wrap: anywhere; }
1121
+ .hjm-section__title { margin: 0; color: var(--hjm-color-text-body); font-size: var(--hjm-type-body-large-size); line-height: var(--hjm-type-body-large-line-height); font-weight: var(--hjm-type-title-weight); overflow-wrap: anywhere; }
1122
1122
  .hjm-section__description { color: var(--hjm-color-text-muted); font-size: var(--hjm-type-caption-size); line-height: var(--hjm-type-caption-line-height); overflow-wrap: anywhere; }
1123
1123
  .hjm-section__action { flex: 0 0 auto; }
1124
1124
  .hjm-section__content { min-inline-size: 0; }
@@ -1183,7 +1183,7 @@ button.hjm-list-row, a.hjm-list-row { cursor: pointer; }
1183
1183
  .hjm-statistic__label { color: var(--hjm-color-text-muted); font-size: var(--hjm-type-label-size); line-height: var(--hjm-type-label-line-height); font-weight: var(--hjm-text-emphasis-medium); overflow-wrap: anywhere; }
1184
1184
  .hjm-statistic[data-density="compact"] .hjm-statistic__label { font-size: var(--hjm-type-caption-size); line-height: var(--hjm-type-caption-line-height); }
1185
1185
  .hjm-statistic__value-row { display: flex; align-items: baseline; flex-wrap: wrap; gap: var(--hjm-space-xxs); min-inline-size: 0; }
1186
- .hjm-statistic__value { color: var(--hjm-statistic-value-color, var(--hjm-color-text)); font-size: var(--hjm-type-heading-size); line-height: var(--hjm-type-heading-line-height); font-weight: var(--hjm-font-weight-semibold); font-variant-numeric: tabular-nums; overflow-wrap: anywhere; }
1186
+ .hjm-statistic__value { color: var(--hjm-statistic-value-color, var(--hjm-color-text)); font-size: var(--hjm-type-title-size); line-height: var(--hjm-type-title-line-height); font-weight: var(--hjm-font-weight-semibold); font-variant-numeric: tabular-nums; overflow-wrap: anywhere; }
1187
1187
  .hjm-statistic[data-density="compact"] .hjm-statistic__value { font-size: var(--hjm-type-body-large-size); line-height: var(--hjm-type-body-large-line-height); }
1188
1188
  .hjm-statistic__affix { color: var(--hjm-color-text-body); font-size: var(--hjm-type-body-size); line-height: var(--hjm-type-body-line-height); font-weight: var(--hjm-text-emphasis-medium); }
1189
1189
  .hjm-statistic__hint { color: var(--hjm-color-text-muted); font-size: var(--hjm-type-caption-size); line-height: var(--hjm-type-caption-line-height); }
@@ -1196,14 +1196,16 @@ button.hjm-list-row, a.hjm-list-row { cursor: pointer; }
1196
1196
  .hjm-statistic-group { grid-template-columns: minmax(0, 1fr); }
1197
1197
  }
1198
1198
 
1199
- .hjm-notice { display: flex; flex-wrap: wrap; align-items: center; gap: var(--hjm-space-sm); padding: var(--hjm-space-md); border: 1px solid; border-radius: var(--hjm-radius-md); color: var(--hjm-color-text-body); background: var(--hjm-color-bg); border-color: var(--hjm-color-border); }
1200
- .hjm-notice[data-tone="info"] { border-color: var(--hjm-accent-info); }
1201
- .hjm-notice[data-tone="success"] { border-color: var(--hjm-accent-success); background: color-mix(in srgb, var(--hjm-accent-success) 10%, var(--hjm-color-bg)); }
1202
- .hjm-notice[data-tone="warning"] { border-color: var(--hjm-accent-warning); background: color-mix(in srgb, var(--hjm-accent-warning) 10%, var(--hjm-color-bg)); }
1203
- .hjm-notice[data-tone="attention"] { border-color: var(--hjm-accent-attention); background: color-mix(in srgb, var(--hjm-accent-attention) 10%, var(--hjm-color-bg)); }
1204
- .hjm-notice[data-tone="danger"] { border-color: var(--hjm-color-danger); background: color-mix(in srgb, var(--hjm-color-danger) 10%, var(--hjm-color-bg)); }
1199
+ /* noticeRecipe 2026-10-25: no outline; tone lives in the tint, the leading accentBar and the icon. The bar is
1200
+ positioned in the padding so it spans the whole notice even when the action wraps to a second line. */
1201
+ .hjm-notice { --hjm-notice-accent: var(--hjm-accent-info); position: relative; display: flex; flex-wrap: wrap; align-items: center; gap: var(--hjm-space-sm); padding: var(--hjm-space-md); padding-inline-start: calc(var(--hjm-space-md) + 4px + var(--hjm-space-sm)); border-radius: var(--hjm-radius-md); color: var(--hjm-color-text-body); background: var(--hjm-color-surface-alt); }
1202
+ .hjm-notice[data-appearance="panel"]::before { content: ""; position: absolute; inset-block: var(--hjm-space-md); inset-inline-start: var(--hjm-space-md); inline-size: 4px; border-radius: var(--hjm-radius-full); background: var(--hjm-notice-accent); }
1203
+ .hjm-notice[data-tone="success"] { --hjm-notice-accent: var(--hjm-accent-success); background: color-mix(in srgb, var(--hjm-accent-success) 10%, var(--hjm-color-bg)); }
1204
+ .hjm-notice[data-tone="warning"] { --hjm-notice-accent: var(--hjm-accent-warning); background: color-mix(in srgb, var(--hjm-accent-warning) 10%, var(--hjm-color-bg)); }
1205
+ .hjm-notice[data-tone="attention"] { --hjm-notice-accent: var(--hjm-accent-attention); background: color-mix(in srgb, var(--hjm-accent-attention) 10%, var(--hjm-color-bg)); }
1206
+ .hjm-notice[data-tone="danger"] { --hjm-notice-accent: var(--hjm-color-danger); background: color-mix(in srgb, var(--hjm-color-danger) 10%, var(--hjm-color-bg)); }
1205
1207
  /* Status is placed inside the saved card/form; Badge carries tone without a second surface. */
1206
- .hjm-notice[data-appearance="status"] { padding: 0; border: 0; background: transparent; }
1208
+ .hjm-notice[data-appearance="status"] { padding: 0; background: transparent; }
1207
1209
  .hjm-notice[data-appearance="status"] .hjm-notice__content { justify-items: start; }
1208
1210
  /* Reserve readable copy; wrap the action instead of crushing its label. */
1209
1211
  .hjm-notice__content { flex: 1 1 60%; min-inline-size: 0; display: grid; gap: var(--hjm-space-xxs); }
@@ -1213,7 +1215,7 @@ button.hjm-list-row, a.hjm-list-row { cursor: pointer; }
1213
1215
  .hjm-notice__action { flex: 0 0 auto; max-inline-size: 100%; }
1214
1216
  .hjm-notice__title, .hjm-notice__description { overflow-wrap: anywhere; }
1215
1217
  /* noticeRecipe/emptyStateRecipe title weight; the <strong> otherwise draws the UA bold (700). */
1216
- .hjm-notice__title { font-weight: var(--hjm-type-title-weight); }
1218
+ .hjm-notice__title { font-weight: var(--hjm-type-title-weight); color: var(--hjm-color-text); }
1217
1219
 
1218
1220
  /* emptyStateRecipe.density.regular paddingVertical xxxl 40 (2026-10-06; Web had xxl 32, Native read the recipe). */
1219
1221
  /* Like Native, a regular empty state fills the rest of a flex host and centers in it; compact (cards, sheets) stays content-high. */
@@ -1731,18 +1733,29 @@ button.hjm-list-row, a.hjm-list-row { cursor: pointer; }
1731
1733
  */
1732
1734
  /* Each hit/hover layer belongs to its own day. Without this containing block
1733
1735
  the last absolute layer covered the whole preview and stole pointer clicks. */
1736
+ /* dateRangeRecipe 2026-10-25: one band between two filled edges (Material 3/Airbnb motif) instead of an underline and
1737
+ outlines; the band is as tall as the date circle and rounds off where a week row starts or ends. */
1738
+ .hjm-date-range { display: grid; gap: var(--hjm-space-md); }
1734
1739
  .hjm-date-range .hjm-calendar__day { position: relative; isolation: isolate; }
1735
1740
  .hjm-date-range .hjm-calendar__day-label { position: relative; z-index: 1; pointer-events: none; }
1736
- .hjm-date-range__cell { position: absolute; inset: 0; border-radius: var(--hjm-radius-sm); pointer-events: auto; }
1737
- .hjm-date-range__cell[data-range="between"] { box-shadow: inset 0 -2px var(--hjm-color-content-brand); background: var(--hjm-color-bg); }
1738
- .hjm-date-range__cell[data-range="start"],
1739
- .hjm-date-range__cell[data-range="end"] { background: var(--hjm-color-bg); outline: 2px solid var(--hjm-color-focus); }
1740
- .hjm-date-range__cell[data-range="none"] { background: transparent; }
1741
+ .hjm-calendar__band { position: absolute; inset-block-start: 0; inset-inline: 0; block-size: var(--hjm-calendar-indicator-size, var(--hjm-calendar-cell-size)); background: color-mix(in srgb, var(--hjm-color-primary) 15%, transparent); pointer-events: none; }
1742
+ .hjm-calendar__day[data-range-band="toEnd"] .hjm-calendar__band { inset-inline-start: 50%; }
1743
+ .hjm-calendar__day[data-range-band="toStart"] .hjm-calendar__band { inset-inline-end: 50%; }
1744
+ .hjm-calendar__day:first-child:not([data-range-band="toEnd"]) .hjm-calendar__band { border-start-start-radius: var(--hjm-radius-full); border-end-start-radius: var(--hjm-radius-full); }
1745
+ .hjm-calendar__day:last-child:not([data-range-band="toStart"]) .hjm-calendar__band { border-start-end-radius: var(--hjm-radius-full); border-end-end-radius: var(--hjm-radius-full); }
1746
+ .hjm-calendar__day[data-today][data-selected] .hjm-calendar__day-label { border-color: transparent; }
1747
+ .hjm-date-range__presets { display: flex; flex-wrap: wrap; gap: var(--hjm-space-xs); }
1748
+ .hjm-date-range__summary { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--hjm-space-xs); }
1749
+ .hjm-date-range__field { display: grid; gap: var(--hjm-space-xxs); min-inline-size: 0; padding: var(--hjm-space-xs) var(--hjm-space-sm); border: 2px solid transparent; border-radius: var(--hjm-radius-md); background: var(--hjm-color-surface-alt); }
1750
+ .hjm-date-range__field[data-active] { border-color: var(--hjm-color-primary); }
1751
+ .hjm-date-range__field-label { color: var(--hjm-color-text-muted); font-size: var(--hjm-type-label-size); line-height: var(--hjm-type-label-line-height); }
1752
+ .hjm-date-range__field-value { overflow: hidden; color: var(--hjm-color-text); font-variant-numeric: tabular-nums; text-overflow: ellipsis; white-space: nowrap; }
1753
+ .hjm-date-range__field[data-empty] .hjm-date-range__field-value { color: var(--hjm-color-text-sub); }
1741
1754
 
1742
1755
  /* AvatarGroup: overlap comes from the recipe ratio, not a per-size pixel value. */
1743
1756
  .hjm-avatar-group { display: inline-flex; align-items: center; }
1744
1757
  .hjm-avatar-group > * + * { margin-inline-start: calc(var(--hjm-avatar-overlap) * -1); }
1745
- .hjm-avatar-group > .hjm-avatar { border: 2px solid var(--hjm-color-bg); border-radius: var(--hjm-radius-full); }
1758
+ .hjm-avatar-group > .hjm-avatar, .hjm-avatar-group > .hjm-identity-action .hjm-avatar { border: 2px solid var(--hjm-color-bg); border-radius: var(--hjm-radius-full); }
1746
1759
  .hjm-avatar-group__overflow {
1747
1760
  display: grid;
1748
1761
  place-items: center;
@@ -1775,7 +1788,7 @@ button.hjm-list-row, a.hjm-list-row { cursor: pointer; }
1775
1788
  font-family: var(--hjm-font-family-code, ui-monospace, SFMono-Regular, Consolas, monospace);
1776
1789
  }
1777
1790
  .hjm-text-format[data-kind="kbd"] {
1778
- border: 1px solid var(--hjm-color-border);
1791
+ border: 1px solid color-mix(in srgb, var(--hjm-color-border-control) 50%, transparent);
1779
1792
  color: var(--hjm-color-text-body);
1780
1793
  font-size: var(--hjm-type-label-size);
1781
1794
  }
@@ -2090,7 +2103,7 @@ button.hjm-list-row, a.hjm-list-row { cursor: pointer; }
2090
2103
  max-block-size: 12rem;
2091
2104
  margin: var(--hjm-space-xxs) 0 0;
2092
2105
  padding: var(--hjm-space-xxs);
2093
- border: 1px solid var(--hjm-color-border);
2106
+ border: 1px solid color-mix(in srgb, var(--hjm-color-border-control) 50%, transparent);
2094
2107
  border-radius: var(--hjm-radius-md);
2095
2108
  background: var(--hjm-color-bg);
2096
2109
  list-style: none;
@@ -2578,7 +2591,7 @@ button.hjm-list-row, a.hjm-list-row { cursor: pointer; }
2578
2591
  block-size: 100dvh;
2579
2592
  min-inline-size: 0;
2580
2593
  overflow: hidden;
2581
- border: 1px solid var(--hjm-color-border);
2594
+ border: 1px solid color-mix(in srgb, var(--hjm-color-border-control) 50%, transparent);
2582
2595
  border-radius: 0;
2583
2596
  color: var(--hjm-color-text);
2584
2597
  background: var(--hjm-color-bg);
@@ -2652,7 +2665,7 @@ button.hjm-list-row, a.hjm-list-row { cursor: pointer; }
2652
2665
  overscroll-behavior: contain;
2653
2666
  box-sizing: border-box;
2654
2667
  padding: var(--hjm-space-md);
2655
- border: 1px solid var(--hjm-color-border);
2668
+ border: 1px solid color-mix(in srgb, var(--hjm-color-border-control) 50%, transparent);
2656
2669
  border-radius: var(--hjm-radius-md);
2657
2670
  color: var(--hjm-color-text);
2658
2671
  background: var(--hjm-color-bg);
@@ -2695,7 +2708,7 @@ button.hjm-list-row, a.hjm-list-row { cursor: pointer; }
2695
2708
  /* menuRecipe.surface (floatingSurfaceContract) padding spacing.xs 8. Until 2026-10-06 Web drew 4 here and in the
2696
2709
  Select/Combobox/ContextMenu popups that share the same surface contract. */
2697
2710
  padding: var(--hjm-menu-padding, var(--hjm-space-xs));
2698
- border: 1px solid var(--hjm-color-border);
2711
+ border: 1px solid color-mix(in srgb, var(--hjm-color-border-control) 50%, transparent);
2699
2712
  border-radius: var(--hjm-radius-md);
2700
2713
  background: var(--hjm-color-bg);
2701
2714
  box-shadow: var(--hjm-shadow-floating);
@@ -2767,7 +2780,7 @@ button.hjm-list-row, a.hjm-list-row { cursor: pointer; }
2767
2780
  .hjm-select__indicator { flex: 0 0 auto; color: var(--hjm-color-text-muted); pointer-events: none; }
2768
2781
  .hjm-select__busy-indicator { flex: 0 0 auto; inline-size: 1em; block-size: 1em; border: 2px solid var(--hjm-color-content-brand); border-inline-end-color: transparent; border-radius: 50%; animation: hjm-spin 800ms linear infinite; }
2769
2782
  .hjm-select__native + .hjm-select__indicator { margin-inline-start: calc(-1 * var(--hjm-space-lg)); }
2770
- .hjm-select__listbox { position: fixed; z-index: var(--hjm-layer-dropdown); max-inline-size: min(26.25rem, calc(100vw - (2 * var(--hjm-space-md)))); max-block-size: 22.5rem; overflow: auto; padding: var(--hjm-select-popover-padding, var(--hjm-space-xs)); /* selectRecipe.popover.padding 8 (was 4 until 2026-10-06) */ border: 1px solid var(--hjm-color-border); border-radius: var(--hjm-radius-md); background: var(--hjm-color-bg); box-shadow: var(--hjm-shadow-floating); }
2783
+ .hjm-select__listbox { position: fixed; z-index: var(--hjm-layer-dropdown); max-inline-size: min(26.25rem, calc(100vw - (2 * var(--hjm-space-md)))); max-block-size: 22.5rem; overflow: auto; padding: var(--hjm-select-popover-padding, var(--hjm-space-xs)); /* selectRecipe.popover.padding 8 (was 4 until 2026-10-06) */ border: 1px solid color-mix(in srgb, var(--hjm-color-border-control) 50%, transparent); border-radius: var(--hjm-radius-md); background: var(--hjm-color-bg); box-shadow: var(--hjm-shadow-floating); }
2771
2784
  .hjm-select__section-label { padding: var(--hjm-space-xs) var(--hjm-space-sm); color: var(--hjm-color-text-muted); font-size: var(--hjm-type-label-size); font-weight: var(--hjm-text-emphasis-medium); }
2772
2785
  .hjm-select__option, .hjm-select__message { min-block-size: var(--hjm-control-min-touch-target); display: flex; align-items: center; gap: var(--hjm-space-sm); padding: var(--hjm-space-xs) var(--hjm-space-sm); border-radius: var(--hjm-radius-sm); overflow-wrap: anywhere; }
2773
2786
  .hjm-select[data-density="comfortable"] .hjm-select__option,
@@ -2797,7 +2810,7 @@ button.hjm-list-row, a.hjm-list-row { cursor: pointer; }
2797
2810
  max-block-size: 22.5rem;
2798
2811
  overflow: auto;
2799
2812
  padding: var(--hjm-combobox-popover-padding, var(--hjm-space-xs)); /* comboboxRecipe.popover = selectRecipe.popover, 8 (was 4 until 2026-10-06) */
2800
- border: 1px solid var(--hjm-color-border);
2813
+ border: 1px solid color-mix(in srgb, var(--hjm-color-border-control) 50%, transparent);
2801
2814
  border-radius: var(--hjm-radius-md);
2802
2815
  background: var(--hjm-color-bg);
2803
2816
  box-shadow: var(--hjm-shadow-floating);
@@ -2883,7 +2896,7 @@ button.hjm-list-row, a.hjm-list-row { cursor: pointer; }
2883
2896
  place-items: center;
2884
2897
  inline-size: var(--hjm-avatar-size, 2.5rem);
2885
2898
  block-size: var(--hjm-avatar-size, 2.5rem);
2886
- border: 1px solid var(--hjm-color-border);
2899
+ border: 1px solid color-mix(in srgb, var(--hjm-color-border-control) 50%, transparent);
2887
2900
  border-radius: 50%;
2888
2901
  color: var(--hjm-color-text-muted);
2889
2902
  background: var(--hjm-color-bg);
@@ -3340,25 +3353,40 @@ button.hjm-list-row, a.hjm-list-row { cursor: pointer; }
3340
3353
  .hjm-menu-morph__item[data-tone="danger"] { color: var(--hjm-color-danger); }
3341
3354
  .hjm-menu-morph__item:disabled { opacity: 0.5; cursor: not-allowed; }
3342
3355
 
3343
- /* Selected colors are user data; control surfaces keep the same canvas tokens as other inputs. */
3344
- .hjm-color-picker { border: 1px solid var(--hjm-color-border); border-radius: var(--hjm-radius-md); background: var(--hjm-color-bg); color: var(--hjm-color-text); padding: 1rem; margin: 0; min-inline-size: 0; overflow-wrap: anywhere; }
3345
- .hjm-color-picker legend { max-inline-size: 100%; overflow-wrap: anywhere; }
3346
- .hjm-color-picker__row { display: flex; flex-wrap: wrap; gap: 0.75rem; }
3347
- .hjm-color-picker label { display: flex; flex-direction: column; gap: 0.5rem; min-inline-size: 0; }
3348
- .hjm-color-picker__hex { flex: 1 1 10rem; }
3349
- .hjm-color-picker input { box-sizing: border-box; min-block-size: var(--hjm-color-picker-target); min-inline-size: 0; max-inline-size: 100%; border: 1px solid var(--hjm-color-border); border-radius: var(--hjm-radius-md); background: var(--hjm-color-bg); color: var(--hjm-color-text); font: inherit; }
3350
- .hjm-color-picker input[type="text"] { inline-size: 100%; padding-inline: 0.5rem; }
3351
- .hjm-color-picker input[type="color"] { inline-size: 3rem; padding: 0.25rem; }
3352
- .hjm-color-picker__opacity { margin-block-start: 0.75rem; }
3353
- .hjm-color-picker__opacity input[type="range"] { accent-color: var(--hjm-color-primary); }
3354
- .hjm-color-picker__preview { block-size: 1.5rem; margin-block-start: 0.75rem; border: 1px solid var(--hjm-color-border); border-radius: var(--hjm-radius-md); }
3355
- .hjm-color-picker__presets { display: flex; flex-wrap: wrap; gap: 0.5rem; margin-block-start: 0.75rem; }
3356
- .hjm-color-picker__presets button { display: inline-flex; align-items: center; gap: 0.5rem; min-block-size: var(--hjm-color-picker-target); max-inline-size: 100%; overflow-wrap: anywhere; border: 1px solid var(--hjm-color-border); border-radius: var(--hjm-radius-md); padding: 0.5rem; background: var(--hjm-color-bg); color: var(--hjm-color-text); font: inherit; cursor: pointer; }
3357
- .hjm-color-picker__presets button[aria-pressed="true"] { border-color: var(--hjm-color-primary); }
3358
- .hjm-color-picker__swatch { inline-size: 1rem; block-size: 1rem; flex-shrink: 0; border: 1px solid var(--hjm-color-border); }
3359
- .hjm-color-picker :is(input, button):focus-visible { outline: 2px solid var(--hjm-color-primary); outline-offset: 2px; }
3360
- .hjm-color-picker__error { color: var(--hjm-color-danger); margin-block: 0.5rem; }
3356
+ /* Selected colors are user data; control surfaces keep the same canvas tokens as other inputs. The 2026-10-25 redesign
3357
+ edits HSV: a saturation/brightness area over the hue colour, then hue and opacity bars (Figma/Procreate Classic). */
3358
+ .hjm-color-picker { --hjm-color-picker-checker: repeating-conic-gradient(#d6d6d6 0% 25%, #ffffff 0% 50%) 0 0 / 12px 12px; display: grid; gap: var(--hjm-space-md); border: 1px solid var(--hjm-color-border); border-radius: var(--hjm-radius-md); background: var(--hjm-color-bg); color: var(--hjm-color-text); padding: 1rem; margin: 0; min-inline-size: 0; overflow-wrap: anywhere; }
3359
+ .hjm-color-picker legend { max-inline-size: 100%; overflow-wrap: anywhere; padding-inline: 0.25rem; }
3360
+ .hjm-color-picker__area { position: relative; aspect-ratio: var(--hjm-color-picker-area-ratio); border-radius: var(--hjm-radius-md); background: linear-gradient(to top, #000, transparent), linear-gradient(to right, #fff, transparent), var(--hjm-color-picker-hue); touch-action: none; cursor: crosshair; user-select: none; }
3361
+ .hjm-color-picker__area[data-disabled] { cursor: not-allowed; }
3362
+ .hjm-color-picker__area:focus-within { outline: var(--hjm-focus-width, 2px) solid var(--hjm-color-focus); outline-offset: 2px; }
3363
+ .hjm-color-picker__area-thumb { position: absolute; inline-size: var(--hjm-color-picker-area-thumb); block-size: var(--hjm-color-picker-area-thumb); box-sizing: border-box; translate: -50% -50%; border: 3px solid #fff; border-radius: 50%; background: var(--hjm-color-picker-opaque); box-shadow: 0 0 0 1px rgb(0 0 0 / 0.3), 0 1px 4px rgb(0 0 0 / 0.35); pointer-events: none; }
3364
+ .hjm-color-picker__bar { appearance: none; -webkit-appearance: none; display: block; inline-size: 100%; block-size: var(--hjm-color-picker-target); margin: 0; background: transparent; cursor: pointer; }
3365
+ .hjm-color-picker__bar::-webkit-slider-runnable-track { block-size: var(--hjm-color-picker-bar); border-radius: 999px; background: var(--hjm-color-picker-bar-fill); box-shadow: inset 0 0 0 1px rgb(0 0 0 / 0.12); }
3366
+ .hjm-color-picker__bar::-moz-range-track { block-size: var(--hjm-color-picker-bar); border-radius: 999px; background: var(--hjm-color-picker-bar-fill); box-shadow: inset 0 0 0 1px rgb(0 0 0 / 0.12); }
3367
+ .hjm-color-picker__bar::-webkit-slider-thumb { -webkit-appearance: none; inline-size: var(--hjm-color-picker-bar-thumb); block-size: var(--hjm-color-picker-bar-thumb); margin-block-start: calc((var(--hjm-color-picker-bar) - var(--hjm-color-picker-bar-thumb)) / 2); box-sizing: border-box; border: 3px solid #fff; border-radius: 50%; background: var(--hjm-color-picker-bar-thumb-fill); box-shadow: 0 0 0 1px rgb(0 0 0 / 0.3), 0 1px 4px rgb(0 0 0 / 0.35); }
3368
+ .hjm-color-picker__bar::-moz-range-thumb { inline-size: var(--hjm-color-picker-bar-thumb); block-size: var(--hjm-color-picker-bar-thumb); box-sizing: border-box; border: 3px solid #fff; border-radius: 50%; background: var(--hjm-color-picker-bar-thumb-fill); box-shadow: 0 0 0 1px rgb(0 0 0 / 0.3), 0 1px 4px rgb(0 0 0 / 0.35); }
3369
+ .hjm-color-picker__bar--hue { --hjm-color-picker-bar-fill: var(--hjm-color-picker-hue-gradient); --hjm-color-picker-bar-thumb-fill: var(--hjm-color-picker-hue); }
3370
+ .hjm-color-picker__bar--alpha { --hjm-color-picker-bar-fill: linear-gradient(to right, transparent, var(--hjm-color-picker-opaque)), var(--hjm-color-picker-checker); --hjm-color-picker-bar-thumb-fill: linear-gradient(var(--hjm-color-picker-current), var(--hjm-color-picker-current)), var(--hjm-color-picker-checker); }
3371
+ .hjm-color-picker__bar:focus-visible { outline: var(--hjm-focus-width, 2px) solid var(--hjm-color-focus); outline-offset: 2px; border-radius: 999px; }
3372
+ .hjm-color-picker__row { display: flex; align-items: flex-end; gap: 0.75rem; }
3373
+ .hjm-color-picker__preview { flex-shrink: 0; inline-size: var(--hjm-color-picker-preview); block-size: var(--hjm-color-picker-preview); border-radius: 50%; background: linear-gradient(var(--hjm-color-picker-current), var(--hjm-color-picker-current)), var(--hjm-color-picker-checker); box-shadow: inset 0 0 0 1px rgb(0 0 0 / 0.15); }
3374
+ .hjm-color-picker__hex { display: flex; flex: 1 1 8rem; flex-direction: column; gap: 0.25rem; min-inline-size: 0; }
3375
+ .hjm-color-picker__hex input { box-sizing: border-box; inline-size: 100%; min-block-size: var(--hjm-color-picker-target); padding-inline: 0.5rem; border: 1px solid var(--hjm-color-border); border-radius: var(--hjm-radius-md); background: var(--hjm-color-bg); color: var(--hjm-color-text); font: inherit; font-variant-numeric: tabular-nums; }
3376
+ .hjm-color-picker__hex input:focus-visible { outline: var(--hjm-focus-width, 2px) solid var(--hjm-color-focus); outline-offset: 2px; }
3377
+ .hjm-color-picker__opacity { min-block-size: var(--hjm-color-picker-target); display: inline-flex; align-items: center; font-variant-numeric: tabular-nums; color: var(--hjm-color-text-muted, inherit); }
3378
+ .hjm-color-picker__error { color: var(--hjm-color-danger); margin: 0; }
3361
3379
  .hjm-color-picker:disabled { opacity: 0.5; }
3380
+ .hjm-color-picker:disabled .hjm-color-picker__bar { cursor: not-allowed; }
3381
+ .hjm-color-swatches { border: 0; margin: 0; padding: 0; min-inline-size: 0; }
3382
+ .hjm-color-swatches legend { padding: 0; margin-block-end: 0.5rem; }
3383
+ .hjm-color-swatches__list { display: flex; flex-wrap: wrap; gap: 0.25rem; }
3384
+ .hjm-color-swatches[data-layout="scroll"] .hjm-color-swatches__list { flex-wrap: nowrap; overflow-x: auto; scrollbar-width: none; overscroll-behavior-x: contain; }
3385
+ .hjm-color-swatches__item { position: relative; display: inline-grid; place-items: center; flex-shrink: 0; inline-size: var(--hjm-color-swatch-target); block-size: var(--hjm-color-swatch-target); cursor: pointer; }
3386
+ .hjm-color-swatches__swatch { inline-size: var(--hjm-color-swatch-size); block-size: var(--hjm-color-swatch-size); border-radius: 50%; background: linear-gradient(var(--hjm-color-swatch), var(--hjm-color-swatch)), repeating-conic-gradient(#d6d6d6 0% 25%, #ffffff 0% 50%) 0 0 / 10px 10px; box-shadow: inset 0 0 0 1px rgb(0 0 0 / 0.15); }
3387
+ .hjm-color-swatches__item input:checked + .hjm-color-swatches__swatch { box-shadow: inset 0 0 0 1px rgb(0 0 0 / 0.15), 0 0 0 var(--hjm-color-swatch-gap) var(--hjm-color-bg), 0 0 0 calc(var(--hjm-color-swatch-gap) + var(--hjm-color-swatch-ring)) var(--hjm-color-text); }
3388
+ .hjm-color-swatches__item input:focus-visible + .hjm-color-swatches__swatch { outline: var(--hjm-focus-width, 2px) solid var(--hjm-color-focus); outline-offset: calc(var(--hjm-color-swatch-gap) + var(--hjm-color-swatch-ring) + 2px); }
3389
+ .hjm-color-swatches:disabled .hjm-color-swatches__item { cursor: not-allowed; opacity: 0.5; }
3362
3390
  /* SVG labels are decorative and print with the content; neither selection nor pointer input is intercepted. */
3363
3391
  .hjm-watermark { position: relative; isolation: isolate; }
3364
3392
  .hjm-watermark__content { position: relative; z-index: 0; overflow-wrap: anywhere; }
@@ -3663,8 +3691,8 @@ button.hjm-chat-message__media-item:focus-visible { outline: 2px solid var(--hjm
3663
3691
  (--hjm-comment-anchor-line, set per row), so like/more glyphs share the author line's centre instead of sitting
3664
3692
  12px below it. When HJM's own like/more is the last control (data-edge), the whole column takes the IconButton edge
3665
3693
  overhang: the 44-wide like count under the heart shares the column, so a margin on the button alone was absorbed. */
3666
- .hjm-comment-row__like { flex: 0 0 auto; display: flex; flex-direction: column; align-items: flex-start; margin-block-start: calc((var(--hjm-comment-anchor-line) - var(--hjm-control-button-medium)) / 2); }
3667
- .hjm-comment-row__like[data-edge="end"] { margin-inline-end: calc(-1 * var(--hjm-icon-button-edge-medium)); }
3694
+ .hjm-comment-row__like { flex: 0 0 auto; display: flex; flex-direction: column; align-items: flex-start; margin-block-start: calc((var(--hjm-comment-anchor-line) - var(--hjm-control-button-small)) / 2); }
3695
+ .hjm-comment-row__like[data-edge="end"] { margin-inline-end: calc(-1 * var(--hjm-icon-button-edge-small)); }
3668
3696
  .hjm-comment-row__like-count { text-align: center; }
3669
3697
  .hjm-comment-row__action { align-self: flex-start; padding: 0; border: 0; background: none; color: var(--hjm-color-text-muted); font: inherit; font-size: var(--hjm-type-caption-size); line-height: var(--hjm-type-caption-line-height); font-weight: var(--hjm-text-emphasis-medium); cursor: pointer; }
3670
3698
  .hjm-comment-row__action:disabled { opacity: 0.5; cursor: default; }
@@ -3789,6 +3817,7 @@ button.hjm-chat-message__media-item:focus-visible { outline: 2px solid var(--hjm
3789
3817
 
3790
3818
  /* Full destination cards keep all names and widths stable; colors remain product semantic roles. */
3791
3819
  .hjm-bottom-navigation[data-selection="tile"] .hjm-bottom-navigation__surface { background: var(--hjm-color-surface-accent); }
3820
+ .hjm-bottom-navigation[data-selection="tile"][data-tone="neutral"] .hjm-bottom-navigation__surface { background: var(--hjm-color-surface); }
3792
3821
  .hjm-bottom-navigation[data-selection="tile"] .hjm-bottom-navigation__list { padding: var(--hjm-space-xxs); gap: var(--hjm-space-xxs); }
3793
3822
  .hjm-bottom-navigation[data-selection="tile"] .hjm-bottom-navigation__item[data-state="selected"] { background: var(--hjm-color-primary); color: var(--hjm-color-on-primary); }
3794
3823
  .hjm-bottom-navigation[data-selection="tile"] .hjm-bottom-navigation__item:not([data-state="selected"]):active { background: var(--hjm-bottom-navigation-pressed-background); }
@@ -3987,3 +4016,36 @@ button.hjm-chat-message__media-item:focus-visible { outline: 2px solid var(--hjm
3987
4016
  .hjm-chat-room__selected-item { display:flex; flex-direction:column; align-items:center; gap:var(--hjm-space-xxs); inline-size:64px; padding:0; border:0; border-radius:var(--hjm-radius-md); background:transparent; color:inherit; cursor:pointer; }
3988
4017
  .hjm-chat-room__selected-name { max-inline-size:100%; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
3989
4018
  :is(.hjm-chat-room__tool,.hjm-chat-room__photo,.hjm-chat-room__selected-item):focus-visible { outline:2px solid var(--hjm-color-content-brand); outline-offset:2px; }
4019
+
4020
+ /* FollowListScreen already receives the screen body inset; external tab panels add no second gutter. */
4021
+ .hjm-follow-list__panel { padding-block: 0; }
4022
+
4023
+ /* Narrow pager placement without shrinking the vertical tap target or overlapping adjacent buttons. */
4024
+ .hjm-page-indicator[data-density="compact"][data-interactive="true"] { gap: 0; }
4025
+ .hjm-page-indicator[data-density="compact"] .hjm-page-indicator__dot { min-inline-size: var(--hjm-space-lg); inline-size: var(--hjm-space-lg); padding-inline: 0; }
4026
+
4027
+ /* Identity navigation preserves small avatar geometry while exposing a keyboard/touch target. */
4028
+ .hjm-identity-action { display: inline-flex; align-items: center; justify-content: center; flex-shrink: 0; min-inline-size: var(--hjm-identity-target); min-block-size: var(--hjm-identity-target); margin: 0; padding: 0; border: 0; border-radius: var(--hjm-radius-full, 9999px); background: transparent; color: inherit; cursor: pointer; }
4029
+ .hjm-identity-action > span { display: inline-flex; }
4030
+ .hjm-identity-action:focus-visible { outline: 2px solid var(--hjm-color-content-brand); outline-offset: 2px; }
4031
+ .hjm-identity-action:active { opacity: var(--hjm-identity-pressed-opacity); }
4032
+ .hjm-identity-action:disabled { cursor: default; }
4033
+
4034
+ /* Independent identity navigation is a sibling of row commands, including links. */
4035
+ .hjm-list-row__profile { display: flex; flex: 0 0 auto; padding-inline-start: var(--hjm-list-row-inline); }
4036
+ .hjm-list-row-frame[data-leading-action] > .hjm-list-row { padding-inline-start: 0; }
4037
+ .hjm-list-row-frame[data-leading-action]:not([data-trailing-action]) > .hjm-list-row { padding-inline-end: var(--hjm-list-row-inline); }
4038
+
4039
+ .hjm-card[data-activation="overlay"] .hjm-card__leading[data-interactive] { position: relative; z-index: 1; }
4040
+
4041
+ /* Header dismissal keeps a single modal surface and leaves the action viewport scrollable. */
4042
+ .hjm-menu__content[data-presentation="bottom"][data-dismiss-placement="header"] { background: var(--hjm-color-bg); padding: var(--hjm-space-sm); }
4043
+ .hjm-menu__header { display: flex; align-items: center; gap: var(--hjm-space-sm); flex-shrink: 0; }
4044
+ .hjm-menu__heading { flex: 1; min-inline-size: 0; display: grid; gap: var(--hjm-space-xxs); }
4045
+ .hjm-menu__title { font-weight: var(--hjm-text-emphasis-strong); }
4046
+ .hjm-menu__subtitle { font-size: var(--hjm-type-label-size); color: var(--hjm-color-text-muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
4047
+
4048
+ /* Relationship lists use the large Avatar (48) and 64px rows so identity stays legible beside actions. */
4049
+ .hjm-follow-list__person { min-block-size: 64px; }
4050
+ .hjm-list-row__leading[data-size="large"] { inline-size: 48px; block-size: 48px; }
4051
+ .hjm-follow-list__relationship { min-inline-size: 108px; }