Login screen redesign
This commit is contained in:
@@ -2,6 +2,7 @@
|
|||||||
import { invalidateAll } from '$app/navigation';
|
import { invalidateAll } from '$app/navigation';
|
||||||
import { goto } from '$app/navigation';
|
import { goto } from '$app/navigation';
|
||||||
import { page } from '$app/state';
|
import { page } from '$app/state';
|
||||||
|
import Lean101Logo from '$lib/components/Lean101Logo.svelte';
|
||||||
import { clientSession, hasModuleAccess, sessionHydrated } from '$lib/session';
|
import { clientSession, hasModuleAccess, sessionHydrated } from '$lib/session';
|
||||||
import { onMount, tick } from 'svelte';
|
import { onMount, tick } from 'svelte';
|
||||||
import packageInfo from '../../../package.json';
|
import packageInfo from '../../../package.json';
|
||||||
@@ -216,6 +217,12 @@
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$effect(() => {
|
||||||
|
if ($sessionHydrated && !$clientSession && !isRootRoute) {
|
||||||
|
goto('/', { replaceState: true });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
onMount(() => {
|
onMount(() => {
|
||||||
syncViewport();
|
syncViewport();
|
||||||
|
|
||||||
@@ -254,6 +261,19 @@
|
|||||||
<title>{pageTitle(page.url.pathname)} | Hunter Premium Produce</title>
|
<title>{pageTitle(page.url.pathname)} | Hunter Premium Produce</title>
|
||||||
</svelte:head>
|
</svelte:head>
|
||||||
|
|
||||||
|
{#if !$clientSession}
|
||||||
|
<div class="signed-out-shell">
|
||||||
|
{#if isRootRoute}
|
||||||
|
{@render children()}
|
||||||
|
{:else}
|
||||||
|
<section class="locked-card loading-card signed-out-card">
|
||||||
|
<p class="workspace-label">Checking Session</p>
|
||||||
|
<h2>Returning to the client login screen.</h2>
|
||||||
|
<p>Only authenticated client users can open workspace routes directly.</p>
|
||||||
|
</section>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
{:else}
|
||||||
<div class="app-shell">
|
<div class="app-shell">
|
||||||
{#if showBottomNav && navOpen}
|
{#if showBottomNav && navOpen}
|
||||||
<button aria-label="Close navigation" class="nav-backdrop" type="button" onclick={() => (navOpen = false)}></button>
|
<button aria-label="Close navigation" class="nav-backdrop" type="button" onclick={() => (navOpen = false)}></button>
|
||||||
@@ -263,8 +283,7 @@
|
|||||||
<aside class="sidebar">
|
<aside class="sidebar">
|
||||||
<div class="brand-row">
|
<div class="brand-row">
|
||||||
<a class="brand" href="/">
|
<a class="brand" href="/">
|
||||||
<span class="brand-mark">HP</span>
|
<Lean101Logo className="sidebar-logo" showTagline={false} />
|
||||||
<span>Hunter Premium Produce</span>
|
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -440,19 +459,12 @@
|
|||||||
</header>
|
</header>
|
||||||
|
|
||||||
<main class="content">
|
<main class="content">
|
||||||
{#if !isRootRoute && (!$sessionHydrated || isRestoringSession)}
|
{#if !isRootRoute && isRestoringSession}
|
||||||
<section class="locked-card loading-card">
|
<section class="locked-card loading-card">
|
||||||
<p class="workspace-label">Checking Session</p>
|
<p class="workspace-label">Checking Session</p>
|
||||||
<h2>Restoring your client workspace.</h2>
|
<h2>Restoring your client workspace.</h2>
|
||||||
<p>Refreshing the current page with the saved browser session before deciding whether sign-in is required.</p>
|
<p>Refreshing the current page with the saved browser session before deciding whether sign-in is required.</p>
|
||||||
</section>
|
</section>
|
||||||
{:else if !isRootRoute && !$clientSession}
|
|
||||||
<section class="locked-card">
|
|
||||||
<p class="workspace-label">Client Sign-In Required</p>
|
|
||||||
<h2>Sign in on the Hunter Premium Produce home page to unlock workspace data.</h2>
|
|
||||||
<p>The client-facing routes stay empty until a valid client session is active.</p>
|
|
||||||
<a href="/">Return to sign-in</a>
|
|
||||||
</section>
|
|
||||||
{:else}
|
{:else}
|
||||||
{@render children()}
|
{@render children()}
|
||||||
{/if}
|
{/if}
|
||||||
@@ -624,7 +636,9 @@
|
|||||||
{/if}
|
{/if}
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
{#if paletteOpen}
|
{/if}
|
||||||
|
|
||||||
|
{#if $clientSession && paletteOpen}
|
||||||
<div class="palette-overlay" role="presentation" onclick={() => (paletteOpen = false)}>
|
<div class="palette-overlay" role="presentation" onclick={() => (paletteOpen = false)}>
|
||||||
<div
|
<div
|
||||||
class="palette"
|
class="palette"
|
||||||
@@ -720,6 +734,15 @@
|
|||||||
min-height: 100vh;
|
min-height: 100vh;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.signed-out-shell {
|
||||||
|
min-height: 100vh;
|
||||||
|
padding: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.signed-out-card {
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
.nav-backdrop {
|
.nav-backdrop {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
@@ -753,14 +776,10 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.brand {
|
.brand {
|
||||||
display: inline-flex;
|
display: block;
|
||||||
align-items: center;
|
width: 100%;
|
||||||
gap: 0.68rem;
|
|
||||||
font-size: 1.08rem;
|
|
||||||
font-weight: 700;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.brand-mark,
|
|
||||||
.nav-icon {
|
.nav-icon {
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@@ -773,10 +792,16 @@
|
|||||||
letter-spacing: 0.04em;
|
letter-spacing: 0.04em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.brand-mark {
|
.sidebar :global(.sidebar-logo) {
|
||||||
width: 1.9rem;
|
width: min(100%, 12.2rem);
|
||||||
height: 1.9rem;
|
}
|
||||||
border-radius: 0.68rem;
|
|
||||||
|
.sidebar :global(.sidebar-logo .logo-copy strong) {
|
||||||
|
font-size: 1.6rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar :global(.sidebar-logo .logo-mark) {
|
||||||
|
width: 2.6rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.nav-toggle,
|
.nav-toggle,
|
||||||
|
|||||||
@@ -0,0 +1,73 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
let { className = '', showTagline = true } = $props<{
|
||||||
|
className?: string;
|
||||||
|
showTagline?: boolean;
|
||||||
|
}>();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class={`lean101-logo ${className}`.trim()}>
|
||||||
|
<span class="logo-mark" aria-hidden="true">
|
||||||
|
<svg viewBox="0 0 320 320" preserveAspectRatio="xMidYMid meet" role="img" focusable="false">
|
||||||
|
<path
|
||||||
|
d="M82 18c4 0 8 1 11 3l82 48c7 4 11 12 11 20v16c0 6-3 11-8 14-5 3-11 3-16 0l-35-21c-12-7-27-7-39 0l-8 5c-12 7-19 20-19 34v107c0 8-4 16-11 20l-2 1c-5 3-11 3-16 0-5-3-8-8-8-14V42c0-9 5-17 13-21l34-20c3-1 7-2 10-2Z"
|
||||||
|
fill="#1672c5"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M145 72c8-5 18-5 26 0l77 45c8 5 13 13 13 22v88c0 9-5 17-13 22l-77 45c-8 5-18 5-26 0l-77-45c-8-5-13-13-13-22v-88c0-9 5-17 13-22l77-45Zm4 29-49 29c-8 5-13 13-13 22v62c0 9 5 17 13 22l49 29c8 5 18 5 26 0l49-29c8-5 13-13 13-22v-62c0-9-5-17-13-22l-49-29c-8-5-18-5-26 0Z"
|
||||||
|
fill="#2e9df4"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M238 201c0-14-7-27-19-34l-8-5c-12-7-27-7-39 0l-35 21c-5 3-11 3-16 0-5-3-8-8-8-14v-16c0-8 4-16 11-20l82-48c3-2 7-3 11-3 3 0 7 1 10 2l34 20c8 4 13 12 13 21v209c0 6-3 11-8 14-5 3-11 3-16 0l-2-1c-7-4-11-12-11-20V201Z"
|
||||||
|
fill="#1672c5"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<span class="logo-copy">
|
||||||
|
<strong>LEAN 101</strong>
|
||||||
|
{#if showTagline}
|
||||||
|
<small>SMARTER IMPROVEMENT SOLUTIONS</small>
|
||||||
|
{/if}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.lean101-logo {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.7rem;
|
||||||
|
color: #0b76c8;
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo-mark {
|
||||||
|
width: 3rem;
|
||||||
|
flex-shrink: 0;
|
||||||
|
line-height: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo-mark svg {
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo-copy {
|
||||||
|
display: grid;
|
||||||
|
gap: 0.14rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo-copy strong {
|
||||||
|
color: #0b76c8;
|
||||||
|
font-size: 1.95rem;
|
||||||
|
font-weight: 800;
|
||||||
|
letter-spacing: 0.03em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo-copy small {
|
||||||
|
color: #6a7680;
|
||||||
|
font-size: 0.54rem;
|
||||||
|
font-weight: 700;
|
||||||
|
letter-spacing: 0.13em;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -1,7 +1,9 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { api } from '$lib/api';
|
import { api } from '$lib/api';
|
||||||
|
import Lean101Logo from '$lib/components/Lean101Logo.svelte';
|
||||||
import { clientSession, sessionHydrated } from '$lib/session';
|
import { clientSession, sessionHydrated } from '$lib/session';
|
||||||
import type { Mix, ProductCostBreakdown, RawMaterial } from '$lib/types';
|
import type { Mix, ProductCostBreakdown, RawMaterial } from '$lib/types';
|
||||||
|
import packageInfo from '../../package.json';
|
||||||
|
|
||||||
type Segment = {
|
type Segment = {
|
||||||
label: string;
|
label: string;
|
||||||
@@ -30,6 +32,8 @@
|
|||||||
let password = $state('changeme');
|
let password = $state('changeme');
|
||||||
let isLoggingIn = $state(false);
|
let isLoggingIn = $state(false);
|
||||||
let loginError = $state('');
|
let loginError = $state('');
|
||||||
|
const currentYear = new Date().getFullYear();
|
||||||
|
const appVersion = `v${packageInfo.version}`;
|
||||||
|
|
||||||
const monthLabels = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep'];
|
const monthLabels = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep'];
|
||||||
|
|
||||||
@@ -252,49 +256,94 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#if !$sessionHydrated}
|
{#if !$sessionHydrated}
|
||||||
<section class="dashboard-intro">
|
<section class="auth-stage auth-stage-loading">
|
||||||
<div>
|
<div class="auth-card auth-card-loading">
|
||||||
<p class="eyebrow">Client Workspace</p>
|
<div class="auth-header">
|
||||||
<h2>Restoring your workspace.</h2>
|
<div class="client-logo-block">
|
||||||
<p>Checking the saved client session before deciding whether sign-in is required.</p>
|
<Lean101Logo className="hero-logo" />
|
||||||
</div>
|
<div class="client-logo-copy">
|
||||||
</section>
|
<p class="eyebrow">Client Workspace</p>
|
||||||
|
<strong>Hunter Premium Produce</strong>
|
||||||
|
<span>Lean 101 client workspace access</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<section class="workspace-banner login-banner loading-banner">
|
<div class="auth-copy">
|
||||||
<div>
|
<h2>Restoring your workspace.</h2>
|
||||||
<p class="eyebrow">Checking Session</p>
|
<p>Checking the saved client session before deciding whether sign-in is required.</p>
|
||||||
<h3>Hold while the app restores your client access state.</h3>
|
</div>
|
||||||
<p>The sign-in form only appears if no valid local session is available.</p>
|
|
||||||
|
<div class="auth-loading-panel">
|
||||||
|
<span class="loading-pulse" aria-hidden="true"></span>
|
||||||
|
<div>
|
||||||
|
<strong>Checking Session</strong>
|
||||||
|
<p>The sign-in form appears only when no valid local client session is available.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="auth-footer">
|
||||||
|
<div class="lean-brand">
|
||||||
|
<Lean101Logo className="footer-logo" showTagline={false} />
|
||||||
|
</div>
|
||||||
|
<div class="auth-meta">
|
||||||
|
<span>{appVersion}</span>
|
||||||
|
<span>© {currentYear} Hunter Premium Produce</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
{:else if !$clientSession}
|
{:else if !$clientSession}
|
||||||
<section class="dashboard-intro">
|
<section class="auth-stage">
|
||||||
<div>
|
<div class="auth-card auth-card-login">
|
||||||
<!-- <p class="eyebrow">Client Workspace</p>-->
|
<div class="auth-header">
|
||||||
<h2>Welcome to the Hunter Premium Produce App</h2>
|
<div class="client-logo-block">
|
||||||
<p>Sign in to load input pricing, Mix Master products, and Scenario Builder.</p>
|
<Lean101Logo className="hero-logo" />
|
||||||
|
<div class="client-logo-copy">
|
||||||
|
<p class="eyebrow">Client Sign-In</p>
|
||||||
|
<strong>Hunter Premium Produce</strong>
|
||||||
|
<span>Lean 101 client workspace access</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<span class="auth-status-pill">Secure Workspace Access</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="auth-copy">
|
||||||
|
<h2>Welcome back.</h2>
|
||||||
|
<p>Sign in to load input pricing, Mix Master products, delivered product costing, and Scenario Builder.</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<form class="signin-form auth-form" onsubmit={handleLogin}>
|
||||||
|
<label class="field">
|
||||||
|
<span>Email</span>
|
||||||
|
<input bind:value={email} type="email" autocomplete="username" placeholder="Email" />
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<label class="field">
|
||||||
|
<span>Password</span>
|
||||||
|
<input bind:value={password} type="password" autocomplete="current-password" placeholder="Password" />
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<button class="primary-button auth-submit" type="submit" disabled={isLoggingIn}>
|
||||||
|
{isLoggingIn ? 'Signing in...' : 'Sign In'}
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
{#if loginError}
|
||||||
|
<p class="login-error">{loginError}</p>
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
<div class="auth-footer">
|
||||||
|
<div class="lean-brand">
|
||||||
|
<Lean101Logo className="footer-logo" showTagline={false} />
|
||||||
|
</div>
|
||||||
|
<div class="auth-meta">
|
||||||
|
<span>{appVersion}</span>
|
||||||
|
<span>© {currentYear} Hunter Premium Produce</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section class="workspace-banner login-banner">
|
|
||||||
<div>
|
|
||||||
<p class="eyebrow">Client Sign-In</p>
|
|
||||||
<h3>Login to Hunter Premium Produce</h3>
|
|
||||||
<p>Enter your username & password to begin</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<form class="signin-form" onsubmit={handleLogin}>
|
|
||||||
<input bind:value={email} type="email" autocomplete="username" placeholder="Email" />
|
|
||||||
<input bind:value={password} type="password" autocomplete="current-password" placeholder="Password" />
|
|
||||||
<button class="primary-button" type="submit" disabled={isLoggingIn}>
|
|
||||||
{isLoggingIn ? 'Signing in...' : 'Sign In'}
|
|
||||||
</button>
|
|
||||||
</form>
|
|
||||||
|
|
||||||
{#if loginError}
|
|
||||||
<p class="login-error">{loginError}</p>
|
|
||||||
{/if}
|
|
||||||
</section>
|
|
||||||
{:else}
|
{:else}
|
||||||
<section class="dashboard-intro">
|
<section class="dashboard-intro">
|
||||||
<div>
|
<div>
|
||||||
@@ -601,6 +650,263 @@
|
|||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.auth-stage {
|
||||||
|
min-height: calc(100vh - 3rem);
|
||||||
|
display: grid;
|
||||||
|
place-items: center;
|
||||||
|
padding: 1rem 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.auth-stage-loading {
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.auth-card {
|
||||||
|
position: relative;
|
||||||
|
width: min(100%, 38rem);
|
||||||
|
display: grid;
|
||||||
|
gap: 1.35rem;
|
||||||
|
padding: 1.5rem;
|
||||||
|
border: 1px solid rgba(212, 226, 218, 0.95);
|
||||||
|
border-radius: 1.7rem;
|
||||||
|
background:
|
||||||
|
radial-gradient(circle at top left, rgba(115, 197, 146, 0.16), transparent 32%),
|
||||||
|
radial-gradient(circle at bottom right, rgba(33, 94, 60, 0.1), transparent 30%),
|
||||||
|
rgba(255, 255, 255, 0.96);
|
||||||
|
box-shadow: 0 28px 70px rgba(17, 37, 25, 0.14);
|
||||||
|
backdrop-filter: blur(14px);
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.auth-card::before {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
inset: 0;
|
||||||
|
background:
|
||||||
|
linear-gradient(135deg, rgba(255, 255, 255, 0.42), transparent 35%),
|
||||||
|
linear-gradient(180deg, transparent, rgba(238, 248, 242, 0.55));
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.auth-card > * {
|
||||||
|
position: relative;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.auth-card-loading {
|
||||||
|
width: min(100%, 34rem);
|
||||||
|
}
|
||||||
|
|
||||||
|
.auth-card-login {
|
||||||
|
width: min(100%, 39rem);
|
||||||
|
}
|
||||||
|
|
||||||
|
.auth-header {
|
||||||
|
display: grid;
|
||||||
|
justify-items: center;
|
||||||
|
gap: 1rem;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.client-logo-block {
|
||||||
|
display: grid;
|
||||||
|
justify-items: center;
|
||||||
|
gap: 1rem;
|
||||||
|
width: 100%;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.client-logo-copy {
|
||||||
|
display: grid;
|
||||||
|
gap: 0.28rem;
|
||||||
|
min-width: 0;
|
||||||
|
justify-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.client-logo-copy .eyebrow {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.client-logo-copy strong {
|
||||||
|
font-size: 1.18rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.client-logo-copy span {
|
||||||
|
color: var(--muted);
|
||||||
|
font-size: 0.88rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
:global(.hero-logo) {
|
||||||
|
width: min(100%, 19rem);
|
||||||
|
}
|
||||||
|
|
||||||
|
:global(.hero-logo .logo-mark) {
|
||||||
|
width: 4.8rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
:global(.hero-logo .logo-copy strong) {
|
||||||
|
font-size: clamp(2rem, 4.6vw, 3.2rem);
|
||||||
|
}
|
||||||
|
|
||||||
|
:global(.hero-logo .logo-copy small) {
|
||||||
|
font-size: 0.64rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.auth-status-pill {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
padding: 0.48rem 0.8rem;
|
||||||
|
border: 1px solid rgba(44, 123, 72, 0.12);
|
||||||
|
border-radius: 999px;
|
||||||
|
background: rgba(240, 249, 244, 0.96);
|
||||||
|
color: #1e6a3d;
|
||||||
|
font-size: 0.78rem;
|
||||||
|
font-weight: 700;
|
||||||
|
letter-spacing: 0.04em;
|
||||||
|
text-transform: uppercase;
|
||||||
|
justify-self: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.auth-copy {
|
||||||
|
display: grid;
|
||||||
|
gap: 0.55rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.auth-copy h2 {
|
||||||
|
font-size: clamp(2.1rem, 4vw, 2.8rem);
|
||||||
|
line-height: 1.02;
|
||||||
|
}
|
||||||
|
|
||||||
|
.auth-copy p {
|
||||||
|
max-width: 32rem;
|
||||||
|
color: var(--muted);
|
||||||
|
font-size: 1rem;
|
||||||
|
line-height: 1.6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.auth-loading-panel {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.95rem;
|
||||||
|
padding: 1rem 1.05rem;
|
||||||
|
border: 1px solid rgba(217, 228, 221, 0.92);
|
||||||
|
border-radius: 1.1rem;
|
||||||
|
background: rgba(248, 251, 249, 0.92);
|
||||||
|
}
|
||||||
|
|
||||||
|
.auth-loading-panel strong,
|
||||||
|
.auth-loading-panel p {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.auth-loading-panel p {
|
||||||
|
margin-top: 0.18rem;
|
||||||
|
color: var(--muted);
|
||||||
|
}
|
||||||
|
|
||||||
|
.loading-pulse {
|
||||||
|
width: 0.95rem;
|
||||||
|
height: 0.95rem;
|
||||||
|
flex-shrink: 0;
|
||||||
|
border-radius: 999px;
|
||||||
|
background: linear-gradient(135deg, #2f7b48 0%, #174b2d 100%);
|
||||||
|
box-shadow: 0 0 0 0 rgba(47, 123, 72, 0.28);
|
||||||
|
animation: pulse 1.8s ease-out infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
.auth-form {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
gap: 0.9rem;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.field {
|
||||||
|
display: grid;
|
||||||
|
gap: 0.4rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.field span {
|
||||||
|
font-size: 0.84rem;
|
||||||
|
font-weight: 700;
|
||||||
|
color: #425248;
|
||||||
|
letter-spacing: 0.02em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.auth-form input {
|
||||||
|
padding: 1rem 1.05rem;
|
||||||
|
border: 1px solid #d6e3db;
|
||||||
|
border-radius: 1rem;
|
||||||
|
background: rgba(248, 251, 249, 0.94);
|
||||||
|
transition:
|
||||||
|
border-color 160ms ease,
|
||||||
|
box-shadow 160ms ease,
|
||||||
|
background-color 160ms ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.auth-form input:focus {
|
||||||
|
outline: none;
|
||||||
|
border-color: #4d9668;
|
||||||
|
box-shadow: 0 0 0 0.24rem rgba(77, 150, 104, 0.12);
|
||||||
|
background: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.auth-submit {
|
||||||
|
width: 100%;
|
||||||
|
min-height: 3.35rem;
|
||||||
|
margin-top: 0.2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.auth-footer {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: 1rem;
|
||||||
|
padding-top: 0.15rem;
|
||||||
|
border-top: 1px solid rgba(217, 228, 221, 0.88);
|
||||||
|
}
|
||||||
|
|
||||||
|
.lean-brand {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
:global(.footer-logo) {
|
||||||
|
width: 9.8rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
:global(.footer-logo .logo-mark) {
|
||||||
|
width: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
:global(.footer-logo .logo-copy strong) {
|
||||||
|
font-size: 1.15rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.auth-meta {
|
||||||
|
display: grid;
|
||||||
|
justify-items: end;
|
||||||
|
gap: 0.12rem;
|
||||||
|
color: var(--muted);
|
||||||
|
font-size: 0.82rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes pulse {
|
||||||
|
0% {
|
||||||
|
box-shadow: 0 0 0 0 rgba(47, 123, 72, 0.26);
|
||||||
|
transform: scale(0.96);
|
||||||
|
}
|
||||||
|
|
||||||
|
70% {
|
||||||
|
box-shadow: 0 0 0 0.7rem rgba(47, 123, 72, 0);
|
||||||
|
transform: scale(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
box-shadow: 0 0 0 0 rgba(47, 123, 72, 0);
|
||||||
|
transform: scale(0.96);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.dashboard-intro,
|
.dashboard-intro,
|
||||||
.workspace-banner,
|
.workspace-banner,
|
||||||
.dashboard-grid,
|
.dashboard-grid,
|
||||||
@@ -1375,6 +1681,30 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 860px) {
|
@media (max-width: 860px) {
|
||||||
|
.auth-stage {
|
||||||
|
min-height: auto;
|
||||||
|
padding: 0.4rem 0 0.8rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.auth-card {
|
||||||
|
padding: 1.15rem;
|
||||||
|
border-radius: 1.35rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.auth-header,
|
||||||
|
.auth-footer {
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: flex-start;
|
||||||
|
}
|
||||||
|
|
||||||
|
.auth-copy h2 {
|
||||||
|
font-size: 1.9rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.auth-meta {
|
||||||
|
justify-items: start;
|
||||||
|
}
|
||||||
|
|
||||||
.dashboard-intro,
|
.dashboard-intro,
|
||||||
.intro-actions,
|
.intro-actions,
|
||||||
.workspace-banner,
|
.workspace-banner,
|
||||||
|
|||||||
Binary file not shown.
|
After Width: | Height: | Size: 15 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 17 KiB |
Reference in New Issue
Block a user