.app.client-app { grid-template-rows: 1fr; color-scheme: light; background: var(--client-bg); } .app-body.client-mode { min-height: 100vh; background: var(--client-bg); } .client-mode .app-main { min-height: 100vh; display: grid; place-items: center; padding: 48px 24px 32px; overflow-y: auto; } .client-shell { position: relative; width: min(100%, 1100px); display: grid; gap: 12px; font-family: 'JetBrains Mono', 'SF Mono', ui-monospace, Menlo, monospace; color: var(--client-text); } .harbor-versions { position: fixed; right: max(14px, env(safe-area-inset-right)); bottom: max(12px, env(safe-area-inset-bottom)); z-index: 40; display: grid; justify-items: end; gap: 4px; color: var(--client-muted); font: 650 12px/1 'JetBrains Mono', 'SF Mono', ui-monospace, Menlo, monospace; font-variant-numeric: tabular-nums; } .harbor-version { display: flex; align-items: center; gap: 6px; opacity: 0.56; transition: color 240ms ease, opacity 240ms ease; } .harbor-version:focus-within, .harbor-version:hover { color: var(--client-text); opacity: 1; } .harbor-version.is-incompatible { color: oklch(0.68 0.15 28); opacity: 0.9; } .harbor-version-code { width: 1.3ch; color: var(--client-accent); font-size: 10px; text-align: center; } .harbor-version-number { display: flex; align-items: center; } .harbor-version-part { position: relative; min-width: 1ch; padding: 5px 2px; border-radius: 5px; cursor: help; text-align: center; } .harbor-version-part:hover, .harbor-version-part:focus-visible { outline: none; color: var(--client-accent); text-shadow: 0 0 8px color-mix(in oklch, var(--client-accent) 48%, transparent); } .harbor-version-part:focus-visible { box-shadow: 0 0 0 1px var(--client-accent); } .harbor-version-tooltip { position: absolute; right: 0; bottom: calc(100% + 7px); width: min(300px, calc(100vw - 28px)); display: grid; gap: 7px; padding: 12px 13px; border-radius: 12px; background: oklch(0.14 0.012 145); box-shadow: 0 9px 30px oklch(0.08 0.015 145 / 0.16); color: oklch(0.88 0.012 145); font-size: 11px; font-weight: 500; line-height: 1.5; text-align: left; opacity: 0; visibility: hidden; filter: blur(2px); pointer-events: none; transform: translateY(3px); transition: opacity 90ms ease, filter 120ms ease, transform 140ms cubic-bezier(0.16, 1, 0.3, 1), visibility 0s 140ms; } .harbor-version-tooltip strong { color: oklch(0.96 0.008 145); font-size: 11px; } .harbor-version-tooltip small { color: var(--client-accent); font-size: 10px; } .harbor-version-tooltip .is-warning { color: oklch(0.68 0.15 28); } .harbor-version-part:hover .harbor-version-tooltip, .harbor-version-part:focus-visible .harbor-version-tooltip { opacity: 1; visibility: visible; filter: blur(0); transform: translateY(0); transition-delay: 20ms, 20ms, 20ms, 0s; } .harbor-brand { position: fixed; top: 50%; left: 50%; z-index: 2; color: var(--harbor-word); font-size: 13px; letter-spacing: -0.035em; transform: translate(-50%, calc(-50% - 25vh)) scale(3); transform-origin: center; transition: transform 1800ms cubic-bezier(0.16, 1, 0.3, 1); user-select: none; pointer-events: none; } .harbor-brand.is-switchable { pointer-events: auto; } .harbor-brand-control { position: relative; appearance: none; border: 0; border-radius: 7px; padding: 3px 5px; background: transparent; color: inherit; font: inherit; letter-spacing: inherit; cursor: pointer; } .harbor-brand-control:focus-visible { outline: 1px solid color-mix(in srgb, var(--harbor-gateway) 55%, transparent); outline-offset: 4px; } .harbor-brand-control:disabled { cursor: wait; } .client-shell.is-first-run .harbor-brand { transform: translate(-50%, calc(-50% - 72px)) scale(1.35); } .harbor-brand-content { position: relative; display: flex; align-items: center; gap: 9px; } .client-shell.is-intro .harbor-brand-content { animation: harbor-startup-brand 760ms cubic-bezier(0.16, 1, 0.3, 1); } .client-shell.is-intro .client-panel, .client-shell.is-intro .client-secondary-menu, .client-shell.is-intro .harbor-versions { animation: harbor-startup-content 720ms 120ms cubic-bezier(0.16, 1, 0.3, 1) both; } @keyframes harbor-startup-brand { from { opacity: 0.35; filter: blur(5px); } } @keyframes harbor-startup-content { from { opacity: 0; filter: blur(6px); } } .harbor-brand svg { width: 24px; height: 24px; fill: none; stroke: currentColor; stroke-width: 1.7; stroke-linecap: round; stroke-linejoin: round; } .harbor-brand .harbor-anchor-left { stroke: var(--harbor-connect); } .harbor-brand .harbor-anchor-right { stroke: var(--harbor-gateway); } .harbor-brand.is-gateway .harbor-anchor-left { stroke: var(--harbor-gateway); } .harbor-brand strong { font-weight: 800; } .harbor-brand-name { display: flex; align-items: center; gap: 0.45em; } .harbor-brand em { color: var(--harbor-connect); font-style: normal; font-weight: 600; } .harbor-brand.is-gateway em { color: var(--harbor-gateway); } .harbor-mode-control, .harbor-mode-stack { position: relative; display: inline-block; width: 4.5em; height: 1.25em; } .harbor-mode-stack { width: 100%; height: 100%; } .harbor-mode-stack em { position: absolute; inset: 0 auto auto 0; transition: color 420ms ease, opacity 420ms ease, filter 420ms ease, transform 560ms cubic-bezier(0.16, 1, 0.3, 1); } .harbor-brand .harbor-mode-connect { z-index: 2; color: var(--harbor-connect); animation: harbor-mode-ambient-front 10s ease-in-out infinite; } .harbor-brand .harbor-mode-gateway { z-index: 1; color: var(--harbor-gateway); opacity: 0.2; filter: blur(0.4px); transform: translate(0.42em, 0.34em) scale(0.96); animation: harbor-mode-ambient-back 10s ease-in-out infinite; } .harbor-mode-gateway > span { display: block; animation: harbor-mode-discovered 520ms cubic-bezier(0.16, 1, 0.3, 1) both; } .harbor-brand.is-gateway-active .harbor-mode-connect { z-index: 1; opacity: 0.18; filter: blur(0.4px); transform: translate(0.42em, 0.34em) scale(0.96); } .harbor-brand.is-gateway-active .harbor-mode-gateway { z-index: 2; opacity: 1; filter: none; transform: none; } @keyframes harbor-mode-discovered { from { opacity: 0; filter: blur(3px); transform: translateX(4.8em); } } .harbor-brand.is-gateway-active .harbor-mode-connect { animation-name: harbor-mode-ambient-back; } .harbor-brand.is-gateway-active .harbor-mode-gateway { animation-name: harbor-mode-ambient-front; } .harbor-brand-control.is-mode-animating .harbor-mode-connect { animation: harbor-mode-float-front 1500ms ease-in-out infinite; } .harbor-brand-control.is-mode-animating .harbor-mode-gateway { animation: harbor-mode-float-back 1500ms ease-in-out infinite; } .harbor-brand.is-gateway-active .harbor-brand-control.is-mode-animating .harbor-mode-connect { animation-name: harbor-mode-float-back; } .harbor-brand.is-gateway-active .harbor-brand-control.is-mode-animating .harbor-mode-gateway { animation-name: harbor-mode-float-front; } @keyframes harbor-mode-float-front { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(0.12em); } } @keyframes harbor-mode-float-back { 0%, 100% { transform: translate(0.42em, 0.34em) scale(0.96); } 50% { transform: translate(0.42em, 0.22em) scale(0.96); } } @keyframes harbor-mode-ambient-front { 0%, 88%, 96%, 100% { transform: translateY(0); } 92% { transform: translateY(0.08em); } } @keyframes harbor-mode-ambient-back { 0%, 88%, 96%, 100% { transform: translate(0.42em, 0.34em) scale(0.96); } 92% { transform: translate(0.42em, 0.26em) scale(0.96); } } .harbor-brand .harbor-mode-swap { position: absolute; top: 50%; left: calc(100% + 4px); width: 14px; height: 14px; opacity: 0.82; stroke-width: 1.35; transform: translateY(-50%); transition: color 320ms ease, opacity 320ms ease, transform 420ms cubic-bezier(0.16, 1, 0.3, 1); animation: harbor-mode-arrows-discovered 260ms 420ms cubic-bezier(0.16, 1, 0.3, 1) both; } @keyframes harbor-mode-arrows-discovered { from { opacity: 0; filter: blur(2px); } } .harbor-mode-swap g { transform-box: view-box; transform-origin: 9px 9px; transform: rotate(var(--harbor-arrow-turn, 0turn)); transition: opacity 420ms ease, filter 420ms ease, transform 560ms cubic-bezier(0.16, 1, 0.3, 1); } .harbor-mode-swap path { transform-box: fill-box; transform-origin: center; transition: opacity 420ms ease, filter 420ms ease, transform 560ms cubic-bezier(0.16, 1, 0.3, 1); } .harbor-mode-swap .is-connect { opacity: 1; stroke: var(--harbor-connect); transition: opacity 420ms ease, filter 420ms ease, transform 560ms cubic-bezier(0.16, 1, 0.3, 1); } .harbor-mode-swap .is-connect path { animation: harbor-arrow-ambient-right 10s ease-in-out infinite; } .harbor-mode-swap .is-gateway { opacity: 0.28; filter: blur(0.45px); stroke: var(--harbor-gateway); transition: opacity 420ms ease, filter 420ms ease, transform 560ms cubic-bezier(0.16, 1, 0.3, 1); } .harbor-mode-swap .is-gateway path { animation: harbor-arrow-ambient-left 10s ease-in-out infinite; } .harbor-brand.is-gateway-active .harbor-mode-swap .is-connect { opacity: 0.28; filter: blur(0.45px); } .harbor-brand.is-gateway-active .harbor-mode-swap .is-gateway { opacity: 1; filter: none; } .harbor-mode-tooltip { position: absolute; bottom: calc(100% + 9px); left: 0; width: calc(100% + 22px); display: grid; gap: 2px; padding: 5px 6px; border-radius: 5px; background: oklch(0.14 0.012 145); box-shadow: 0 5px 18px oklch(0.08 0.015 145 / 0.1); color: oklch(0.88 0.012 145); font-size: 4px; line-height: 1.5; letter-spacing: 0; text-align: left; opacity: 0; visibility: hidden; filter: blur(2px); pointer-events: none; transform: translateY(3px); transition: opacity 90ms ease, filter 120ms ease, transform 140ms cubic-bezier(0.16, 1, 0.3, 1), visibility 0s 140ms; } .harbor-mode-tooltip strong { color: oklch(0.96 0.008 145); font-size: 4.2px; } .harbor-brand-control:hover .harbor-mode-tooltip, .harbor-brand-control:focus-visible .harbor-mode-tooltip { opacity: 1; visibility: visible; filter: blur(0); transform: translateY(0); transition-delay: 20ms, 20ms, 20ms, 0s; } .harbor-brand-control:hover .harbor-mode-swap, .harbor-brand-control:focus-visible .harbor-mode-swap { opacity: 1; } .harbor-brand-control.is-mode-animating .harbor-mode-swap .is-connect path { animation: harbor-arrow-float-right 1500ms ease-in-out infinite; } .harbor-brand-control.is-mode-animating .harbor-mode-swap .is-gateway path { animation: harbor-arrow-float-left 1500ms ease-in-out infinite; } @keyframes harbor-arrow-float-right { 0%, 100% { transform: translateX(0); } 50% { transform: translateX(1.25px); } } @keyframes harbor-arrow-float-left { 0%, 100% { transform: translateX(0); } 50% { transform: translateX(-1.25px); } } @keyframes harbor-arrow-ambient-right { 0%, 88%, 96%, 100% { transform: translateX(0); } 92% { transform: translateX(0.75px); } } @keyframes harbor-arrow-ambient-left { 0%, 88%, 96%, 100% { transform: translateX(0); } 92% { transform: translateX(-0.75px); } } .client-secondary-menu { position: fixed; top: 50%; right: max(14px, env(safe-area-inset-right)); z-index: 60; display: grid; gap: 6px; transform: translateY(-50%); } .client-panel { position: relative; display: grid; grid-template-columns: minmax(0, 1fr) minmax(240px, 280px) minmax(0, 1fr); place-items: center; width: 100%; min-height: 520px; padding: 24px 0; } .client-panel.is-setup { grid-template-columns: minmax(0, 1fr); } .client-panel.is-setup .client-form { grid-column: 1; justify-self: center; } .client-panel.is-gateway-home { grid-template-rows: minmax(0, 1fr) auto; row-gap: 28px; } .client-gateway-route-summary { min-height: 54px; display: grid; justify-items: center; gap: 2px; margin-top: 6px; } .client-gateway-route-summary strong { max-width: min(300px, 100%); min-height: 20px; overflow: hidden; color: var(--client-text); font-size: 15px; letter-spacing: -0.035em; text-overflow: ellipsis; white-space: nowrap; } .client-gateway-route-slot { width: 100%; min-height: 16px; overflow: hidden; color: var(--client-accent); font-size: 9px; font-weight: 700; text-overflow: ellipsis; white-space: nowrap; } .client-panel.has-subscription .client-form { height: var(--client-work-height); } .client-panel.is-gateway-home .client-state-copy { min-height: 136px; } @media (min-width: 921px) { .client-panel.has-subscription { --client-work-height: min(640px, calc(100vh - 120px)); --client-power-top: calc((var(--client-work-height) - 96px) / 2); transform: translateY(-9vh); } .client-panel.has-subscription .client-form-content { padding-top: var(--client-power-top); } } @media (max-width: 920px) { .client-mode .app-main { place-items: start center; } .client-shell { width: 100%; } .client-panel, .client-panel.is-setup { grid-template-columns: minmax(0, 1fr); gap: 40px; min-height: 0; padding: 110px 6px 72px; } .client-power-section, .client-form, .client-panel.is-setup .client-form { grid-column: 1; justify-self: center; width: min(100%, 380px); } .client-power-section { order: 1; } .client-gateway-summary { grid-row: auto; order: 2; } .client-form { height: auto; max-height: none; overflow-y: visible; overscroll-behavior: auto; } .harbor-brand, .client-shell.is-first-run .harbor-brand { position: absolute; top: 28px; transform: translateX(-50%) scale(1.55); } .client-inline-error.is-connection, .client-inline-error.is-subscription { position: static; width: min(100%, 360px); transform: none; } } @media (max-width: 560px) { .client-local-rule { grid-template-columns: 24px 104px minmax(0, 1fr) 28px; } .client-local-rule-status { grid-column: 3; text-align: left; } .client-mode .app-main { padding: 20px 14px; } .client-stale-banner { width: calc(100% - 28px); grid-template-columns: 1fr auto; } .client-stale-banner span { grid-column: 1 / -1; grid-row: 2; } .client-panel { position: static; grid-template-columns: 1fr; gap: 26px; min-height: 0; padding: 96px 6px 72px; } .client-power-section { padding-bottom: 40px; } .client-inline-error.is-connection { top: auto; bottom: 0; } .client-form-content { gap: 24px; } .harbor-brand { transform: translateX(-50%) scale(1.35); } .client-secondary-menu { right: 8px; } .client-duration-toggle > .client-tooltip { right: calc(50% + 36px); max-width: 110px; } .client-copy-button { min-height: 44px; font-size: 10px; } .client-server-filters button, .client-server-mode-toggle, .client-server-check, .client-server-group-toggle, .client-server-more, .client-server-favorite { min-height: 44px; } .client-server-check { width: 44px; height: 44px; } .client-server-toolbar { grid-template-rows: 44px 44px; } .client-server-toolbar.is-single { grid-template-rows: 44px; } .client-local-rule { grid-template-columns: 44px minmax(0, 1fr) 44px; } .client-local-rule-enabled, .client-local-rule-delete { width: 44px; height: 44px; } .client-local-rules-header > span, .client-local-rules-group > span, .client-instructions-header span, .client-instruction-summary > span { font-size: 10px; } .client-instructions-sheet { padding: 40px 58px 60px 18px; } .client-subscription-sheet { padding: 70px 58px 60px 18px; } .client-local-rules-sheet { padding: 40px 58px 60px 18px; } .client-local-rules-header h2 { font-size: 18px; } .client-local-rule { gap: 8px; } .client-local-rule-enabled { grid-column: 1; grid-row: 1; } .client-rule-type { grid-column: 2; grid-row: 1; } .client-local-rule-delete { grid-column: 3; grid-row: 1; } .client-local-rule input { grid-column: 2 / -1; grid-row: 2; } .client-instructions-header h2 { font-size: 18px; } .client-instruction-block:nth-child(n) { margin-inline: 0; } .client-form { position: relative; width: 100%; transform: none; } .client-panel.is-setup .client-form { transform: none; } }