| author | |
| committer | |
| log | 5dcb59ed6c191589e730fb964aabad005466eb6d |
| tree | 77babc90b134bf5c63322d7dbfd17643ff73e4e3 |
| parent | 08e18b7833c9b5d33bfcd1ce8976dcb67c11dde5 |
| signature | Signed by PGP key B5690EEEBB952194 |
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>79 files changed, 359 insertions(+), 131 deletions(-)
apps/desktop/src/permissions/MacPermissionHelper.ts+1-1| ... | @@ -52,7 +52,7 @@ body { margin: 0; background: transparent; color: var(--text); font: 15px/22px - | ... | @@ -52,7 +52,7 @@ body { margin: 0; background: transparent; color: var(--text); font: 15px/22px - |
| 52 | #panel { position: relative; margin: 2px; padding: 20px; height: 136px; border: 1px solid var(--line); border-radius: 24px; background: var(--base); } | 52 | #panel { position: relative; margin: 2px; padding: 20px; height: 136px; border: 1px solid var(--line); border-radius: 24px; background: var(--base); } |
| 53 | header { font-weight: 600; white-space: nowrap; } | 53 | header { font-weight: 600; white-space: nowrap; } |
| 54 | button { font: inherit; color: inherit; } | 54 | button { font: inherit; color: inherit; } |
| 55 | button:focus-visible { outline: 2px solid #007aff; outline-offset: 3px; } | 55 | button:focus-visible { outline: 2px solid #007aff; outline-offset: -2px; } |
| 56 | #close { position: absolute; right: 8px; top: 6px; width: 22px; height: 22px; padding: 0; border: 0; border-radius: 50%; background: var(--base); font-size: 18px; cursor: pointer; opacity: 0; } | 56 | #close { position: absolute; right: 8px; top: 6px; width: 22px; height: 22px; padding: 0; border: 0; border-radius: 50%; background: var(--base); font-size: 18px; cursor: pointer; opacity: 0; } |
| 57 | #panel:hover #close, #close:focus-visible { opacity: 1; } | 57 | #panel:hover #close, #close:focus-visible { opacity: 1; } |
| 58 | #app { display: flex; align-items: center; gap: 12px; width: 100%; height: 52px; margin-top: 20px; padding: 8px 12px; border: 0; border-radius: 10px; background: var(--row); cursor: grab; text-align: left; font-size: 16px; font-weight: 600; } | 58 | #app { display: flex; align-items: center; gap: 12px; width: 100%; height: 52px; margin-top: 20px; padding: 8px 12px; border: 0; border-radius: 10px; background: var(--row); cursor: grab; text-align: left; font-size: 16px; font-weight: 600; } |
apps/desktop/src/preview/Annotation.css+1-1| ... | @@ -64,5 +64,5 @@ input:focus-visible, | ... | @@ -64,5 +64,5 @@ input:focus-visible, |
| 64 | select:focus-visible, | 64 | select:focus-visible, |
| 65 | textarea:focus-visible { | 65 | textarea:focus-visible { |
| 66 | outline: 2px solid color-mix(in srgb, var(--t3-ring) 72%, transparent); | 66 | outline: 2px solid color-mix(in srgb, var(--t3-ring) 72%, transparent); |
| 67 | outline-offset: 1px; | 67 | outline-offset: -2px; |
| 68 | } | 68 | } |
apps/desktop/src/preview/AnnotationStyles.generated.ts+1-1| ... | @@ -1,3 +1,3 @@ | ... | @@ -1,3 +1,3 @@ |
| 1 | // Generated by scripts/build-preview-annotation-css.mjs. Do not edit. | 1 | // Generated by scripts/build-preview-annotation-css.mjs. Do not edit. |
| 2 | export const previewAnnotationStyles = | 2 | export const previewAnnotationStyles = |
| 3 | '/*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */\n@layer properties;\n:root, :host {\n --spacing: 0.25rem;\n --text-xs: 0.75rem;\n --text-xs--line-height: calc(1 / 0.75);\n --text-sm: 0.875rem;\n --text-sm--line-height: calc(1.25 / 0.875);\n --text-lg: 1.125rem;\n --text-lg--line-height: calc(1.75 / 1.125);\n --font-weight-medium: 500;\n --font-weight-semibold: 600;\n --font-weight-bold: 700;\n --blur-xl: 24px;\n --default-font-family: var(--t3-font-sans);\n --default-mono-font-family: var(--t3-font-mono);\n}\n*, ::after, ::before, ::backdrop, ::file-selector-button {\n box-sizing: border-box;\n margin: 0;\n padding: 0;\n border: 0 solid;\n}\nhtml, :host {\n line-height: 1.5;\n -webkit-text-size-adjust: 100%;\n tab-size: 4;\n font-family: var(--default-font-family, -apple-system, BlinkMacSystemFont, \'Segoe UI\', Roboto, \'Helvetica Neue\', \'Noto Sans\', Arial, sans-serif, \'Apple Color Emoji\', \'Segoe UI Emoji\', \'Segoe UI Symbol\', \'Noto Color Emoji\');\n font-feature-settings: var(--default-font-feature-settings, normal);\n font-variation-settings: var(--default-font-variation-settings, normal);\n -webkit-tap-highlight-color: transparent;\n}\nhr {\n height: 0;\n color: inherit;\n border-top-width: 1px;\n}\nabbr:where([title]) {\n -webkit-text-decoration: underline dotted;\n text-decoration: underline dotted;\n}\nh1, h2, h3, h4, h5, h6 {\n font-size: inherit;\n font-weight: inherit;\n}\na {\n color: inherit;\n -webkit-text-decoration: inherit;\n text-decoration: inherit;\n}\nb, strong {\n font-weight: bolder;\n}\ncode, kbd, samp, pre {\n font-family: var(--default-mono-font-family, ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, \'Liberation Mono\', \'Courier New\', monospace);\n font-feature-settings: var(--default-mono-font-feature-settings, normal);\n font-variation-settings: var(--default-mono-font-variation-settings, normal);\n font-size: 1em;\n}\nsmall {\n font-size: 80%;\n}\nsub, sup {\n font-size: 75%;\n line-height: 0;\n position: relative;\n vertical-align: baseline;\n}\nsub {\n bottom: -0.25em;\n}\nsup {\n top: -0.5em;\n}\ntable {\n text-indent: 0;\n border-color: inherit;\n border-collapse: collapse;\n}\n:-moz-focusring:where(:not(iframe)) {\n outline: auto;\n}\nprogress {\n vertical-align: baseline;\n}\nsummary {\n display: list-item;\n}\nol, ul, menu {\n list-style: none;\n}\nimg, svg, video, canvas, audio, iframe, embed, object {\n display: block;\n vertical-align: middle;\n}\nimg, video {\n max-width: 100%;\n height: auto;\n}\nbutton, input, select, optgroup, textarea, ::file-selector-button {\n font: inherit;\n font-feature-settings: inherit;\n font-variation-settings: inherit;\n letter-spacing: inherit;\n color: inherit;\n border-radius: 0;\n background-color: transparent;\n opacity: 1;\n}\n:where(select:is([multiple], [size])) optgroup {\n font-weight: bolder;\n}\n:where(select:is([multiple], [size])) optgroup option {\n padding-inline-start: 20px;\n}\n::file-selector-button {\n margin-inline-end: 4px;\n}\n::placeholder {\n opacity: 1;\n}\n@supports (not (-webkit-appearance: -apple-pay-button)) or (contain-intrinsic-size: 1px) {\n ::placeholder {\n color: currentcolor;\n @supports (color: color-mix(in lab, red, red)) {\n color: color-mix(in oklab, currentcolor 50%, transparent);\n }\n }\n}\ntextarea {\n resize: vertical;\n}\n::-webkit-search-decoration {\n -webkit-appearance: none;\n}\n::-webkit-date-and-time-value {\n min-height: 1lh;\n text-align: inherit;\n}\n::-webkit-datetime-edit {\n display: inline-flex;\n}\n::-webkit-datetime-edit-fields-wrapper {\n padding: 0;\n}\n::-webkit-datetime-edit, ::-webkit-datetime-edit-year-field, ::-webkit-datetime-edit-month-field, ::-webkit-datetime-edit-day-field, ::-webkit-datetime-edit-hour-field, ::-webkit-datetime-edit-minute-field, ::-webkit-datetime-edit-second-field, ::-webkit-datetime-edit-millisecond-field, ::-webkit-datetime-edit-meridiem-field {\n padding-block: 0;\n}\n::-webkit-calendar-picker-indicator {\n line-height: 1;\n}\n:-moz-ui-invalid {\n box-shadow: none;\n}\nbutton, input:where([type=\'button\'], [type=\'reset\'], [type=\'submit\']), ::file-selector-button {\n appearance: button;\n}\n::-webkit-inner-spin-button, ::-webkit-outer-spin-button {\n height: auto;\n}\n[hidden]:where(:not([hidden=\'until-found\'])) {\n display: none !important;\n}\n.pointer-events-auto {\n pointer-events: auto;\n}\n.pointer-events-none {\n pointer-events: none;\n}\n.absolute {\n position: absolute;\n}\n.fixed {\n position: fixed;\n}\n.inset-0 {\n inset: 0px;\n}\n.top-1\\/2 {\n top: calc(1 / 2 * 100%);\n}\n.top-2\\.5 {\n top: calc(var(--spacing) * 2.5);\n}\n.right-2 {\n right: calc(var(--spacing) * 2);\n}\n.left-1\\/2 {\n left: calc(1 / 2 * 100%);\n}\n.z-1 {\n z-index: 1;\n}\n.block {\n display: block;\n}\n.flex {\n display: flex;\n}\n.grid {\n display: grid;\n}\n.hidden {\n display: none;\n}\n.inline-flex {\n display: inline-flex;\n}\n.h-7 {\n height: calc(var(--spacing) * 7);\n}\n.h-8 {\n height: calc(var(--spacing) * 8);\n}\n.max-h-24 {\n max-height: calc(var(--spacing) * 24);\n}\n.max-h-\\[calc\\(100vh-16px\\)\\] {\n max-height: calc(100vh - 16px);\n}\n.max-h-\\[min\\(176px\\,calc\\(100vh-180px\\)\\)\\] {\n max-height: min(176px, calc(100vh - 180px));\n}\n.min-h-7 {\n min-height: calc(var(--spacing) * 7);\n}\n.min-h-8 {\n min-height: calc(var(--spacing) * 8);\n}\n.w-6 {\n width: calc(var(--spacing) * 6);\n}\n.w-8 {\n width: calc(var(--spacing) * 8);\n}\n.w-\\[min\\(360px\\,calc\\(100vw-16px\\)\\)\\] {\n width: min(360px, calc(100vw - 16px));\n}\n.w-full {\n width: 100%;\n}\n.max-w-70 {\n max-width: calc(var(--spacing) * 70);\n}\n.min-w-0 {\n min-width: 0px;\n}\n.flex-1 {\n flex: 1;\n}\n.shrink-0 {\n flex-shrink: 0;\n}\n.-translate-x-1\\/2 {\n --tw-translate-x: calc(calc(1 / 2 * 100%) * -1);\n translate: var(--tw-translate-x) var(--tw-translate-y);\n}\n.-translate-y-1\\/2 {\n --tw-translate-y: calc(calc(1 / 2 * 100%) * -1);\n translate: var(--tw-translate-x) var(--tw-translate-y);\n}\n.cursor-grab {\n cursor: grab;\n}\n.cursor-pointer {\n cursor: pointer;\n}\n.resize {\n resize: both;\n}\n.resize-none {\n resize: none;\n}\n.appearance-none {\n appearance: none;\n}\n.grid-cols-\\[22px_minmax\\(0\\,1fr\\)\\] {\n grid-template-columns: 22px minmax(0,1fr);\n}\n.grid-cols-\\[82px_minmax\\(0\\,1fr\\)\\] {\n grid-template-columns: 82px minmax(0,1fr);\n}\n.flex-col {\n flex-direction: column;\n}\n.items-center {\n align-items: center;\n}\n.items-start {\n align-items: flex-start;\n}\n.justify-center {\n justify-content: center;\n}\n.gap-0\\.5 {\n gap: calc(var(--spacing) * 0.5);\n}\n.gap-1 {\n gap: var(--spacing);\n}\n.gap-2 {\n gap: calc(var(--spacing) * 2);\n}\n.overflow-auto {\n overflow: auto;\n}\n.overflow-hidden {\n overflow: hidden;\n}\n.overflow-y-hidden {\n overflow-y: hidden;\n}\n.rounded-lg {\n border-radius: var(--t3-radius);\n}\n.rounded-md {\n border-radius: calc(var(--t3-radius) - 2px);\n}\n.rounded-xl {\n border-radius: calc(var(--t3-radius) + 4px);\n}\n.border {\n border-style: var(--tw-border-style);\n border-width: 1px;\n}\n.border-0 {\n border-style: var(--tw-border-style);\n border-width: 0px;\n}\n.border-t {\n border-top-style: var(--tw-border-style);\n border-top-width: 1px;\n}\n.border-b {\n border-bottom-style: var(--tw-border-style);\n border-bottom-width: 1px;\n}\n.border-border {\n border-color: var(--t3-border);\n}\n.border-input {\n border-color: var(--t3-input);\n}\n.border-primary {\n border-color: var(--t3-primary);\n}\n.border-transparent {\n border-color: transparent;\n}\n.border-b-transparent {\n border-bottom-color: transparent;\n}\n.bg-background {\n background-color: var(--t3-background);\n}\n.bg-muted {\n background-color: var(--t3-muted);\n}\n.bg-muted\\/40 {\n background-color: var(--t3-muted);\n @supports (color: color-mix(in lab, red, red)) {\n background-color: color-mix(in oklab, var(--t3-muted) 40%, transparent);\n }\n}\n.bg-popover\\/95 {\n background-color: var(--t3-popover);\n @supports (color: color-mix(in lab, red, red)) {\n background-color: color-mix(in oklab, var(--t3-popover) 95%, transparent);\n }\n}\n.bg-popover\\/96 {\n background-color: var(--t3-popover);\n @supports (color: color-mix(in lab, red, red)) {\n background-color: color-mix(in oklab, var(--t3-popover) 96%, transparent);\n }\n}\n.bg-primary {\n background-color: var(--t3-primary);\n}\n.bg-primary\\/10 {\n background-color: var(--t3-primary);\n @supports (color: color-mix(in lab, red, red)) {\n background-color: color-mix(in oklab, var(--t3-primary) 10%, transparent);\n }\n}\n.bg-transparent {\n background-color: transparent;\n}\n.p-0 {\n padding: 0px;\n}\n.p-1 {\n padding: var(--spacing);\n}\n.p-2 {\n padding: calc(var(--spacing) * 2);\n}\n.px-0 {\n padding-inline: 0px;\n}\n.px-1 {\n padding-inline: var(--spacing);\n}\n.px-2 {\n padding-inline: calc(var(--spacing) * 2);\n}\n.px-2\\.5 {\n padding-inline: calc(var(--spacing) * 2.5);\n}\n.px-3 {\n padding-inline: calc(var(--spacing) * 3);\n}\n.py-1 {\n padding-block: var(--spacing);\n}\n.py-1\\.5 {\n padding-block: calc(var(--spacing) * 1.5);\n}\n.py-2 {\n padding-block: calc(var(--spacing) * 2);\n}\n.font-mono {\n font-family: var(--t3-font-mono);\n}\n.font-sans {\n font-family: var(--t3-font-sans);\n}\n.text-lg {\n font-size: var(--text-lg);\n line-height: var(--tw-leading, var(--text-lg--line-height));\n}\n.text-sm {\n font-size: var(--text-sm);\n line-height: var(--tw-leading, var(--text-sm--line-height));\n}\n.text-xs {\n font-size: var(--text-xs);\n line-height: var(--tw-leading, var(--text-xs--line-height));\n}\n.leading-5 {\n --tw-leading: calc(var(--spacing) * 5);\n line-height: calc(var(--spacing) * 5);\n}\n.font-bold {\n --tw-font-weight: var(--font-weight-bold);\n font-weight: var(--font-weight-bold);\n}\n.font-medium {\n --tw-font-weight: var(--font-weight-medium);\n font-weight: var(--font-weight-medium);\n}\n.font-semibold {\n --tw-font-weight: var(--font-weight-semibold);\n font-weight: var(--font-weight-semibold);\n}\n.text-foreground {\n color: var(--t3-foreground);\n}\n.text-muted-foreground {\n color: var(--t3-muted-foreground);\n}\n.text-popover-foreground {\n color: var(--t3-popover-foreground);\n}\n.text-primary {\n color: var(--t3-primary);\n}\n.text-primary-foreground {\n color: var(--t3-primary-foreground);\n}\n.shadow-2xl {\n --tw-shadow: 0 25px 50px -12px var(--tw-shadow-color, rgb(0 0 0 / 0.25));\n box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);\n}\n.shadow-lg {\n --tw-shadow: 0 10px 15px -3px var(--tw-shadow-color, rgb(0 0 0 / 0.1)), 0 4px 6px -4px var(--tw-shadow-color, rgb(0 0 0 / 0.1));\n box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);\n}\n.shadow-md {\n --tw-shadow: 0 4px 6px -1px var(--tw-shadow-color, rgb(0 0 0 / 0.1)), 0 2px 4px -2px var(--tw-shadow-color, rgb(0 0 0 / 0.1));\n box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);\n}\n.shadow-sm {\n --tw-shadow: 0 1px 3px 0 var(--tw-shadow-color, rgb(0 0 0 / 0.1)), 0 1px 2px -1px var(--tw-shadow-color, rgb(0 0 0 / 0.1));\n box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);\n}\n.shadow-xs {\n --tw-shadow: 0 1px 2px 0 var(--tw-shadow-color, rgb(0 0 0 / 0.05));\n box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);\n}\n.ring-0 {\n --tw-ring-shadow: var(--tw-ring-inset,) 0 0 0 calc(0px + var(--tw-ring-offset-width)) var(--tw-ring-color, currentcolor);\n box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);\n}\n.blur {\n --tw-blur: blur(8px);\n filter: var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,);\n}\n.backdrop-blur-xl {\n --tw-backdrop-blur: blur(var(--blur-xl));\n -webkit-backdrop-filter: var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);\n backdrop-filter: var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);\n}\n.outline-none {\n --tw-outline-style: none;\n outline-style: none;\n}\n.select-none {\n -webkit-user-select: none;\n user-select: none;\n}\n.placeholder\\:text-muted-foreground::placeholder {\n color: var(--t3-muted-foreground);\n}\n@media (hover: hover) {\n .hover\\:bg-accent:hover {\n background-color: var(--t3-accent);\n }\n .hover\\:bg-primary\\/90:hover {\n background-color: var(--t3-primary);\n }\n @supports (color: color-mix(in lab, red, red)) {\n .hover\\:bg-primary\\/90:hover {\n background-color: color-mix(in oklab, var(--t3-primary) 90%, transparent);\n }\n }\n .hover\\:text-accent-foreground:hover {\n color: var(--t3-accent-foreground);\n }\n}\n.focus\\:border-b-primary:focus {\n border-bottom-color: var(--t3-primary);\n}\n.focus\\:ring-0:focus {\n --tw-ring-shadow: var(--tw-ring-inset,) 0 0 0 calc(0px + var(--tw-ring-offset-width)) var(--tw-ring-color, currentcolor);\n box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);\n}\n.focus\\:outline-none:focus {\n --tw-outline-style: none;\n outline-style: none;\n}\n.disabled\\:pointer-events-none:disabled {\n pointer-events: none;\n}\n.disabled\\:opacity-60:disabled {\n opacity: 60%;\n}\n:host {\n --t3-font-sans: "DM Sans Variable", "DM Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui,\n sans-serif;\n --t3-font-mono: "SF Mono", "SFMono-Regular", "JetBrains Mono", Consolas, "Liberation Mono", Menlo, monospace;\n --t3-radius: 0.625rem;\n --t3-background: white;\n --t3-foreground: oklch(0.269 0 0);\n --t3-popover: white;\n --t3-popover-foreground: oklch(0.269 0 0);\n --t3-primary: oklch(0.488 0.217 264);\n --t3-primary-foreground: white;\n --t3-muted: rgb(0 0 0 / 4%);\n --t3-muted-foreground: oklch(0.556 0 0);\n --t3-accent: rgb(0 0 0 / 4%);\n --t3-accent-foreground: oklch(0.269 0 0);\n --t3-border: rgb(0 0 0 / 8%);\n --t3-input: rgb(0 0 0 / 10%);\n --t3-ring: oklch(0.488 0.217 264);\n color: var(--t3-foreground);\n font-family: var(--t3-font-sans);\n}\n* {\n box-sizing: border-box;\n border-color: var(--t3-border);\n}\nbutton, input, select, textarea {\n font: inherit;\n}\nbutton:focus-visible, input:focus-visible, select:focus-visible, textarea:focus-visible {\n outline: 2px solid var(--t3-ring);\n @supports (color: color-mix(in lab, red, red)) {\n outline: 2px solid color-mix(in srgb, var(--t3-ring) 72%, transparent);\n }\n outline-offset: 1px;\n}\n@property --tw-translate-x {\n syntax: "*";\n inherits: false;\n initial-value: 0;\n}\n@property --tw-translate-y {\n syntax: "*";\n inherits: false;\n initial-value: 0;\n}\n@property --tw-translate-z {\n syntax: "*";\n inherits: false;\n initial-value: 0;\n}\n@property --tw-border-style {\n syntax: "*";\n inherits: false;\n initial-value: solid;\n}\n@property --tw-leading {\n syntax: "*";\n inherits: false;\n}\n@property --tw-font-weight {\n syntax: "*";\n inherits: false;\n}\n@property --tw-shadow {\n syntax: "*";\n inherits: false;\n initial-value: 0 0 #0000;\n}\n@property --tw-shadow-color {\n syntax: "*";\n inherits: false;\n}\n@property --tw-shadow-alpha {\n syntax: "<percentage>";\n inherits: false;\n initial-value: 100%;\n}\n@property --tw-inset-shadow {\n syntax: "*";\n inherits: false;\n initial-value: 0 0 #0000;\n}\n@property --tw-inset-shadow-color {\n syntax: "*";\n inherits: false;\n}\n@property --tw-inset-shadow-alpha {\n syntax: "<percentage>";\n inherits: false;\n initial-value: 100%;\n}\n@property --tw-ring-color {\n syntax: "*";\n inherits: false;\n}\n@property --tw-ring-shadow {\n syntax: "*";\n inherits: false;\n initial-value: 0 0 #0000;\n}\n@property --tw-inset-ring-color {\n syntax: "*";\n inherits: false;\n}\n@property --tw-inset-ring-shadow {\n syntax: "*";\n inherits: false;\n initial-value: 0 0 #0000;\n}\n@property --tw-ring-inset {\n syntax: "*";\n inherits: false;\n}\n@property --tw-ring-offset-width {\n syntax: "<length>";\n inherits: false;\n initial-value: 0px;\n}\n@property --tw-ring-offset-color {\n syntax: "*";\n inherits: false;\n initial-value: #fff;\n}\n@property --tw-ring-offset-shadow {\n syntax: "*";\n inherits: false;\n initial-value: 0 0 #0000;\n}\n@property --tw-blur {\n syntax: "*";\n inherits: false;\n}\n@property --tw-brightness {\n syntax: "*";\n inherits: false;\n}\n@property --tw-contrast {\n syntax: "*";\n inherits: false;\n}\n@property --tw-grayscale {\n syntax: "*";\n inherits: false;\n}\n@property --tw-hue-rotate {\n syntax: "*";\n inherits: false;\n}\n@property --tw-invert {\n syntax: "*";\n inherits: false;\n}\n@property --tw-opacity {\n syntax: "*";\n inherits: false;\n}\n@property --tw-saturate {\n syntax: "*";\n inherits: false;\n}\n@property --tw-sepia {\n syntax: "*";\n inherits: false;\n}\n@property --tw-drop-shadow {\n syntax: "*";\n inherits: false;\n}\n@property --tw-drop-shadow-color {\n syntax: "*";\n inherits: false;\n}\n@property --tw-drop-shadow-alpha {\n syntax: "<percentage>";\n inherits: false;\n initial-value: 100%;\n}\n@property --tw-drop-shadow-size {\n syntax: "*";\n inherits: false;\n}\n@property --tw-backdrop-blur {\n syntax: "*";\n inherits: false;\n}\n@property --tw-backdrop-brightness {\n syntax: "*";\n inherits: false;\n}\n@property --tw-backdrop-contrast {\n syntax: "*";\n inherits: false;\n}\n@property --tw-backdrop-grayscale {\n syntax: "*";\n inherits: false;\n}\n@property --tw-backdrop-hue-rotate {\n syntax: "*";\n inherits: false;\n}\n@property --tw-backdrop-invert {\n syntax: "*";\n inherits: false;\n}\n@property --tw-backdrop-opacity {\n syntax: "*";\n inherits: false;\n}\n@property --tw-backdrop-saturate {\n syntax: "*";\n inherits: false;\n}\n@property --tw-backdrop-sepia {\n syntax: "*";\n inherits: false;\n}\n@layer properties {\n @supports ((-webkit-hyphens: none) and (not (margin-trim: inline))) or ((-moz-orient: inline) and (not (color:rgb(from red r g b)))) {\n *, ::before, ::after, ::backdrop {\n --tw-translate-x: 0;\n --tw-translate-y: 0;\n --tw-translate-z: 0;\n --tw-border-style: solid;\n --tw-leading: initial;\n --tw-font-weight: initial;\n --tw-shadow: 0 0 #0000;\n --tw-shadow-color: initial;\n --tw-shadow-alpha: 100%;\n --tw-inset-shadow: 0 0 #0000;\n --tw-inset-shadow-color: initial;\n --tw-inset-shadow-alpha: 100%;\n --tw-ring-color: initial;\n --tw-ring-shadow: 0 0 #0000;\n --tw-inset-ring-color: initial;\n --tw-inset-ring-shadow: 0 0 #0000;\n --tw-ring-inset: initial;\n --tw-ring-offset-width: 0px;\n --tw-ring-offset-color: #fff;\n --tw-ring-offset-shadow: 0 0 #0000;\n --tw-blur: initial;\n --tw-brightness: initial;\n --tw-contrast: initial;\n --tw-grayscale: initial;\n --tw-hue-rotate: initial;\n --tw-invert: initial;\n --tw-opacity: initial;\n --tw-saturate: initial;\n --tw-sepia: initial;\n --tw-drop-shadow: initial;\n --tw-drop-shadow-color: initial;\n --tw-drop-shadow-alpha: 100%;\n --tw-drop-shadow-size: initial;\n --tw-backdrop-blur: initial;\n --tw-backdrop-brightness: initial;\n --tw-backdrop-contrast: initial;\n --tw-backdrop-grayscale: initial;\n --tw-backdrop-hue-rotate: initial;\n --tw-backdrop-invert: initial;\n --tw-backdrop-opacity: initial;\n --tw-backdrop-saturate: initial;\n --tw-backdrop-sepia: initial;\n }\n }\n}\n'; | 3 | '/*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */\n@layer properties;\n:root, :host {\n --spacing: 0.25rem;\n --text-xs: 0.75rem;\n --text-xs--line-height: calc(1 / 0.75);\n --text-sm: 0.875rem;\n --text-sm--line-height: calc(1.25 / 0.875);\n --text-lg: 1.125rem;\n --text-lg--line-height: calc(1.75 / 1.125);\n --font-weight-medium: 500;\n --font-weight-semibold: 600;\n --font-weight-bold: 700;\n --blur-xl: 24px;\n --default-font-family: var(--t3-font-sans);\n --default-mono-font-family: var(--t3-font-mono);\n}\n*, ::after, ::before, ::backdrop, ::file-selector-button {\n box-sizing: border-box;\n margin: 0;\n padding: 0;\n border: 0 solid;\n}\nhtml, :host {\n line-height: 1.5;\n -webkit-text-size-adjust: 100%;\n tab-size: 4;\n font-family: var(--default-font-family, -apple-system, BlinkMacSystemFont, \'Segoe UI\', Roboto, \'Helvetica Neue\', \'Noto Sans\', Arial, sans-serif, \'Apple Color Emoji\', \'Segoe UI Emoji\', \'Segoe UI Symbol\', \'Noto Color Emoji\');\n font-feature-settings: var(--default-font-feature-settings, normal);\n font-variation-settings: var(--default-font-variation-settings, normal);\n -webkit-tap-highlight-color: transparent;\n}\nhr {\n height: 0;\n color: inherit;\n border-top-width: 1px;\n}\nabbr:where([title]) {\n -webkit-text-decoration: underline dotted;\n text-decoration: underline dotted;\n}\nh1, h2, h3, h4, h5, h6 {\n font-size: inherit;\n font-weight: inherit;\n}\na {\n color: inherit;\n -webkit-text-decoration: inherit;\n text-decoration: inherit;\n}\nb, strong {\n font-weight: bolder;\n}\ncode, kbd, samp, pre {\n font-family: var(--default-mono-font-family, ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, \'Liberation Mono\', \'Courier New\', monospace);\n font-feature-settings: var(--default-mono-font-feature-settings, normal);\n font-variation-settings: var(--default-mono-font-variation-settings, normal);\n font-size: 1em;\n}\nsmall {\n font-size: 80%;\n}\nsub, sup {\n font-size: 75%;\n line-height: 0;\n position: relative;\n vertical-align: baseline;\n}\nsub {\n bottom: -0.25em;\n}\nsup {\n top: -0.5em;\n}\ntable {\n text-indent: 0;\n border-color: inherit;\n border-collapse: collapse;\n}\n:-moz-focusring:where(:not(iframe)) {\n outline: auto;\n}\nprogress {\n vertical-align: baseline;\n}\nsummary {\n display: list-item;\n}\nol, ul, menu {\n list-style: none;\n}\nimg, svg, video, canvas, audio, iframe, embed, object {\n display: block;\n vertical-align: middle;\n}\nimg, video {\n max-width: 100%;\n height: auto;\n}\nbutton, input, select, optgroup, textarea, ::file-selector-button {\n font: inherit;\n font-feature-settings: inherit;\n font-variation-settings: inherit;\n letter-spacing: inherit;\n color: inherit;\n border-radius: 0;\n background-color: transparent;\n opacity: 1;\n}\n:where(select:is([multiple], [size])) optgroup {\n font-weight: bolder;\n}\n:where(select:is([multiple], [size])) optgroup option {\n padding-inline-start: 20px;\n}\n::file-selector-button {\n margin-inline-end: 4px;\n}\n::placeholder {\n opacity: 1;\n}\n@supports (not (-webkit-appearance: -apple-pay-button)) or (contain-intrinsic-size: 1px) {\n ::placeholder {\n color: currentcolor;\n @supports (color: color-mix(in lab, red, red)) {\n color: color-mix(in oklab, currentcolor 50%, transparent);\n }\n }\n}\ntextarea {\n resize: vertical;\n}\n::-webkit-search-decoration {\n -webkit-appearance: none;\n}\n::-webkit-date-and-time-value {\n min-height: 1lh;\n text-align: inherit;\n}\n::-webkit-datetime-edit {\n display: inline-flex;\n}\n::-webkit-datetime-edit-fields-wrapper {\n padding: 0;\n}\n::-webkit-datetime-edit, ::-webkit-datetime-edit-year-field, ::-webkit-datetime-edit-month-field, ::-webkit-datetime-edit-day-field, ::-webkit-datetime-edit-hour-field, ::-webkit-datetime-edit-minute-field, ::-webkit-datetime-edit-second-field, ::-webkit-datetime-edit-millisecond-field, ::-webkit-datetime-edit-meridiem-field {\n padding-block: 0;\n}\n::-webkit-calendar-picker-indicator {\n line-height: 1;\n}\n:-moz-ui-invalid {\n box-shadow: none;\n}\nbutton, input:where([type=\'button\'], [type=\'reset\'], [type=\'submit\']), ::file-selector-button {\n appearance: button;\n}\n::-webkit-inner-spin-button, ::-webkit-outer-spin-button {\n height: auto;\n}\n[hidden]:where(:not([hidden=\'until-found\'])) {\n display: none !important;\n}\n.pointer-events-auto {\n pointer-events: auto;\n}\n.pointer-events-none {\n pointer-events: none;\n}\n.visible {\n visibility: visible;\n}\n.absolute {\n position: absolute;\n}\n.fixed {\n position: fixed;\n}\n.static {\n position: static;\n}\n.inset-0 {\n inset: 0px;\n}\n.top-1\\/2 {\n top: calc(1 / 2 * 100%);\n}\n.top-2\\.5 {\n top: calc(var(--spacing) * 2.5);\n}\n.right-2 {\n right: calc(var(--spacing) * 2);\n}\n.left-1\\/2 {\n left: calc(1 / 2 * 100%);\n}\n.z-1 {\n z-index: 1;\n}\n.block {\n display: block;\n}\n.flex {\n display: flex;\n}\n.grid {\n display: grid;\n}\n.hidden {\n display: none;\n}\n.inline-flex {\n display: inline-flex;\n}\n.h-7 {\n height: calc(var(--spacing) * 7);\n}\n.h-8 {\n height: calc(var(--spacing) * 8);\n}\n.max-h-24 {\n max-height: calc(var(--spacing) * 24);\n}\n.max-h-\\[calc\\(100vh-16px\\)\\] {\n max-height: calc(100vh - 16px);\n}\n.max-h-\\[min\\(176px\\,calc\\(100vh-180px\\)\\)\\] {\n max-height: min(176px, calc(100vh - 180px));\n}\n.min-h-7 {\n min-height: calc(var(--spacing) * 7);\n}\n.min-h-8 {\n min-height: calc(var(--spacing) * 8);\n}\n.w-6 {\n width: calc(var(--spacing) * 6);\n}\n.w-8 {\n width: calc(var(--spacing) * 8);\n}\n.w-\\[min\\(360px\\,calc\\(100vw-16px\\)\\)\\] {\n width: min(360px, calc(100vw - 16px));\n}\n.w-full {\n width: 100%;\n}\n.max-w-70 {\n max-width: calc(var(--spacing) * 70);\n}\n.min-w-0 {\n min-width: 0px;\n}\n.flex-1 {\n flex: 1;\n}\n.shrink-0 {\n flex-shrink: 0;\n}\n.-translate-x-1\\/2 {\n --tw-translate-x: calc(calc(1 / 2 * 100%) * -1);\n translate: var(--tw-translate-x) var(--tw-translate-y);\n}\n.-translate-y-1\\/2 {\n --tw-translate-y: calc(calc(1 / 2 * 100%) * -1);\n translate: var(--tw-translate-x) var(--tw-translate-y);\n}\n.cursor-grab {\n cursor: grab;\n}\n.cursor-pointer {\n cursor: pointer;\n}\n.resize {\n resize: both;\n}\n.resize-none {\n resize: none;\n}\n.appearance-none {\n appearance: none;\n}\n.grid-cols-\\[22px_minmax\\(0\\,1fr\\)\\] {\n grid-template-columns: 22px minmax(0,1fr);\n}\n.grid-cols-\\[82px_minmax\\(0\\,1fr\\)\\] {\n grid-template-columns: 82px minmax(0,1fr);\n}\n.flex-col {\n flex-direction: column;\n}\n.items-center {\n align-items: center;\n}\n.items-start {\n align-items: flex-start;\n}\n.justify-center {\n justify-content: center;\n}\n.gap-0\\.5 {\n gap: calc(var(--spacing) * 0.5);\n}\n.gap-1 {\n gap: var(--spacing);\n}\n.gap-2 {\n gap: calc(var(--spacing) * 2);\n}\n.overflow-auto {\n overflow: auto;\n}\n.overflow-hidden {\n overflow: hidden;\n}\n.overflow-y-hidden {\n overflow-y: hidden;\n}\n.rounded-lg {\n border-radius: var(--t3-radius);\n}\n.rounded-md {\n border-radius: calc(var(--t3-radius) - 2px);\n}\n.rounded-xl {\n border-radius: calc(var(--t3-radius) + 4px);\n}\n.border {\n border-style: var(--tw-border-style);\n border-width: 1px;\n}\n.border-0 {\n border-style: var(--tw-border-style);\n border-width: 0px;\n}\n.border-t {\n border-top-style: var(--tw-border-style);\n border-top-width: 1px;\n}\n.border-b {\n border-bottom-style: var(--tw-border-style);\n border-bottom-width: 1px;\n}\n.border-border {\n border-color: var(--t3-border);\n}\n.border-input {\n border-color: var(--t3-input);\n}\n.border-primary {\n border-color: var(--t3-primary);\n}\n.border-transparent {\n border-color: transparent;\n}\n.border-b-transparent {\n border-bottom-color: transparent;\n}\n.bg-background {\n background-color: var(--t3-background);\n}\n.bg-muted {\n background-color: var(--t3-muted);\n}\n.bg-muted\\/40 {\n background-color: var(--t3-muted);\n @supports (color: color-mix(in lab, red, red)) {\n background-color: color-mix(in oklab, var(--t3-muted) 40%, transparent);\n }\n}\n.bg-popover\\/95 {\n background-color: var(--t3-popover);\n @supports (color: color-mix(in lab, red, red)) {\n background-color: color-mix(in oklab, var(--t3-popover) 95%, transparent);\n }\n}\n.bg-popover\\/96 {\n background-color: var(--t3-popover);\n @supports (color: color-mix(in lab, red, red)) {\n background-color: color-mix(in oklab, var(--t3-popover) 96%, transparent);\n }\n}\n.bg-primary {\n background-color: var(--t3-primary);\n}\n.bg-primary\\/10 {\n background-color: var(--t3-primary);\n @supports (color: color-mix(in lab, red, red)) {\n background-color: color-mix(in oklab, var(--t3-primary) 10%, transparent);\n }\n}\n.bg-transparent {\n background-color: transparent;\n}\n.p-0 {\n padding: 0px;\n}\n.p-1 {\n padding: var(--spacing);\n}\n.p-2 {\n padding: calc(var(--spacing) * 2);\n}\n.px-0 {\n padding-inline: 0px;\n}\n.px-1 {\n padding-inline: var(--spacing);\n}\n.px-2 {\n padding-inline: calc(var(--spacing) * 2);\n}\n.px-2\\.5 {\n padding-inline: calc(var(--spacing) * 2.5);\n}\n.px-3 {\n padding-inline: calc(var(--spacing) * 3);\n}\n.py-1 {\n padding-block: var(--spacing);\n}\n.py-1\\.5 {\n padding-block: calc(var(--spacing) * 1.5);\n}\n.py-2 {\n padding-block: calc(var(--spacing) * 2);\n}\n.font-mono {\n font-family: var(--t3-font-mono);\n}\n.font-sans {\n font-family: var(--t3-font-sans);\n}\n.text-lg {\n font-size: var(--text-lg);\n line-height: var(--tw-leading, var(--text-lg--line-height));\n}\n.text-sm {\n font-size: var(--text-sm);\n line-height: var(--tw-leading, var(--text-sm--line-height));\n}\n.text-xs {\n font-size: var(--text-xs);\n line-height: var(--tw-leading, var(--text-xs--line-height));\n}\n.leading-5 {\n --tw-leading: calc(var(--spacing) * 5);\n line-height: calc(var(--spacing) * 5);\n}\n.font-bold {\n --tw-font-weight: var(--font-weight-bold);\n font-weight: var(--font-weight-bold);\n}\n.font-medium {\n --tw-font-weight: var(--font-weight-medium);\n font-weight: var(--font-weight-medium);\n}\n.font-semibold {\n --tw-font-weight: var(--font-weight-semibold);\n font-weight: var(--font-weight-semibold);\n}\n.text-foreground {\n color: var(--t3-foreground);\n}\n.text-muted-foreground {\n color: var(--t3-muted-foreground);\n}\n.text-popover-foreground {\n color: var(--t3-popover-foreground);\n}\n.text-primary {\n color: var(--t3-primary);\n}\n.text-primary-foreground {\n color: var(--t3-primary-foreground);\n}\n.shadow-2xl {\n --tw-shadow: 0 25px 50px -12px var(--tw-shadow-color, rgb(0 0 0 / 0.25));\n box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);\n}\n.shadow-lg {\n --tw-shadow: 0 10px 15px -3px var(--tw-shadow-color, rgb(0 0 0 / 0.1)), 0 4px 6px -4px var(--tw-shadow-color, rgb(0 0 0 / 0.1));\n box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);\n}\n.shadow-md {\n --tw-shadow: 0 4px 6px -1px var(--tw-shadow-color, rgb(0 0 0 / 0.1)), 0 2px 4px -2px var(--tw-shadow-color, rgb(0 0 0 / 0.1));\n box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);\n}\n.shadow-sm {\n --tw-shadow: 0 1px 3px 0 var(--tw-shadow-color, rgb(0 0 0 / 0.1)), 0 1px 2px -1px var(--tw-shadow-color, rgb(0 0 0 / 0.1));\n box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);\n}\n.shadow-xs {\n --tw-shadow: 0 1px 2px 0 var(--tw-shadow-color, rgb(0 0 0 / 0.05));\n box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);\n}\n.ring-0 {\n --tw-ring-shadow: var(--tw-ring-inset,) 0 0 0 calc(0px + var(--tw-ring-offset-width)) var(--tw-ring-color, currentcolor);\n box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);\n}\n.blur {\n --tw-blur: blur(8px);\n filter: var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,);\n}\n.backdrop-blur-xl {\n --tw-backdrop-blur: blur(var(--blur-xl));\n -webkit-backdrop-filter: var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);\n backdrop-filter: var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);\n}\n.outline-none {\n --tw-outline-style: none;\n outline-style: none;\n}\n.select-none {\n -webkit-user-select: none;\n user-select: none;\n}\n.placeholder\\:text-muted-foreground::placeholder {\n color: var(--t3-muted-foreground);\n}\n@media (hover: hover) {\n .hover\\:bg-accent:hover {\n background-color: var(--t3-accent);\n }\n .hover\\:bg-primary\\/90:hover {\n background-color: var(--t3-primary);\n }\n @supports (color: color-mix(in lab, red, red)) {\n .hover\\:bg-primary\\/90:hover {\n background-color: color-mix(in oklab, var(--t3-primary) 90%, transparent);\n }\n }\n .hover\\:text-accent-foreground:hover {\n color: var(--t3-accent-foreground);\n }\n}\n.focus\\:border-b-primary:focus {\n border-bottom-color: var(--t3-primary);\n}\n.focus\\:ring-0:focus {\n --tw-ring-shadow: var(--tw-ring-inset,) 0 0 0 calc(0px + var(--tw-ring-offset-width)) var(--tw-ring-color, currentcolor);\n box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);\n}\n.focus\\:outline-none:focus {\n --tw-outline-style: none;\n outline-style: none;\n}\n.disabled\\:pointer-events-none:disabled {\n pointer-events: none;\n}\n.disabled\\:opacity-60:disabled {\n opacity: 60%;\n}\n:host {\n --t3-font-sans: "DM Sans Variable", "DM Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui,\n sans-serif;\n --t3-font-mono: "SF Mono", "SFMono-Regular", "JetBrains Mono", Consolas, "Liberation Mono", Menlo, monospace;\n --t3-radius: 0.625rem;\n --t3-background: white;\n --t3-foreground: oklch(0.269 0 0);\n --t3-popover: white;\n --t3-popover-foreground: oklch(0.269 0 0);\n --t3-primary: oklch(0.488 0.217 264);\n --t3-primary-foreground: white;\n --t3-muted: rgb(0 0 0 / 4%);\n --t3-muted-foreground: oklch(0.556 0 0);\n --t3-accent: rgb(0 0 0 / 4%);\n --t3-accent-foreground: oklch(0.269 0 0);\n --t3-border: rgb(0 0 0 / 8%);\n --t3-input: rgb(0 0 0 / 10%);\n --t3-ring: oklch(0.488 0.217 264);\n color: var(--t3-foreground);\n font-family: var(--t3-font-sans);\n}\n* {\n box-sizing: border-box;\n border-color: var(--t3-border);\n}\nbutton, input, select, textarea {\n font: inherit;\n}\nbutton:focus-visible, input:focus-visible, select:focus-visible, textarea:focus-visible {\n outline: 2px solid var(--t3-ring);\n @supports (color: color-mix(in lab, red, red)) {\n outline: 2px solid color-mix(in srgb, var(--t3-ring) 72%, transparent);\n }\n outline-offset: -2px;\n}\n@property --tw-translate-x {\n syntax: "*";\n inherits: false;\n initial-value: 0;\n}\n@property --tw-translate-y {\n syntax: "*";\n inherits: false;\n initial-value: 0;\n}\n@property --tw-translate-z {\n syntax: "*";\n inherits: false;\n initial-value: 0;\n}\n@property --tw-border-style {\n syntax: "*";\n inherits: false;\n initial-value: solid;\n}\n@property --tw-leading {\n syntax: "*";\n inherits: false;\n}\n@property --tw-font-weight {\n syntax: "*";\n inherits: false;\n}\n@property --tw-shadow {\n syntax: "*";\n inherits: false;\n initial-value: 0 0 #0000;\n}\n@property --tw-shadow-color {\n syntax: "*";\n inherits: false;\n}\n@property --tw-shadow-alpha {\n syntax: "<percentage>";\n inherits: false;\n initial-value: 100%;\n}\n@property --tw-inset-shadow {\n syntax: "*";\n inherits: false;\n initial-value: 0 0 #0000;\n}\n@property --tw-inset-shadow-color {\n syntax: "*";\n inherits: false;\n}\n@property --tw-inset-shadow-alpha {\n syntax: "<percentage>";\n inherits: false;\n initial-value: 100%;\n}\n@property --tw-ring-color {\n syntax: "*";\n inherits: false;\n}\n@property --tw-ring-shadow {\n syntax: "*";\n inherits: false;\n initial-value: 0 0 #0000;\n}\n@property --tw-inset-ring-color {\n syntax: "*";\n inherits: false;\n}\n@property --tw-inset-ring-shadow {\n syntax: "*";\n inherits: false;\n initial-value: 0 0 #0000;\n}\n@property --tw-ring-inset {\n syntax: "*";\n inherits: false;\n}\n@property --tw-ring-offset-width {\n syntax: "<length>";\n inherits: false;\n initial-value: 0px;\n}\n@property --tw-ring-offset-color {\n syntax: "*";\n inherits: false;\n initial-value: #fff;\n}\n@property --tw-ring-offset-shadow {\n syntax: "*";\n inherits: false;\n initial-value: 0 0 #0000;\n}\n@property --tw-blur {\n syntax: "*";\n inherits: false;\n}\n@property --tw-brightness {\n syntax: "*";\n inherits: false;\n}\n@property --tw-contrast {\n syntax: "*";\n inherits: false;\n}\n@property --tw-grayscale {\n syntax: "*";\n inherits: false;\n}\n@property --tw-hue-rotate {\n syntax: "*";\n inherits: false;\n}\n@property --tw-invert {\n syntax: "*";\n inherits: false;\n}\n@property --tw-opacity {\n syntax: "*";\n inherits: false;\n}\n@property --tw-saturate {\n syntax: "*";\n inherits: false;\n}\n@property --tw-sepia {\n syntax: "*";\n inherits: false;\n}\n@property --tw-drop-shadow {\n syntax: "*";\n inherits: false;\n}\n@property --tw-drop-shadow-color {\n syntax: "*";\n inherits: false;\n}\n@property --tw-drop-shadow-alpha {\n syntax: "<percentage>";\n inherits: false;\n initial-value: 100%;\n}\n@property --tw-drop-shadow-size {\n syntax: "*";\n inherits: false;\n}\n@property --tw-backdrop-blur {\n syntax: "*";\n inherits: false;\n}\n@property --tw-backdrop-brightness {\n syntax: "*";\n inherits: false;\n}\n@property --tw-backdrop-contrast {\n syntax: "*";\n inherits: false;\n}\n@property --tw-backdrop-grayscale {\n syntax: "*";\n inherits: false;\n}\n@property --tw-backdrop-hue-rotate {\n syntax: "*";\n inherits: false;\n}\n@property --tw-backdrop-invert {\n syntax: "*";\n inherits: false;\n}\n@property --tw-backdrop-opacity {\n syntax: "*";\n inherits: false;\n}\n@property --tw-backdrop-saturate {\n syntax: "*";\n inherits: false;\n}\n@property --tw-backdrop-sepia {\n syntax: "*";\n inherits: false;\n}\n@layer properties {\n @supports ((-webkit-hyphens: none) and (not (margin-trim: inline))) or ((-moz-orient: inline) and (not (color:rgb(from red r g b)))) {\n *, ::before, ::after, ::backdrop {\n --tw-translate-x: 0;\n --tw-translate-y: 0;\n --tw-translate-z: 0;\n --tw-border-style: solid;\n --tw-leading: initial;\n --tw-font-weight: initial;\n --tw-shadow: 0 0 #0000;\n --tw-shadow-color: initial;\n --tw-shadow-alpha: 100%;\n --tw-inset-shadow: 0 0 #0000;\n --tw-inset-shadow-color: initial;\n --tw-inset-shadow-alpha: 100%;\n --tw-ring-color: initial;\n --tw-ring-shadow: 0 0 #0000;\n --tw-inset-ring-color: initial;\n --tw-inset-ring-shadow: 0 0 #0000;\n --tw-ring-inset: initial;\n --tw-ring-offset-width: 0px;\n --tw-ring-offset-color: #fff;\n --tw-ring-offset-shadow: 0 0 #0000;\n --tw-blur: initial;\n --tw-brightness: initial;\n --tw-contrast: initial;\n --tw-grayscale: initial;\n --tw-hue-rotate: initial;\n --tw-invert: initial;\n --tw-opacity: initial;\n --tw-saturate: initial;\n --tw-sepia: initial;\n --tw-drop-shadow: initial;\n --tw-drop-shadow-color: initial;\n --tw-drop-shadow-alpha: 100%;\n --tw-drop-shadow-size: initial;\n --tw-backdrop-blur: initial;\n --tw-backdrop-brightness: initial;\n --tw-backdrop-contrast: initial;\n --tw-backdrop-grayscale: initial;\n --tw-backdrop-hue-rotate: initial;\n --tw-backdrop-invert: initial;\n --tw-backdrop-opacity: initial;\n --tw-backdrop-saturate: initial;\n --tw-backdrop-sepia: initial;\n }\n }\n}\n'; |
apps/desktop/src/preview/PickPreload.ts+46-6| ... | @@ -316,12 +316,43 @@ function createBox(color: string, fill: string): HTMLDivElement { | ... | @@ -316,12 +316,43 @@ function createBox(color: string, fill: string): HTMLDivElement { |
| 316 | } | 316 | } |
| 317 | 317 | ||
| 318 | function positionBox(node: HTMLElement, rect: PreviewAnnotationRect): void { | 318 | function positionBox(node: HTMLElement, rect: PreviewAnnotationRect): void { |
| 319 | if (rect.width <= 0 || rect.height <= 0) { | ||
| 320 | node.style.display = "none"; | ||
| 321 | return; | ||
| 322 | } | ||
| 319 | node.style.display = "block"; | 323 | node.style.display = "block"; |
| 320 | node.style.transform = `translate(${rect.x}px, ${rect.y}px)`; | 324 | node.style.transform = `translate(${rect.x}px, ${rect.y}px)`; |
| 321 | node.style.width = `${rect.width}px`; | 325 | node.style.width = `${rect.width}px`; |
| 322 | node.style.height = `${rect.height}px`; | 326 | node.style.height = `${rect.height}px`; |
| 323 | } | 327 | } |
| 324 | 328 | ||
| 329 | /** Clamps a box to the viewport and clipping ancestors, so its border is never painted off-screen. */ | ||
| 330 | function visibleElementRect(element: Element): PreviewAnnotationRect { | ||
| 331 | const rect = element.getBoundingClientRect(); | ||
| 332 | let left = Math.max(0, rect.left); | ||
| 333 | let top = Math.max(0, rect.top); | ||
| 334 | let right = Math.min(document.documentElement.clientWidth, rect.right); | ||
| 335 | let bottom = Math.min(document.documentElement.clientHeight, rect.bottom); | ||
| 336 | if (getComputedStyle(element).position !== "fixed") { | ||
| 337 | for (let ancestor = element.parentElement; ancestor; ancestor = ancestor.parentElement) { | ||
| 338 | if (ancestor === document.body || ancestor === document.documentElement) break; | ||
| 339 | const style = getComputedStyle(ancestor); | ||
| 340 | const bounds = ancestor.getBoundingClientRect(); | ||
| 341 | const clipLeft = bounds.left + ancestor.clientLeft; | ||
| 342 | const clipTop = bounds.top + ancestor.clientTop; | ||
| 343 | if (style.overflowX !== "visible") { | ||
| 344 | left = Math.max(left, clipLeft); | ||
| 345 | right = Math.min(right, clipLeft + ancestor.clientWidth); | ||
| 346 | } | ||
| 347 | if (style.overflowY !== "visible") { | ||
| 348 | top = Math.max(top, clipTop); | ||
| 349 | bottom = Math.min(bottom, clipTop + ancestor.clientHeight); | ||
| 350 | } | ||
| 351 | } | ||
| 352 | } | ||
| 353 | return { x: left, y: top, width: Math.max(0, right - left), height: Math.max(0, bottom - top) }; | ||
| 354 | } | ||
| 355 | |||
| 325 | function createLabel(): HTMLDivElement { | 356 | function createLabel(): HTMLDivElement { |
| 326 | const label = document.createElement("div"); | 357 | const label = document.createElement("div"); |
| 327 | label.setAttribute(OVERLAY_ATTRIBUTE, ""); | 358 | label.setAttribute(OVERLAY_ATTRIBUTE, ""); |
| ... | @@ -343,11 +374,15 @@ function updateSelectedVisual(target: SelectedElement): void { | ... | @@ -343,11 +374,15 @@ function updateSelectedVisual(target: SelectedElement): void { |
| 343 | target.label.style.display = "none"; | 374 | target.label.style.display = "none"; |
| 344 | return; | 375 | return; |
| 345 | } | 376 | } |
| 346 | const rect = target.element.getBoundingClientRect(); | 377 | const rect = visibleElementRect(target.element); |
| 347 | positionBox(target.outline, rectFromDomRect(rect)); | 378 | positionBox(target.outline, rect); |
| 379 | if (rect.width === 0 || rect.height === 0) { | ||
| 380 | target.label.style.display = "none"; | ||
| 381 | return; | ||
| 382 | } | ||
| 348 | target.label.textContent = describeRawElement(target.element); | 383 | target.label.textContent = describeRawElement(target.element); |
| 349 | target.label.style.display = "block"; | 384 | target.label.style.display = "block"; |
| 350 | target.label.style.transform = `translate(${Math.max(4, rect.left)}px, ${Math.max(4, rect.top - 22)}px)`; | 385 | target.label.style.transform = `translate(${Math.max(4, rect.x)}px, ${Math.max(4, rect.y - 22)}px)`; |
| 351 | } | 386 | } |
| 352 | 387 | ||
| 353 | function toStackFrame(frame: { | 388 | function toStackFrame(frame: { |
| ... | @@ -995,8 +1030,9 @@ function startAnnotation(sendEnabled: boolean): void { | ... | @@ -995,8 +1030,9 @@ function startAnnotation(sendEnabled: boolean): void { |
| 995 | const getAnnotationBounds = (): PreviewAnnotationRect | null => | 1030 | const getAnnotationBounds = (): PreviewAnnotationRect | null => |
| 996 | unionRects( | 1031 | unionRects( |
| 997 | [ | 1032 | [ |
| 998 | ...Array.from(selected.values(), (target) => | 1033 | // Follow the visible outline, so a clipped selection does not anchor the editor off-screen. |
| 999 | rectFromDomRect(target.element.getBoundingClientRect()), | 1034 | ...Array.from(selected.values(), (target) => visibleElementRect(target.element)).filter( |
| 1035 | (rect) => rect.width > 0 && rect.height > 0, | ||
| 1000 | ), | 1036 | ), |
| 1001 | ...regions.map((region) => region.rect), | 1037 | ...regions.map((region) => region.rect), |
| 1002 | ...strokes.map((stroke) => stroke.bounds), | 1038 | ...strokes.map((stroke) => stroke.bounds), |
| ... | @@ -1108,6 +1144,8 @@ function startAnnotation(sendEnabled: boolean): void { | ... | @@ -1108,6 +1144,8 @@ function startAnnotation(sendEnabled: boolean): void { |
| 1108 | for (const target of selected.values()) updateSelectedVisual(target); | 1144 | for (const target of selected.values()) updateSelectedVisual(target); |
| 1109 | queueEditorLayout(); | 1145 | queueEditorLayout(); |
| 1110 | }; | 1146 | }; |
| 1147 | // A scrollbar appearing narrows the viewport without a window resize. | ||
| 1148 | const rootResizeObserver = new ResizeObserver(repaint); | ||
| 1111 | 1149 | ||
| 1112 | const removeTargetAtPoint = (x: number, y: number): boolean => { | 1150 | const removeTargetAtPoint = (x: number, y: number): boolean => { |
| 1113 | for (const target of Array.from(selected.values()).toReversed()) { | 1151 | for (const target of Array.from(selected.values()).toReversed()) { |
| ... | @@ -1192,7 +1230,7 @@ function startAnnotation(sendEnabled: boolean): void { | ... | @@ -1192,7 +1230,7 @@ function startAnnotation(sendEnabled: boolean): void { |
| 1192 | } | 1230 | } |
| 1193 | if (tool === "select" && dragStart === null) { | 1231 | if (tool === "select" && dragStart === null) { |
| 1194 | const target = pickFromPoint(event.clientX, event.clientY); | 1232 | const target = pickFromPoint(event.clientX, event.clientY); |
| 1195 | if (target) positionBox(hoverOutline, rectFromDomRect(target.getBoundingClientRect())); | 1233 | if (target) positionBox(hoverOutline, visibleElementRect(target)); |
| 1196 | else clearHoverOutline(); | 1234 | else clearHoverOutline(); |
| 1197 | return; | 1235 | return; |
| 1198 | } | 1236 | } |
| ... | @@ -1310,6 +1348,7 @@ function startAnnotation(sendEnabled: boolean): void { | ... | @@ -1310,6 +1348,7 @@ function startAnnotation(sendEnabled: boolean): void { |
| 1310 | const teardown = (notifyMain: boolean): void => { | 1348 | const teardown = (notifyMain: boolean): void => { |
| 1311 | if (finished) return; | 1349 | if (finished) return; |
| 1312 | finished = true; | 1350 | finished = true; |
| 1351 | rootResizeObserver.disconnect(); | ||
| 1313 | restoreStyles(); | 1352 | restoreStyles(); |
| 1314 | window.removeEventListener("pointermove", onPointerMove, true); | 1353 | window.removeEventListener("pointermove", onPointerMove, true); |
| 1315 | window.removeEventListener("pointerdown", onPointerDown, true); | 1354 | window.removeEventListener("pointerdown", onPointerDown, true); |
| ... | @@ -1445,6 +1484,7 @@ function startAnnotation(sendEnabled: boolean): void { | ... | @@ -1445,6 +1484,7 @@ function startAnnotation(sendEnabled: boolean): void { |
| 1445 | ipcRenderer.on(CANCEL_PICK_CHANNEL, onCancel); | 1484 | ipcRenderer.on(CANCEL_PICK_CHANNEL, onCancel); |
| 1446 | ipcRenderer.on(ANNOTATION_CAPTURED_CHANNEL, onCaptured); | 1485 | ipcRenderer.on(ANNOTATION_CAPTURED_CHANNEL, onCaptured); |
| 1447 | document.documentElement.appendChild(host); | 1486 | document.documentElement.appendChild(host); |
| 1487 | rootResizeObserver.observe(document.documentElement); | ||
| 1448 | refreshToolButtons(); | 1488 | refreshToolButtons(); |
| 1449 | updateStatus(); | 1489 | updateStatus(); |
| 1450 | activeSession = { | 1490 | activeSession = { |
apps/server/src/htmlRender/HtmlRender.test.ts+4-1| ... | @@ -244,10 +244,12 @@ describe("HtmlRender", () => { | ... | @@ -244,10 +244,12 @@ describe("HtmlRender", () => { |
| 244 | const htmlRender = yield* HtmlRender.HtmlRender; | 244 | const htmlRender = yield* HtmlRender.HtmlRender; |
| 245 | const preview = yield* htmlRender.preview({ | 245 | const preview = yield* htmlRender.preview({ |
| 246 | html: [ | 246 | html: [ |
| 247 | '<!doctype html><html><head></head><body><div style="height:300px;background:var(--accent)"></div>', | 247 | '<!doctype html><html><head></head><body><div id="page" tabindex="0" style="height:300px;background:var(--accent)"></div>', |
| 248 | '<img src="/nonexistent/t3-missing.png" hidden>', | 248 | '<img src="/nonexistent/t3-missing.png" hidden>', |
| 249 | "<script>", | 249 | "<script>", |
| 250 | "const root = getComputedStyle(document.documentElement);", | 250 | "const root = getComputedStyle(document.documentElement);", |
| 251 | 'const page = document.getElementById("page"); page.focus();', | ||
| 252 | 'const focus = getComputedStyle(page); console.log("focus", focus.outlineWidth, focus.outlineOffset, page.getBoundingClientRect().width, document.documentElement.scrollWidth);', | ||
| 251 | 'console.log("ready", 3); console.info(root.getPropertyValue("--font-sans"));', | 253 | 'console.log("ready", 3); console.info(root.getPropertyValue("--font-sans"));', |
| 252 | 'console.warn(root.getPropertyValue("--background")); console.error("boom");', | 254 | 'console.warn(root.getPropertyValue("--background")); console.error("boom");', |
| 253 | "</script>", | 255 | "</script>", |
| ... | @@ -271,6 +273,7 @@ describe("HtmlRender", () => { | ... | @@ -271,6 +273,7 @@ describe("HtmlRender", () => { |
| 271 | expect(preview.consoleMessages).toEqual( | 273 | expect(preview.consoleMessages).toEqual( |
| 272 | expect.arrayContaining([ | 274 | expect.arrayContaining([ |
| 273 | { level: "log", text: "ready 3" }, | 275 | { level: "log", text: "ready 3" }, |
| 276 | { level: "log", text: "focus 2px -2px 400 400" }, | ||
| 274 | { level: "info", text: HTML_RENDER_MEASURE_FONTS.sans }, | 277 | { level: "info", text: HTML_RENDER_MEASURE_FONTS.sans }, |
| 275 | { | 278 | { |
| 276 | level: "warning", | 279 | level: "warning", |
apps/web/src/components/ContextChip.tsx+2-2| ... | @@ -23,7 +23,7 @@ import { cn } from "~/lib/utils"; | ... | @@ -23,7 +23,7 @@ import { cn } from "~/lib/utils"; |
| 23 | * span with tabIndex for a tooltip) gets the focus outline. | 23 | * span with tabIndex for a tooltip) gets the focus outline. |
| 24 | */ | 24 | */ |
| 25 | const contextChipVariants = cva( | 25 | const contextChipVariants = cva( |
| 26 | "inline-flex h-[1.41em] max-w-full items-center gap-[0.33em] rounded-[0.5em] border px-[0.5em] align-middle font-medium text-[0.86em] leading-none [&_svg]:block [&_svg]:size-[1.17em] [&_svg]:shrink-0 [&_svg]:self-center [button&,a&,[data-popup-open]&]:cursor-pointer [button&,a&]:transition-colors [button&,a&]:motion-reduce:transition-none focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-foreground disabled:cursor-default", | 26 | "inline-flex h-[1.41em] max-w-full items-center gap-[0.33em] rounded-[0.5em] border px-[0.5em] align-middle font-medium text-[0.86em] leading-none [&_svg]:block [&_svg]:size-[1.17em] [&_svg]:shrink-0 [&_svg]:self-center [button&,a&,[data-popup-open]&]:cursor-pointer [button&,a&]:transition-colors [button&,a&]:motion-reduce:transition-none focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-foreground disabled:cursor-default", |
| 27 | { | 27 | { |
| 28 | defaultVariants: { kind: "neutral" }, | 28 | defaultVariants: { kind: "neutral" }, |
| 29 | variants: { | 29 | variants: { |
| ... | @@ -117,7 +117,7 @@ function ContextChipLabel({ className, ...props }: React.ComponentProps<"span">) | ... | @@ -117,7 +117,7 @@ function ContextChipLabel({ className, ...props }: React.ComponentProps<"span">) |
| 117 | function ContextChipAction({ className, render, ...props }: useRender.ComponentProps<"button">) { | 117 | function ContextChipAction({ className, render, ...props }: useRender.ComponentProps<"button">) { |
| 118 | const defaultProps = { | 118 | const defaultProps = { |
| 119 | className: cn( | 119 | className: cn( |
| 120 | "ml-[0.17em] inline-flex size-[1.17em] shrink-0 cursor-pointer items-center justify-center rounded-sm text-current transition-colors hover:bg-(--context-chip-accent,var(--color-foreground))/17 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring motion-reduce:transition-none [&_svg]:size-[0.85em]", | 120 | "ml-[0.17em] inline-flex size-[1.17em] shrink-0 cursor-pointer items-center justify-center rounded-sm text-current transition-colors hover:bg-(--context-chip-accent,var(--color-foreground))/17 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-inset focus-visible:ring-ring motion-reduce:transition-none [&_svg]:size-[0.85em]", |
| 121 | className, | 121 | className, |
| 122 | ), | 122 | ), |
| 123 | "data-slot": "context-chip-action", | 123 | "data-slot": "context-chip-action", |
apps/web/src/components/GitActionsControl.tsx+5-5| ... | @@ -793,9 +793,9 @@ function PublishRepositoryDialog(props: PublishRepositoryDialogProps) { | ... | @@ -793,9 +793,9 @@ function PublishRepositoryDialog(props: PublishRepositoryDialogProps) { |
| 793 | value={option.value} | 793 | value={option.value} |
| 794 | className={cn( | 794 | className={cn( |
| 795 | "relative flex cursor-pointer items-center gap-3 rounded-lg border px-3 py-3 text-left outline-none transition-[background-color,border-color,box-shadow]", | 795 | "relative flex cursor-pointer items-center gap-3 rounded-lg border px-3 py-3 text-left outline-none transition-[background-color,border-color,box-shadow]", |
| 796 | "focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:ring-offset-background", | 796 | "focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:ring-offset-background", |
| 797 | isSelected | 797 | isSelected |
| 798 | ? "border-primary bg-background shadow-sm ring-2 ring-primary/35 dark:border-transparent dark:bg-primary/10 dark:shadow-none dark:ring-1 dark:ring-primary/30" | 798 | ? "border-primary bg-background shadow-sm ring-2 ring-inset ring-primary/35 dark:border-transparent dark:bg-primary/10 dark:shadow-none dark:ring-1 dark:ring-primary/30" |
| 799 | : "border-border bg-background hover:border-foreground/20 hover:bg-muted/50 dark:border-transparent dark:bg-white/[0.035] dark:hover:bg-accent", | 799 | : "border-border bg-background hover:border-foreground/20 hover:bg-muted/50 dark:border-transparent dark:bg-white/[0.035] dark:hover:bg-accent", |
| 800 | )} | 800 | )} |
| 801 | > | 801 | > |
| ... | @@ -817,7 +817,7 @@ function PublishRepositoryDialog(props: PublishRepositoryDialogProps) { | ... | @@ -817,7 +817,7 @@ function PublishRepositoryDialog(props: PublishRepositoryDialogProps) { |
| 817 | > | 817 | > |
| 818 | Repository | 818 | Repository |
| 819 | </label> | 819 | </label> |
| 820 | <div className="flex items-stretch overflow-hidden rounded-md border border-input bg-background focus-within:outline-2 focus-within:-outline-offset-1 focus-within:outline-ring"> | 820 | <div className="flex items-stretch overflow-hidden rounded-md border border-input bg-background focus-within:outline-2 focus-within:-outline-offset-2 focus-within:outline-ring"> |
| 821 | <span className="flex shrink-0 items-center gap-1.5 border-r border-input bg-muted/50 px-2.5 font-mono text-xs text-muted-foreground"> | 821 | <span className="flex shrink-0 items-center gap-1.5 border-r border-input bg-muted/50 px-2.5 font-mono text-xs text-muted-foreground"> |
| 822 | <currentPublishProvider.Icon className="size-3.5" /> | 822 | <currentPublishProvider.Icon className="size-3.5" /> |
| 823 | {publishHost}/ | 823 | {publishHost}/ |
| ... | @@ -879,9 +879,9 @@ function PublishRepositoryDialog(props: PublishRepositoryDialogProps) { | ... | @@ -879,9 +879,9 @@ function PublishRepositoryDialog(props: PublishRepositoryDialogProps) { |
| 879 | value={option.value} | 879 | value={option.value} |
| 880 | className={cn( | 880 | className={cn( |
| 881 | "relative flex cursor-pointer items-center gap-3 rounded-lg border px-3 py-2.5 text-left outline-none transition-[background-color,border-color,box-shadow]", | 881 | "relative flex cursor-pointer items-center gap-3 rounded-lg border px-3 py-2.5 text-left outline-none transition-[background-color,border-color,box-shadow]", |
| 882 | "focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:ring-offset-background", | 882 | "focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:ring-offset-background", |
| 883 | isSelected | 883 | isSelected |
| 884 | ? "border-primary bg-background shadow-sm ring-2 ring-primary/35 dark:border-transparent dark:bg-primary/10 dark:shadow-none dark:ring-1 dark:ring-primary/30" | 884 | ? "border-primary bg-background shadow-sm ring-2 ring-inset ring-primary/35 dark:border-transparent dark:bg-primary/10 dark:shadow-none dark:ring-1 dark:ring-primary/30" |
| 885 | : "border-border bg-background hover:border-foreground/20 hover:bg-muted/50 dark:border-transparent dark:bg-white/[0.035] dark:hover:bg-accent", | 885 | : "border-border bg-background hover:border-foreground/20 hover:bg-muted/50 dark:border-transparent dark:bg-white/[0.035] dark:hover:bg-accent", |
| 886 | )} | 886 | )} |
| 887 | > | 887 | > |
apps/web/src/components/LegacySidebar.tsx+5-5| ... | @@ -246,7 +246,7 @@ const PROJECT_GROUPING_MODE_LABELS: Record<SidebarProjectGroupingMode, string> = | ... | @@ -246,7 +246,7 @@ const PROJECT_GROUPING_MODE_LABELS: Record<SidebarProjectGroupingMode, string> = |
| 246 | separate: "Keep separate", | 246 | separate: "Keep separate", |
| 247 | }; | 247 | }; |
| 248 | const SIDEBAR_ICON_ACTION_BUTTON_CLASS = | 248 | const SIDEBAR_ICON_ACTION_BUTTON_CLASS = |
| 249 | "inline-flex h-6 min-w-6 cursor-pointer items-center justify-center rounded-md px-0.75 text-icon-muted hover:text-foreground focus-visible:outline-hidden focus-visible:ring-1 focus-visible:ring-ring"; | 249 | "inline-flex h-6 min-w-6 cursor-pointer items-center justify-center rounded-md px-0.75 text-icon-muted hover:text-foreground focus-visible:outline-hidden focus-visible:ring-1 focus-visible:ring-inset focus-visible:ring-ring"; |
| 250 | 250 | ||
| 251 | function SidebarThreadDetailPrewarmer({ threadRef }: { readonly threadRef: ScopedThreadRef }) { | 251 | function SidebarThreadDetailPrewarmer({ threadRef }: { readonly threadRef: ScopedThreadRef }) { |
| 252 | useEnvironmentThread(threadRef.environmentId, threadRef.threadId); | 252 | useEnvironmentThread(threadRef.environmentId, threadRef.threadId); |
| ... | @@ -769,7 +769,7 @@ const SidebarThreadRow = memo(function SidebarThreadRow(props: SidebarThreadRowP | ... | @@ -769,7 +769,7 @@ const SidebarThreadRow = memo(function SidebarThreadRow(props: SidebarThreadRowP |
| 769 | target="_blank" | 769 | target="_blank" |
| 770 | rel="noopener noreferrer" | 770 | rel="noopener noreferrer" |
| 771 | aria-label={prStatus.tooltip} | 771 | aria-label={prStatus.tooltip} |
| 772 | className={`inline-flex items-center justify-center ${prStatus.colorClass} cursor-pointer rounded-sm outline-hidden focus-visible:ring-1 focus-visible:ring-ring`} | 772 | className={`inline-flex items-center justify-center ${prStatus.colorClass} cursor-pointer rounded-sm outline-hidden focus-visible:ring-1 focus-visible:ring-inset focus-visible:ring-ring`} |
| 773 | onPointerDown={(event) => event.stopPropagation()} | 773 | onPointerDown={(event) => event.stopPropagation()} |
| 774 | onClick={handlePrClick} | 774 | onClick={handlePrClick} |
| 775 | > | 775 | > |
| ... | @@ -835,7 +835,7 @@ const SidebarThreadRow = memo(function SidebarThreadRow(props: SidebarThreadRowP | ... | @@ -835,7 +835,7 @@ const SidebarThreadRow = memo(function SidebarThreadRow(props: SidebarThreadRowP |
| 835 | <button | 835 | <button |
| 836 | type="button" | 836 | type="button" |
| 837 | aria-label={`Open localhost:${discoveredPorts[0]?.port ?? ""}`} | 837 | aria-label={`Open localhost:${discoveredPorts[0]?.port ?? ""}`} |
| 838 | className="inline-flex cursor-pointer items-center justify-center text-success-foreground outline-hidden focus-visible:ring-1 focus-visible:ring-ring" | 838 | className="inline-flex cursor-pointer items-center justify-center text-success-foreground outline-hidden focus-visible:ring-1 focus-visible:ring-inset focus-visible:ring-ring" |
| 839 | onClick={handleOpenDiscoveredPort} | 839 | onClick={handleOpenDiscoveredPort} |
| 840 | /> | 840 | /> |
| 841 | } | 841 | } |
| ... | @@ -880,7 +880,7 @@ const SidebarThreadRow = memo(function SidebarThreadRow(props: SidebarThreadRowP | ... | @@ -880,7 +880,7 @@ const SidebarThreadRow = memo(function SidebarThreadRow(props: SidebarThreadRowP |
| 880 | data-thread-selection-safe | 880 | data-thread-selection-safe |
| 881 | data-testid={`thread-archive-confirm-${thread.id}`} | 881 | data-testid={`thread-archive-confirm-${thread.id}`} |
| 882 | aria-label={`Confirm archive ${thread.title}`} | 882 | aria-label={`Confirm archive ${thread.title}`} |
| 883 | className="absolute top-1/2 right-1 inline-flex h-5 -translate-y-1/2 cursor-pointer items-center rounded-md bg-destructive/12 px-2 text-3xs font-medium text-destructive transition-colors hover:bg-destructive/18 focus-visible:outline-hidden focus-visible:ring-1 focus-visible:ring-destructive/40" | 883 | className="absolute top-1/2 right-1 inline-flex h-5 -translate-y-1/2 cursor-pointer items-center rounded-md bg-destructive/12 px-2 text-3xs font-medium text-destructive transition-colors hover:bg-destructive/18 focus-visible:outline-hidden focus-visible:ring-1 focus-visible:ring-inset focus-visible:ring-destructive/40" |
| 884 | onPointerDown={stopPropagationOnPointerDown} | 884 | onPointerDown={stopPropagationOnPointerDown} |
| 885 | onClick={handleConfirmArchiveClick} | 885 | onClick={handleConfirmArchiveClick} |
| 886 | > | 886 | > |
| ... | @@ -2955,7 +2955,7 @@ function SortableProjectItem({ | ... | @@ -2955,7 +2955,7 @@ function SortableProjectItem({ |
| 2955 | }} | 2955 | }} |
| 2956 | className={`group/menu-item relative rounded-md ${ | 2956 | className={`group/menu-item relative rounded-md ${ |
| 2957 | isDragging ? "z-20 opacity-80" : "" | 2957 | isDragging ? "z-20 opacity-80" : "" |
| 2958 | } ${isOver && !isDragging ? "ring-1 ring-primary/40" : ""}`} | 2958 | } ${isOver && !isDragging ? "ring-1 ring-inset ring-primary/40" : ""}`} |
| 2959 | data-sidebar="menu-item" | 2959 | data-sidebar="menu-item" |
| 2960 | data-slot="sidebar-menu-item" | 2960 | data-slot="sidebar-menu-item" |
| 2961 | > | 2961 | > |
apps/web/src/components/RightPanelTabs.tsx+1-1| ... | @@ -1193,7 +1193,7 @@ export function RightPanelTabs(props: RightPanelTabsProps) { | ... | @@ -1193,7 +1193,7 @@ export function RightPanelTabs(props: RightPanelTabsProps) { |
| 1193 | {renamingDevice === surface.id ? ( | 1193 | {renamingDevice === surface.id ? ( |
| 1194 | <input | 1194 | <input |
| 1195 | aria-label="Device tab name" | 1195 | aria-label="Device tab name" |
| 1196 | className="w-24 min-w-0 rounded-sm bg-background px-1 outline-none ring-1 ring-ring" | 1196 | className="w-24 min-w-0 rounded-sm bg-background px-1 outline-none ring-1 ring-inset ring-ring" |
| 1197 | defaultValue={title} | 1197 | defaultValue={title} |
| 1198 | ref={(element) => { | 1198 | ref={(element) => { |
| 1199 | element?.focus(); | 1199 | element?.focus(); |
apps/web/src/components/Sidebar.tsx+3-3| ... | @@ -1763,7 +1763,7 @@ const SidebarThreadRow = memo(function SidebarThreadRow(props: { | ... | @@ -1763,7 +1763,7 @@ const SidebarThreadRow = memo(function SidebarThreadRow(props: { |
| 1763 | type="button" | 1763 | type="button" |
| 1764 | aria-label="Unpin thread" | 1764 | aria-label="Unpin thread" |
| 1765 | onClick={handleUnpinClick} | 1765 | onClick={handleUnpinClick} |
| 1766 | className="group/unpin inline-flex cursor-pointer items-center rounded-sm text-muted-foreground/65 outline-none transition-colors hover:text-foreground focus-visible:ring-2 focus-visible:ring-ring" | 1766 | className="group/unpin inline-flex cursor-pointer items-center rounded-sm text-muted-foreground/65 outline-none transition-colors hover:text-foreground focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring" |
| 1767 | /> | 1767 | /> |
| 1768 | } | 1768 | } |
| 1769 | > | 1769 | > |
| ... | @@ -1876,7 +1876,7 @@ const SidebarThreadRow = memo(function SidebarThreadRow(props: { | ... | @@ -1876,7 +1876,7 @@ const SidebarThreadRow = memo(function SidebarThreadRow(props: { |
| 1876 | type="button" | 1876 | type="button" |
| 1877 | aria-label="Dismiss Woke notification" | 1877 | aria-label="Dismiss Woke notification" |
| 1878 | onClick={handleAcknowledgeWokeClick} | 1878 | onClick={handleAcknowledgeWokeClick} |
| 1879 | className="inline-flex cursor-pointer items-center gap-1 rounded-sm text-xs font-medium text-warning-foreground outline-none hover:underline focus-visible:ring-2 focus-visible:ring-ring" | 1879 | className="inline-flex cursor-pointer items-center gap-1 rounded-sm text-xs font-medium text-warning-foreground outline-none hover:underline focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring" |
| 1880 | > | 1880 | > |
| 1881 | <AlarmClockIcon aria-hidden className="size-3" /> | 1881 | <AlarmClockIcon aria-hidden className="size-3" /> |
| 1882 | <span role="status">Woke</span> | 1882 | <span role="status">Woke</span> |
| ... | @@ -2040,7 +2040,7 @@ const SidebarThreadRow = memo(function SidebarThreadRow(props: { | ... | @@ -2040,7 +2040,7 @@ const SidebarThreadRow = memo(function SidebarThreadRow(props: { |
| 2040 | aria-label="Dismiss Woke notification" | 2040 | aria-label="Dismiss Woke notification" |
| 2041 | onClick={handleAcknowledgeWokeClick} | 2041 | onClick={handleAcknowledgeWokeClick} |
| 2042 | className={cn( | 2042 | className={cn( |
| 2043 | "inline-flex cursor-pointer items-center gap-1 rounded-sm font-medium outline-none hover:underline focus-visible:ring-2 focus-visible:ring-ring", | 2043 | "inline-flex cursor-pointer items-center gap-1 rounded-sm font-medium outline-none hover:underline focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring", |
| 2044 | topStatus.className, | 2044 | topStatus.className, |
| 2045 | )} | 2045 | )} |
| 2046 | > | 2046 | > |
apps/web/src/components/auth/ConnectAgentSurface.tsx+2-2| ... | @@ -311,9 +311,9 @@ function AccessOption({ | ... | @@ -311,9 +311,9 @@ function AccessOption({ |
| 311 | value={access} | 311 | value={access} |
| 312 | className={cn( | 312 | className={cn( |
| 313 | "flex cursor-pointer items-start gap-3 rounded-lg border px-3 py-2.5 text-left outline-none transition-[background-color,border-color,box-shadow]", | 313 | "flex cursor-pointer items-start gap-3 rounded-lg border px-3 py-2.5 text-left outline-none transition-[background-color,border-color,box-shadow]", |
| 314 | "focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:ring-offset-background", | 314 | "focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:ring-offset-background", |
| 315 | selected | 315 | selected |
| 316 | ? "border-primary bg-background ring-2 ring-primary/25 dark:border-transparent dark:bg-primary/10 dark:ring-1 dark:ring-primary/30" | 316 | ? "border-primary bg-background ring-2 ring-inset ring-primary/25 dark:border-transparent dark:bg-primary/10 dark:ring-1 dark:ring-primary/30" |
| 317 | : "border-border bg-background hover:bg-muted/50 dark:border-transparent dark:bg-white/[0.035] dark:hover:bg-accent", | 317 | : "border-border bg-background hover:bg-muted/50 dark:border-transparent dark:bg-white/[0.035] dark:hover:bg-accent", |
| 318 | )} | 318 | )} |
| 319 | > | 319 | > |
apps/web/src/components/chat/ChangedFilesTree.tsx+2-2| ... | @@ -178,7 +178,7 @@ export const ChangedFilesTree = memo(function ChangedFilesTree(props: { | ... | @@ -178,7 +178,7 @@ export const ChangedFilesTree = memo(function ChangedFilesTree(props: { |
| 178 | type="button" | 178 | type="button" |
| 179 | data-scroll-anchor-ignore | 179 | data-scroll-anchor-ignore |
| 180 | aria-expanded={isExpanded} | 180 | aria-expanded={isExpanded} |
| 181 | className="group flex w-full items-center gap-2 rounded-md py-1.5 pr-2 text-left transition-colors hover:bg-accent/60 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:ring-offset-background" | 181 | className="group flex w-full items-center gap-2 rounded-md py-1.5 pr-2 text-left transition-colors hover:bg-accent/60 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:ring-offset-background" |
| 182 | style={{ paddingLeft: `${leftPadding}px` }} | 182 | style={{ paddingLeft: `${leftPadding}px` }} |
| 183 | onClick={() => toggleDirectory(node.path)} | 183 | onClick={() => toggleDirectory(node.path)} |
| 184 | > | 184 | > |
| ... | @@ -213,7 +213,7 @@ export const ChangedFilesTree = memo(function ChangedFilesTree(props: { | ... | @@ -213,7 +213,7 @@ export const ChangedFilesTree = memo(function ChangedFilesTree(props: { |
| 213 | <button | 213 | <button |
| 214 | key={`file:${node.path}`} | 214 | key={`file:${node.path}`} |
| 215 | type="button" | 215 | type="button" |
| 216 | className="group flex w-full items-center gap-2 rounded-md py-1.5 pr-2 text-left transition-colors hover:bg-accent/60 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:ring-offset-background" | 216 | className="group flex w-full items-center gap-2 rounded-md py-1.5 pr-2 text-left transition-colors hover:bg-accent/60 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:ring-offset-background" |
| 217 | style={{ paddingLeft: `${leftPadding}px` }} | 217 | style={{ paddingLeft: `${leftPadding}px` }} |
| 218 | onClick={() => onOpenTurnDiff(runId, node.path)} | 218 | onClick={() => onOpenTurnDiff(runId, node.path)} |
| 219 | onContextMenu={ | 219 | onContextMenu={ |
apps/web/src/components/chat/ChatComposer.tsx+3-3| ... | @@ -5314,7 +5314,7 @@ export const ChatComposer = memo(function ChatComposer(props: ChatComposerProps) | ... | @@ -5314,7 +5314,7 @@ export const ChatComposer = memo(function ChatComposer(props: ChatComposerProps) |
| 5314 | {restingImagePreviewCounts.overflowCount > 0 ? ( | 5314 | {restingImagePreviewCounts.overflowCount > 0 ? ( |
| 5315 | <button | 5315 | <button |
| 5316 | type="button" | 5316 | type="button" |
| 5317 | className="flex size-7 shrink-0 cursor-pointer items-center justify-center rounded-md border border-border/70 bg-muted/60 font-medium text-secondary-label text-xs tabular-nums outline-none hover:bg-muted focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:ring-offset-background" | 5317 | className="flex size-7 shrink-0 cursor-pointer items-center justify-center rounded-md border border-border/70 bg-muted/60 font-medium text-secondary-label text-xs tabular-nums outline-none hover:bg-muted focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:ring-offset-background" |
| 5318 | aria-label={`Show ${String(restingImagePreviewCounts.overflowCount)} more image attachments`} | 5318 | aria-label={`Show ${String(restingImagePreviewCounts.overflowCount)} more image attachments`} |
| 5319 | onPointerDown={(event) => event.preventDefault()} | 5319 | onPointerDown={(event) => event.preventDefault()} |
| 5320 | onClick={() => { | 5320 | onClick={() => { |
| ... | @@ -6947,8 +6947,8 @@ export const ChatComposer = memo(function ChatComposer(props: ChatComposerProps) | ... | @@ -6947,8 +6947,8 @@ export const ChatComposer = memo(function ChatComposer(props: ChatComposerProps) |
| 6947 | data-chat-composer-mobile-collapsed={isComposerCollapsedMobile ? "true" : "false"} | 6947 | data-chat-composer-mobile-collapsed={isComposerCollapsedMobile ? "true" : "false"} |
| 6948 | className={cn( | 6948 | className={cn( |
| 6949 | "rounded-3xl transition-[background-color] duration-200", | 6949 | "rounded-3xl transition-[background-color] duration-200", |
| 6950 | "in-data-[thread-context-over]:bg-accent/45 in-data-[thread-context-over]:ring-1 in-data-[thread-context-over]:ring-primary/70", | 6950 | "in-data-[thread-context-over]:bg-accent/45 in-data-[thread-context-over]:ring-1 in-data-[thread-context-over]:ring-inset in-data-[thread-context-over]:ring-primary/70", |
| 6951 | isDragOverComposer ? "bg-accent/45 ring-1 ring-primary/70" : null, | 6951 | isDragOverComposer ? "bg-accent/45 ring-1 ring-inset ring-primary/70" : null, |
| 6952 | projectSelectionRequired ? "opacity-75" : null, | 6952 | projectSelectionRequired ? "opacity-75" : null, |
| 6953 | composerProviderState.composerSurfaceClassName, | 6953 | composerProviderState.composerSurfaceClassName, |
| 6954 | )} | 6954 | )} |
apps/web/src/components/chat/ChatHeader.tsx+4-4| ... | @@ -323,7 +323,7 @@ export const ChatHeader = memo(function ChatHeader({ | ... | @@ -323,7 +323,7 @@ export const ChatHeader = memo(function ChatHeader({ |
| 323 | type="button" | 323 | type="button" |
| 324 | aria-label={`New thread in ${activeProjectName}`} | 324 | aria-label={`New thread in ${activeProjectName}`} |
| 325 | onClick={onNewThreadInProject} | 325 | onClick={onNewThreadInProject} |
| 326 | className="inline-flex min-w-0 max-w-full cursor-pointer items-center gap-1.5 rounded-sm text-muted-foreground transition-colors hover:text-foreground focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring" | 326 | className="inline-flex min-w-0 max-w-full cursor-pointer items-center gap-1.5 rounded-sm text-muted-foreground transition-colors hover:text-foreground focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring" |
| 327 | /> | 327 | /> |
| 328 | } | 328 | } |
| 329 | > | 329 | > |
| ... | @@ -350,7 +350,7 @@ export const ChatHeader = memo(function ChatHeader({ | ... | @@ -350,7 +350,7 @@ export const ChatHeader = memo(function ChatHeader({ |
| 350 | type="button" | 350 | type="button" |
| 351 | aria-label={`Open parent thread: ${parentThreadLink.title}`} | 351 | aria-label={`Open parent thread: ${parentThreadLink.title}`} |
| 352 | onClick={() => onOpenThread(parentThreadLink.threadId)} | 352 | onClick={() => onOpenThread(parentThreadLink.threadId)} |
| 353 | className="inline-flex min-w-0 max-w-full cursor-pointer items-center rounded-sm text-muted-foreground transition-colors hover:text-foreground focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring" | 353 | className="inline-flex min-w-0 max-w-full cursor-pointer items-center rounded-sm text-muted-foreground transition-colors hover:text-foreground focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring" |
| 354 | /> | 354 | /> |
| 355 | } | 355 | } |
| 356 | > | 356 | > |
| ... | @@ -379,7 +379,7 @@ export const ChatHeader = memo(function ChatHeader({ | ... | @@ -379,7 +379,7 @@ export const ChatHeader = memo(function ChatHeader({ |
| 379 | <input | 379 | <input |
| 380 | autoFocus | 380 | autoFocus |
| 381 | aria-label="Thread title" | 381 | aria-label="Thread title" |
| 382 | className="min-w-0 flex-1 rounded-sm bg-transparent text-sm font-medium text-foreground outline-none ring-1 ring-ring/50 focus:ring-ring" | 382 | className="min-w-0 flex-1 rounded-sm bg-transparent text-sm font-medium text-foreground outline-none ring-1 ring-inset ring-ring/50 focus:ring-ring" |
| 383 | defaultValue={renamingTitle} | 383 | defaultValue={renamingTitle} |
| 384 | onBlur={(event) => { | 384 | onBlur={(event) => { |
| 385 | if (renameCommittedRef.current) return; | 385 | if (renameCommittedRef.current) return; |
| ... | @@ -409,7 +409,7 @@ export const ChatHeader = memo(function ChatHeader({ | ... | @@ -409,7 +409,7 @@ export const ChatHeader = memo(function ChatHeader({ |
| 409 | onClick={openMenuFromTitle} | 409 | onClick={openMenuFromTitle} |
| 410 | onDoubleClick={canOperateThread ? handleTitleDoubleClick : undefined} | 410 | onDoubleClick={canOperateThread ? handleTitleDoubleClick : undefined} |
| 411 | onBlur={cancelPendingTitleMenu} | 411 | onBlur={cancelPendingTitleMenu} |
| 412 | className="group/thread-title inline-flex min-w-0 max-w-full cursor-pointer items-center gap-1 rounded-sm text-left focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring" | 412 | className="group/thread-title inline-flex min-w-0 max-w-full cursor-pointer items-center gap-1 rounded-sm text-left focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring" |
| 413 | /> | 413 | /> |
| 414 | } | 414 | } |
| 415 | > | 415 | > |
apps/web/src/components/chat/ComposerControl.tsx+1-1| ... | @@ -16,7 +16,7 @@ export type ComposerControlSize = "sm" | "xs"; | ... | @@ -16,7 +16,7 @@ export type ComposerControlSize = "sm" | "xs"; |
| 16 | */ | 16 | */ |
| 17 | function composerControlClassName(size: ComposerControlSize, className?: string) { | 17 | function composerControlClassName(size: ComposerControlSize, className?: string) { |
| 18 | return cn( | 18 | return cn( |
| 19 | "relative inline-flex shrink-0 cursor-pointer items-center justify-center whitespace-nowrap rounded-(--control-radius) border border-transparent text-base outline-none hover:bg-accent data-pressed:bg-accent focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:ring-offset-background disabled:pointer-events-none disabled:opacity-64 data-disabled:pointer-events-none data-disabled:opacity-64 pointer-coarse:after:absolute pointer-coarse:after:size-full pointer-coarse:after:min-h-11 pointer-coarse:after:min-w-11 [&:active:not([aria-haspopup])]:scale-[0.97] [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg]:-mx-0.5 [&_svg[data-composer-control-icon]]:mx-0", | 19 | "relative inline-flex shrink-0 cursor-pointer items-center justify-center whitespace-nowrap rounded-(--control-radius) border border-transparent text-base outline-none hover:bg-accent data-pressed:bg-accent focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:ring-offset-background disabled:pointer-events-none disabled:opacity-64 data-disabled:pointer-events-none data-disabled:opacity-64 pointer-coarse:after:absolute pointer-coarse:after:size-full pointer-coarse:after:min-h-11 pointer-coarse:after:min-w-11 [&:active:not([aria-haspopup])]:scale-[0.97] [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg]:-mx-0.5 [&_svg[data-composer-control-icon]]:mx-0", |
| 20 | size === "xs" | 20 | size === "xs" |
| 21 | ? "h-7 gap-1 px-1.75 font-normal text-muted-foreground/70 text-sm hover:text-foreground/80 sm:h-6 sm:text-xs [&_svg:not([class*='size-'])]:size-4 sm:[&_svg:not([class*='size-'])]:size-3.5 [&_svg[data-composer-control-chevron]]:ms-0 [&_svg[data-composer-control-chevron]]:-me-1" | 21 | ? "h-7 gap-1 px-1.75 font-normal text-muted-foreground/70 text-sm hover:text-foreground/80 sm:h-6 sm:text-xs [&_svg:not([class*='size-'])]:size-4 sm:[&_svg:not([class*='size-'])]:size-3.5 [&_svg[data-composer-control-chevron]]:ms-0 [&_svg[data-composer-control-chevron]]:-me-1" |
| 22 | : "h-7 gap-1.5 px-2.5 font-medium text-secondary-label [&_svg:not([class*='text-'])]:text-muted-foreground hover:text-foreground sm:text-sm [&_svg:not([class*='size-'])]:size-4.5 sm:[&_svg:not([class*='size-'])]:size-4", | 22 | : "h-7 gap-1.5 px-2.5 font-medium text-secondary-label [&_svg:not([class*='text-'])]:text-muted-foreground hover:text-foreground sm:text-sm [&_svg:not([class*='size-'])]:size-4.5 sm:[&_svg:not([class*='size-'])]:size-4", |
apps/web/src/components/chat/ComposerPendingUserInputPanel.tsx+1-1| ... | @@ -261,7 +261,7 @@ const ComposerPendingUserInputCard = memo(function ComposerPendingUserInputCard( | ... | @@ -261,7 +261,7 @@ const ComposerPendingUserInputCard = memo(function ComposerPendingUserInputCard( |
| 261 | (!customAnswerActive && progress.selectedOptionValues.includes(optionValue)); | 261 | (!customAnswerActive && progress.selectedOptionValues.includes(optionValue)); |
| 262 | const shortcutKey = index < 9 ? index + 1 : null; | 262 | const shortcutKey = index < 9 ? index + 1 : null; |
| 263 | const className = cn( | 263 | const className = cn( |
| 264 | "group flex w-full items-center gap-2 rounded-md px-2.5 py-2 text-left outline-none transition-colors duration-150 focus-visible:ring-1 focus-visible:ring-primary/25", | 264 | "group flex w-full items-center gap-2 rounded-md px-2.5 py-2 text-left outline-none transition-colors duration-150 focus-visible:ring-1 focus-visible:ring-inset focus-visible:ring-primary/25", |
| 265 | isSelected | 265 | isSelected |
| 266 | ? "bg-muted/55 text-foreground" | 266 | ? "bg-muted/55 text-foreground" |
| 267 | : "bg-transparent text-foreground/85 hover:bg-muted/30", | 267 | : "bg-transparent text-foreground/85 hover:bg-muted/30", |
apps/web/src/components/chat/ComposerPrimaryActions.tsx+2-2| ... | @@ -79,7 +79,7 @@ const formatPendingPrimaryActionLabel = (input: { | ... | @@ -79,7 +79,7 @@ const formatPendingPrimaryActionLabel = (input: { |
| 79 | // The composer's labeled primary actions (Submit, Refine, Implement) share the send button's | 79 | // The composer's labeled primary actions (Submit, Refine, Implement) share the send button's |
| 80 | // message-action pill, so they are composer-owned buttons rather than restyled Buttons. | 80 | // message-action pill, so they are composer-owned buttons rather than restyled Buttons. |
| 81 | const messageActionPillClassName = | 81 | const messageActionPillClassName = |
| 82 | "inline-flex shrink-0 cursor-pointer items-center justify-center gap-1.5 whitespace-nowrap rounded-full bg-message-action font-medium text-base text-message-action-foreground shadow-xs shadow-message-action/24 outline-none hover:bg-message-action-hover focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:ring-offset-background disabled:pointer-events-none disabled:opacity-64 disabled:shadow-none sm:text-sm"; | 82 | "inline-flex shrink-0 cursor-pointer items-center justify-center gap-1.5 whitespace-nowrap rounded-full bg-message-action font-medium text-base text-message-action-foreground shadow-xs shadow-message-action/24 outline-none hover:bg-message-action-hover focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:ring-offset-background disabled:pointer-events-none disabled:opacity-64 disabled:shadow-none sm:text-sm"; |
| 83 | 83 | ||
| 84 | const preventPointerFocus: PointerEventHandler<HTMLElement> = (event) => { | 84 | const preventPointerFocus: PointerEventHandler<HTMLElement> = (event) => { |
| 85 | event.preventDefault(); | 85 | event.preventDefault(); |
| ... | @@ -370,7 +370,7 @@ export const ComposerPrimaryActions = memo(function ComposerPrimaryActions({ | ... | @@ -370,7 +370,7 @@ export const ComposerPrimaryActions = memo(function ComposerPrimaryActions({ |
| 370 | <button | 370 | <button |
| 371 | type="button" | 371 | type="button" |
| 372 | className={cn( | 372 | className={cn( |
| 373 | "flex h-7 shrink-0 cursor-pointer items-center gap-1.5 rounded-full border px-2.5 text-xs tabular-nums outline-none transition-colors focus-visible:ring-2 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-64 [&_svg]:pointer-events-none [&_svg]:size-3.5", | 373 | "flex h-7 shrink-0 cursor-pointer items-center gap-1.5 rounded-full border px-2.5 text-xs tabular-nums outline-none transition-colors focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-64 [&_svg]:pointer-events-none [&_svg]:size-3.5", |
| 374 | keepFullHistory | 374 | keepFullHistory |
| 375 | ? "border-border text-muted-foreground hover:text-foreground" | 375 | ? "border-border text-muted-foreground hover:text-foreground" |
| 376 | : "border-warning/40 text-warning hover:bg-warning/8", | 376 | : "border-warning/40 text-warning hover:bg-warning/8", |
apps/web/src/components/chat/ComposerServerUpdateStatus.tsx+1-1| ... | @@ -47,7 +47,7 @@ export function ComposerServerUpdateStatus({ | ... | @@ -47,7 +47,7 @@ export function ComposerServerUpdateStatus({ |
| 47 | <button | 47 | <button |
| 48 | type="button" | 48 | type="button" |
| 49 | aria-label={`${title}: ${detail}`} | 49 | aria-label={`${title}: ${detail}`} |
| 50 | className="block max-w-full cursor-help truncate rounded-sm text-left outline-none focus-visible:ring-2 focus-visible:ring-ring" | 50 | className="block max-w-full cursor-help truncate rounded-sm text-left outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring" |
| 51 | onClick={() => setDetailsOpen(true)} | 51 | onClick={() => setDetailsOpen(true)} |
| 52 | > | 52 | > |
| 53 | {title} | 53 | {title} |
apps/web/src/components/chat/ComposerStashMenu.tsx+1-1| ... | @@ -164,7 +164,7 @@ export const ComposerStashMenu = memo(function ComposerStashMenu(props: { | ... | @@ -164,7 +164,7 @@ export const ComposerStashMenu = memo(function ComposerStashMenu(props: { |
| 164 | <ComposerBanner.Content> | 164 | <ComposerBanner.Content> |
| 165 | <button | 165 | <button |
| 166 | type="button" | 166 | type="button" |
| 167 | className="min-w-0 flex-1 cursor-pointer truncate text-left text-foreground/80 outline-none before:absolute before:inset-0 before:rounded-sm focus-visible:before:ring-2 focus-visible:before:ring-ring" | 167 | className="min-w-0 flex-1 cursor-pointer truncate text-left text-foreground/80 outline-none before:absolute before:inset-0 before:rounded-sm focus-visible:before:ring-2 focus-visible:before:ring-inset focus-visible:before:ring-ring" |
| 168 | data-stash-restore={entry.id} | 168 | data-stash-restore={entry.id} |
| 169 | aria-label={`Restore stashed prompt: ${stashEntrySnippet(entry)}`} | 169 | aria-label={`Restore stashed prompt: ${stashEntrySnippet(entry)}`} |
| 170 | onPointerDown={(event) => event.preventDefault()} | 170 | onPointerDown={(event) => event.preventDefault()} |
apps/web/src/components/chat/DraftHeroHeadline.tsx+1-1| ... | @@ -312,7 +312,7 @@ export function DraftHeroHeadline({ | ... | @@ -312,7 +312,7 @@ export function DraftHeroHeadline({ |
| 312 | <button | 312 | <button |
| 313 | type="button" | 313 | type="button" |
| 314 | onClick={openAddProject} | 314 | onClick={openAddProject} |
| 315 | className="pointer-events-auto inline cursor-pointer border-muted-foreground/35 border-b border-dotted text-muted-foreground/60 transition-colors hover:border-muted-foreground/60 hover:text-muted-foreground/80 focus-visible:rounded-sm focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring" | 315 | className="pointer-events-auto inline cursor-pointer border-muted-foreground/35 border-b border-dotted text-muted-foreground/60 transition-colors hover:border-muted-foreground/60 hover:text-muted-foreground/80 focus-visible:rounded-sm focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring" |
| 316 | > | 316 | > |
| 317 | {activeProjectTitle ?? "Add a project"} | 317 | {activeProjectTitle ?? "Add a project"} |
| 318 | </button> | 318 | </button> |
apps/web/src/components/chat/MessagesTimeline.tsx+3-3| ... | @@ -1817,7 +1817,7 @@ function TimelineMinimap({ | ... | @@ -1817,7 +1817,7 @@ function TimelineMinimap({ |
| 1817 | /> | 1817 | /> |
| 1818 | <button | 1818 | <button |
| 1819 | aria-label={`Jump to message: ${activeItem?.userText ?? "User message"}`} | 1819 | aria-label={`Jump to message: ${activeItem?.userText ?? "User message"}`} |
| 1820 | className="absolute inset-y-0 left-0 w-full cursor-pointer bg-transparent focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring/70" | 1820 | className="absolute inset-y-0 left-0 w-full cursor-pointer bg-transparent focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring/70" |
| 1821 | onBlur={() => setActiveIndex(null)} | 1821 | onBlur={() => setActiveIndex(null)} |
| 1822 | onClick={(event) => { | 1822 | onClick={(event) => { |
| 1823 | if (timelineMinimapEventTargetsPreview(event.target)) { | 1823 | if (timelineMinimapEventTargetsPreview(event.target)) { |
| ... | @@ -2457,7 +2457,7 @@ function UserTimelineRow({ row }: { row: Extract<TimelineRow, { kind: "message" | ... | @@ -2457,7 +2457,7 @@ function UserTimelineRow({ row }: { row: Extract<TimelineRow, { kind: "message" |
| 2457 | type="button" | 2457 | type="button" |
| 2458 | aria-label={`Preview ${file.name}`} | 2458 | aria-label={`Preview ${file.name}`} |
| 2459 | onClick={() => ctx.onFileOpen(file)} | 2459 | onClick={() => ctx.onFileOpen(file)} |
| 2460 | className="focus-visible:ring-ring/70 flex min-w-0 flex-1 cursor-pointer items-center gap-2 rounded-md py-1 text-left text-sm hover:underline focus-visible:ring-2 focus-visible:outline-none focus-visible:ring-inset" | 2460 | className="focus-visible:ring-ring/70 flex min-w-0 flex-1 cursor-pointer items-center gap-2 rounded-md py-1 text-left text-sm hover:underline focus-visible:ring-2 focus-visible:ring-inset focus-visible:outline-none" |
| 2461 | > | 2461 | > |
| 2462 | {fileIdentity} | 2462 | {fileIdentity} |
| 2463 | <EyeIcon className="size-4 shrink-0" /> | 2463 | <EyeIcon className="size-4 shrink-0" /> |
| ... | @@ -5674,7 +5674,7 @@ function WorkEntryLogRow(props: WorkEntryRowProps) { | ... | @@ -5674,7 +5674,7 @@ function WorkEntryLogRow(props: WorkEntryRowProps) { |
| 5674 | {createdThread ? ( | 5674 | {createdThread ? ( |
| 5675 | <button | 5675 | <button |
| 5676 | type="button" | 5676 | type="button" |
| 5677 | className="shrink-0 rounded-sm text-sm text-primary hover:underline focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring" | 5677 | className="shrink-0 rounded-sm text-sm text-primary hover:underline focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring" |
| 5678 | aria-label={`Open ${createdThread.title ?? "created thread"}`} | 5678 | aria-label={`Open ${createdThread.title ?? "created thread"}`} |
| 5679 | onClick={(event) => { | 5679 | onClick={(event) => { |
| 5680 | event.stopPropagation(); | 5680 | event.stopPropagation(); |
apps/web/src/components/chat/ThreadDetailsControl.tsx+1-1| ... | @@ -49,7 +49,7 @@ export function ThreadDetailsControl({ | ... | @@ -49,7 +49,7 @@ export function ThreadDetailsControl({ |
| 49 | { | 49 | { |
| 50 | type: render ? undefined : "button", | 50 | type: render ? undefined : "button", |
| 51 | className: cn( | 51 | className: cn( |
| 52 | "relative inline-flex shrink-0 cursor-pointer items-center whitespace-nowrap border outline-none transition-[box-shadow,scale] [&:active:not([aria-haspopup])]:scale-[0.97] focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:ring-offset-background pointer-coarse:after:absolute pointer-coarse:after:size-full pointer-coarse:after:min-h-11 pointer-coarse:after:min-w-11 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 disabled:pointer-events-none disabled:opacity-64 aria-disabled:cursor-not-allowed aria-disabled:opacity-64 [&_svg]:shrink-0", | 52 | "relative inline-flex shrink-0 cursor-pointer items-center whitespace-nowrap border outline-none transition-[box-shadow,scale] [&:active:not([aria-haspopup])]:scale-[0.97] focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:ring-offset-background pointer-coarse:after:absolute pointer-coarse:after:size-full pointer-coarse:after:min-h-11 pointer-coarse:after:min-w-11 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 disabled:pointer-events-none disabled:opacity-64 aria-disabled:cursor-not-allowed aria-disabled:opacity-64 [&_svg]:shrink-0", |
| 53 | parts[part], | 53 | parts[part], |
| 54 | multiline && "h-auto min-h-8 py-0.75 disabled:opacity-100 sm:h-auto", | 54 | multiline && "h-auto min-h-8 py-0.75 disabled:opacity-100 sm:h-auto", |
| 55 | tone === "muted" && "text-muted-foreground/70 hover:text-foreground/80", | 55 | tone === "muted" && "text-muted-foreground/70 hover:text-foreground/80", |
apps/web/src/components/chat/V2LifecycleRow.tsx+1-1| ... | @@ -596,7 +596,7 @@ function HandoffEndpoint(props: { | ... | @@ -596,7 +596,7 @@ function HandoffEndpoint(props: { |
| 596 | render={ | 596 | render={ |
| 597 | <span | 597 | <span |
| 598 | tabIndex={0} | 598 | tabIndex={0} |
| 599 | className="inline-flex min-w-0 items-center gap-1 rounded-sm focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring" | 599 | className="inline-flex min-w-0 items-center gap-1 rounded-sm focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring" |
| 600 | > | 600 | > |
| 601 | <ProviderInstanceIcon | 601 | <ProviderInstanceIcon |
| 602 | driverKind={entry?.driverKind ?? ProviderDriverKind.make(props.instanceId)} | 602 | driverKind={entry?.driverKind ?? ProviderDriverKind.make(props.instanceId)} |
apps/web/src/components/chat/ZoomableImage.tsx+1-1| ... | @@ -150,7 +150,7 @@ export function ZoomableImage({ | ... | @@ -150,7 +150,7 @@ export function ZoomableImage({ |
| 150 | aria-label={`${name}, zoomable image`} | 150 | aria-label={`${name}, zoomable image`} |
| 151 | aria-description="Click to zoom in or return to fit. Scroll to zoom, drag to pan. Use Enter to toggle zoom, plus or minus to zoom, and 0 to fit." | 151 | aria-description="Click to zoom in or return to fit. Scroll to zoom, drag to pan. Use Enter to toggle zoom, plus or minus to zoom, and 0 to fit." |
| 152 | tabIndex={0} | 152 | tabIndex={0} |
| 153 | className="max-w-[var(--media-width)] overflow-auto overscroll-contain rounded-lg bg-background shadow-2xl ring-1 ring-border/70 outline-none focus-visible:ring-2 focus-visible:ring-ring" | 153 | className="max-w-[var(--media-width)] overflow-auto overscroll-contain rounded-lg bg-background shadow-2xl ring-1 ring-border/70 outline-none focus-visible:outline-2 focus-visible:outline-solid focus-visible:-outline-offset-2 focus-visible:outline-ring" |
| 154 | style={{ | 154 | style={{ |
| 155 | width: width || undefined, | 155 | width: width || undefined, |
| 156 | height: height || undefined, | 156 | height: height || undefined, |
apps/web/src/components/files/FileBreadcrumbs.tsx+1-1| ... | @@ -237,7 +237,7 @@ function DirectoryBreadcrumb(props: FileBreadcrumbsProps & { readonly crumb: Fil | ... | @@ -237,7 +237,7 @@ function DirectoryBreadcrumb(props: FileBreadcrumbsProps & { readonly crumb: Fil |
| 237 | <button | 237 | <button |
| 238 | type="button" | 238 | type="button" |
| 239 | aria-label={`Browse ${props.crumb.label}`} | 239 | aria-label={`Browse ${props.crumb.label}`} |
| 240 | className="relative block max-w-40 cursor-pointer rounded-sm px-0.5 text-left text-muted-foreground outline-none pointer-coarse:after:-inset-y-3 pointer-coarse:after:absolute pointer-coarse:after:inset-x-0 hover:bg-accent hover:text-foreground focus-visible:ring-2 focus-visible:ring-ring data-popup-open:bg-accent data-popup-open:text-foreground" | 240 | className="relative block max-w-40 cursor-pointer rounded-sm px-0.5 text-left text-muted-foreground outline-none pointer-coarse:after:-inset-y-3 pointer-coarse:after:absolute pointer-coarse:after:inset-x-0 hover:bg-accent hover:text-foreground focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring data-popup-open:bg-accent data-popup-open:text-foreground" |
| 241 | /> | 241 | /> |
| 242 | } | 242 | } |
| 243 | /> | 243 | /> |
apps/web/src/components/files/fileSurfaceChrome.tsx+1-1| ... | @@ -153,7 +153,7 @@ export function FileSurfaceFailure(props: { | ... | @@ -153,7 +153,7 @@ export function FileSurfaceFailure(props: { |
| 153 | <button | 153 | <button |
| 154 | type="button" | 154 | type="button" |
| 155 | onClick={props.onRetry} | 155 | onClick={props.onRetry} |
| 156 | className="rounded-md border border-input px-2.5 py-1 text-xs text-foreground hover:bg-accent focus-visible:ring-2 focus-visible:ring-ring" | 156 | className="rounded-md border border-input px-2.5 py-1 text-xs text-foreground hover:bg-accent focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring" |
| 157 | > | 157 | > |
| 158 | Try again | 158 | Try again |
| 159 | </button> | 159 | </button> |
apps/web/src/components/media/MediaVideoPlayer.tsx+1-1| ... | @@ -203,7 +203,7 @@ export function MediaVideoPlayer({ | ... | @@ -203,7 +203,7 @@ export function MediaVideoPlayer({ |
| 203 | type="button" | 203 | type="button" |
| 204 | aria-label={label ? `Play ${label}` : "Play video"} | 204 | aria-label={label ? `Play ${label}` : "Play video"} |
| 205 | onClick={onOpen} | 205 | onClick={onOpen} |
| 206 | className="absolute inset-0 flex cursor-pointer items-center justify-center rounded-lg focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring" | 206 | className="absolute inset-0 flex cursor-pointer items-center justify-center rounded-lg focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-ring" |
| 207 | > | 207 | > |
| 208 | <span className="flex size-8 items-center justify-center rounded-full bg-black/50 text-white"> | 208 | <span className="flex size-8 items-center justify-center rounded-full bg-black/50 text-white"> |
| 209 | <PlayIcon aria-hidden className="size-4 fill-current" /> | 209 | <PlayIcon aria-hidden className="size-4 fill-current" /> |
apps/web/src/components/preview/PreviewRecentUrlCard.tsx+1-1| ... | @@ -44,7 +44,7 @@ export function PreviewRecentUrlCard({ threadRef, entry, onOpen, onRemove }: Pro | ... | @@ -44,7 +44,7 @@ export function PreviewRecentUrlCard({ threadRef, entry, onOpen, onRemove }: Pro |
| 44 | type="button" | 44 | type="button" |
| 45 | aria-label={`Remove ${label} from history`} | 45 | aria-label={`Remove ${label} from history`} |
| 46 | onClick={onRemove} | 46 | onClick={onRemove} |
| 47 | className="absolute right-3 rounded p-1 text-muted-foreground opacity-0 hover:bg-accent hover:text-foreground focus-visible:opacity-100 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring group-hover:opacity-100" | 47 | className="absolute right-3 rounded p-1 text-muted-foreground opacity-0 hover:bg-accent hover:text-foreground focus-visible:opacity-100 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring group-hover:opacity-100" |
| 48 | > | 48 | > |
| 49 | <X className="size-3.5" /> | 49 | <X className="size-3.5" /> |
| 50 | </button> | 50 | </button> |
apps/web/src/components/projectScriptEditor.tsx+1-1| ... | @@ -369,7 +369,7 @@ export function ProjectScriptEditorDialog({ | ... | @@ -369,7 +369,7 @@ export function ProjectScriptEditorDialog({ |
| 369 | type="button" | 369 | type="button" |
| 370 | className={`relative flex flex-col items-center gap-2 rounded-md border px-2 py-2 text-xs dark:border-transparent ${ | 370 | className={`relative flex flex-col items-center gap-2 rounded-md border px-2 py-2 text-xs dark:border-transparent ${ |
| 371 | isSelected | 371 | isSelected |
| 372 | ? "border-primary/70 bg-primary/10 dark:ring-1 dark:ring-primary/30" | 372 | ? "border-primary/70 bg-primary/10 ring-inset dark:ring-1 dark:ring-primary/30" |
| 373 | : "border-border/70 hover:bg-accent/60 dark:bg-white/[0.035]" | 373 | : "border-border/70 hover:bg-accent/60 dark:bg-white/[0.035]" |
| 374 | }`} | 374 | }`} |
| 375 | onClick={() => { | 375 | onClick={() => { |
apps/web/src/components/pullRequest/PullRequestCopyableCode.tsx+1-1| ... | @@ -32,7 +32,7 @@ export function PullRequestCopyableCode({ | ... | @@ -32,7 +32,7 @@ export function PullRequestCopyableCode({ |
| 32 | <button | 32 | <button |
| 33 | type="button" | 33 | type="button" |
| 34 | className={cn( | 34 | className={cn( |
| 35 | "relative grid w-fit min-w-0 max-w-full shrink cursor-pointer rounded px-1 py-0.5 text-left outline-none transition-colors pointer-coarse:after:absolute pointer-coarse:after:size-full pointer-coarse:after:min-h-11 pointer-coarse:after:min-w-11 hover:bg-accent/45 hover:text-foreground focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:ring-offset-background", | 35 | "relative grid w-fit min-w-0 max-w-full shrink cursor-pointer rounded px-1 py-0.5 text-left outline-none transition-colors pointer-coarse:after:absolute pointer-coarse:after:size-full pointer-coarse:after:min-h-11 pointer-coarse:after:min-w-11 hover:bg-accent/45 hover:text-foreground focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:ring-offset-background", |
| 36 | className, | 36 | className, |
| 37 | )} | 37 | )} |
| 38 | aria-label={isCopied ? copiedLabel : copyLabel} | 38 | aria-label={isCopied ? copiedLabel : copyLabel} |
apps/web/src/components/pullRequest/PullRequestDetailPanel.tsx+1-1| ... | @@ -380,7 +380,7 @@ function PullRequestBaseFreshnessWarning({ | ... | @@ -380,7 +380,7 @@ function PullRequestBaseFreshnessWarning({ |
| 380 | type="button" | 380 | type="button" |
| 381 | aria-label={summary} | 381 | aria-label={summary} |
| 382 | className={cn( | 382 | className={cn( |
| 383 | "inline-flex min-w-0 shrink-0 cursor-help items-center gap-1 rounded-sm text-warning-foreground outline-none focus-visible:ring-2 focus-visible:ring-ring", | 383 | "inline-flex min-w-0 shrink-0 cursor-help items-center gap-1 rounded-sm text-warning-foreground outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring", |
| 384 | className, | 384 | className, |
| 385 | )} | 385 | )} |
| 386 | /> | 386 | /> |
apps/web/src/components/pullRequest/PullRequestReactions.tsx+2-2| ... | @@ -23,7 +23,7 @@ import { | ... | @@ -23,7 +23,7 @@ import { |
| 23 | } from "./pullRequestReactions.logic"; | 23 | } from "./pullRequestReactions.logic"; |
| 24 | 24 | ||
| 25 | const PILL_CLASS = | 25 | const PILL_CLASS = |
| 26 | "inline-flex h-6 shrink-0 items-center gap-1 rounded-full border px-2 text-xs outline-none transition-colors focus-visible:ring-2 focus-visible:ring-ring"; | 26 | "inline-flex h-6 shrink-0 items-center gap-1 rounded-full border px-2 text-xs outline-none transition-colors focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring"; |
| 27 | 27 | ||
| 28 | const EMPTY_PENDING: ReadonlyMap<PullRequestReactionContent, boolean> = new Map(); | 28 | const EMPTY_PENDING: ReadonlyMap<PullRequestReactionContent, boolean> = new Map(); |
| 29 | 29 | ||
| ... | @@ -148,7 +148,7 @@ export function PullRequestReactionBar({ | ... | @@ -148,7 +148,7 @@ export function PullRequestReactionBar({ |
| 148 | aria-pressed={reacted} | 148 | aria-pressed={reacted} |
| 149 | aria-label={pullRequestReactionName(content)} | 149 | aria-label={pullRequestReactionName(content)} |
| 150 | className={cn( | 150 | className={cn( |
| 151 | "flex size-7 items-center justify-center rounded-md text-base outline-none hover:bg-accent focus-visible:ring-2 focus-visible:ring-ring", | 151 | "flex size-7 items-center justify-center rounded-md text-base outline-none hover:bg-accent focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring", |
| 152 | reacted && "bg-primary/10", | 152 | reacted && "bg-primary/10", |
| 153 | )} | 153 | )} |
| 154 | onClick={() => { | 154 | onClick={() => { |
apps/web/src/components/pullRequest/PullRequestRow.tsx+1-1| ... | @@ -136,7 +136,7 @@ function PullRequestRowImpl({ | ... | @@ -136,7 +136,7 @@ function PullRequestRowImpl({ |
| 136 | className={cn( | 136 | className={cn( |
| 137 | PULL_REQUEST_ROW_CLASS, | 137 | PULL_REQUEST_ROW_CLASS, |
| 138 | PAGE_ROW_CLASS, | 138 | PAGE_ROW_CLASS, |
| 139 | "min-w-0 flex-1 cursor-pointer transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring", | 139 | "min-w-0 flex-1 cursor-pointer transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-inset focus-visible:ring-ring", |
| 140 | )} | 140 | )} |
| 141 | > | 141 | > |
| 142 | <PullRequestRowGlyph | 142 | <PullRequestRowGlyph |
apps/web/src/components/pullRequest/PullRequestTimelineTab.tsx+1-1| ... | @@ -376,7 +376,7 @@ function CommitEvent({ | ... | @@ -376,7 +376,7 @@ function CommitEvent({ |
| 376 | return ( | 376 | return ( |
| 377 | <button | 377 | <button |
| 378 | type="button" | 378 | type="button" |
| 379 | className="group relative mb-5 block w-full cursor-pointer rounded-sm pl-12 text-left outline-none [contain-intrinsic-block-size:48px] [content-visibility:auto] focus-visible:ring-2 focus-visible:ring-ring" | 379 | className="group relative mb-5 block w-full cursor-pointer rounded-sm pl-12 text-left outline-none [contain-intrinsic-block-size:48px] [content-visibility:auto] focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring" |
| 380 | aria-label={`View commit ${event.id}`} | 380 | aria-label={`View commit ${event.id}`} |
| 381 | onClick={() => onOpen(event.id)} | 381 | onClick={() => onOpen(event.id)} |
| 382 | > | 382 | > |
apps/web/src/components/settings/AddProviderInstanceDialog.tsx+1-1| ... | @@ -435,7 +435,7 @@ export function AddProviderInstanceDialog({ | ... | @@ -435,7 +435,7 @@ export function AddProviderInstanceDialog({ |
| 435 | <RadioPrimitive.Root | 435 | <RadioPrimitive.Root |
| 436 | key={option.driverKind} | 436 | key={option.driverKind} |
| 437 | value={option.driverKind} | 437 | value={option.driverKind} |
| 438 | className="relative flex cursor-pointer items-center gap-3 rounded-lg bg-card px-3 py-3 text-left text-muted-foreground outline-none ring-1 ring-black/5 hover:bg-muted focus-visible:ring-2 focus-visible:ring-ring data-checked:bg-primary/8 data-checked:text-foreground data-checked:ring-2 data-checked:ring-primary data-checked:hover:bg-primary/8 dark:bg-white/3 dark:ring-white/5 dark:hover:bg-white/5 dark:data-checked:bg-primary/15 dark:data-checked:ring-primary dark:data-checked:hover:bg-primary/15" | 438 | className="relative flex cursor-pointer items-center gap-3 rounded-lg bg-card px-3 py-3 text-left text-muted-foreground outline-none ring-1 ring-black/5 hover:bg-muted focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring data-checked:bg-primary/8 data-checked:text-foreground data-checked:ring-2 data-checked:ring-inset data-checked:ring-primary data-checked:hover:bg-primary/8 dark:bg-white/3 dark:ring-white/5 dark:hover:bg-white/5 dark:data-checked:bg-primary/15 dark:data-checked:ring-primary dark:data-checked:hover:bg-primary/15" |
| 439 | > | 439 | > |
| 440 | <ProviderInstanceIcon | 440 | <ProviderInstanceIcon |
| 441 | driverKind={option.driverKind} | 441 | driverKind={option.driverKind} |
apps/web/src/components/settings/BrowserImportWizard.tsx+1-1| ... | @@ -457,7 +457,7 @@ function SelectableTile({ | ... | @@ -457,7 +457,7 @@ function SelectableTile({ |
| 457 | aria-pressed={selected} | 457 | aria-pressed={selected} |
| 458 | onClick={onSelect} | 458 | onClick={onSelect} |
| 459 | className={cn( | 459 | className={cn( |
| 460 | "flex w-full cursor-pointer items-center justify-between gap-3 rounded-lg border px-3 py-2 text-left outline-none transition-colors focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:ring-offset-background", | 460 | "flex w-full cursor-pointer items-center justify-between gap-3 rounded-lg border px-3 py-2 text-left outline-none transition-colors focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:ring-offset-background", |
| 461 | selected | 461 | selected |
| 462 | ? "border-primary bg-primary/8" | 462 | ? "border-primary bg-primary/8" |
| 463 | : "border-border/60 hover:border-border hover:bg-muted/40", | 463 | : "border-border/60 hover:border-border hover:bg-muted/40", |
apps/web/src/components/settings/CodexSetupSection.tsx+1-1| ... | @@ -1098,7 +1098,7 @@ function CodexSignInDescription({ | ... | @@ -1098,7 +1098,7 @@ function CodexSignInDescription({ |
| 1098 | return ( | 1098 | return ( |
| 1099 | <button | 1099 | <button |
| 1100 | type="button" | 1100 | type="button" |
| 1101 | className="inline-flex items-center gap-1.5 rounded-sm text-left leading-relaxed outline-none focus-visible:ring-2 focus-visible:ring-ring" | 1101 | className="inline-flex items-center gap-1.5 rounded-sm text-left leading-relaxed outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring" |
| 1102 | aria-label="Having trouble signing in?" | 1102 | aria-label="Having trouble signing in?" |
| 1103 | aria-expanded={expanded} | 1103 | aria-expanded={expanded} |
| 1104 | aria-controls={controls} | 1104 | aria-controls={controls} |
apps/web/src/components/settings/ConnectionsSettings.tsx+4-4| ... | @@ -870,7 +870,7 @@ const PairingLinkListRow = memo(function PairingLinkListRow({ | ... | @@ -870,7 +870,7 @@ const PairingLinkListRow = memo(function PairingLinkListRow({ |
| 870 | role="radio" | 870 | role="radio" |
| 871 | aria-checked={isSelected} | 871 | aria-checked={isSelected} |
| 872 | className={cn( | 872 | className={cn( |
| 873 | "flex w-full items-baseline gap-2 rounded-lg border px-2.5 py-1.5 text-left outline-none focus-visible:ring-2 focus-visible:ring-ring", | 873 | "flex w-full items-baseline gap-2 rounded-lg border px-2.5 py-1.5 text-left outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring", |
| 874 | isSelected | 874 | isSelected |
| 875 | ? "border-foreground/60 bg-muted/30" | 875 | ? "border-foreground/60 bg-muted/30" |
| 876 | : "border-border/50 hover:bg-muted/20", | 876 | : "border-border/50 hover:bg-muted/20", |
| ... | @@ -1651,7 +1651,7 @@ function SavedBackendListRow({ | ... | @@ -1651,7 +1651,7 @@ function SavedBackendListRow({ |
| 1651 | type="button" | 1651 | type="button" |
| 1652 | aria-expanded={routesOpen} | 1652 | aria-expanded={routesOpen} |
| 1653 | onClick={() => setRoutesOpen((open) => !open)} | 1653 | onClick={() => setRoutesOpen((open) => !open)} |
| 1654 | className="inline-flex shrink-0 items-center gap-0.5 rounded-sm text-muted-foreground outline-none hover:text-foreground focus-visible:ring-1 focus-visible:ring-ring" | 1654 | className="inline-flex shrink-0 items-center gap-0.5 rounded-sm text-muted-foreground outline-none hover:text-foreground focus-visible:ring-1 focus-visible:ring-inset focus-visible:ring-ring" |
| 1655 | > | 1655 | > |
| 1656 | {routeCount === 1 ? "Routes" : `${routeCount} routes`} | 1656 | {routeCount === 1 ? "Routes" : `${routeCount} routes`} |
| 1657 | <ChevronRightIcon | 1657 | <ChevronRightIcon |
| ... | @@ -1670,7 +1670,7 @@ function SavedBackendListRow({ | ... | @@ -1670,7 +1670,7 @@ function SavedBackendListRow({ |
| 1670 | aria-expanded={permissionsOpen} | 1670 | aria-expanded={permissionsOpen} |
| 1671 | aria-controls={`remote-permissions-${environmentId}`} | 1671 | aria-controls={`remote-permissions-${environmentId}`} |
| 1672 | onClick={() => setPermissionsOpen((open) => !open)} | 1672 | onClick={() => setPermissionsOpen((open) => !open)} |
| 1673 | className="inline-flex shrink-0 items-center gap-0.5 rounded-sm text-muted-foreground outline-none hover:text-foreground focus-visible:ring-1 focus-visible:ring-ring" | 1673 | className="inline-flex shrink-0 items-center gap-0.5 rounded-sm text-muted-foreground outline-none hover:text-foreground focus-visible:ring-1 focus-visible:ring-inset focus-visible:ring-ring" |
| 1674 | > | 1674 | > |
| 1675 | Permissions | 1675 | Permissions |
| 1676 | <ChevronRightIcon | 1676 | <ChevronRightIcon |
| ... | @@ -3718,7 +3718,7 @@ export function ConnectionsSettings() { | ... | @@ -3718,7 +3718,7 @@ export function ConnectionsSettings() { |
| 3718 | ) : null} | 3718 | ) : null} |
| 3719 | {primaryEnvironment ? ( | 3719 | {primaryEnvironment ? ( |
| 3720 | <details className="group px-3 sm:px-4"> | 3720 | <details className="group px-3 sm:px-4"> |
| 3721 | <summary className="flex min-h-11 cursor-pointer list-none items-center gap-2 rounded-md text-sm font-medium outline-none focus-visible:ring-2 focus-visible:ring-ring [&::-webkit-details-marker]:hidden"> | 3721 | <summary className="flex min-h-11 cursor-pointer list-none items-center gap-2 rounded-md text-sm font-medium outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring [&::-webkit-details-marker]:hidden"> |
| 3722 | Permissions | 3722 | Permissions |
| 3723 | <ChevronRightIcon | 3723 | <ChevronRightIcon |
| 3724 | aria-hidden | 3724 | aria-hidden |
apps/web/src/components/settings/EnvironmentRoutesList.tsx+1-1| ... | @@ -195,7 +195,7 @@ function SortableRouteRow({ | ... | @@ -195,7 +195,7 @@ function SortableRouteRow({ |
| 195 | {...attributes} | 195 | {...attributes} |
| 196 | {...listeners} | 196 | {...listeners} |
| 197 | aria-label={`Reorder ${label}, position ${position}`} | 197 | aria-label={`Reorder ${label}, position ${position}`} |
| 198 | className="flex size-6 shrink-0 cursor-grab touch-none items-center justify-center rounded text-muted-foreground/70 outline-none hover:text-foreground focus-visible:ring-2 focus-visible:ring-ring active:cursor-grabbing" | 198 | className="flex size-6 shrink-0 cursor-grab touch-none items-center justify-center rounded text-muted-foreground/70 outline-none hover:text-foreground focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring active:cursor-grabbing" |
| 199 | > | 199 | > |
| 200 | <GripVerticalIcon className="size-3.5" /> | 200 | <GripVerticalIcon className="size-3.5" /> |
| 201 | </button> | 201 | </button> |
apps/web/src/components/settings/FoldedSettingsSection.tsx+2-2| ... | @@ -46,7 +46,7 @@ export function FoldedSettingsSection({ | ... | @@ -46,7 +46,7 @@ export function FoldedSettingsSection({ |
| 46 | className="flex min-h-7 items-start justify-between gap-4 px-3 sm:px-4" | 46 | className="flex min-h-7 items-start justify-between gap-4 px-3 sm:px-4" |
| 47 | > | 47 | > |
| 48 | <h2> | 48 | <h2> |
| 49 | <CollapsibleTrigger className="flex min-h-7 items-center gap-2 rounded-md text-sm font-normal text-foreground/70 outline-none focus-visible:ring-2 focus-visible:ring-ring"> | 49 | <CollapsibleTrigger className="flex min-h-7 items-center gap-2 rounded-md text-sm font-normal text-foreground/70 outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring"> |
| 50 | {title} | 50 | {title} |
| 51 | <ChevronRightIcon | 51 | <ChevronRightIcon |
| 52 | aria-hidden | 52 | aria-hidden |
| ... | @@ -72,7 +72,7 @@ export function FoldedSettingsSection({ | ... | @@ -72,7 +72,7 @@ export function FoldedSettingsSection({ |
| 72 | <section id={id} ref={targetRef} tabIndex={-1} className="outline-none"> | 72 | <section id={id} ref={targetRef} tabIndex={-1} className="outline-none"> |
| 73 | <Collapsible open={open} onOpenChange={setOpen} render={<SettingsGroup divided={false} />}> | 73 | <Collapsible open={open} onOpenChange={setOpen} render={<SettingsGroup divided={false} />}> |
| 74 | <div className="flex items-center gap-4 px-3 sm:px-4"> | 74 | <div className="flex items-center gap-4 px-3 sm:px-4"> |
| 75 | <CollapsibleTrigger className="flex min-h-11 min-w-0 flex-1 items-center gap-2 py-2 text-left outline-none focus-visible:ring-2 focus-visible:ring-ring rounded-md"> | 75 | <CollapsibleTrigger className="flex min-h-11 min-w-0 flex-1 items-center gap-2 py-2 text-left outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring rounded-md"> |
| 76 | <ChevronRightIcon | 76 | <ChevronRightIcon |
| 77 | aria-hidden | 77 | aria-hidden |
| 78 | className={cn( | 78 | className={cn( |
apps/web/src/components/settings/KeybindingsSettings.tsx+2-2| ... | @@ -230,7 +230,7 @@ function WarningTooltipIcon({ | ... | @@ -230,7 +230,7 @@ function WarningTooltipIcon({ |
| 230 | tabIndex={focusable ? 0 : undefined} | 230 | tabIndex={focusable ? 0 : undefined} |
| 231 | aria-label={label} | 231 | aria-label={label} |
| 232 | className={cn( | 232 | className={cn( |
| 233 | "inline-flex size-5 shrink-0 items-center justify-center rounded-sm text-warning outline-none transition-colors hover:bg-warning/10 focus-visible:ring-3 focus-visible:ring-warning/25", | 233 | "inline-flex size-5 shrink-0 items-center justify-center rounded-sm text-warning outline-none transition-colors hover:bg-warning/10 focus-visible:ring-3 focus-visible:ring-inset focus-visible:ring-warning/25", |
| 234 | className, | 234 | className, |
| 235 | )} | 235 | )} |
| 236 | /> | 236 | /> |
| ... | @@ -818,7 +818,7 @@ function KeybindingKeyControl({ | ... | @@ -818,7 +818,7 @@ function KeybindingKeyControl({ |
| 818 | onClick={() => setDraft({ isRecording: true })} | 818 | onClick={() => setDraft({ isRecording: true })} |
| 819 | aria-label={`Edit shortcut for ${commandLabel(row.command)}: ${formatShortcutLabel(row.binding.shortcut)}`} | 819 | aria-label={`Edit shortcut for ${commandLabel(row.command)}: ${formatShortcutLabel(row.binding.shortcut)}`} |
| 820 | className={cn( | 820 | className={cn( |
| 821 | "inline-flex h-8 cursor-pointer items-center rounded-md border border-transparent px-1.5 sm:h-7 outline-none transition-colors hover:border-border/70 hover:bg-accent focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/24", | 821 | "inline-flex h-8 cursor-pointer items-center rounded-md border border-transparent px-1.5 sm:h-7 outline-none transition-colors hover:border-border/70 hover:bg-accent focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-inset focus-visible:ring-ring/24", |
| 822 | pillClassName, | 822 | pillClassName, |
| 823 | )} | 823 | )} |
| 824 | > | 824 | > |
apps/web/src/components/settings/PanelAnimationsPreview.tsx+1-1| ... | @@ -11,7 +11,7 @@ export function PanelAnimationsPreview({ durationMs }: { durationMs: number }) { | ... | @@ -11,7 +11,7 @@ export function PanelAnimationsPreview({ durationMs }: { durationMs: number }) { |
| 11 | <button | 11 | <button |
| 12 | type="button" | 12 | type="button" |
| 13 | aria-label="Replay panel animation preview" | 13 | aria-label="Replay panel animation preview" |
| 14 | className="flex h-10 w-full cursor-pointer overflow-hidden rounded-lg border border-border bg-background p-1 shadow-xs/5 outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:ring-offset-background" | 14 | className="flex h-10 w-full cursor-pointer overflow-hidden rounded-lg border border-border bg-background p-1 shadow-xs/5 outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:ring-offset-background" |
| 15 | onClick={() => setPanelsOpen((open) => !open)} | 15 | onClick={() => setPanelsOpen((open) => !open)} |
| 16 | style={{ "--preview-duration": `${durationMs}ms` } as CSSProperties} | 16 | style={{ "--preview-duration": `${durationMs}ms` } as CSSProperties} |
| 17 | > | 17 | > |
apps/web/src/components/settings/ProjectIconPickerDialog.tsx+3-3| ... | @@ -131,7 +131,7 @@ export function ProjectIconPickerDialog({ | ... | @@ -131,7 +131,7 @@ export function ProjectIconPickerDialog({ |
| 131 | aria-label={option.label} | 131 | aria-label={option.label} |
| 132 | aria-pressed={color === option.value} | 132 | aria-pressed={color === option.value} |
| 133 | className={cn( | 133 | className={cn( |
| 134 | "flex size-6 items-center justify-center rounded-full border border-transparent outline-none focus-visible:ring-2 focus-visible:ring-ring", | 134 | "flex size-6 items-center justify-center rounded-full border border-transparent outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring", |
| 135 | color === option.value && "border-foreground/64", | 135 | color === option.value && "border-foreground/64", |
| 136 | )} | 136 | )} |
| 137 | onClick={() => setColor(option.value)} | 137 | onClick={() => setColor(option.value)} |
| ... | @@ -161,7 +161,7 @@ export function ProjectIconPickerDialog({ | ... | @@ -161,7 +161,7 @@ export function ProjectIconPickerDialog({ |
| 161 | aria-label={iconLabel(name)} | 161 | aria-label={iconLabel(name)} |
| 162 | aria-pressed={iconName === name} | 162 | aria-pressed={iconName === name} |
| 163 | className={cn( | 163 | className={cn( |
| 164 | "flex aspect-square items-center justify-center rounded-md border border-transparent outline-none hover:bg-accent focus-visible:ring-2 focus-visible:ring-ring", | 164 | "flex aspect-square items-center justify-center rounded-md border border-transparent outline-none hover:bg-accent focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring", |
| 165 | iconName === name && "border-border bg-accent", | 165 | iconName === name && "border-border bg-accent", |
| 166 | selectedColorClassName, | 166 | selectedColorClassName, |
| 167 | )} | 167 | )} |
| ... | @@ -211,7 +211,7 @@ export function ProjectIconPickerDialog({ | ... | @@ -211,7 +211,7 @@ export function ProjectIconPickerDialog({ |
| 211 | aria-label={option.label} | 211 | aria-label={option.label} |
| 212 | aria-pressed={emoji === option.emoji} | 212 | aria-pressed={emoji === option.emoji} |
| 213 | className={cn( | 213 | className={cn( |
| 214 | "flex aspect-square items-center justify-center rounded-md border border-transparent text-xl outline-none hover:bg-accent focus-visible:ring-2 focus-visible:ring-ring", | 214 | "flex aspect-square items-center justify-center rounded-md border border-transparent text-xl outline-none hover:bg-accent focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring", |
| 215 | emoji === option.emoji && "border-border bg-accent", | 215 | emoji === option.emoji && "border-border bg-accent", |
| 216 | )} | 216 | )} |
| 217 | onClick={() => setEmoji(option.emoji)} | 217 | onClick={() => setEmoji(option.emoji)} |
apps/web/src/components/settings/ProviderInstanceCard.tsx+1-1| ... | @@ -923,7 +923,7 @@ export function ProviderInstanceCard({ | ... | @@ -923,7 +923,7 @@ export function ProviderInstanceCard({ |
| 923 | > | 923 | > |
| 924 | <button | 924 | <button |
| 925 | type="button" | 925 | type="button" |
| 926 | className="pointer-events-auto absolute inset-0 cursor-pointer rounded-md outline-none focus-visible:ring-2 focus-visible:ring-ring" | 926 | className="pointer-events-auto absolute inset-0 cursor-pointer rounded-md outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring" |
| 927 | onClick={onSelect} | 927 | onClick={onSelect} |
| 928 | aria-label={`Select ${displayName}`} | 928 | aria-label={`Select ${displayName}`} |
| 929 | aria-pressed={selected} | 929 | aria-pressed={selected} |
apps/web/src/components/settings/ThemeColorPicker.tsx+2-2| ... | @@ -266,7 +266,7 @@ function ThemeColorPicker({ | ... | @@ -266,7 +266,7 @@ function ThemeColorPicker({ |
| 266 | render={ | 266 | render={ |
| 267 | <button | 267 | <button |
| 268 | aria-label={`Choose ${label} color`} | 268 | aria-label={`Choose ${label} color`} |
| 269 | className="relative flex size-6 shrink-0 cursor-pointer items-center justify-center rounded-full border border-foreground/30 transition-transform hover:scale-105 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background" | 269 | className="relative flex size-6 shrink-0 cursor-pointer items-center justify-center rounded-full border border-foreground/30 transition-transform hover:scale-105 focus-visible:outline-2 focus-visible:outline-solid focus-visible:-outline-offset-2 focus-visible:outline-ring" |
| 270 | onFocus={onInteract} | 270 | onFocus={onInteract} |
| 271 | onPointerDown={onInteract} | 271 | onPointerDown={onInteract} |
| 272 | type="button" | 272 | type="button" |
| ... | @@ -333,7 +333,7 @@ export const ThemeColorField = memo(function ThemeColorField({ | ... | @@ -333,7 +333,7 @@ export const ThemeColorField = memo(function ThemeColorField({ |
| 333 | <button | 333 | <button |
| 334 | aria-label={`${selected ? "Hide" : "Show"} ${label} usage`} | 334 | aria-label={`${selected ? "Hide" : "Show"} ${label} usage`} |
| 335 | aria-pressed={selected} | 335 | aria-pressed={selected} |
| 336 | className="flex min-w-0 flex-1 cursor-pointer items-center rounded-md text-left text-sm text-muted-foreground outline-none hover:text-foreground focus-visible:ring-2 focus-visible:ring-ring" | 336 | className="flex min-w-0 flex-1 cursor-pointer items-center rounded-md text-left text-sm text-muted-foreground outline-none hover:text-foreground focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring" |
| 337 | onClick={() => onToggleSelected?.(role)} | 337 | onClick={() => onToggleSelected?.(role)} |
| 338 | type="button" | 338 | type="button" |
| 339 | > | 339 | > |
apps/web/src/components/settings/ThemeImportDialog.tsx+1-1| ... | @@ -111,7 +111,7 @@ function ThemeJsonEditor({ | ... | @@ -111,7 +111,7 @@ function ThemeJsonEditor({ |
| 111 | }, []); | 111 | }, []); |
| 112 | 112 | ||
| 113 | return ( | 113 | return ( |
| 114 | <div className="relative overflow-hidden rounded-xl border border-input bg-background shadow-xs/5 focus-within:border-ring focus-within:ring-3 focus-within:ring-ring/24"> | 114 | <div className="relative overflow-hidden rounded-xl border border-input bg-background shadow-xs/5 focus-within:border-ring focus-within:ring-3 focus-within:ring-inset focus-within:ring-ring/24"> |
| 115 | {isPlainText ? null : ( | 115 | {isPlainText ? null : ( |
| 116 | <pre | 116 | <pre |
| 117 | ref={highlightRef} | 117 | ref={highlightRef} |
apps/web/src/components/settings/ThemePreviewCircles.tsx+1-1| ... | @@ -187,7 +187,7 @@ export function ThemePreviewCircles({ | ... | @@ -187,7 +187,7 @@ export function ThemePreviewCircles({ |
| 187 | aria-label={`Use ${label} ${mode} mode`} | 187 | aria-label={`Use ${label} ${mode} mode`} |
| 188 | aria-pressed={isPicked} | 188 | aria-pressed={isPicked} |
| 189 | className={cn( | 189 | className={cn( |
| 190 | "relative flex size-[68px] shrink-0 transform-gpu cursor-pointer items-center justify-center rounded-full p-1 outline-none transition-transform hover:scale-105 focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-card", | 190 | "relative flex size-[68px] shrink-0 transform-gpu cursor-pointer items-center justify-center rounded-full p-1 outline-none transition-transform hover:scale-105 focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-card", |
| 191 | isPicked && "hover:scale-100", | 191 | isPicked && "hover:scale-100", |
| 192 | )} | 192 | )} |
| 193 | onClick={(event) => { | 193 | onClick={(event) => { |
apps/web/src/components/settings/ThemeSettings.tsx+9-7| ... | @@ -197,7 +197,7 @@ function ThemeLibraryCard({ | ... | @@ -197,7 +197,7 @@ function ThemeLibraryCard({ |
| 197 | : `Use ${mode} variant, currently ${selected.option.label}` | 197 | : `Use ${mode} variant, currently ${selected.option.label}` |
| 198 | } | 198 | } |
| 199 | aria-pressed={isActive} | 199 | aria-pressed={isActive} |
| 200 | className="absolute left-1/2 top-2 z-20 flex size-14 items-center justify-center rounded-full outline-none focus-visible:ring-2 focus-visible:ring-ring" | 200 | className="absolute left-1/2 top-2 z-20 flex size-14 items-center justify-center rounded-full outline-none focus-visible:outline-2 focus-visible:outline-solid focus-visible:-outline-offset-2 focus-visible:outline-ring" |
| 201 | style={{ | 201 | style={{ |
| 202 | transform: `translateX(calc(-50% + ${rootOffsetX}px))`, | 202 | transform: `translateX(calc(-50% + ${rootOffsetX}px))`, |
| 203 | }} | 203 | }} |
| ... | @@ -216,7 +216,7 @@ function ThemeLibraryCard({ | ... | @@ -216,7 +216,7 @@ function ThemeLibraryCard({ |
| 216 | {isActive ? ( | 216 | {isActive ? ( |
| 217 | <span | 217 | <span |
| 218 | aria-hidden | 218 | aria-hidden |
| 219 | className="pointer-events-none absolute inset-0 rounded-full ring-2 ring-ring" | 219 | className="pointer-events-none absolute inset-0 rounded-full ring-2 ring-inset ring-ring" |
| 220 | /> | 220 | /> |
| 221 | ) : null} | 221 | ) : null} |
| 222 | {isActive ? ( | 222 | {isActive ? ( |
| ... | @@ -256,8 +256,10 @@ function ThemeLibraryCard({ | ... | @@ -256,8 +256,10 @@ function ThemeLibraryCard({ |
| 256 | aria-label={`Use ${option.label} for ${mode} mode${optionIsActive ? ", currently active" : ""}`} | 256 | aria-label={`Use ${option.label} for ${mode} mode${optionIsActive ? ", currently active" : ""}`} |
| 257 | aria-pressed={optionIsActive} | 257 | aria-pressed={optionIsActive} |
| 258 | className={cn( | 258 | className={cn( |
| 259 | "absolute left-1/2 top-1 z-30 flex size-7 items-center justify-center rounded-full bg-background shadow-sm outline-none transition-[opacity,transform] duration-200 ease-out motion-reduce:transition-none focus-visible:ring-2 focus-visible:ring-ring", | 259 | "absolute left-1/2 top-1 z-30 flex size-7 items-center justify-center rounded-full bg-background shadow-sm outline-none transition-[opacity,transform] duration-200 ease-out motion-reduce:transition-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring", |
| 260 | optionIsActive ? "ring-2 ring-ring" : "ring-1 ring-border/70", | 260 | optionIsActive |
| 261 | ? "ring-2 ring-inset ring-ring" | ||
| 262 | : "ring-1 ring-border/70", | ||
| 261 | )} | 263 | )} |
| 262 | style={{ | 264 | style={{ |
| 263 | opacity: isOpen ? 1 : 0, | 265 | opacity: isOpen ? 1 : 0, |
| ... | @@ -303,7 +305,7 @@ function ThemeLibraryCard({ | ... | @@ -303,7 +305,7 @@ function ThemeLibraryCard({ |
| 303 | <button | 305 | <button |
| 304 | aria-label={`Use ${variantNavigation ? `${variantNavigation.collectionLabel}, ${theme.label} variant` : `${theme.label} theme`}${isActive ? ", currently active" : ""}`} | 306 | aria-label={`Use ${variantNavigation ? `${variantNavigation.collectionLabel}, ${theme.label} variant` : `${theme.label} theme`}${isActive ? ", currently active" : ""}`} |
| 305 | aria-pressed={isActive} | 307 | aria-pressed={isActive} |
| 306 | className="min-w-0 cursor-pointer truncate rounded-sm text-left text-sm font-medium text-foreground outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-card" | 308 | className="min-w-0 cursor-pointer truncate rounded-sm text-left text-sm font-medium text-foreground outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-card" |
| 307 | type="button" | 309 | type="button" |
| 308 | onClick={(event) => { | 310 | onClick={(event) => { |
| 309 | event.stopPropagation(); | 311 | event.stopPropagation(); |
| ... | @@ -726,7 +728,7 @@ export function ThemeLibrary({ | ... | @@ -726,7 +728,7 @@ export function ThemeLibrary({ |
| 726 | aria-label={mode === "system" ? "Follow the system appearance" : `Use ${mode} mode`} | 728 | aria-label={mode === "system" ? "Follow the system appearance" : `Use ${mode} mode`} |
| 727 | aria-pressed={isActive} | 729 | aria-pressed={isActive} |
| 728 | className={cn( | 730 | className={cn( |
| 729 | "flex cursor-pointer flex-col items-stretch gap-1.5 rounded-xl border p-2 outline-none transition-colors focus-visible:ring-2 focus-visible:ring-ring", | 731 | "flex cursor-pointer flex-col items-stretch gap-1.5 rounded-xl border p-2 outline-none transition-colors focus-visible:outline-2 focus-visible:outline-solid focus-visible:-outline-offset-2 focus-visible:outline-ring", |
| 730 | isActive | 732 | isActive |
| 731 | ? "border-transparent bg-accent/30" | 733 | ? "border-transparent bg-accent/30" |
| 732 | : "border-border/70 bg-card/60 hover:bg-accent/10", | 734 | : "border-border/70 bg-card/60 hover:bg-accent/10", |
| ... | @@ -989,7 +991,7 @@ export function ThemeLibrary({ | ... | @@ -989,7 +991,7 @@ export function ThemeLibrary({ |
| 989 | <span className="absolute right-2 top-2 inline-grid size-5 grid-cols-1 sm:size-4"> | 991 | <span className="absolute right-2 top-2 inline-grid size-5 grid-cols-1 sm:size-4"> |
| 990 | <input | 992 | <input |
| 991 | checked={checked} | 993 | checked={checked} |
| 992 | className="col-start-1 row-start-1 size-full appearance-none rounded-sm border border-input bg-background outline-none checked:border-primary checked:bg-primary focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring dark:not-checked:bg-input/32 forced-colors:appearance-auto" | 994 | className="col-start-1 row-start-1 size-full appearance-none rounded-sm border border-input bg-background outline-none checked:border-primary checked:bg-primary focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-ring checked:focus-visible:inset-ring-3 checked:focus-visible:inset-ring-background dark:not-checked:bg-input/32 forced-colors:appearance-auto" |
| 993 | id={checkboxId} | 995 | id={checkboxId} |
| 994 | name="themes-to-remove" | 996 | name="themes-to-remove" |
| 995 | type="checkbox" | 997 | type="checkbox" |
apps/web/src/components/settings/settingsLayout.tsx+1-1| ... | @@ -375,7 +375,7 @@ export function SettingsRow({ | ... | @@ -375,7 +375,7 @@ export function SettingsRow({ |
| 375 | // Focusable so keyboard users can still reach the explanation. | 375 | // Focusable so keyboard users can still reach the explanation. |
| 376 | <span | 376 | <span |
| 377 | tabIndex={0} | 377 | tabIndex={0} |
| 378 | className="flex w-full items-center rounded-md outline-none focus-visible:ring-2 focus-visible:ring-ring @min-[32rem]/settings-row:w-auto" | 378 | className="flex w-full items-center rounded-md outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring @min-[32rem]/settings-row:w-auto" |
| 379 | /> | 379 | /> |
| 380 | } | 380 | } |
| 381 | > | 381 | > |
apps/web/src/components/sidebar/SidebarChrome.tsx+1-1| ... | @@ -112,7 +112,7 @@ function SidebarBrand({ onBackdrop }: { onBackdrop: boolean }) { | ... | @@ -112,7 +112,7 @@ function SidebarBrand({ onBackdrop }: { onBackdrop: boolean }) { |
| 112 | <Link | 112 | <Link |
| 113 | aria-label="Go to threads" | 113 | aria-label="Go to threads" |
| 114 | className={cn( | 114 | className={cn( |
| 115 | "relative z-10 ml-[var(--workspace-titlebar-content-left)] hidden h-7 w-fit min-w-0 shrink-0 items-center overflow-hidden rounded-md outline-hidden ring-ring focus-visible:ring-2 md:flex", | 115 | "relative z-10 ml-[var(--workspace-titlebar-content-left)] hidden h-7 w-fit min-w-0 shrink-0 items-center overflow-hidden rounded-md outline-hidden ring-ring focus-visible:ring-2 focus-visible:ring-inset md:flex", |
| 116 | onBackdrop ? "text-white" : "text-foreground", | 116 | onBackdrop ? "text-white" : "text-foreground", |
| 117 | )} | 117 | )} |
| 118 | to="/" | 118 | to="/" |
apps/web/src/components/sidebar/SidebarProviderUpdatePill.tsx+1-1| ... | @@ -195,7 +195,7 @@ export function SidebarProviderUpdatePill() { | ... | @@ -195,7 +195,7 @@ export function SidebarProviderUpdatePill() { |
| 195 | <button | 195 | <button |
| 196 | type="button" | 196 | type="button" |
| 197 | aria-label="Dismiss provider update notice" | 197 | aria-label="Dismiss provider update notice" |
| 198 | className="relative z-[1] mr-1 flex size-5 shrink-0 cursor-pointer items-center justify-center rounded-md opacity-70 outline-none hover:opacity-100 focus-visible:opacity-100 focus-visible:ring-2 focus-visible:ring-ring" | 198 | className="relative z-[1] mr-1 flex size-5 shrink-0 cursor-pointer items-center justify-center rounded-md opacity-70 outline-none hover:opacity-100 focus-visible:opacity-100 focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring" |
| 199 | onClick={() => startExit(displayedView.key, null, displayedView.key)} | 199 | onClick={() => startExit(displayedView.key, null, displayedView.key)} |
| 200 | > | 200 | > |
| 201 | <XIcon className="size-3.5 shrink-0" /> | 201 | <XIcon className="size-3.5 shrink-0" /> |
apps/web/src/components/sidebar/SidebarUpdatePill.tsx+1-1| ... | @@ -303,7 +303,7 @@ function SidebarUpdateControl() { | ... | @@ -303,7 +303,7 @@ function SidebarUpdateControl() { |
| 303 | aria-label={tooltip} | 303 | aria-label={tooltip} |
| 304 | aria-disabled={isInteractionDisabled || undefined} | 304 | aria-disabled={isInteractionDisabled || undefined} |
| 305 | className={cn( | 305 | className={cn( |
| 306 | "inline-flex size-8 items-center justify-center rounded-full outline-hidden ring-ring transition-colors focus-visible:ring-2", | 306 | "inline-flex size-8 items-center justify-center rounded-full outline-hidden ring-ring transition-colors focus-visible:ring-2 focus-visible:ring-inset", |
| 307 | isInteractionDisabled ? "cursor-not-allowed" : "cursor-pointer", | 307 | isInteractionDisabled ? "cursor-not-allowed" : "cursor-pointer", |
| 308 | showUpdateIconState | 308 | showUpdateIconState |
| 309 | ? cn( | 309 | ? cn( |
apps/web/src/components/sidebar/SidebarUpdateReleaseNotes.tsx+1-1| ... | @@ -30,7 +30,7 @@ function ReleaseLink({ | ... | @@ -30,7 +30,7 @@ function ReleaseLink({ |
| 30 | }) { | 30 | }) { |
| 31 | return ( | 31 | return ( |
| 32 | <a | 32 | <a |
| 33 | className="mt-2 inline-flex items-center gap-1 rounded-sm text-xs leading-5 text-muted-foreground underline decoration-dotted underline-offset-4 outline-none transition-colors hover:text-foreground focus-visible:text-foreground focus-visible:ring-2 focus-visible:ring-ring" | 33 | className="mt-2 inline-flex items-center gap-1 rounded-sm text-xs leading-5 text-muted-foreground underline decoration-dotted underline-offset-4 outline-none transition-colors hover:text-foreground focus-visible:text-foreground focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring" |
| 34 | href={releaseUrl} | 34 | href={releaseUrl} |
| 35 | onClick={(event) => { | 35 | onClick={(event) => { |
| 36 | event.preventDefault(); | 36 | event.preventDefault(); |
apps/web/src/components/ui/badge.tsx+1-1| ... | @@ -7,7 +7,7 @@ import { cva, type VariantProps } from "class-variance-authority"; | ... | @@ -7,7 +7,7 @@ import { cva, type VariantProps } from "class-variance-authority"; |
| 7 | import { cn } from "~/lib/utils"; | 7 | import { cn } from "~/lib/utils"; |
| 8 | 8 | ||
| 9 | const badgeVariants = cva( | 9 | const badgeVariants = cva( |
| 10 | "relative inline-flex shrink-0 items-center justify-center gap-1 whitespace-nowrap rounded-sm border border-transparent font-medium outline-none transition-shadow focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:ring-offset-background disabled:pointer-events-none disabled:opacity-64 [&_svg:not([class*='opacity-'])]:opacity-80 [&_svg:not([class*='size-'])]:size-3.5 sm:[&_svg:not([class*='size-'])]:size-3 [&_svg]:pointer-events-none [&_svg]:shrink-0 [button&,a&]:cursor-pointer [button&,a&]:pointer-coarse:after:absolute [button&,a&]:pointer-coarse:after:size-full [button&,a&]:pointer-coarse:after:min-h-11 [button&,a&]:pointer-coarse:after:min-w-11", | 10 | "relative inline-flex shrink-0 items-center justify-center gap-1 whitespace-nowrap rounded-sm border border-transparent font-medium outline-none transition-shadow focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:ring-offset-background disabled:pointer-events-none disabled:opacity-64 [&_svg:not([class*='opacity-'])]:opacity-80 [&_svg:not([class*='size-'])]:size-3.5 sm:[&_svg:not([class*='size-'])]:size-3 [&_svg]:pointer-events-none [&_svg]:shrink-0 [button&,a&]:cursor-pointer [button&,a&]:pointer-coarse:after:absolute [button&,a&]:pointer-coarse:after:size-full [button&,a&]:pointer-coarse:after:min-h-11 [button&,a&]:pointer-coarse:after:min-w-11", |
| 11 | { | 11 | { |
| 12 | defaultVariants: { | 12 | defaultVariants: { |
| 13 | size: "default", | 13 | size: "default", |
apps/web/src/components/ui/button.tsx+1-1| ... | @@ -8,7 +8,7 @@ import type * as React from "react"; | ... | @@ -8,7 +8,7 @@ import type * as React from "react"; |
| 8 | import { cn } from "~/lib/utils"; | 8 | import { cn } from "~/lib/utils"; |
| 9 | 9 | ||
| 10 | const buttonVariants = cva( | 10 | const buttonVariants = cva( |
| 11 | "[--control-icon-color:currentColor] [&_svg]:-mx-0.5 relative inline-flex shrink-0 cursor-pointer items-center justify-center gap-2 whitespace-nowrap rounded-[var(--control-radius)] border font-medium text-base outline-none transition-[box-shadow,scale] [&:active:not([aria-haspopup])]:scale-[0.97] before:pointer-events-none before:absolute before:inset-0 before:rounded-[calc(var(--control-radius)-1px)] pointer-coarse:after:absolute pointer-coarse:after:size-full pointer-coarse:after:min-h-11 pointer-coarse:after:min-w-11 focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:ring-offset-background disabled:pointer-events-none disabled:opacity-64 aria-disabled:cursor-not-allowed aria-disabled:opacity-64 sm:text-sm [&_svg:not([class*='text-'])]:text-[var(--control-icon-color)] [&_svg:not([class*='size-'])]:size-4.5 sm:[&_svg:not([class*='size-'])]:size-4 [&_svg]:pointer-events-none [&_svg]:shrink-0", | 11 | "[--control-icon-color:currentColor] [&_svg]:-mx-0.5 relative inline-flex shrink-0 cursor-pointer items-center justify-center gap-2 whitespace-nowrap rounded-[var(--control-radius)] border font-medium text-base outline-none transition-[box-shadow,scale] [&:active:not([aria-haspopup])]:scale-[0.97] before:pointer-events-none before:absolute before:inset-0 before:rounded-[calc(var(--control-radius)-1px)] pointer-coarse:after:absolute pointer-coarse:after:size-full pointer-coarse:after:min-h-11 pointer-coarse:after:min-w-11 focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:ring-offset-background disabled:pointer-events-none disabled:opacity-64 aria-disabled:cursor-not-allowed aria-disabled:opacity-64 sm:text-sm [&_svg:not([class*='text-'])]:text-[var(--control-icon-color)] [&_svg:not([class*='size-'])]:size-4.5 sm:[&_svg:not([class*='size-'])]:size-4 [&_svg]:pointer-events-none [&_svg]:shrink-0", |
| 12 | { | 12 | { |
| 13 | defaultVariants: { | 13 | defaultVariants: { |
| 14 | size: "default", | 14 | size: "default", |
apps/web/src/components/ui/calendar.tsx+2-2| ... | @@ -56,11 +56,11 @@ export function Calendar({ | ... | @@ -56,11 +56,11 @@ export function Calendar({ |
| 56 | day: "size-(--cell-size) text-sm py-px", | 56 | day: "size-(--cell-size) text-sm py-px", |
| 57 | day_button: cn( | 57 | day_button: cn( |
| 58 | buttonClassNames, | 58 | buttonClassNames, |
| 59 | "in-data-disabled:pointer-events-none in-[.range-middle]:rounded-none in-[.range-end:not(.range-start)]:rounded-s-none in-[.range-start:not(.range-end)]:rounded-e-none in-[.range-middle]:in-data-selected:bg-accent in-data-selected:bg-primary in-[.range-middle]:in-data-selected:text-foreground in-data-disabled:text-muted-foreground/72 in-data-outside:text-muted-foreground/72 in-data-selected:in-data-outside:text-primary-foreground in-data-selected:text-primary-foreground in-data-disabled:line-through outline-none in-[[data-selected]:not(.range-middle)]:transition-[border-radius,box-shadow] focus-visible:z-1 focus-visible:ring-[3px] focus-visible:ring-ring/50", | 59 | "in-data-disabled:pointer-events-none in-[.range-middle]:rounded-none in-[.range-end:not(.range-start)]:rounded-s-none in-[.range-start:not(.range-end)]:rounded-e-none in-[.range-middle]:in-data-selected:bg-accent in-data-selected:bg-primary in-[.range-middle]:in-data-selected:text-foreground in-data-disabled:text-muted-foreground/72 in-data-outside:text-muted-foreground/72 in-data-selected:in-data-outside:text-primary-foreground in-data-selected:text-primary-foreground in-data-disabled:line-through outline-none in-[[data-selected]:not(.range-middle)]:transition-[border-radius,box-shadow] focus-visible:z-1 focus-visible:ring-[3px] focus-visible:ring-inset focus-visible:ring-ring/50", |
| 60 | ), | 60 | ), |
| 61 | dropdown: "absolute bg-popover inset-0 opacity-0", | 61 | dropdown: "absolute bg-popover inset-0 opacity-0", |
| 62 | dropdown_root: | 62 | dropdown_root: |
| 63 | "relative has-focus:border-ring has-focus:ring-ring/50 has-focus:ring-[3px] border border-input shadow-xs/5 rounded-lg px-[calc(--spacing(3)-1px)] h-9 sm:h-8 [&_svg:not([class*='opacity-'])]:opacity-80 [&_svg:not([class*='size-'])]:size-4.5 sm:[&_svg:not([class*='size-'])]:size-4 [&_svg]:pointer-events-none [&_svg]:-me-1", | 63 | "relative has-focus:border-ring has-focus:ring-ring/50 has-focus:ring-[3px] has-focus:ring-inset border border-input shadow-xs/5 rounded-lg px-[calc(--spacing(3)-1px)] h-9 sm:h-8 [&_svg:not([class*='opacity-'])]:opacity-80 [&_svg:not([class*='size-'])]:size-4.5 sm:[&_svg:not([class*='size-'])]:size-4 [&_svg]:pointer-events-none [&_svg]:-me-1", |
| 64 | dropdowns: | 64 | dropdowns: |
| 65 | "w-full flex items-center text-base sm:text-sm justify-center h-(--cell-size) gap-1.5 *:[span]:font-medium", | 65 | "w-full flex items-center text-base sm:text-sm justify-center h-(--cell-size) gap-1.5 *:[span]:font-medium", |
| 66 | hidden: "invisible", | 66 | hidden: "invisible", |
apps/web/src/components/ui/checkbox.tsx+3-2| ... | @@ -8,14 +8,15 @@ function Checkbox({ className, ...props }: CheckboxPrimitive.Root.Props) { | ... | @@ -8,14 +8,15 @@ function Checkbox({ className, ...props }: CheckboxPrimitive.Root.Props) { |
| 8 | return ( | 8 | return ( |
| 9 | <CheckboxPrimitive.Root | 9 | <CheckboxPrimitive.Root |
| 10 | className={cn( | 10 | className={cn( |
| 11 | "relative inline-flex size-4.5 shrink-0 items-center justify-center rounded-[.25rem] border border-input bg-background not-dark:bg-clip-padding shadow-xs/5 outline-none ring-ring transition-shadow before:pointer-events-none before:absolute before:inset-0 before:rounded-[3px] not-data-disabled:not-data-checked:not-aria-invalid:before:shadow-[0_1px_--theme(--color-black/4%)] focus-visible:ring-2 focus-visible:ring-offset-1 focus-visible:ring-offset-background aria-invalid:border-destructive/36 focus-visible:aria-invalid:border-destructive/64 focus-visible:aria-invalid:ring-destructive/48 data-disabled:opacity-64 sm:size-4 dark:not-data-checked:bg-input/32 dark:aria-invalid:ring-destructive/24 dark:not-data-disabled:not-data-checked:not-aria-invalid:before:shadow-[0_-1px_--theme(--color-white/6%)] [[data-disabled],[data-checked],[aria-invalid]]:shadow-none", | 11 | "relative inline-flex size-4.5 shrink-0 items-center justify-center rounded-[.25rem] border border-input bg-background not-dark:bg-clip-padding shadow-xs/5 outline-none transition-shadow before:pointer-events-none before:absolute before:inset-0 before:rounded-[3px] not-data-disabled:not-data-checked:not-aria-invalid:before:shadow-[0_1px_--theme(--color-black/4%)] focus-visible:outline-2 focus-visible:outline-solid focus-visible:-outline-offset-2 focus-visible:outline-ring aria-invalid:border-destructive/36 focus-visible:aria-invalid:border-destructive/64 focus-visible:aria-invalid:outline-destructive/48 data-disabled:opacity-64 sm:size-4 dark:not-data-checked:bg-input/32 dark:focus-visible:aria-invalid:outline-destructive/24 dark:not-data-disabled:not-data-checked:not-aria-invalid:before:shadow-[0_-1px_--theme(--color-white/6%)] [[data-disabled],[data-checked],[aria-invalid]]:shadow-none", |
| 12 | className, | 12 | className, |
| 13 | )} | 13 | )} |
| 14 | data-slot="checkbox" | 14 | data-slot="checkbox" |
| 15 | {...props} | 15 | {...props} |
| 16 | > | 16 | > |
| 17 | {/* Leave a contrasting inner gap inside the 2px focus outline. */} | ||
| 17 | <CheckboxPrimitive.Indicator | 18 | <CheckboxPrimitive.Indicator |
| 18 | className="-inset-px absolute flex items-center justify-center rounded-[.25rem] text-primary-foreground data-unchecked:hidden data-checked:bg-primary data-indeterminate:text-foreground" | 19 | className="-inset-px absolute flex items-center justify-center rounded-[.25rem] text-primary-foreground data-unchecked:hidden data-checked:bg-primary data-indeterminate:text-foreground in-[[data-slot=checkbox]:focus-visible]:inset-shadow-[0_0_0_3px_var(--background)] in-[[data-slot=checkbox]:focus-visible]:outline-2 in-[[data-slot=checkbox]:focus-visible]:outline-solid in-[[data-slot=checkbox]:focus-visible]:-outline-offset-2 in-[[data-slot=checkbox]:focus-visible]:outline-inherit" |
| 19 | data-slot="checkbox-indicator" | 20 | data-slot="checkbox-indicator" |
| 20 | render={(props, state) => ( | 21 | render={(props, state) => ( |
| 21 | <span {...props}> | 22 | <span {...props}> |
apps/web/src/components/ui/color-picker.tsx+2-2| ... | @@ -116,7 +116,7 @@ export function ColorSaturationValuePlane({ | ... | @@ -116,7 +116,7 @@ export function ColorSaturationValuePlane({ |
| 116 | aria-label={`${label} saturation and brightness`} | 116 | aria-label={`${label} saturation and brightness`} |
| 117 | role="group" | 117 | role="group" |
| 118 | className={cn( | 118 | className={cn( |
| 119 | "relative cursor-crosshair touch-none overflow-hidden bg-[linear-gradient(to_top,#000,transparent),linear-gradient(to_right,#fff,transparent)] has-[:focus-visible]:ring-2 has-[:focus-visible]:ring-ring has-[:focus-visible]:ring-offset-2 has-[:focus-visible]:ring-offset-popover", | 119 | "relative cursor-crosshair touch-none overflow-hidden bg-[linear-gradient(to_top,#000,transparent),linear-gradient(to_right,#fff,transparent)] has-[:focus-visible]:ring-2 has-[:focus-visible]:ring-inset has-[:focus-visible]:ring-ring has-[:focus-visible]:ring-offset-2 has-[:focus-visible]:ring-offset-popover", |
| 120 | variant === "edge" ? "h-36 rounded-none" : "h-32 rounded-lg", | 120 | variant === "edge" ? "h-36 rounded-none" : "h-32 rounded-lg", |
| 121 | className, | 121 | className, |
| 122 | )} | 122 | )} |
| ... | @@ -200,7 +200,7 @@ export function ColorHueSlider({ | ... | @@ -200,7 +200,7 @@ export function ColorHueSlider({ |
| 200 | aria-valuemin={0} | 200 | aria-valuemin={0} |
| 201 | aria-valuenow={Math.round(value)} | 201 | aria-valuenow={Math.round(value)} |
| 202 | className={cn( | 202 | className={cn( |
| 203 | "relative flex h-6 cursor-pointer touch-none items-center rounded-full outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-popover", | 203 | "relative flex h-6 cursor-pointer touch-none items-center rounded-full outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-popover", |
| 204 | className, | 204 | className, |
| 205 | )} | 205 | )} |
| 206 | role="slider" | 206 | role="slider" |
apps/web/src/components/ui/input-group.tsx+1-1| ... | @@ -7,7 +7,7 @@ import { cn } from "~/lib/utils"; | ... | @@ -7,7 +7,7 @@ import { cn } from "~/lib/utils"; |
| 7 | import { Input, type InputProps } from "~/components/ui/input"; | 7 | import { Input, type InputProps } from "~/components/ui/input"; |
| 8 | 8 | ||
| 9 | const inputGroupVariants = cva( | 9 | const inputGroupVariants = cva( |
| 10 | "relative inline-flex w-full min-w-0 items-center rounded-[var(--control-radius)] border text-base text-foreground ring-ring/24 transition-shadow has-[input:focus-visible,textarea:focus-visible]:has-[input[aria-invalid],textarea[aria-invalid]]:border-destructive/64 has-[input:focus-visible,textarea:focus-visible]:has-[input[aria-invalid],textarea[aria-invalid]]:ring-destructive/16 has-[textarea]:h-auto has-data-[align=block-end]:h-auto has-data-[align=block-start]:h-auto has-data-[align=block-end]:flex-col has-data-[align=block-start]:flex-col has-[input:focus-visible,textarea:focus-visible]:border-ring has-[input[aria-invalid],textarea[aria-invalid]]:border-destructive/36 has-autofill:bg-foreground/4 has-[input:disabled,textarea:disabled]:opacity-64 has-[input:disabled,textarea:disabled,input:focus-visible,textarea:focus-visible,input[aria-invalid],textarea[aria-invalid]]:shadow-none has-[input:focus-visible,textarea:focus-visible]:ring-[3px] sm:text-sm dark:has-autofill:bg-foreground/8 dark:has-[input[aria-invalid],textarea[aria-invalid]]:ring-destructive/24 has-data-[align=inline-start]:**:[[data-size=sm]_input]:ps-1.5 has-data-[align=inline-end]:**:[[data-size=sm]_input]:pe-1.5 *:[[data-slot=input-control],[data-slot=textarea-control]]:contents *:[[data-slot=input-control],[data-slot=textarea-control]]:before:hidden has-[[data-align=block-start],[data-align=block-end]]:**:[input]:h-auto has-data-[align=inline-start]:**:[input]:ps-2 has-data-[align=inline-end]:**:[input]:pe-2 has-data-[align=block-end]:**:[input]:pt-1.5 has-data-[align=block-start]:**:[input]:pb-1.5 **:[textarea]:min-h-20.5 **:[textarea]:resize-none **:[textarea]:py-[calc(--spacing(3)-1px)] **:[textarea]:max-sm:min-h-23.5 **:[textarea_button]:rounded-[calc(var(--control-radius)-1px)]", | 10 | "relative inline-flex w-full min-w-0 items-center rounded-[var(--control-radius)] border text-base text-foreground ring-ring/24 transition-shadow has-[input:focus-visible,textarea:focus-visible]:has-[input[aria-invalid],textarea[aria-invalid]]:border-destructive/64 has-[input:focus-visible,textarea:focus-visible]:has-[input[aria-invalid],textarea[aria-invalid]]:ring-destructive/16 has-[textarea]:h-auto has-data-[align=block-end]:h-auto has-data-[align=block-start]:h-auto has-data-[align=block-end]:flex-col has-data-[align=block-start]:flex-col has-[input:focus-visible,textarea:focus-visible]:border-ring has-[input[aria-invalid],textarea[aria-invalid]]:border-destructive/36 has-autofill:bg-foreground/4 has-[input:disabled,textarea:disabled]:opacity-64 has-[input:disabled,textarea:disabled,input:focus-visible,textarea:focus-visible,input[aria-invalid],textarea[aria-invalid]]:shadow-none has-[input:focus-visible,textarea:focus-visible]:ring-[3px] has-[input:focus-visible,textarea:focus-visible]:ring-inset sm:text-sm dark:has-autofill:bg-foreground/8 dark:has-[input[aria-invalid],textarea[aria-invalid]]:ring-destructive/24 has-data-[align=inline-start]:**:[[data-size=sm]_input]:ps-1.5 has-data-[align=inline-end]:**:[[data-size=sm]_input]:pe-1.5 *:[[data-slot=input-control],[data-slot=textarea-control]]:contents *:[[data-slot=input-control],[data-slot=textarea-control]]:before:hidden has-[[data-align=block-start],[data-align=block-end]]:**:[input]:h-auto has-data-[align=inline-start]:**:[input]:ps-2 has-data-[align=inline-end]:**:[input]:pe-2 has-data-[align=block-end]:**:[input]:pt-1.5 has-data-[align=block-start]:**:[input]:pb-1.5 **:[textarea]:min-h-20.5 **:[textarea]:resize-none **:[textarea]:py-[calc(--spacing(3)-1px)] **:[textarea]:max-sm:min-h-23.5 **:[textarea_button]:rounded-[calc(var(--control-radius)-1px)]", |
| 11 | { | 11 | { |
| 12 | defaultVariants: { | 12 | defaultVariants: { |
| 13 | variant: "default", | 13 | variant: "default", |
apps/web/src/components/ui/input.tsx+1-1| ... | @@ -65,7 +65,7 @@ function Input({ | ... | @@ -65,7 +65,7 @@ function Input({ |
| 65 | className={ | 65 | className={ |
| 66 | cn( | 66 | cn( |
| 67 | !unstyled && | 67 | !unstyled && |
| 68 | "relative inline-flex w-full rounded-lg border border-input bg-background not-dark:bg-clip-padding text-base text-foreground shadow-xs/5 ring-ring/24 transition-shadow before:pointer-events-none before:absolute before:inset-0 before:rounded-[calc(var(--radius-lg)-1px)] not-has-disabled:not-has-focus-visible:not-has-aria-invalid:before:shadow-[0_1px_--theme(--color-black/4%)] has-focus-visible:has-aria-invalid:border-destructive/64 has-focus-visible:has-aria-invalid:ring-destructive/16 has-aria-invalid:border-destructive/36 has-focus-visible:border-ring has-autofill:bg-foreground/4 has-disabled:opacity-64 has-[:disabled,:focus-visible,[aria-invalid]]:shadow-none has-focus-visible:ring-[3px] sm:text-sm dark:bg-input/32 dark:has-autofill:bg-foreground/8 dark:has-aria-invalid:ring-destructive/24 dark:not-has-disabled:not-has-focus-visible:not-has-aria-invalid:before:shadow-[0_-1px_--theme(--color-white/6%)]", | 68 | "relative inline-flex w-full rounded-lg border border-input bg-background not-dark:bg-clip-padding text-base text-foreground shadow-xs/5 ring-ring/24 transition-shadow before:pointer-events-none before:absolute before:inset-0 before:rounded-[calc(var(--radius-lg)-1px)] not-has-disabled:not-has-focus-visible:not-has-aria-invalid:before:shadow-[0_1px_--theme(--color-black/4%)] has-focus-visible:has-aria-invalid:border-destructive/64 has-focus-visible:has-aria-invalid:ring-destructive/16 has-aria-invalid:border-destructive/36 has-focus-visible:border-ring has-autofill:bg-foreground/4 has-disabled:opacity-64 has-[:disabled,:focus-visible,[aria-invalid]]:shadow-none has-focus-visible:ring-[3px] has-focus-visible:ring-inset sm:text-sm dark:bg-input/32 dark:has-autofill:bg-foreground/8 dark:has-aria-invalid:ring-destructive/24 dark:not-has-disabled:not-has-focus-visible:not-has-aria-invalid:before:shadow-[0_-1px_--theme(--color-white/6%)]", |
| 69 | !unstyled && | 69 | !unstyled && |
| 70 | size === "compact" && | 70 | size === "compact" && |
| 71 | "rounded-md before:rounded-[calc(var(--radius-md)-1px)]", | 71 | "rounded-md before:rounded-[calc(var(--radius-md)-1px)]", |
apps/web/src/components/ui/menu.tsx+1-1| ... | @@ -145,7 +145,7 @@ function MenuCheckboxItem({ | ... | @@ -145,7 +145,7 @@ function MenuCheckboxItem({ |
| 145 | <> | 145 | <> |
| 146 | <span className="col-start-1">{children}</span> | 146 | <span className="col-start-1">{children}</span> |
| 147 | <MenuPrimitive.CheckboxItemIndicator | 147 | <MenuPrimitive.CheckboxItemIndicator |
| 148 | className="inset-shadow-[0_1px_--theme(--color-black/4%)] inline-flex h-[calc(var(--thumb-size)+2px)] w-[calc(var(--thumb-size)*2-2px)] shrink-0 items-center rounded-full p-px outline-none transition-[background-color,box-shadow] duration-200 [--thumb-size:--spacing(4)] focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:ring-offset-background data-checked:bg-primary data-unchecked:bg-input data-disabled:opacity-64 sm:[--thumb-size:--spacing(3)]" | 148 | className="inset-shadow-[0_1px_--theme(--color-black/4%)] inline-flex h-[calc(var(--thumb-size)+2px)] w-[calc(var(--thumb-size)*2-2px)] shrink-0 items-center rounded-full p-px outline-none transition-[background-color,box-shadow] duration-200 [--thumb-size:--spacing(4)] focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:ring-offset-background data-checked:bg-primary data-unchecked:bg-input data-disabled:opacity-64 sm:[--thumb-size:--spacing(3)]" |
| 149 | keepMounted | 149 | keepMounted |
| 150 | > | 150 | > |
| 151 | <span className="pointer-events-none block aspect-square h-full in-[[data-slot=menu-checkbox-item][data-checked]]:origin-[var(--thumb-size)_50%] origin-left in-[[data-slot=menu-checkbox-item][data-checked]]:translate-x-[calc(var(--thumb-size)-4px)] in-[[data-slot=menu-checkbox-item]:active]:not-data-disabled:scale-x-110 in-[[data-slot=menu-checkbox-item]:active]:rounded-[var(--thumb-size)/calc(var(--thumb-size)*1.10)] rounded-(--thumb-size) bg-background shadow-sm/5 will-change-transform [transition:translate_.15s,border-radius_.15s,scale_.1s_.1s,transform-origin_.15s]" /> | 151 | <span className="pointer-events-none block aspect-square h-full in-[[data-slot=menu-checkbox-item][data-checked]]:origin-[var(--thumb-size)_50%] origin-left in-[[data-slot=menu-checkbox-item][data-checked]]:translate-x-[calc(var(--thumb-size)-4px)] in-[[data-slot=menu-checkbox-item]:active]:not-data-disabled:scale-x-110 in-[[data-slot=menu-checkbox-item]:active]:rounded-[var(--thumb-size)/calc(var(--thumb-size)*1.10)] rounded-(--thumb-size) bg-background shadow-sm/5 will-change-transform [transition:translate_.15s,border-radius_.15s,scale_.1s_.1s,transform-origin_.15s]" /> |
apps/web/src/components/ui/number-field.tsx+1-1| ... | @@ -33,7 +33,7 @@ export function NumberFieldGroup({ | ... | @@ -33,7 +33,7 @@ export function NumberFieldGroup({ |
| 33 | return ( | 33 | return ( |
| 34 | <NumberFieldPrimitive.Group | 34 | <NumberFieldPrimitive.Group |
| 35 | className={cn( | 35 | className={cn( |
| 36 | "relative flex w-full justify-between rounded-lg border border-input bg-background not-dark:bg-clip-padding text-base text-foreground shadow-xs/5 ring-ring/24 transition-shadow before:pointer-events-none before:absolute before:inset-0 before:rounded-[calc(var(--radius-lg)-1px)] not-data-disabled:not-focus-within:not-aria-invalid:before:shadow-[0_1px_--theme(--color-black/4%)] focus-within:border-ring focus-within:ring-[3px] has-aria-invalid:border-destructive/36 has-autofill:bg-foreground/4 focus-within:has-aria-invalid:border-destructive/64 focus-within:has-aria-invalid:ring-destructive/48 data-disabled:pointer-events-none data-disabled:opacity-64 sm:text-sm dark:bg-input/32 dark:has-autofill:bg-foreground/8 dark:has-aria-invalid:ring-destructive/24 dark:not-data-disabled:not-focus-within:not-aria-invalid:before:shadow-[0_-1px_--theme(--color-white/6%)] [&_svg:not([class*='size-'])]:size-4.5 sm:[&_svg:not([class*='size-'])]:size-4 [&_svg]:pointer-events-none [&_svg]:shrink-0 [[data-disabled],:focus-within,[aria-invalid]]:shadow-none", | 36 | "relative flex w-full justify-between rounded-lg border border-input bg-background not-dark:bg-clip-padding text-base text-foreground shadow-xs/5 ring-ring/24 transition-shadow before:pointer-events-none before:absolute before:inset-0 before:rounded-[calc(var(--radius-lg)-1px)] not-data-disabled:not-focus-within:not-aria-invalid:before:shadow-[0_1px_--theme(--color-black/4%)] focus-within:border-ring focus-within:ring-[3px] focus-within:ring-inset has-aria-invalid:border-destructive/36 has-autofill:bg-foreground/4 focus-within:has-aria-invalid:border-destructive/64 focus-within:has-aria-invalid:ring-destructive/48 data-disabled:pointer-events-none data-disabled:opacity-64 sm:text-sm dark:bg-input/32 dark:has-autofill:bg-foreground/8 dark:has-aria-invalid:ring-destructive/24 dark:not-data-disabled:not-focus-within:not-aria-invalid:before:shadow-[0_-1px_--theme(--color-white/6%)] [&_svg:not([class*='size-'])]:size-4.5 sm:[&_svg:not([class*='size-'])]:size-4 [&_svg]:pointer-events-none [&_svg]:shrink-0 [[data-disabled],:focus-within,[aria-invalid]]:shadow-none", |
| 37 | className, | 37 | className, |
| 38 | )} | 38 | )} |
| 39 | data-slot="number-field-group" | 39 | data-slot="number-field-group" |
apps/web/src/components/ui/radio-group.tsx+3-2| ... | @@ -19,14 +19,15 @@ function Radio({ className, ...props }: RadioPrimitive.Root.Props) { | ... | @@ -19,14 +19,15 @@ function Radio({ className, ...props }: RadioPrimitive.Root.Props) { |
| 19 | return ( | 19 | return ( |
| 20 | <RadioPrimitive.Root | 20 | <RadioPrimitive.Root |
| 21 | className={cn( | 21 | className={cn( |
| 22 | "relative inline-flex size-4.5 shrink-0 items-center justify-center rounded-full border border-input bg-background not-dark:bg-clip-padding shadow-xs/5 outline-none transition-shadow before:pointer-events-none before:absolute before:inset-0 before:rounded-full not-data-disabled:not-data-checked:not-aria-invalid:before:shadow-[0_1px_--theme(--color-black/4%)] focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:ring-offset-background aria-invalid:border-destructive/36 focus-visible:aria-invalid:border-destructive/64 focus-visible:aria-invalid:ring-destructive/48 data-disabled:opacity-64 sm:size-4 dark:not-data-checked:bg-input/32 dark:aria-invalid:ring-destructive/24 dark:not-data-disabled:not-data-checked:not-aria-invalid:before:shadow-[0_-1px_--theme(--color-white/6%)] [[data-disabled],[data-checked],[aria-invalid]]:shadow-none", | 22 | "relative inline-flex size-4.5 shrink-0 items-center justify-center rounded-full border border-input bg-background not-dark:bg-clip-padding shadow-xs/5 outline-none transition-shadow before:pointer-events-none before:absolute before:inset-0 before:rounded-full not-data-disabled:not-data-checked:not-aria-invalid:before:shadow-[0_1px_--theme(--color-black/4%)] focus-visible:outline-2 focus-visible:outline-solid focus-visible:-outline-offset-2 focus-visible:outline-ring aria-invalid:border-destructive/36 focus-visible:aria-invalid:border-destructive/64 focus-visible:aria-invalid:outline-destructive/48 data-disabled:opacity-64 sm:size-4 dark:not-data-checked:bg-input/32 dark:focus-visible:aria-invalid:outline-destructive/24 dark:not-data-disabled:not-data-checked:not-aria-invalid:before:shadow-[0_-1px_--theme(--color-white/6%)] [[data-disabled],[data-checked],[aria-invalid]]:shadow-none", |
| 23 | className, | 23 | className, |
| 24 | )} | 24 | )} |
| 25 | data-slot="radio" | 25 | data-slot="radio" |
| 26 | {...props} | 26 | {...props} |
| 27 | > | 27 | > |
| 28 | {/* Leave a contrasting inner gap inside the 2px focus outline. */} | ||
| 28 | <RadioPrimitive.Indicator | 29 | <RadioPrimitive.Indicator |
| 29 | className="-inset-px absolute flex size-4.5 items-center justify-center rounded-full before:size-2 before:rounded-full before:bg-primary-foreground data-unchecked:hidden data-checked:bg-primary sm:size-4 sm:before:size-1.5" | 30 | className="-inset-px absolute flex size-4.5 items-center justify-center rounded-full before:size-2 before:rounded-full before:bg-primary-foreground data-unchecked:hidden data-checked:bg-primary sm:size-4 sm:before:size-1.5 in-[[data-slot=radio]:focus-visible]:inset-shadow-[0_0_0_3px_var(--background)] in-[[data-slot=radio]:focus-visible]:outline-2 in-[[data-slot=radio]:focus-visible]:outline-solid in-[[data-slot=radio]:focus-visible]:-outline-offset-2 in-[[data-slot=radio]:focus-visible]:outline-inherit" |
| 30 | data-slot="radio-indicator" | 31 | data-slot="radio-indicator" |
| 31 | /> | 32 | /> |
| 32 | </RadioPrimitive.Root> | 33 | </RadioPrimitive.Root> |
apps/web/src/components/ui/scroll-area.tsx+3-2| ... | @@ -57,11 +57,12 @@ function ScrollArea({ | ... | @@ -57,11 +57,12 @@ function ScrollArea({ |
| 57 | <ScrollAreaPrimitive.Viewport | 57 | <ScrollAreaPrimitive.Viewport |
| 58 | {...(viewportTabIndex === undefined ? {} : { tabIndex: viewportTabIndex })} | 58 | {...(viewportTabIndex === undefined ? {} : { tabIndex: viewportTabIndex })} |
| 59 | className={cn( | 59 | className={cn( |
| 60 | "h-full max-h-[inherit] overflow-auto overscroll-contain rounded-[inherit] outline-none transition-shadow focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:ring-offset-background data-has-overflow-x:overscroll-x-contain", | 60 | "h-full max-h-[inherit] overflow-auto overscroll-contain rounded-[inherit] outline-none transition-shadow focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:ring-offset-background data-has-overflow-x:overscroll-x-contain", |
| 61 | chainVerticalScroll && "overscroll-y-auto", | 61 | chainVerticalScroll && "overscroll-y-auto", |
| 62 | scrollFade && | 62 | scrollFade && |
| 63 | "mask-t-from-[calc(100%-min(var(--fade-size),var(--scroll-area-overflow-y-start)))] mask-b-from-[calc(100%-min(var(--fade-size),var(--scroll-area-overflow-y-end)))] mask-l-from-[calc(100%-min(var(--fade-size),var(--scroll-area-overflow-x-start)))] mask-r-from-[calc(100%-min(var(--fade-size),var(--scroll-area-overflow-x-end)))] [--fade-size:1.5rem]", | 63 | "mask-t-from-[calc(100%-min(var(--fade-size),var(--scroll-area-overflow-y-start)))] mask-b-from-[calc(100%-min(var(--fade-size),var(--scroll-area-overflow-y-end)))] mask-l-from-[calc(100%-min(var(--fade-size),var(--scroll-area-overflow-x-start)))] mask-r-from-[calc(100%-min(var(--fade-size),var(--scroll-area-overflow-x-end)))] focus-visible:mask-none [--fade-size:1.5rem]", |
| 64 | scrollFade && scrollFadePadding && "scroll-p-[var(--fade-size)]", | 64 | scrollFade && scrollFadePadding && "scroll-p-[var(--fade-size)]", |
| 65 | scrollFade && !scrollFadePadding && "has-focus-visible:mask-none", | ||
| 65 | scrollbarGutter && "scrollbar-gutter-stable", | 66 | scrollbarGutter && "scrollbar-gutter-stable", |
| 66 | hideScrollbars && | 67 | hideScrollbars && |
| 67 | "[-ms-overflow-style:none] [scrollbar-width:none] [&::-webkit-scrollbar]:hidden", | 68 | "[-ms-overflow-style:none] [scrollbar-width:none] [&::-webkit-scrollbar]:hidden", |
apps/web/src/components/ui/select.tsx+2-2| ... | @@ -20,9 +20,9 @@ const selectTriggerVariants = cva( | ... | @@ -20,9 +20,9 @@ const selectTriggerVariants = cva( |
| 20 | variants: { | 20 | variants: { |
| 21 | variant: { | 21 | variant: { |
| 22 | default: | 22 | default: |
| 23 | "w-full min-w-36 border-input bg-background not-dark:bg-clip-padding text-foreground shadow-xs/5 ring-ring/24 before:pointer-events-none before:absolute before:inset-0 before:rounded-[calc(var(--radius-lg)-1px)] not-data-disabled:not-focus-visible:not-aria-invalid:not-data-pressed:before:shadow-[0_1px_--theme(--color-black/4%)] pointer-coarse:after:absolute pointer-coarse:after:size-full pointer-coarse:after:min-h-11 focus-visible:border-ring focus-visible:ring-[3px] aria-invalid:border-destructive/36 focus-visible:aria-invalid:border-destructive/64 focus-visible:aria-invalid:ring-destructive/16 dark:bg-input/32 dark:aria-invalid:ring-destructive/24 dark:not-data-disabled:not-focus-visible:not-aria-invalid:not-data-pressed:before:shadow-[0_-1px_--theme(--color-white/6%)] [&_svg:not([class*='opacity-'])]:opacity-80 [&_svg:not([class*='text-'])]:text-icon-muted [[data-disabled],:focus-visible,[aria-invalid],[data-pressed]]:shadow-none", | 23 | "w-full min-w-36 border-input bg-background not-dark:bg-clip-padding text-foreground shadow-xs/5 ring-ring/24 before:pointer-events-none before:absolute before:inset-0 before:rounded-[calc(var(--radius-lg)-1px)] not-data-disabled:not-focus-visible:not-aria-invalid:not-data-pressed:before:shadow-[0_1px_--theme(--color-black/4%)] pointer-coarse:after:absolute pointer-coarse:after:size-full pointer-coarse:after:min-h-11 focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-inset aria-invalid:border-destructive/36 focus-visible:aria-invalid:border-destructive/64 focus-visible:aria-invalid:ring-destructive/16 dark:bg-input/32 dark:aria-invalid:ring-destructive/24 dark:not-data-disabled:not-focus-visible:not-aria-invalid:not-data-pressed:before:shadow-[0_-1px_--theme(--color-white/6%)] [&_svg:not([class*='opacity-'])]:opacity-80 [&_svg:not([class*='text-'])]:text-icon-muted [[data-disabled],:focus-visible,[aria-invalid],[data-pressed]]:shadow-none", |
| 24 | ghost: | 24 | ghost: |
| 25 | "border-transparent text-secondary-label focus-visible:ring-2 focus-visible:ring-ring data-pressed:bg-accent [:hover,[data-pressed]]:bg-accent [:hover,[data-pressed]]:text-foreground", | 25 | "border-transparent text-secondary-label focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring data-pressed:bg-accent [:hover,[data-pressed]]:bg-accent [:hover,[data-pressed]]:text-foreground", |
| 26 | }, | 26 | }, |
| 27 | size: { | 27 | size: { |
| 28 | compact: | 28 | compact: |
apps/web/src/components/ui/sidebar.tsx+2-2| ... | @@ -660,7 +660,7 @@ function SidebarMenuItem({ className, ...props }: React.ComponentProps<"li">) { | ... | @@ -660,7 +660,7 @@ function SidebarMenuItem({ className, ...props }: React.ComponentProps<"li">) { |
| 660 | } | 660 | } |
| 661 | 661 | ||
| 662 | const sidebarMenuButtonVariants = cva( | 662 | const sidebarMenuButtonVariants = cva( |
| 663 | "peer/menu-button flex w-full cursor-pointer items-center gap-[var(--sidebar-control-gap)] overflow-hidden text-left outline-hidden ring-ring transition-[width,height,padding] hover:bg-sidebar-row-hover hover:text-sidebar-foreground focus-visible:ring-2 active:bg-sidebar-row-active active:text-sidebar-foreground disabled:pointer-events-none disabled:opacity-64 aria-disabled:pointer-events-none aria-disabled:opacity-64 data-[active=true]:bg-sidebar-row-selected data-[active=true]:font-medium data-[active=true]:text-sidebar-foreground data-[state=open]:hover:bg-sidebar-row-hover data-[state=open]:hover:text-sidebar-foreground group-data-[collapsible=icon]:size-8! group-data-[collapsible=icon]:p-[var(--sidebar-content-inset)]! [&>span:last-child]:truncate [&>svg:not([class*='size-'])]:size-4 [&>svg]:shrink-0 [&>svg]:text-[var(--sidebar-icon-color)] hover:[&>svg]:text-sidebar-foreground active:[&>svg]:text-sidebar-foreground data-[active=true]:[&>svg]:text-sidebar-foreground", | 663 | "peer/menu-button flex w-full cursor-pointer items-center gap-[var(--sidebar-control-gap)] overflow-hidden text-left outline-hidden ring-ring transition-[width,height,padding] hover:bg-sidebar-row-hover hover:text-sidebar-foreground focus-visible:ring-2 focus-visible:ring-inset active:bg-sidebar-row-active active:text-sidebar-foreground disabled:pointer-events-none disabled:opacity-64 aria-disabled:pointer-events-none aria-disabled:opacity-64 data-[active=true]:bg-sidebar-row-selected data-[active=true]:font-medium data-[active=true]:text-sidebar-foreground data-[state=open]:hover:bg-sidebar-row-hover data-[state=open]:hover:text-sidebar-foreground group-data-[collapsible=icon]:size-8! group-data-[collapsible=icon]:p-[var(--sidebar-content-inset)]! [&>span:last-child]:truncate [&>svg:not([class*='size-'])]:size-4 [&>svg]:shrink-0 [&>svg]:text-[var(--sidebar-icon-color)] hover:[&>svg]:text-sidebar-foreground active:[&>svg]:text-sidebar-foreground data-[active=true]:[&>svg]:text-sidebar-foreground", |
| 664 | { | 664 | { |
| 665 | defaultVariants: { | 665 | defaultVariants: { |
| 666 | size: "default", | 666 | size: "default", |
| ... | @@ -773,7 +773,7 @@ function SidebarMenuSubButton({ | ... | @@ -773,7 +773,7 @@ function SidebarMenuSubButton({ |
| 773 | }) { | 773 | }) { |
| 774 | const defaultProps = { | 774 | const defaultProps = { |
| 775 | className: cn( | 775 | className: cn( |
| 776 | "-translate-x-px flex h-7 min-w-0 cursor-pointer items-center gap-2 overflow-hidden rounded-lg px-2 text-sidebar-foreground outline-hidden ring-ring hover:bg-sidebar-row-hover hover:text-sidebar-foreground focus-visible:ring-2 active:bg-sidebar-row-active active:text-sidebar-foreground disabled:pointer-events-none disabled:opacity-64 aria-disabled:pointer-events-none aria-disabled:opacity-64 [&>span:last-child]:truncate [&>svg:not([class*='size-'])]:size-4 [&>svg]:shrink-0 [&>svg]:text-sidebar-muted-foreground", | 776 | "-translate-x-px flex h-7 min-w-0 cursor-pointer items-center gap-2 overflow-hidden rounded-lg px-2 text-sidebar-foreground outline-hidden ring-ring hover:bg-sidebar-row-hover hover:text-sidebar-foreground focus-visible:ring-2 focus-visible:ring-inset active:bg-sidebar-row-active active:text-sidebar-foreground disabled:pointer-events-none disabled:opacity-64 aria-disabled:pointer-events-none aria-disabled:opacity-64 [&>span:last-child]:truncate [&>svg:not([class*='size-'])]:size-4 [&>svg]:shrink-0 [&>svg]:text-sidebar-muted-foreground", |
| 777 | "data-[active=true]:bg-sidebar-row-selected data-[active=true]:text-sidebar-foreground", | 777 | "data-[active=true]:bg-sidebar-row-selected data-[active=true]:text-sidebar-foreground", |
| 778 | size === "sm" && "text-xs", | 778 | size === "sm" && "text-xs", |
| 779 | size === "md" && "text-sm", | 779 | size === "md" && "text-sm", |
apps/web/src/components/ui/switch.tsx+1-1| ... | @@ -18,7 +18,7 @@ function Switch({ | ... | @@ -18,7 +18,7 @@ function Switch({ |
| 18 | return ( | 18 | return ( |
| 19 | <SwitchPrimitive.Root | 19 | <SwitchPrimitive.Root |
| 20 | className={cn( | 20 | className={cn( |
| 21 | "inline-flex h-[calc(var(--thumb-size)+2px)] w-[calc(var(--thumb-size)*2-2px)] shrink-0 cursor-pointer items-center rounded-full p-[2px] outline-none transition-[background-color,box-shadow] duration-200 focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:ring-offset-background data-checked:bg-primary data-unchecked:bg-input data-disabled:cursor-not-allowed data-disabled:opacity-64 data-[mixed]:bg-input", | 21 | "inline-flex h-[calc(var(--thumb-size)+2px)] w-[calc(var(--thumb-size)*2-2px)] shrink-0 cursor-pointer items-center rounded-full p-[2px] outline-none transition-[background-color,box-shadow] duration-200 focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:ring-offset-background data-checked:bg-primary data-unchecked:bg-input data-disabled:cursor-not-allowed data-disabled:opacity-64 data-[mixed]:bg-input", |
| 22 | size === "sm" | 22 | size === "sm" |
| 23 | ? "[--thumb-size:--spacing(4)] sm:[--thumb-size:--spacing(3.5)]" | 23 | ? "[--thumb-size:--spacing(4)] sm:[--thumb-size:--spacing(3.5)]" |
| 24 | : "[--thumb-size:--spacing(5)] sm:[--thumb-size:--spacing(4)]", | 24 | : "[--thumb-size:--spacing(5)] sm:[--thumb-size:--spacing(4)]", |
apps/web/src/components/ui/textarea.tsx+1-1| ... | @@ -17,7 +17,7 @@ function Textarea({ className, size = "default", unstyled = false, ...props }: T | ... | @@ -17,7 +17,7 @@ function Textarea({ className, size = "default", unstyled = false, ...props }: T |
| 17 | className={ | 17 | className={ |
| 18 | cn( | 18 | cn( |
| 19 | !unstyled && | 19 | !unstyled && |
| 20 | "relative inline-flex w-full rounded-lg border border-input bg-background not-dark:bg-clip-padding text-base text-foreground shadow-xs/5 ring-ring/24 transition-shadow before:pointer-events-none before:absolute before:inset-0 before:rounded-[calc(var(--radius-lg)-1px)] has-focus-visible:has-aria-invalid:border-destructive/64 has-focus-visible:has-aria-invalid:ring-destructive/16 has-aria-invalid:border-destructive/36 has-focus-visible:border-ring has-disabled:opacity-64 has-[:disabled,:focus-visible,[aria-invalid]]:shadow-none has-focus-visible:ring-[3px] not-has-disabled:has-not-focus-visible:not-has-aria-invalid:before:shadow-[0_1px_--theme(--color-black/4%)] sm:text-sm dark:bg-input/32 dark:has-aria-invalid:ring-destructive/24 dark:not-has-disabled:has-not-focus-visible:not-has-aria-invalid:before:shadow-[0_-1px_--theme(--color-white/6%)]", | 20 | "relative inline-flex w-full rounded-lg border border-input bg-background not-dark:bg-clip-padding text-base text-foreground shadow-xs/5 ring-ring/24 transition-shadow before:pointer-events-none before:absolute before:inset-0 before:rounded-[calc(var(--radius-lg)-1px)] has-focus-visible:has-aria-invalid:border-destructive/64 has-focus-visible:has-aria-invalid:ring-destructive/16 has-aria-invalid:border-destructive/36 has-focus-visible:border-ring has-disabled:opacity-64 has-[:disabled,:focus-visible,[aria-invalid]]:shadow-none has-focus-visible:ring-[3px] has-focus-visible:ring-inset not-has-disabled:has-not-focus-visible:not-has-aria-invalid:before:shadow-[0_1px_--theme(--color-black/4%)] sm:text-sm dark:bg-input/32 dark:has-aria-invalid:ring-destructive/24 dark:not-has-disabled:has-not-focus-visible:not-has-aria-invalid:before:shadow-[0_-1px_--theme(--color-white/6%)]", |
| 21 | className, | 21 | className, |
| 22 | ) || undefined | 22 | ) || undefined |
| 23 | } | 23 | } |
apps/web/src/components/ui/toast.tsx+2-2| ... | @@ -98,7 +98,7 @@ const toastCornerDismissClass = "absolute z-20 -top-1.5 -right-1.5"; | ... | @@ -98,7 +98,7 @@ const toastCornerDismissClass = "absolute z-20 -top-1.5 -right-1.5"; |
| 98 | const toastCornerOrbClass = cn( | 98 | const toastCornerOrbClass = cn( |
| 99 | "inline-flex size-6 shrink-0 cursor-pointer items-center justify-center rounded-full border border-border/60 bg-popover/92 text-muted-foreground shadow-sm outline-none backdrop-blur-sm", | 99 | "inline-flex size-6 shrink-0 cursor-pointer items-center justify-center rounded-full border border-border/60 bg-popover/92 text-muted-foreground shadow-sm outline-none backdrop-blur-sm", |
| 100 | "transition-[color,background-color,box-shadow] hover:bg-popover hover:text-foreground", | 100 | "transition-[color,background-color,box-shadow] hover:bg-popover hover:text-foreground", |
| 101 | "focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:ring-offset-background", | 101 | "focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:ring-offset-background", |
| 102 | ); | 102 | ); |
| 103 | 103 | ||
| 104 | function handleToastDismissClick( | 104 | function handleToastDismissClick( |
| ... | @@ -225,7 +225,7 @@ function ToastDescriptionAndExpandable({ | ... | @@ -225,7 +225,7 @@ function ToastDescriptionAndExpandable({ |
| 225 | className={cn( | 225 | className={cn( |
| 226 | "group flex min-w-0 w-full cursor-pointer select-none items-start gap-1.5 rounded-sm text-left outline-none ring-offset-background", | 226 | "group flex min-w-0 w-full cursor-pointer select-none items-start gap-1.5 rounded-sm text-left outline-none ring-offset-background", |
| 227 | "transition-colors hover:bg-muted/40", | 227 | "transition-colors hover:bg-muted/40", |
| 228 | "focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:ring-offset-background", | 228 | "focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:ring-offset-background", |
| 229 | )} | 229 | )} |
| 230 | onClick={toggle} | 230 | onClick={toggle} |
| 231 | onKeyDown={onKeyDown} | 231 | onKeyDown={onKeyDown} |
apps/web/src/components/ui/toggle.tsx+1-1| ... | @@ -6,7 +6,7 @@ import { cva, type VariantProps } from "class-variance-authority"; | ... | @@ -6,7 +6,7 @@ import { cva, type VariantProps } from "class-variance-authority"; |
| 6 | import { cn } from "~/lib/utils"; | 6 | import { cn } from "~/lib/utils"; |
| 7 | 7 | ||
| 8 | const toggleVariants = cva( | 8 | const toggleVariants = cva( |
| 9 | "[&_svg]:-mx-0.5 relative inline-flex shrink-0 cursor-pointer select-none items-center justify-center gap-2 whitespace-nowrap rounded-lg border font-medium text-base text-foreground outline-none transition-shadow before:pointer-events-none before:absolute before:inset-0 before:rounded-[calc(var(--radius-lg)-1px)] pointer-coarse:after:absolute pointer-coarse:after:size-full pointer-coarse:after:min-h-11 pointer-coarse:after:min-w-11 hover:bg-accent focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:ring-offset-background disabled:pointer-events-none disabled:opacity-64 aria-disabled:opacity-64 data-pressed:bg-input/64 data-pressed:text-accent-foreground sm:text-sm [&_svg:not([class*='opacity-'])]:opacity-80 [&_svg:not([class*='size-'])]:size-4.5 sm:[&_svg:not([class*='size-'])]:size-4 [&_svg]:pointer-events-none [&_svg]:shrink-0", | 9 | "[&_svg]:-mx-0.5 relative inline-flex shrink-0 cursor-pointer select-none items-center justify-center gap-2 whitespace-nowrap rounded-lg border font-medium text-base text-foreground outline-none transition-shadow before:pointer-events-none before:absolute before:inset-0 before:rounded-[calc(var(--radius-lg)-1px)] pointer-coarse:after:absolute pointer-coarse:after:size-full pointer-coarse:after:min-h-11 pointer-coarse:after:min-w-11 hover:bg-accent focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:ring-offset-background disabled:pointer-events-none disabled:opacity-64 aria-disabled:opacity-64 data-pressed:bg-input/64 data-pressed:text-accent-foreground sm:text-sm [&_svg:not([class*='opacity-'])]:opacity-80 [&_svg:not([class*='size-'])]:size-4.5 sm:[&_svg:not([class*='size-'])]:size-4 [&_svg]:pointer-events-none [&_svg]:shrink-0", |
| 10 | { | 10 | { |
| 11 | defaultVariants: { | 11 | defaultVariants: { |
| 12 | size: "default", | 12 | size: "default", |
apps/web/src/components/ui/wizard.tsx+2-2| ... | @@ -96,11 +96,11 @@ export function WizardSteps({ | ... | @@ -96,11 +96,11 @@ export function WizardSteps({ |
| 96 | ? { type: "button" as const, disabled: isStepDisabled?.(index) } | 96 | ? { type: "button" as const, disabled: isStepDisabled?.(index) } |
| 97 | : {})} | 97 | : {})} |
| 98 | className={cn( | 98 | className={cn( |
| 99 | "flex w-full min-w-0 items-center gap-2 rounded-lg px-2.5 py-2 text-left outline-none focus-visible:ring-2 focus-visible:ring-ring max-sm:justify-center max-sm:px-2", | 99 | "flex w-full min-w-0 items-center gap-2 rounded-lg px-2.5 py-2 text-left outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring max-sm:justify-center max-sm:px-2", |
| 100 | onStepChange && | 100 | onStepChange && |
| 101 | "cursor-pointer hover:bg-card disabled:cursor-default disabled:hover:bg-transparent", | 101 | "cursor-pointer hover:bg-card disabled:cursor-default disabled:hover:bg-transparent", |
| 102 | index === currentStep && | 102 | index === currentStep && |
| 103 | "bg-card text-foreground shadow-xs ring-1 ring-black/5 hover:bg-card dark:shadow-none dark:ring-white/5", | 103 | "bg-card text-foreground shadow-xs ring-1 ring-inset ring-black/5 hover:bg-card dark:shadow-none dark:ring-white/5", |
| 104 | )} | 104 | )} |
| 105 | aria-current={index === currentStep ? "step" : undefined} | 105 | aria-current={index === currentStep ? "step" : undefined} |
| 106 | aria-label={`${step}, step ${index + 1}${index < currentStep && summaries?.[index] ? `, ${summaries?.[index]}` : ""}`} | 106 | aria-label={`${step}, step ${index + 1}${index < currentStep && summaries?.[index] ? `, ${summaries?.[index]}` : ""}`} |
apps/web/src/components/usage/UsageLimits.tsx+1-1| ... | @@ -110,7 +110,7 @@ function WindowBar({ | ... | @@ -110,7 +110,7 @@ function WindowBar({ |
| 110 | role="img" | 110 | role="img" |
| 111 | aria-label={summary} | 111 | aria-label={summary} |
| 112 | tabIndex={0} | 112 | tabIndex={0} |
| 113 | className="relative h-6 cursor-default rounded-full outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background" | 113 | className="relative h-6 cursor-default rounded-full outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background" |
| 114 | /> | 114 | /> |
| 115 | } | 115 | } |
| 116 | > | 116 | > |
apps/web/src/components/usage/UsageLimitsPooled.tsx+1-1| ... | @@ -255,7 +255,7 @@ function PoolSegment({ | ... | @@ -255,7 +255,7 @@ function PoolSegment({ |
| 255 | type="button" | 255 | type="button" |
| 256 | style={{ gridColumn: index, gridRow: 1 }} | 256 | style={{ gridColumn: index, gridRow: 1 }} |
| 257 | aria-label={`${account.displayName ?? (account.email ? accountInitials(account.email) : account.driver)}: ${remaining}% left${resetsIn ? `, ${resetsIn}` : ""}${credits ? `, ${credits} reset ${credits === 1 ? "credit" : "credits"} banked` : ""}`} | 257 | aria-label={`${account.displayName ?? (account.email ? accountInitials(account.email) : account.driver)}: ${remaining}% left${resetsIn ? `, ${resetsIn}` : ""}${credits ? `, ${credits} reset ${credits === 1 ? "credit" : "credits"} banked` : ""}`} |
| 258 | className="relative h-5 min-w-0 cursor-pointer overflow-hidden rounded-md bg-muted text-start outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background data-[popup-open]:ring-1 data-[popup-open]:ring-border @2xl/pool:h-8" | 258 | className="relative h-5 min-w-0 cursor-pointer overflow-hidden rounded-md bg-muted text-start outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background data-[popup-open]:ring-1 data-[popup-open]:ring-inset data-[popup-open]:ring-border @2xl/pool:h-8" |
| 259 | /> | 259 | /> |
| 260 | } | 260 | } |
| 261 | > | 261 | > |
apps/web/src/index.css+13-7| ... | @@ -684,6 +684,12 @@ html[data-mobile-composer-route-transition="true"]::view-transition-old(t3-mobil | ... | @@ -684,6 +684,12 @@ html[data-mobile-composer-route-transition="true"]::view-transition-old(t3-mobil |
| 684 | * { | 684 | * { |
| 685 | @apply border-border outline-ring/50; | 685 | @apply border-border outline-ring/50; |
| 686 | } | 686 | } |
| 687 | /* The app's 2px outlines stay inside controls at clipped and scrollport edges. */ | ||
| 688 | *, | ||
| 689 | ::before, | ||
| 690 | ::after { | ||
| 691 | outline-offset: -2px; | ||
| 692 | } | ||
| 687 | :where([data-slot="menu-popup"], [data-slot="select-popup"], [data-slot="popover-popup"]):focus, | 693 | :where([data-slot="menu-popup"], [data-slot="select-popup"], [data-slot="popover-popup"]):focus, |
| 688 | :where( | 694 | :where( |
| 689 | [data-slot="menu-popup"], | 695 | [data-slot="menu-popup"], |
| ... | @@ -887,10 +893,10 @@ html[data-mobile-composer-route-transition="true"]::view-transition-old(t3-mobil | ... | @@ -887,10 +893,10 @@ html[data-mobile-composer-route-transition="true"]::view-transition-old(t3-mobil |
| 887 | @keyframes settings-search-target-pulse { | 893 | @keyframes settings-search-target-pulse { |
| 888 | 0%, | 894 | 0%, |
| 889 | 100% { | 895 | 100% { |
| 890 | box-shadow: 0 0 0 0 transparent; | 896 | box-shadow: inset 0 0 0 0 transparent; |
| 891 | } | 897 | } |
| 892 | 50% { | 898 | 50% { |
| 893 | box-shadow: 0 0 0 2px color-mix(in oklab, var(--color-primary) 70%, transparent); | 899 | box-shadow: inset 0 0 0 2px color-mix(in oklab, var(--color-primary) 70%, transparent); |
| 894 | } | 900 | } |
| 895 | } | 901 | } |
| 896 | 902 | ||
| ... | @@ -1015,14 +1021,14 @@ html[data-mobile-composer-route-transition="true"]::view-transition-old(t3-mobil | ... | @@ -1015,14 +1021,14 @@ html[data-mobile-composer-route-transition="true"]::view-transition-old(t3-mobil |
| 1015 | 1021 | ||
| 1016 | .settings-slider:focus-visible::-webkit-slider-thumb { | 1022 | .settings-slider:focus-visible::-webkit-slider-thumb { |
| 1017 | box-shadow: | 1023 | box-shadow: |
| 1018 | 0 0 0 3px var(--background), | 1024 | inset 0 0 0 1px var(--background), |
| 1019 | 0 0 0 5px var(--ring); | 1025 | inset 0 0 0 3px var(--ring); |
| 1020 | } | 1026 | } |
| 1021 | 1027 | ||
| 1022 | .settings-slider:focus-visible::-moz-range-thumb { | 1028 | .settings-slider:focus-visible::-moz-range-thumb { |
| 1023 | box-shadow: | 1029 | box-shadow: |
| 1024 | 0 0 0 3px var(--background), | 1030 | inset 0 0 0 1px var(--background), |
| 1025 | 0 0 0 5px var(--ring); | 1031 | inset 0 0 0 3px var(--ring); |
| 1026 | } | 1032 | } |
| 1027 | 1033 | ||
| 1028 | @media (forced-colors: active) { | 1034 | @media (forced-colors: active) { |
| ... | @@ -2255,7 +2261,7 @@ code { | ... | @@ -2255,7 +2261,7 @@ code { |
| 2255 | /* Selected chips (node selection from arrowing into or clicking a chip). */ | 2261 | /* Selected chips (node selection from arrowing into or clicking a chip). */ |
| 2256 | .composer-tiptap .ProseMirror-selectednode { | 2262 | .composer-tiptap .ProseMirror-selectednode { |
| 2257 | outline: 2px solid var(--ring); | 2263 | outline: 2px solid var(--ring); |
| 2258 | outline-offset: 1px; | 2264 | outline-offset: -2px; |
| 2259 | border-radius: 6px; | 2265 | border-radius: 6px; |
| 2260 | } | 2266 | } |
| 2261 | 2267 |
oxlint-plugin-t3code/index.ts+2| ... | @@ -7,6 +7,7 @@ import noInlineSchemaCompile from "./rules/no-inline-schema-compile.ts"; | ... | @@ -7,6 +7,7 @@ import noInlineSchemaCompile from "./rules/no-inline-schema-compile.ts"; |
| 7 | import noManualEffectRuntimeInTests from "./rules/no-manual-effect-runtime-in-tests.ts"; | 7 | import noManualEffectRuntimeInTests from "./rules/no-manual-effect-runtime-in-tests.ts"; |
| 8 | import noMobileUniwindThemeEscapeHatches from "./rules/no-mobile-uniwind-theme-escape-hatches.ts"; | 8 | import noMobileUniwindThemeEscapeHatches from "./rules/no-mobile-uniwind-theme-escape-hatches.ts"; |
| 9 | import noNativeTitleTooltip from "./rules/no-native-title-tooltip.ts"; | 9 | import noNativeTitleTooltip from "./rules/no-native-title-tooltip.ts"; |
| 10 | import noOutsetStateIndicators from "./rules/no-outset-state-indicators.ts"; | ||
| 10 | import noRawMcpRegistration from "./rules/no-raw-mcp-registration.ts"; | 11 | import noRawMcpRegistration from "./rules/no-raw-mcp-registration.ts"; |
| 11 | import noTestInLoop from "./rules/no-test-in-loop.ts"; | 12 | import noTestInLoop from "./rules/no-test-in-loop.ts"; |
| 12 | import noRpcPermissionBypass from "./rules/no-rpc-permission-bypass.ts"; | 13 | import noRpcPermissionBypass from "./rules/no-rpc-permission-bypass.ts"; |
| ... | @@ -27,6 +28,7 @@ export default definePlugin({ | ... | @@ -27,6 +28,7 @@ export default definePlugin({ |
| 27 | "no-manual-effect-runtime-in-tests": noManualEffectRuntimeInTests, | 28 | "no-manual-effect-runtime-in-tests": noManualEffectRuntimeInTests, |
| 28 | "no-mobile-uniwind-theme-escape-hatches": noMobileUniwindThemeEscapeHatches, | 29 | "no-mobile-uniwind-theme-escape-hatches": noMobileUniwindThemeEscapeHatches, |
| 29 | "no-native-title-tooltip": noNativeTitleTooltip, | 30 | "no-native-title-tooltip": noNativeTitleTooltip, |
| 31 | "no-outset-state-indicators": noOutsetStateIndicators, | ||
| 30 | "no-raw-mcp-registration": noRawMcpRegistration, | 32 | "no-raw-mcp-registration": noRawMcpRegistration, |
| 31 | "no-test-in-loop": noTestInLoop, | 33 | "no-test-in-loop": noTestInLoop, |
| 32 | "no-rpc-permission-bypass": noRpcPermissionBypass, | 34 | "no-rpc-permission-bypass": noRpcPermissionBypass, |
oxlint-plugin-t3code/rules/no-outset-state-indicators.ts created+126| ... | @@ -0,0 +1,126 @@ | ||
| 1 | import { defineRule, type ESTree } from "@oxlint/plugins"; | ||
| 2 | |||
| 3 | const CLASS_COMPOSERS = new Set(["cn", "clsx", "classNames", "cva", "twMerge"]); | ||
| 4 | const STATE_VARIANT = | ||
| 5 | /(?:^|[^\w])(?:focus(?:-visible|-within)?|selected|checked|pressed)(?=$|[^\w])/u; | ||
| 6 | const RING_WIDTH = /^ring(?:-(?:[1-9]\d*|\[[^\]]+\]|\(length:[^)]+\)))?$/u; | ||
| 7 | // Pixel widths only; arbitrary values like `outline-[#243c5a]` are colors. | ||
| 8 | const OUTLINE_WIDTH = /^outline-(?:(\d+)|\[(?:length:)?(\d+(?:\.\d+)?)px\])$/u; | ||
| 9 | const INWARD_OFFSET = /^-outline-offset-(\d+)$/u; | ||
| 10 | |||
| 11 | /** Splits `dark:[&_a]:ring-2!` into its variants and utility, ignoring colons inside brackets. */ | ||
| 12 | function parseClass(token: string) { | ||
| 13 | const variants: string[] = []; | ||
| 14 | let depth = 0; | ||
| 15 | let start = 0; | ||
| 16 | for (let index = 0; index < token.length; index++) { | ||
| 17 | const character = token[index]; | ||
| 18 | if (character === "[" || character === "(") depth++; | ||
| 19 | else if (character === "]" || character === ")") depth--; | ||
| 20 | else if (character === ":" && depth === 0) { | ||
| 21 | variants.push(token.slice(start, index)); | ||
| 22 | start = index + 1; | ||
| 23 | } | ||
| 24 | } | ||
| 25 | return { variants, utility: token.slice(start).replace(/^!|!$/gu, "") }; | ||
| 26 | } | ||
| 27 | |||
| 28 | type ParsedClass = ReturnType<typeof parseClass>; | ||
| 29 | |||
| 30 | /** A companion applies when its variants are a subset of the indicator's variants. */ | ||
| 31 | const covers = (companion: ParsedClass, indicator: ParsedClass) => | ||
| 32 | companion.variants.every((variant) => indicator.variants.includes(variant)); | ||
| 33 | |||
| 34 | const isClassComposer = (node: ESTree.Node) => | ||
| 35 | node.type === "CallExpression" && | ||
| 36 | node.callee.type === "Identifier" && | ||
| 37 | CLASS_COMPOSERS.has(node.callee.name); | ||
| 38 | |||
| 39 | /** Strings a composition always includes; branches, class maps, and other calls are not guaranteed. */ | ||
| 40 | function collectStrings(node: unknown, out: string[]) { | ||
| 41 | if (Array.isArray(node)) { | ||
| 42 | for (const child of node) collectStrings(child, out); | ||
| 43 | return; | ||
| 44 | } | ||
| 45 | if (typeof node !== "object" || node === null || !("type" in node)) return; | ||
| 46 | const current = node as ESTree.Node; | ||
| 47 | if (/^(?:Conditional|Logical|Object)Expression$/u.test(current.type)) return; | ||
| 48 | if (current.type === "CallExpression" && !isClassComposer(current)) return; | ||
| 49 | if (current.type === "Literal" && typeof current.value === "string") out.push(current.value); | ||
| 50 | if (current.type === "TemplateElement") out.push(current.value.cooked ?? current.value.raw); | ||
| 51 | for (const [key, value] of Object.entries(current)) { | ||
| 52 | if (key !== "parent") collectStrings(value, out); | ||
| 53 | } | ||
| 54 | } | ||
| 55 | |||
| 56 | /** Classes guaranteed alongside a node by each enclosing `cn(...)`, so sibling companions count. */ | ||
| 57 | function scopeClasses(node: ESTree.Node, own: ParsedClass[]) { | ||
| 58 | const strings: string[] = []; | ||
| 59 | for (let current = node.parent; current; current = current.parent) { | ||
| 60 | if (/Statement$|Declaration$|^JSX(?:Attribute|Element)$/u.test(current.type)) break; | ||
| 61 | if (isClassComposer(current)) collectStrings(current, strings); | ||
| 62 | } | ||
| 63 | return [...own, ...strings.join(" ").split(/\s+/u).map(parseClass)]; | ||
| 64 | } | ||
| 65 | |||
| 66 | function offenders(text: string, node: ESTree.Node) { | ||
| 67 | const own = text.split(/\s+/u).filter(Boolean).map(parseClass); | ||
| 68 | const found: string[] = []; | ||
| 69 | let scope: ParsedClass[] | undefined; | ||
| 70 | for (const token of own) { | ||
| 71 | const { utility, variants } = token; | ||
| 72 | const label = [...variants, utility].join(":"); | ||
| 73 | // Positive offsets push the outline out of the element; the app default is inward. | ||
| 74 | if (/^outline-offset-|^\[outline-offset:/u.test(utility)) { | ||
| 75 | found.push(label); | ||
| 76 | continue; | ||
| 77 | } | ||
| 78 | if (!STATE_VARIANT.test(variants.join(":"))) continue; | ||
| 79 | if (RING_WIDTH.test(utility)) { | ||
| 80 | scope ??= scopeClasses(node, own); | ||
| 81 | const inset = scope.some((other) => other.utility === "ring-inset" && covers(other, token)); | ||
| 82 | if (!inset) found.push(label); | ||
| 83 | continue; | ||
| 84 | } | ||
| 85 | const outline = OUTLINE_WIDTH.exec(utility); | ||
| 86 | if (outline) { | ||
| 87 | const width = Number(outline[1] ?? outline[2]); | ||
| 88 | if (width <= 2) continue; | ||
| 89 | scope ??= scopeClasses(node, own); | ||
| 90 | const inward = scope.some((other) => { | ||
| 91 | const offset = INWARD_OFFSET.exec(other.utility); | ||
| 92 | return offset !== null && Number(offset[1]) >= width && covers(other, token); | ||
| 93 | }); | ||
| 94 | if (!inward) found.push(label); | ||
| 95 | } | ||
| 96 | } | ||
| 97 | return found; | ||
| 98 | } | ||
| 99 | |||
| 100 | export default defineRule({ | ||
| 101 | meta: { | ||
| 102 | type: "problem", | ||
| 103 | docs: { | ||
| 104 | description: | ||
| 105 | "Keep focus and selection indicators inside their element, where an ancestor cannot clip them.", | ||
| 106 | }, | ||
| 107 | }, | ||
| 108 | create(context) { | ||
| 109 | const check = (node: ESTree.Node, text: string) => { | ||
| 110 | for (const utility of offenders(text, node)) { | ||
| 111 | context.report({ | ||
| 112 | node, | ||
| 113 | message: `${utility} paints a focus or selection indicator outside its element, where an ancestor can clip it. Add ring-inset under the same variant, drop the positive outline offset, or use a negative offset at least as wide as the outline.`, | ||
| 114 | }); | ||
| 115 | } | ||
| 116 | }; | ||
| 117 | return { | ||
| 118 | Literal(node) { | ||
| 119 | if (typeof node.value === "string") check(node, node.value); | ||
| 120 | }, | ||
| 121 | TemplateLiteral(node) { | ||
| 122 | check(node, node.quasis.map((part) => part.value.cooked ?? part.value.raw).join(" ")); | ||
| 123 | }, | ||
| 124 | }; | ||
| 125 | }, | ||
| 126 | }); | ||
oxlint-plugin-t3code/rules/no-unscoped-has.test.ts+39| ... | @@ -122,3 +122,42 @@ describe("t3code/no-unscoped-has", () => { | ... | @@ -122,3 +122,42 @@ describe("t3code/no-unscoped-has", () => { |
| 122 | `const className = "[body:has([data-dialog-open])_&]:overflow-hidden";`, | 122 | `const className = "[body:has([data-dialog-open])_&]:overflow-hidden";`, |
| 123 | ); | 123 | ); |
| 124 | }); | 124 | }); |
| 125 | |||
| 126 | const indicators = createOxlintRuleHarness("t3code/no-outset-state-indicators", { | ||
| 127 | filename: "fixture.tsx", | ||
| 128 | }); | ||
| 129 | |||
| 130 | describe("t3code/no-outset-state-indicators", () => { | ||
| 131 | describe.each( | ||
| 132 | Object.entries({ | ||
| 133 | "inset state rings": `const el = <button className="focus-visible:ring-2 focus-visible:ring-inset ring-1 ring-border" />;`, | ||
| 134 | "an unconditional inset": `const el = <button className="ring-inset data-selected:ring-2" />;`, | ||
| 135 | "an inset in a sibling composer argument": `const value = cn(active && "dark:focus-visible:ring-2", "focus-visible:ring-inset");`, | ||
| 136 | "an inset in a nested conditional composer": `const value = cn(enabled && cn("focus-visible:ring-2", "focus-visible:ring-inset"));`, | ||
| 137 | "outlines covered by the inward default": `const el = <button className="focus-visible:outline-2 focus-visible:outline-ring" />;`, | ||
| 138 | "wider outlines with a matching inward offset": `const el = <button className="focus-visible:outline-3 focus-visible:-outline-offset-3" />;`, | ||
| 139 | "arbitrary pixel outlines with a matching inward offset": `const el = <button className="focus-visible:outline-[3px] focus-visible:-outline-offset-3" />;`, | ||
| 140 | "arbitrary outline colors": `const el = <button className="focus-visible:outline-[#243c5a]" />;`, | ||
| 141 | "decorative rings without a state": `const el = <img className="ring-2 ring-background" />;`, | ||
| 142 | prose: `const note = "the focus ring stays visible";`, | ||
| 143 | }), | ||
| 144 | )("valid: %s", (name, source) => { | ||
| 145 | indicators.valid(name, source); | ||
| 146 | }); | ||
| 147 | |||
| 148 | describe.each( | ||
| 149 | Object.entries({ | ||
| 150 | "state rings without an inset": `const el = <button className="focus-visible:ring-2 focus-visible:ring-ring" />;`, | ||
| 151 | "an inset from another state": `const el = <button className="focus:ring-inset focus-visible:ring-2" />;`, | ||
| 152 | "an inset from another conditional branch": `const value = cn(active ? "focus:ring-2" : "ring-inset");`, | ||
| 153 | "an inset passed to another function": `const value = cn("focus-visible:ring-2", label("ring-inset"));`, | ||
| 154 | "arbitrary state ring widths": `const value = cn("has-[:focus-visible]:ring-[3px]");`, | ||
| 155 | "positive outline offsets": `const el = <button className="focus-visible:outline-2 focus-visible:outline-offset-2" />;`, | ||
| 156 | "arbitrary outline offsets": `const el = <button className="focus-visible:[outline-offset:2px]" />;`, | ||
| 157 | "wide outlines without an inward offset": | ||
| 158 | "const className = `focus-visible:outline-4 ${layout}`;", | ||
| 159 | }), | ||
| 160 | )("invalid: %s", (name, source) => { | ||
| 161 | indicators.invalid(name, source); | ||
| 162 | }); | ||
| 163 | }); |
packages/shared/src/htmlRender.ts+3-1| ... | @@ -325,7 +325,9 @@ export function htmlRenderThemeMessage(theme: HtmlRenderTheme) { | ... | @@ -325,7 +325,9 @@ export function htmlRenderThemeMessage(theme: HtmlRenderTheme) { |
| 325 | // reply reads as a box within the thread, so it stays hidden. | 325 | // reply reads as a box within the thread, so it stays hidden. |
| 326 | const BASE_CSS = | 326 | const BASE_CSS = |
| 327 | "html{background:var(--background);color:var(--foreground);font-family:var(--font-sans);font-size:14px;line-height:1.5;-webkit-font-smoothing:antialiased;-webkit-text-size-adjust:100%;scrollbar-width:none}" + | 327 | "html{background:var(--background);color:var(--foreground);font-family:var(--font-sans);font-size:14px;line-height:1.5;-webkit-font-smoothing:antialiased;-webkit-text-size-adjust:100%;scrollbar-width:none}" + |
| 328 | "html::-webkit-scrollbar{display:none}body{margin:0}code,kbd,pre,samp{font-family:var(--font-mono)}"; | 328 | "html::-webkit-scrollbar{display:none}body{margin:0}code,kbd,pre,samp{font-family:var(--font-mono)}" + |
| 329 | // Focus outlines paint inside the element, so the frame edge never clips them. | ||
| 330 | ":where(:focus-visible){outline:2px solid var(--ring)}:focus-visible{outline-width:2px!important;outline-offset:-2px!important}"; | ||
| 329 | 331 | ||
| 330 | function rootRule(theme: HtmlRenderTheme): string { | 332 | function rootRule(theme: HtmlRenderTheme): string { |
| 331 | const declarations = Object.entries(theme.variables) | 333 | const declarations = Object.entries(theme.variables) |
vite.config.ts+5| ... | @@ -256,6 +256,11 @@ export default defineConfig({ | ... | @@ -256,6 +256,11 @@ export default defineConfig({ |
| 256 | files: ["apps/web/src/**"], | 256 | files: ["apps/web/src/**"], |
| 257 | rules: { "shadcn/no-unknown-classes": "error" }, | 257 | rules: { "shadcn/no-unknown-classes": "error" }, |
| 258 | }, | 258 | }, |
| 259 | { | ||
| 260 | // State indicators paint inward; decorative rings keep their own geometry. | ||
| 261 | files: ["apps/web/src/**"], | ||
| 262 | rules: { "t3code/no-outset-state-indicators": "error" }, | ||
| 263 | }, | ||
| 259 | { | 264 | { |
| 260 | // Colors come from theme tokens so status tones follow custom themes. components/ui | 265 | // Colors come from theme tokens so status tones follow custom themes. components/ui |
| 261 | // has no findings and stays covered too. | 266 | // has no findings and stays covered too. |