.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; }