/*
* Custom Tailwind v4 utilities migrated from packages/config/ui.config.js
* (addUtilities + matchUtilities) and packages/config/tailwind.config.js
* (the .bg legacy shim).
*/
/*
* The `bg` class worked in Tailwind v3 but stopped working in v4. Restored as
* an alias for `bg-default` to avoid a wide rename across the codebase.
* Should be deprecated in favor of `bg-default`.
*/
@utility bg {
background-color: var(--background);
}
/*
* Soft shimmer gradient used by LoadingLine.
*/
@utility line-loading-bg {
background: rgb(0, 0, 0);
background: linear-gradient(
90deg,
rgba(0, 0, 0, 0) 0%,
rgba(255, 255, 255, 0.65) 50%,
rgba(0, 0, 0, 0) 100%
);
}
@utility line-loading-bg-light {
background: rgb(0, 0, 0);
background: linear-gradient(
90deg,
rgba(0, 0, 0, 0) 0%,
rgba(33, 33, 33, 0.65) 50%,
rgba(0, 0, 0, 0) 100%
);
}
/* may be unused — verify before pruning */
@utility mask-fadeout-right {
-webkit-mask-image: linear-gradient(to right, white 98%, transparent 100%);
mask-image: linear-gradient(to right, white 98%, transparent 100%);
}
/* may be unused — verify before pruning */
@utility mask-fadeout-left {
-webkit-mask-image: linear-gradient(to left, white 98%, transparent 100%);
mask-image: linear-gradient(to left, white 98%, transparent 100%);
}
/*
* Functional color utilities. The `--value(--color-*)` token accepts any
* registered --color-* design token (e.g. highlight-foreground-light).
*/
/* may be unused — verify before pruning */
@utility highlight-* {
box-shadow: inset 0 1px 0 0 --value(--color-*);
}
/* may be unused — verify before pruning */
@utility subhighlight-* {
box-shadow: inset 0 -1px 0 0 --value(--color-*);
}
/*
* Inline-SVG grid background. Used by ProjectLinker as bg-grid-black/5 and
* bg-grid-white/5 for the integrations onboarding visuals.
*/
@utility bg-grid-* {
background-image: url("data:image/svg+xml;utf8,");
}
@utility no-scrollbar {
-ms-overflow-style: none; /* IE and Edge */
scrollbar-width: none; /* Firefox */
&::-webkit-scrollbar {
display: none; /* Chrome, Safari, Opera */
}
}
/*
* Text shimmer (shadcn shimmer utility, inlined so we don't pull in the full
* shadcn CSS package). Apply `shimmer` to text to draw attention.
*/
@property --shimmer-angle {
syntax: '';
inherits: true;
initial-value: 20deg;
}
@property --shimmer-image {
syntax: '*';
inherits: false;
}
@property --shimmer-text-fill {
syntax: '*';
inherits: false;
}
@utility shimmer {
--_spread: var(--shimmer-spread, calc(3ch + 40px));
--_base: currentColor;
--_highlight: var(--shimmer-color, oklch(from currentColor l c h / calc(alpha* 0.2)));
background-image: var(
--shimmer-image,
linear-gradient(
calc(90deg + var(--shimmer-angle)),
var(--_base) calc(50% - var(--_spread)),
color-mix(in oklch, var(--_highlight), var(--_base) 50%) calc(50% - var(--_spread) * 0.5),
var(--_highlight) 50%,
color-mix(in oklch, var(--_highlight), var(--_base) 50%) calc(50% + var(--_spread) * 0.5),
var(--_base) calc(50% + var(--_spread))
)
);
background-repeat: no-repeat;
background-size: calc(200% + var(--_spread) * 2) 100%;
background-position: 0 0;
background-clip: text;
-webkit-background-clip: text;
-webkit-text-fill-color: var(--shimmer-text-fill, transparent);
animation: tw-shimmer var(--shimmer-duration, 2s) linear infinite;
transition: -webkit-text-fill-color 0.5s ease;
/* Fade to solid text on dismiss — keep the gradient until fill is opaque */
&[data-shimmer-fading] {
-webkit-text-fill-color: currentColor;
animation-play-state: paused;
}
@variant dark {
--_highlight: var(
--shimmer-color,
oklch(from currentColor max(0.8, calc(l + 0.4)) c h / calc(alpha + 0.4))
);
}
&:where([dir='rtl'], [dir='rtl'] *) {
animation-direction: reverse;
}
}
@utility shimmer-once {
animation-iteration-count: 1;
}
@utility shimmer-reverse {
animation-direction: reverse;
}
@utility shimmer-none {
--shimmer-image: none;
--shimmer-text-fill: currentColor;
background-image: none;
-webkit-text-fill-color: currentColor;
}
@utility shimmer-color-* {
--shimmer-color: --value(--color-*, [color]);
--shimmer-color: color-mix(
in oklch,
--value(--color-*, [color]) calc(--modifier(integer) * 1%),
transparent
);
}
@utility shimmer-duration-* {
--shimmer-duration: calc(--value(integer) * 1ms);
}
@utility shimmer-spread-* {
--shimmer-spread: calc(var(--spacing) * --value(integer));
--shimmer-spread: --value([length], [percentage]);
}
@utility shimmer-angle-* {
--shimmer-angle: calc(--value(integer) * 1deg);
}
@media (prefers-reduced-motion: reduce) {
.shimmer {
animation: none;
background-image: none;
-webkit-text-fill-color: currentColor;
}
}
/*
* Canonical keyboard focus rings. Prefer these over inventing local ring/outline
* stacks.
*
* - focus-ring: default offset ring (buttons, inputs, most controls).
* `outline-hidden` stays always-on so mouse click does not show the browser
* default; the ring is `:focus-visible` only.
* - focus-inset: dense/flush surfaces such as interactive
s. Must use
* outline (not ring/box-shadow) — box-shadow on table-row is unreliable,
* especially in Safari. Do NOT pair with outline-hidden: that sets
* outline-style: none and suppresses the focus outline.
*/
@utility focus-ring {
@apply outline-hidden focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background;
}
@utility focus-inset {
&:focus-visible {
outline-style: solid;
outline-width: 2px;
outline-offset: -2px;
outline-color: var(--ring);
border-radius: var(--radius-md, 0.375rem);
}
}