654 lines
16 KiB
CSS
654 lines
16 KiB
CSS
.client-local-rules-header {
|
|
display: grid;
|
|
grid-template-columns: minmax(0, 1fr) auto;
|
|
gap: 9px;
|
|
margin: 0 8px 34px;
|
|
}
|
|
|
|
.client-local-rules-header > span,
|
|
.client-local-rules-group > span {
|
|
color: var(--client-muted);
|
|
font: var(--type-label);
|
|
letter-spacing: var(--type-label-tracking);
|
|
text-transform: var(--type-label-transform);
|
|
}
|
|
|
|
.client-local-rules-header h2 {
|
|
grid-column: 1 / -1;
|
|
font: var(--type-drawer-title);
|
|
letter-spacing: var(--type-drawer-title-tracking);
|
|
text-transform: var(--type-drawer-title-transform);
|
|
}
|
|
|
|
.client-local-rules-header p {
|
|
grid-column: 1 / -1;
|
|
max-width: 46ch;
|
|
color: var(--client-muted);
|
|
font: var(--type-body);
|
|
letter-spacing: var(--type-body-tracking);
|
|
text-transform: var(--type-body-transform);
|
|
}
|
|
|
|
.client-local-rules-save {
|
|
align-self: center;
|
|
padding: 0;
|
|
border: 0;
|
|
background: transparent;
|
|
color: var(--client-accent);
|
|
font: var(--type-control);
|
|
letter-spacing: var(--type-control-tracking);
|
|
text-transform: var(--type-control-transform);
|
|
cursor: pointer;
|
|
transition: color 200ms ease, filter 300ms ease, opacity 220ms ease, transform 300ms cubic-bezier(0.16, 1, 0.3, 1);
|
|
}
|
|
|
|
.client-local-rules-save:hover:not(:disabled) {
|
|
filter: drop-shadow(0 0 7px color-mix(in oklch, var(--client-accent) 42%, transparent));
|
|
transform: translateY(-1px);
|
|
}
|
|
|
|
.client-local-rules-save:disabled {
|
|
opacity: 0.28;
|
|
cursor: default;
|
|
}
|
|
|
|
.client-local-rules-header .client-local-rules-runtime {
|
|
color: oklch(0.68 0.14 72);
|
|
animation: client-local-rules-notice 480ms cubic-bezier(0.16, 1, 0.3, 1) both;
|
|
}
|
|
|
|
.client-local-rules-form,
|
|
.client-local-rules-group,
|
|
.client-local-rules-list {
|
|
display: grid;
|
|
}
|
|
|
|
.client-local-rules-form {
|
|
gap: 28px;
|
|
}
|
|
|
|
.client-local-rules-group {
|
|
gap: 11px;
|
|
}
|
|
|
|
.client-local-rules-list {
|
|
position: relative;
|
|
gap: 0;
|
|
padding-left: 14px;
|
|
}
|
|
|
|
.client-local-rules-list.has-order-flow::before {
|
|
content: '';
|
|
position: absolute;
|
|
top: 22px;
|
|
bottom: 22px;
|
|
left: 3px;
|
|
width: 1px;
|
|
background: linear-gradient(to bottom, transparent, color-mix(in oklch, var(--client-accent) 46%, transparent) 15%, color-mix(in oklch, var(--client-accent) 46%, transparent) 85%, transparent);
|
|
box-shadow: 0 0 7px color-mix(in oklch, var(--client-accent) 24%, transparent);
|
|
}
|
|
|
|
.client-local-rules-list.has-order-flow::after {
|
|
content: '';
|
|
position: absolute;
|
|
bottom: 18px;
|
|
left: 0;
|
|
width: 7px;
|
|
height: 6px;
|
|
background: color-mix(in oklch, var(--client-accent) 64%, transparent);
|
|
clip-path: polygon(0 0, 100% 0, 50% 100%);
|
|
filter: drop-shadow(0 0 4px color-mix(in oklch, var(--client-accent) 36%, transparent));
|
|
}
|
|
|
|
.client-local-rule {
|
|
--client-rule-drag-y: 0px;
|
|
--client-rule-route-color: var(--client-accent);
|
|
position: relative;
|
|
isolation: isolate;
|
|
min-width: 0;
|
|
display: grid;
|
|
grid-template-columns: 44px 24px 104px minmax(84px, 1fr) 34px 16px 28px;
|
|
align-items: center;
|
|
column-gap: 6px;
|
|
padding: 4px 0;
|
|
border-radius: 10px;
|
|
background: color-mix(in oklch, var(--client-rule-route-color) 6%, transparent);
|
|
animation: client-row-enter 560ms cubic-bezier(0.16, 1, 0.3, 1) both;
|
|
transition: background 320ms ease, box-shadow 180ms ease, opacity 260ms ease, filter 360ms ease;
|
|
}
|
|
|
|
.client-local-rule[data-route='direct'] {
|
|
--client-rule-route-color: light-dark(oklch(0.52 0.11 240), oklch(0.76 0.1 240));
|
|
}
|
|
|
|
.client-local-rule + .client-local-rule::before {
|
|
content: '';
|
|
position: absolute;
|
|
top: 0;
|
|
right: 0;
|
|
left: 44px;
|
|
height: 1px;
|
|
background: linear-gradient(90deg, color-mix(in oklch, var(--client-muted) 24%, transparent), color-mix(in oklch, var(--client-muted) 9%, transparent) 72%, transparent);
|
|
}
|
|
|
|
.client-local-rule:has(.client-rule-type.is-open) {
|
|
z-index: 5;
|
|
}
|
|
|
|
.client-local-rule-status {
|
|
width: 16px;
|
|
height: 44px;
|
|
display: grid;
|
|
place-items: center;
|
|
color: var(--client-muted);
|
|
}
|
|
|
|
.client-rule-status-dot {
|
|
width: 6px;
|
|
height: 6px;
|
|
border-radius: 50%;
|
|
border: 1px solid currentColor;
|
|
background: transparent;
|
|
opacity: 0.58;
|
|
transition: color 280ms ease, border 280ms ease, border-radius 280ms ease, background 280ms ease, opacity 280ms ease, filter 360ms ease, transform 280ms cubic-bezier(0.16, 1, 0.3, 1);
|
|
}
|
|
|
|
.client-local-rule.is-active .client-rule-status-dot {
|
|
color: var(--client-accent);
|
|
border: 0;
|
|
background: currentColor;
|
|
opacity: 1;
|
|
filter: drop-shadow(0 0 5px color-mix(in oklch, var(--client-accent) 52%, transparent));
|
|
transform: scale(1.14);
|
|
}
|
|
|
|
.client-local-rule.is-unsaved .client-rule-status-dot {
|
|
width: 7px;
|
|
height: 7px;
|
|
border: 1.5px solid currentColor;
|
|
border-radius: 1px;
|
|
color: var(--client-warning, oklch(0.72 0.12 72));
|
|
opacity: 1;
|
|
transform: rotate(45deg);
|
|
}
|
|
|
|
.client-local-rule.is-pending .client-rule-status-dot {
|
|
width: 8px;
|
|
height: 8px;
|
|
border: 1.5px dashed currentColor;
|
|
color: var(--client-warning, oklch(0.72 0.12 72));
|
|
opacity: 1;
|
|
}
|
|
|
|
.client-local-rule.is-disabled .client-rule-status-dot {
|
|
width: 8px;
|
|
height: 2px;
|
|
border: 0;
|
|
border-radius: 999px;
|
|
background: var(--client-muted);
|
|
transform: none;
|
|
}
|
|
|
|
.client-local-rule.is-disabled > :not(.client-rule-handle):not(.client-row-delete):not(.client-delete-strike) {
|
|
opacity: 0.42;
|
|
filter: saturate(0);
|
|
}
|
|
|
|
.client-local-rule.is-dragging {
|
|
z-index: 6;
|
|
animation: none;
|
|
background: color-mix(in oklch, var(--client-rule-route-color) 11%, transparent);
|
|
box-shadow: 0 10px 28px color-mix(in oklch, var(--client-rule-route-color) 16%, transparent);
|
|
transform: translateY(var(--client-rule-drag-y));
|
|
}
|
|
|
|
.client-local-rule.is-removing {
|
|
pointer-events: none;
|
|
animation: client-row-leave 820ms cubic-bezier(0.7, 0, 0.84, 0) both;
|
|
}
|
|
|
|
.client-local-rule-enabled-wrap {
|
|
width: 24px;
|
|
height: 44px;
|
|
display: grid;
|
|
place-items: center;
|
|
}
|
|
|
|
.client-local-rule-enabled {
|
|
width: 24px;
|
|
height: 32px;
|
|
display: grid;
|
|
place-items: center;
|
|
padding: 0;
|
|
border: 0;
|
|
background: transparent;
|
|
color: var(--client-muted);
|
|
cursor: pointer;
|
|
}
|
|
|
|
.client-rule-handle {
|
|
width: 44px;
|
|
height: 44px;
|
|
display: grid;
|
|
place-items: center;
|
|
padding: 0;
|
|
border: 0;
|
|
background: transparent;
|
|
color: var(--client-muted);
|
|
cursor: grab;
|
|
touch-action: none;
|
|
transition: color 180ms ease, filter 180ms ease;
|
|
}
|
|
|
|
.client-rule-handle svg {
|
|
width: 18px;
|
|
height: 32px;
|
|
overflow: visible;
|
|
padding: 2px 1px;
|
|
border-radius: 7px;
|
|
background: color-mix(in oklch, currentColor 6%, transparent);
|
|
fill: currentColor;
|
|
transition: background 220ms ease, transform 220ms cubic-bezier(0.16, 1, 0.3, 1);
|
|
}
|
|
|
|
.client-rule-handle:hover:not(:disabled),
|
|
.client-rule-handle:focus-visible,
|
|
.client-rule-handle[aria-pressed='true'] {
|
|
outline: 0;
|
|
color: var(--client-accent);
|
|
filter: drop-shadow(0 0 6px color-mix(in oklch, var(--client-accent) 48%, transparent));
|
|
}
|
|
|
|
.client-rule-handle[aria-pressed='true'] {
|
|
cursor: grabbing;
|
|
}
|
|
|
|
.client-rule-handle:hover:not(:disabled) svg,
|
|
.client-rule-handle:focus-visible svg,
|
|
.client-rule-handle[aria-pressed='true'] svg {
|
|
background: color-mix(in oklch, currentColor 12%, transparent);
|
|
transform: scale(1.04);
|
|
}
|
|
|
|
.client-rule-handle:disabled {
|
|
opacity: 0.28;
|
|
cursor: default;
|
|
}
|
|
|
|
.client-local-rule-enabled svg {
|
|
width: 18px;
|
|
height: 18px;
|
|
overflow: visible;
|
|
fill: none;
|
|
stroke: currentColor;
|
|
stroke-linecap: round;
|
|
stroke-linejoin: round;
|
|
transition: color 260ms ease, filter 360ms ease, transform 420ms cubic-bezier(0.16, 1, 0.3, 1);
|
|
}
|
|
|
|
.client-local-rule-enabled circle {
|
|
stroke-width: 1.4;
|
|
transition: fill 320ms ease, stroke 260ms ease;
|
|
}
|
|
|
|
.client-rule-check {
|
|
stroke-width: 1.8;
|
|
stroke-dasharray: 12;
|
|
stroke-dashoffset: 12;
|
|
transition: opacity 160ms ease, stroke-dashoffset 360ms cubic-bezier(0.16, 1, 0.3, 1);
|
|
}
|
|
|
|
.client-local-rule-enabled[aria-checked='true'] {
|
|
color: var(--client-rule-route-color);
|
|
}
|
|
|
|
.client-local-rule-enabled[aria-checked='true'] svg {
|
|
filter: drop-shadow(0 0 7px color-mix(in oklch, var(--client-rule-route-color) 48%, transparent));
|
|
transform: scale(1.08);
|
|
}
|
|
|
|
.client-local-rule-enabled[aria-checked='true'] circle {
|
|
fill: color-mix(in oklch, var(--client-rule-route-color) 12%, transparent);
|
|
}
|
|
|
|
.client-local-rule-enabled[aria-checked='true'] .client-rule-check {
|
|
stroke-dashoffset: 0;
|
|
}
|
|
|
|
.client-rule-type {
|
|
position: relative;
|
|
min-width: 0;
|
|
z-index: 1;
|
|
}
|
|
|
|
.client-rule-type.is-open {
|
|
z-index: 4;
|
|
}
|
|
|
|
.client-rule-type-trigger {
|
|
width: 100%;
|
|
height: 34px;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
gap: 8px;
|
|
padding: 0;
|
|
border: 0;
|
|
background: transparent;
|
|
color: var(--client-text);
|
|
font: var(--type-label);
|
|
letter-spacing: var(--type-label-tracking);
|
|
text-transform: var(--type-label-transform);
|
|
text-align: left;
|
|
cursor: pointer;
|
|
transition: color 220ms ease, text-shadow 300ms ease;
|
|
}
|
|
|
|
.client-rule-type-trigger svg {
|
|
width: 9px;
|
|
fill: none;
|
|
stroke: currentColor;
|
|
stroke-width: 1.5;
|
|
transition: transform 420ms cubic-bezier(0.16, 1, 0.3, 1);
|
|
}
|
|
|
|
.client-rule-type.is-open .client-rule-type-trigger {
|
|
color: var(--client-accent);
|
|
text-shadow: 0 0 10px color-mix(in oklch, var(--client-accent) 44%, transparent);
|
|
}
|
|
|
|
.client-rule-type.is-open .client-rule-type-trigger svg {
|
|
transform: rotate(180deg);
|
|
}
|
|
|
|
.client-rule-type-list {
|
|
position: absolute;
|
|
top: calc(100% - 1px);
|
|
left: -8px;
|
|
z-index: 3;
|
|
width: max-content;
|
|
min-width: calc(100% + 16px);
|
|
display: grid;
|
|
gap: 1px;
|
|
padding: 7px 8px;
|
|
background: color-mix(in oklch, var(--client-bg) 91%, transparent);
|
|
-webkit-backdrop-filter: blur(18px);
|
|
backdrop-filter: blur(18px);
|
|
opacity: 0;
|
|
visibility: hidden;
|
|
filter: blur(8px);
|
|
transform: translateY(-8px) scale(0.97);
|
|
transform-origin: top left;
|
|
pointer-events: none;
|
|
transition: opacity 200ms ease, filter 360ms ease, transform 420ms cubic-bezier(0.16, 1, 0.3, 1), visibility 0s 420ms;
|
|
}
|
|
|
|
.client-rule-type.is-open .client-rule-type-list {
|
|
opacity: 1;
|
|
visibility: visible;
|
|
filter: blur(0);
|
|
transform: translateY(0) scale(1);
|
|
pointer-events: auto;
|
|
transition-delay: 0s;
|
|
}
|
|
|
|
.client-rule-type-list button {
|
|
padding: 7px 6px;
|
|
border: 0;
|
|
background: transparent;
|
|
color: var(--client-muted);
|
|
font: var(--type-label);
|
|
letter-spacing: var(--type-label-tracking);
|
|
text-transform: var(--type-label-transform);
|
|
text-align: left;
|
|
white-space: nowrap;
|
|
cursor: pointer;
|
|
opacity: 0;
|
|
filter: blur(5px);
|
|
transform: translateY(-5px);
|
|
transition: color 180ms ease, opacity 260ms ease, filter 340ms ease, transform 380ms cubic-bezier(0.16, 1, 0.3, 1);
|
|
}
|
|
|
|
.client-rule-type.is-open .client-rule-type-list button {
|
|
opacity: 1;
|
|
filter: blur(0);
|
|
transform: translateY(0);
|
|
}
|
|
|
|
.client-rule-type.is-open .client-rule-type-list button:nth-child(2) {
|
|
transition-delay: 35ms;
|
|
}
|
|
|
|
.client-rule-type.is-open .client-rule-type-list button:nth-child(3) {
|
|
transition-delay: 70ms;
|
|
}
|
|
|
|
.client-rule-type-list button:hover,
|
|
.client-rule-type-list button:focus-visible,
|
|
.client-rule-type-list button[aria-selected='true'] {
|
|
outline: 0;
|
|
color: var(--client-accent);
|
|
text-shadow: 0 0 9px color-mix(in oklch, var(--client-accent) 40%, transparent);
|
|
}
|
|
|
|
.client-local-rule input {
|
|
min-width: 0;
|
|
height: 34px;
|
|
padding: 0 2px;
|
|
border: 0;
|
|
outline: 0;
|
|
background: transparent;
|
|
color: var(--client-text);
|
|
font: var(--type-control);
|
|
letter-spacing: var(--type-control-tracking);
|
|
text-transform: var(--type-control-transform);
|
|
box-shadow: 0 1px 0 transparent;
|
|
transition: color 220ms ease, box-shadow 300ms ease, text-shadow 300ms ease;
|
|
}
|
|
|
|
.client-local-rule input::placeholder {
|
|
color: color-mix(in oklch, var(--client-muted) 70%, transparent);
|
|
}
|
|
|
|
.client-local-rule input:focus {
|
|
box-shadow: 0 1px 0 color-mix(in oklch, var(--client-accent) 58%, transparent);
|
|
text-shadow: 0 0 9px color-mix(in oklch, var(--client-accent) 22%, transparent);
|
|
}
|
|
|
|
.client-rule-outbound {
|
|
width: 34px;
|
|
height: 34px;
|
|
display: block;
|
|
}
|
|
|
|
.client-rule-outbound button {
|
|
width: 34px;
|
|
height: 34px;
|
|
display: grid;
|
|
place-items: center;
|
|
padding: 0;
|
|
border: 0;
|
|
border-radius: 50%;
|
|
background: transparent;
|
|
color: var(--client-rule-route-color);
|
|
cursor: pointer;
|
|
transition: color 220ms ease, filter 320ms ease, background 220ms ease;
|
|
}
|
|
|
|
.client-rule-outbound svg {
|
|
width: 20px;
|
|
height: 20px;
|
|
fill: none;
|
|
stroke: currentColor;
|
|
stroke-width: 1.7;
|
|
stroke-linecap: round;
|
|
stroke-linejoin: round;
|
|
transition: transform 320ms cubic-bezier(0.16, 1, 0.3, 1);
|
|
}
|
|
|
|
.client-rule-outbound button:disabled {
|
|
cursor: default;
|
|
}
|
|
|
|
.client-rule-outbound button:focus-visible {
|
|
outline: 0;
|
|
background: color-mix(in oklch, var(--client-rule-route-color) 10%, transparent);
|
|
filter: drop-shadow(0 0 5px color-mix(in oklch, var(--client-rule-route-color) 36%, transparent));
|
|
}
|
|
|
|
.client-rule-outbound button:hover:not(:disabled) {
|
|
background: color-mix(in oklch, var(--client-rule-route-color) 10%, transparent);
|
|
filter: drop-shadow(0 0 5px color-mix(in oklch, var(--client-rule-route-color) 36%, transparent));
|
|
}
|
|
|
|
.client-rule-outbound button.is-direct:hover:not(:disabled) svg,
|
|
.client-rule-outbound button.is-direct:focus-visible svg {
|
|
transform: translateX(2px);
|
|
}
|
|
|
|
.client-rule-outbound button.is-vpn:hover:not(:disabled) svg,
|
|
.client-rule-outbound button.is-vpn:focus-visible svg {
|
|
transform: translateY(-1px) rotate(3deg) scale(1.05);
|
|
}
|
|
|
|
.client-rule-reorder-instructions,
|
|
.client-rule-reorder-live {
|
|
position: absolute;
|
|
width: 1px;
|
|
height: 1px;
|
|
padding: 0;
|
|
margin: -1px;
|
|
overflow: hidden;
|
|
clip-path: inset(50%);
|
|
white-space: nowrap;
|
|
border: 0;
|
|
}
|
|
|
|
.client-local-rules-empty {
|
|
padding: 14px 4px 4px;
|
|
color: var(--client-muted);
|
|
font: var(--type-control);
|
|
letter-spacing: var(--type-control-tracking);
|
|
text-transform: var(--type-control-transform);
|
|
}
|
|
|
|
.client-local-rules-help {
|
|
grid-column: 1 / -1;
|
|
margin-top: 4px;
|
|
}
|
|
|
|
.client-local-rules-help summary {
|
|
width: fit-content;
|
|
color: var(--client-muted);
|
|
font: var(--type-label);
|
|
letter-spacing: var(--type-label-tracking);
|
|
text-transform: var(--type-label-transform);
|
|
cursor: pointer;
|
|
transition: color 220ms ease, text-shadow 300ms ease;
|
|
}
|
|
|
|
.client-local-rules-help summary:hover,
|
|
.client-local-rules-help summary:focus-visible {
|
|
outline: 0;
|
|
color: var(--client-accent);
|
|
text-shadow: 0 0 9px color-mix(in oklch, var(--client-accent) 34%, transparent);
|
|
}
|
|
|
|
.client-local-rules-help > div {
|
|
max-width: 48ch;
|
|
display: grid;
|
|
gap: 8px;
|
|
margin-top: 10px;
|
|
padding: 10px 12px;
|
|
border-radius: 10px;
|
|
background: color-mix(in oklch, var(--client-accent) 5%, transparent);
|
|
animation: client-local-rules-notice 280ms ease both;
|
|
}
|
|
|
|
.client-local-rules-help > div p {
|
|
max-width: 48ch;
|
|
margin: 0;
|
|
color: var(--client-muted);
|
|
font: var(--type-label);
|
|
letter-spacing: var(--type-label-tracking);
|
|
text-transform: var(--type-label-transform);
|
|
}
|
|
|
|
.client-inline-error.is-routing {
|
|
position: static;
|
|
width: 100%;
|
|
transform: none;
|
|
}
|
|
|
|
.client-local-rules-actions {
|
|
display: flex;
|
|
justify-content: flex-end;
|
|
gap: 10px;
|
|
}
|
|
|
|
.client-local-rules-actions button {
|
|
padding: 8px 0 8px 14px;
|
|
border: 0;
|
|
background: transparent;
|
|
color: var(--client-text);
|
|
font: var(--type-control);
|
|
letter-spacing: var(--type-control-tracking);
|
|
text-transform: var(--type-control-transform);
|
|
cursor: pointer;
|
|
transition: color 200ms ease, filter 300ms ease, transform 300ms cubic-bezier(0.16, 1, 0.3, 1);
|
|
}
|
|
|
|
.client-local-rules-actions button:hover:not(:disabled) {
|
|
color: var(--client-accent);
|
|
filter: drop-shadow(0 0 7px color-mix(in oklch, var(--client-accent) 40%, transparent));
|
|
transform: translateY(-1px);
|
|
}
|
|
|
|
.client-local-rules-actions button:disabled {
|
|
opacity: 0.45;
|
|
cursor: wait;
|
|
}
|
|
|
|
@keyframes client-local-rules-notice {
|
|
from { opacity: 0; filter: blur(6px); transform: translateY(-6px); }
|
|
to { opacity: 1; filter: blur(0); transform: translateY(0); }
|
|
}
|
|
|
|
.client-route-rules-pending {
|
|
min-height: 17px;
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 10px;
|
|
margin: -10px 0 -8px;
|
|
color: var(--client-warning, oklch(0.72 0.12 72));
|
|
font: var(--type-label);
|
|
letter-spacing: var(--type-label-tracking);
|
|
text-transform: var(--type-label-transform);
|
|
opacity: 0;
|
|
filter: blur(5px);
|
|
transform: translateY(-3px);
|
|
transition: opacity 240ms ease, filter 320ms ease, transform 320ms cubic-bezier(0.16, 1, 0.3, 1);
|
|
}
|
|
|
|
.client-route-rules-pending.is-visible {
|
|
opacity: 1;
|
|
filter: blur(0);
|
|
transform: translateY(0);
|
|
}
|
|
|
|
.client-route-rules-pending button {
|
|
padding: 0;
|
|
border: 0;
|
|
background: transparent;
|
|
color: var(--client-accent);
|
|
font: inherit;
|
|
cursor: pointer;
|
|
text-decoration: underline;
|
|
text-underline-offset: 3px;
|
|
}
|
|
|
|
.client-route-rules-pending button:disabled {
|
|
cursor: default;
|
|
opacity: 0.35;
|
|
}
|