Feat: Deploy de Implementações/Ajustes

This commit is contained in:
Eduardo 2026-03-02 17:24:31 -03:00
parent 59c2cb828e
commit 851f8d6fc2
12 changed files with 466 additions and 92 deletions

BIN
public/linegestao-logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 154 KiB

After

Width:  |  Height:  |  Size: 152 KiB

View File

@ -9,16 +9,24 @@
</button>
<a routerLink="/dashboard" class="logo-area" (click)="closeMenu()">
<div class="logo-icon">
<i class="bi bi-layers-fill"></i>
</div>
<div class="logo-text">
Line<span class="highlight">Gestão</span>
<img src="linegestao-logo.png" alt="Line Gestão" class="logo-symbol" />
<div class="lg-wordmark" [attr.aria-label]="headerLogoAriaLabel">
<div class="lg-wordmark__line">Line</div>
<div class="lg-wordmark__movel">{{ headerLogoSubtitle }}</div>
</div>
</a>
</div>
<div class="logged-actions">
<div class="client-header-context" *ngIf="isClientHeader">
<div class="client-chip" [title]="clientTenantDisplayName || 'Cliente'">
<span class="client-chip__icon" aria-hidden="true">
<i class="bi bi-building"></i>
</span>
<span class="client-chip__name">{{ clientTenantDisplayNameAbbrev }}</span>
</div>
</div>
<div class="notifications-menu" [class.open]="notificationsOpen" (click)="$event.stopPropagation()">
<button
type="button"
@ -184,7 +192,7 @@
<button type="button" class="options-item" (click)="goToProfile()">
<i class="bi bi-person-circle"></i> Perfil
</button>
<div class="divider"></div>
<div class="divider" *ngIf="isSysAdmin"></div>
<button type="button" class="options-item" *ngIf="isSysAdmin" (click)="openCreateUserModal()">
<i class="bi bi-person-plus"></i> Criar novo usuário
</button>
@ -209,8 +217,11 @@
<ng-template #publicHeader>
<a routerLink="/" class="logo-area">
<div class="logo-icon"><i class="bi bi-layers-fill"></i></div>
<div class="logo-text">Line<span class="highlight">Gestão</span></div>
<img src="linegestao-logo.png" alt="Line Gestão" class="logo-symbol" />
<div class="lg-wordmark" aria-label="Line Gestão">
<div class="lg-wordmark__line">Line</div>
<div class="lg-wordmark__movel">Gestão</div>
</div>
</a>
<nav class="nav-links">
<a href="https://www.linemovel.com.br/empresas" target="_blank" class="nav-link">Para Empresas</a>
@ -507,8 +518,11 @@
<aside *ngIf="isLoggedHeader" class="side-menu" [class.open]="menuOpen" (click)="$event.stopPropagation()">
<div class="side-menu-header">
<a class="side-logo" routerLink="/dashboard" (click)="closeMenu()">
<span class="side-logo-icon"><i class="bi bi-layers-fill"></i></span>
<span class="side-logo-text">Line<span class="highlight">Gestão</span></span>
<img src="linegestao-logo.png" alt="Line Gestão" class="side-logo-symbol" />
<div class="side-wordmark" aria-label="Line Gestão">
<div class="side-wordmark__line">Line</div>
<div class="side-wordmark__movel">Gestão</div>
</div>
</a>
<button type="button" class="close-btn" (click)="closeMenu()"><i class="bi bi-x-lg"></i></button>
</div>
@ -546,8 +560,5 @@
<a *ngIf="canViewAll" routerLink="/trocanumero" routerLinkActive="active" class="side-item" (click)="closeMenu()">
<i class="bi bi-arrow-left-right"></i> <span>Troca de número</span>
</a>
<a *ngIf="isSysAdmin" routerLink="/system/fornecer-usuario" routerLinkActive="active" class="side-item" (click)="closeMenu()">
<i class="bi bi-shield-lock-fill"></i> <span>Criar credenciais do cliente</span>
</a>
</div>
</aside>

View File

@ -10,6 +10,9 @@ $text-main: #111827;
$text-muted: #6b7280;
$bg-light: #f9fafb;
$border-color: #e5e7eb;
$logo-primary-blue-light: #004dcc;
$logo-primary-purple-dark: #6a0dad;
$logo-secondary-grey: #757575;
/* Utils */
* { box-sizing: border-box; }
@ -39,15 +42,68 @@ $border-color: #e5e7eb;
}
.logo-area {
display: flex; align-items: center; gap: 10px; text-decoration: none; color: #111827;
.logo-icon {
width: 36px; height: 36px; background: conic-gradient(from 210deg, #2f6bff, #7c3aed, #ec4899, #f59e0b, #22c55e, #2f6bff);
color: #fff; border-radius: 50%; display: grid; place-items: center; font-size: 18px; box-shadow: 0 6px 14px rgba(47, 107, 255, 0.2);
display: flex; align-items: center; gap: 14px; text-decoration: none; color: #111827; min-width: 0;
}
.logo-text {
font-size: 19px; font-weight: 700; letter-spacing: -0.5px;
.highlight { background: linear-gradient(90deg, #2f6bff 0%, #7c3aed 55%, #ec4899 100%); -webkit-background-clip: text; background-clip: text; color: transparent; }
.logo-symbol {
width: 48px;
height: 48px;
object-fit: contain;
flex: 0 0 auto;
filter: drop-shadow(0 8px 14px rgba(106, 13, 173, 0.2));
}
.lg-wordmark {
display: inline-flex;
flex-direction: column;
line-height: 0.92;
user-select: none;
-webkit-font-smoothing: antialiased;
text-rendering: geometricPrecision;
min-width: 0;
--scale: 0.34;
}
.lg-wordmark__line {
font-family: 'Poppins', 'Nunito', system-ui, -apple-system, Segoe UI, Roboto, Arial, sans-serif;
font-weight: 800;
font-size: calc(96px * var(--scale));
letter-spacing: -0.02em;
white-space: nowrap;
background: linear-gradient(
180deg,
#c8c3ff 0%,
#7a6cff 26%,
#4b3fe6 52%,
#2b21c8 74%,
#120a78 100%
);
-webkit-background-clip: text;
background-clip: text;
color: transparent;
-webkit-text-stroke: 0;
text-shadow: 0 1px 1px rgba(15, 23, 42, 0.12);
}
.lg-wordmark__movel {
font-family: 'Poppins', 'Nunito', system-ui, -apple-system, Segoe UI, Roboto, Arial, sans-serif;
font-weight: 700;
font-size: calc(34px * var(--scale));
letter-spacing: -0.01em;
white-space: nowrap;
margin-left: calc(0.33em * var(--scale));
margin-top: calc(-6px * var(--scale));
background: linear-gradient(
180deg,
#6f7f96 0%,
#4b5b72 48%,
#2f3d52 100%
);
-webkit-background-clip: text;
background-clip: text;
color: transparent;
-webkit-text-stroke: 0;
text-shadow: 0 1px 1px rgba(15, 23, 42, 0.12);
}
.nav-links { display: flex; align-items: center; justify-content: center; gap: 22px; flex: 1; }
@ -66,6 +122,58 @@ $border-color: #e5e7eb;
@media (max-width: 900px) { .nav-links { display: none; } }
.logged-actions { display: flex; align-items: center; gap: 12px; margin-left: auto; }
.client-header-context {
display: flex;
align-items: center;
justify-content: center;
min-width: 0;
max-width: min(390px, 38vw);
padding-right: 2px;
}
.client-chip {
display: flex;
align-items: center;
gap: 10px;
min-width: 0;
max-width: 100%;
padding: 6px 12px 6px 8px;
border-radius: 999px;
border: 1px solid rgba(28, 56, 201, 0.2);
background: linear-gradient(135deg, #ffffff 0%, #f5f8ff 55%, #eef2ff 100%);
box-shadow: 0 8px 20px rgba(17, 24, 39, 0.08);
transition: box-shadow 0.2s ease, transform 0.2s ease;
}
.client-chip:hover {
transform: translateY(-1px);
box-shadow: 0 10px 22px rgba(17, 24, 39, 0.1);
}
.client-chip__icon {
width: 28px;
height: 28px;
min-width: 28px;
border-radius: 999px;
display: grid;
place-items: center;
color: #fff;
background: linear-gradient(135deg, #2653d9 0%, #6a0dad 100%);
box-shadow: 0 4px 10px rgba(38, 83, 217, 0.28);
font-size: 12px;
}
.client-chip__name {
font-size: 14px;
font-weight: 800;
color: #0f172a;
line-height: 1.15;
max-width: min(290px, 27vw);
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
@media (min-width: 1200px) {
.header-inner.container {
max-width: none;
@ -637,7 +745,7 @@ $border-color: #e5e7eb;
/* SIDE MENU */
.menu-overlay { position: fixed; inset: 0; background: rgba(0,0,0,0.5); z-index: 1050; }
.side-menu {
position: fixed; top: 0; left: 0; height: 100vh; width: 260px; background: #fff; box-shadow: 4px 0 20px rgba(0,0,0,0.1); transform: translateX(-100%); transition: transform 0.3s cubic-bezier(0.16, 1, 0.3, 1); z-index: 1100; display: flex; flex-direction: column;
position: fixed; top: 0; left: 0; height: 100vh; width: 280px; background: #fff; box-shadow: 4px 0 20px rgba(0,0,0,0.1); transform: translateX(-100%); transition: transform 0.3s cubic-bezier(0.16, 1, 0.3, 1); z-index: 1100; display: flex; flex-direction: column;
&.open { transform: translateX(0); }
}
.side-menu-header { padding: 20px; display: flex; justify-content: space-between; align-items: center; border-bottom: 1px solid $border-color; }
@ -655,7 +763,74 @@ $border-color: #e5e7eb;
transition: color 0.2s ease;
&:hover { color: $primary; }
}
.side-logo { display: flex; align-items: center; gap: 10px; text-decoration: none; color: $text-main; font-weight: 700; .side-logo-icon { width: 32px; height: 32px; background: $primary; color: #fff; border-radius: 50%; display: grid; place-items: center; } }
.side-logo {
display: flex;
align-items: center;
gap: 12px;
text-decoration: none;
color: $text-main;
min-width: 0;
}
.side-logo-symbol {
width: 42px;
height: 42px;
object-fit: contain;
flex: 0 0 auto;
filter: drop-shadow(0 4px 9px rgba(106, 13, 173, 0.2));
}
.side-wordmark {
display: inline-flex;
flex-direction: row;
align-items: baseline;
gap: 6px;
line-height: 1;
min-width: 0;
--scale: 0.23;
}
.side-wordmark__line {
font-family: 'Poppins', 'Nunito', system-ui, -apple-system, Segoe UI, Roboto, Arial, sans-serif;
font-weight: 800;
font-size: calc(92px * var(--scale));
letter-spacing: -0.02em;
white-space: nowrap;
background: linear-gradient(
180deg,
#c8c3ff 0%,
#7a6cff 26%,
#4b3fe6 52%,
#2b21c8 74%,
#120a78 100%
);
-webkit-background-clip: text;
background-clip: text;
color: transparent;
line-height: 1;
}
.side-wordmark__movel {
font-family: 'Poppins', 'Nunito', system-ui, -apple-system, Segoe UI, Roboto, Arial, sans-serif;
font-weight: 800;
font-size: calc(92px * var(--scale));
letter-spacing: -0.012em;
white-space: nowrap;
margin-left: 0;
margin-top: 0;
background: linear-gradient(
180deg,
#aeb8c7 0%,
#6b778d 50%,
#3f4b60 100%
);
-webkit-background-clip: text;
background-clip: text;
color: transparent;
line-height: 1;
position: relative;
top: 0;
}
.side-menu-body { padding: 16px; display: flex; flex-direction: column; gap: 4px; }
.side-item {
padding: 10px 12px; border-radius: 8px; color: $text-main; text-decoration: none; font-size: 14px; font-weight: 500; display: flex; align-items: center; gap: 10px;
@ -686,17 +861,46 @@ $border-color: #e5e7eb;
.logo-area {
min-width: 0;
.logo-text {
font-size: 16px;
white-space: nowrap;
}
.lg-wordmark {
--scale: 0.29;
}
.logo-symbol {
width: 42px;
height: 42px;
}
.logged-actions {
gap: 8px;
}
.client-header-context {
max-width: min(310px, 34vw);
}
.client-chip {
gap: 8px;
padding: 5px 10px 5px 6px;
}
.client-chip__icon {
width: 24px;
height: 24px;
min-width: 24px;
font-size: 11px;
}
.client-chip__name {
font-size: 13px;
max-width: min(240px, 24vw);
}
.side-wordmark {
--scale: 0.21;
}
.notifications-dropdown {
right: 0;
width: min(360px, calc(100vw - 24px));
@ -769,17 +973,15 @@ $border-color: #e5e7eb;
.logo-area {
gap: 8px;
min-width: 0;
.logo-icon {
width: 32px;
height: 32px;
font-size: 16px;
}
.logo-text {
font-size: 14px;
line-height: 1;
.logo-symbol {
width: 36px;
height: 36px;
}
.lg-wordmark {
--scale: 0.22;
}
/* Header público (Home/Login/Register): mantém logo visível e CTA fixo à direita */
@ -788,13 +990,15 @@ $border-color: #e5e7eb;
min-width: 0;
}
.header-inner > .logo-area .logo-text {
.header-inner > .logo-area .lg-wordmark {
display: block;
font-size: 14px;
line-height: 1;
white-space: nowrap;
}
.header-inner > .logo-area .lg-wordmark {
--scale: 0.2;
}
.header-inner > .header-actions {
margin-left: auto;
flex: 0 0 auto;
@ -808,8 +1012,12 @@ $border-color: #e5e7eb;
}
/* Header logado: mantém nome visível, porém menor para smartphone */
.left-logged .logo-area .logo-text {
font-size: 13px;
.left-logged .logo-area .lg-wordmark {
--scale: 0.2;
}
.client-header-context {
display: none;
}
.logged-actions {
@ -1112,16 +1320,13 @@ $border-color: #e5e7eb;
gap: 6px;
}
.header-inner > .logo-area .logo-icon {
width: 30px;
height: 30px;
font-size: 15px;
.header-inner > .logo-area .logo-symbol {
width: 32px;
height: 32px;
}
.header-inner > .logo-area .logo-text {
display: block;
font-size: 13px;
letter-spacing: -0.25px;
.header-inner > .logo-area .lg-wordmark {
--scale: 0.18;
}
.header-inner > .header-actions .btn-login-header {
@ -1134,10 +1339,8 @@ $border-color: #e5e7eb;
gap: 6px;
}
.left-logged .logo-area .logo-text {
display: block;
font-size: 12px;
letter-spacing: -0.2px;
.left-logged .logo-area .lg-wordmark {
--scale: 0.175;
}
.logged-actions {

View File

@ -2,6 +2,7 @@ import { Component, HostListener, Inject, ElementRef, ViewChild, AfterViewInit,
import { RouterLink, Router, NavigationEnd } from '@angular/router';
import { CommonModule, isPlatformBrowser } from '@angular/common';
import { PLATFORM_ID } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { filter } from 'rxjs/operators';
import { AuthService } from '../../services/auth.service';
import { NotificationsService, NotificationDto } from '../../services/notifications.service';
@ -10,6 +11,7 @@ import { FormBuilder, FormGroup, ReactiveFormsModule, Validators, AbstractContro
import { HttpErrorResponse } from '@angular/common/http';
import { CustomSelectComponent } from '../custom-select/custom-select';
import { Subscription } from 'rxjs';
import { environment } from '../../../environments/environment';
import { confirmActionModal, confirmDeletionWithTyping, showDeletionWarning } from '../../utils/destructive-confirmation';
@Component({
@ -33,6 +35,9 @@ export class Header implements AfterViewInit, OnDestroy {
isHome = false;
isSysAdmin = false;
canViewAll = false;
clientTenantDisplayName = '';
private clientTenantNameTenantId: string | null = null;
private readonly baseApi: string;
notifications: NotificationDto[] = [];
notificationsLoading = false;
notificationsError = false;
@ -97,10 +102,14 @@ export class Header implements AfterViewInit, OnDestroy {
private authService: AuthService,
private notificationsService: NotificationsService,
private usersService: UsersService,
private http: HttpClient,
private fb: FormBuilder,
private hostElement: ElementRef<HTMLElement>,
@Inject(PLATFORM_ID) private platformId: object
) {
const raw = (environment.apiUrl || '').replace(/\/+$/, '');
this.baseApi = raw.toLowerCase().endsWith('/api') ? raw : `${raw}/api`;
this.createUserForm = this.fb.group(
{
nome: ['', [Validators.required, Validators.minLength(2)]],
@ -205,12 +214,22 @@ export class Header implements AfterViewInit, OnDestroy {
if (!isPlatformBrowser(this.platformId)) {
this.isSysAdmin = false;
this.canViewAll = false;
this.clientTenantDisplayName = '';
this.clientTenantNameTenantId = null;
return;
}
const isSysAdmin = this.authService.hasRole('sysadmin');
const isGestor = this.authService.hasRole('gestor');
this.isSysAdmin = isSysAdmin;
this.canViewAll = isSysAdmin || isGestor;
if (!this.isClientHeader) {
this.clientTenantDisplayName = '';
this.clientTenantNameTenantId = null;
return;
}
this.ensureClientTenantName();
}
toggleMenu() {
@ -435,6 +454,22 @@ export class Header implements AfterViewInit, OnDestroy {
return this.notifications.filter(n => !n.lida).length;
}
get isClientHeader(): boolean {
return this.isLoggedHeader && !this.canViewAll;
}
get headerLogoSubtitle(): string {
return this.isClientHeader ? 'Gestão Empresas' : 'Gestão';
}
get headerLogoAriaLabel(): string {
return `Line ${this.headerLogoSubtitle}`;
}
get clientTenantDisplayNameAbbrev(): string {
return this.abbreviateClientTenantName(this.clientTenantDisplayName);
}
get notificationsVisible() {
return this.notificationsView === 'lidas'
? this.notifications.filter(n => n.lida)
@ -1130,4 +1165,66 @@ export class Header implements AfterViewInit, OnDestroy {
private getHeaderElement(): HTMLElement | null {
return this.hostElement.nativeElement.querySelector('.app-header');
}
private ensureClientTenantName() {
const profile = this.authService.currentUserProfile;
const tenantId = String(profile?.tenantId || '').trim();
if (!tenantId) {
this.clientTenantDisplayName = '';
this.clientTenantNameTenantId = null;
return;
}
if (this.clientTenantNameTenantId === tenantId && this.clientTenantDisplayName) {
return;
}
this.clientTenantNameTenantId = tenantId;
this.clientTenantDisplayName = '';
this.http.get<string[]>(`${this.baseApi}/lines/clients`).subscribe({
next: (clients) => {
const list = (clients || [])
.map((x) => String(x ?? '').trim())
.filter((x) => !!x && x.localeCompare('RESERVA', 'pt-BR', { sensitivity: 'base' }) !== 0);
this.clientTenantDisplayName = list[0] || this.resolveFallbackClientTenantName();
},
error: () => {
this.clientTenantDisplayName = this.resolveFallbackClientTenantName();
},
});
}
private resolveFallbackClientTenantName(): string {
const profileName = String(this.authService.currentUserProfile?.nome || '').trim();
if (profileName) return profileName;
return 'Cliente';
}
private abbreviateClientTenantName(value: string): string {
const name = (value || '').trim();
if (!name) return 'Cliente';
const maxLen = 30;
if (name.length <= maxLen) return name;
const parts = name.split(/\s+/).filter(Boolean);
if (parts.length === 1) {
return `${parts[0].slice(0, maxLen - 1)}`;
}
const first = parts[0];
const last = parts[parts.length - 1];
let candidate = `${first} ${last}`;
if (candidate.length <= maxLen) return candidate;
const shortFirst = `${first.slice(0, Math.max(3, maxLen - (last.length + 3)))}.`;
candidate = `${shortFirst} ${last}`;
if (candidate.length <= maxLen) return candidate;
return `${name.slice(0, maxLen - 1)}`;
}
}

View File

@ -354,15 +354,6 @@
<span class="lbl">Ativas</span>
<span class="val">{{ statusResumo.ativos | number:'1.0-0' }}</span>
</div>
<div class="status-item">
<span class="dot d-blocked-soft"></span>
<span class="lbl">Demais Linhas</span>
<span class="val">{{ clientDemaisLinhas | number:'1.0-0' }}</span>
</div>
<div class="status-item total-row">
<span class="lbl">Total</span>
<span class="val">{{ statusResumo.total | number:'1.0-0' }}</span>
</div>
</div>
</div>
</div>

View File

@ -206,11 +206,11 @@
}
.hero-label {
font-size: 12px;
font-size: 11px;
font-weight: 700;
text-transform: uppercase;
color: var(--text-muted);
letter-spacing: 0.03em;
letter-spacing: 0.02em;
}
.hero-value {

View File

@ -1250,13 +1250,6 @@ export class Dashboard implements OnInit, AfterViewInit, OnDestroy {
if (this.isCliente) {
const overview = this.clientOverview;
const cards: KpiCard[] = [
{
key: 'linhas_total',
title: 'Total de Linhas',
value: this.formatInt(overview.totalLinhas),
icon: 'bi bi-sim-fill',
hint: 'Base do cliente',
},
{
key: 'linhas_ativas',
title: 'Linhas Ativas',
@ -1432,10 +1425,10 @@ export class Dashboard implements OnInit, AfterViewInit, OnDestroy {
// 1. Status Pie
if (this.chartStatusPie?.nativeElement) {
const chartLabels = this.isCliente
? ['Ativas', 'Demais linhas']
? ['Ativas']
: ['Ativos', 'Perda/Roubo', 'Bloq 120d', 'Reservas', 'Outros'];
const chartData = this.isCliente
? [this.statusResumo.ativos, this.clientDemaisLinhas]
? [this.statusResumo.ativos]
: [
this.statusResumo.ativos,
this.statusResumo.perdaRoubo,
@ -1444,7 +1437,7 @@ export class Dashboard implements OnInit, AfterViewInit, OnDestroy {
this.statusResumo.outras,
];
const chartColors = this.isCliente
? [palette.status.ativos, '#cbd5e1']
? [palette.status.ativos]
: [
palette.status.ativos,
palette.status.blocked,
@ -1870,10 +1863,6 @@ export class Dashboard implements OnInit, AfterViewInit, OnDestroy {
return Number.isNaN(n) ? null : n;
}
get clientDemaisLinhas(): number {
return Math.max(0, (this.statusResumo.total ?? 0) - (this.statusResumo.ativos ?? 0));
}
trackByKpiKey = (_: number, item: KpiCard) => item.key;
private getPalette() {

View File

@ -1704,7 +1704,7 @@
<span class="lbl">Linha</span>
<span class="val text-blue fs-4">{{ detailData.linha || '-' }}</span>
</div>
<div class="info-item span-2">
<div class="info-item span-2" *ngIf="!isClientRestricted">
<span class="lbl">Cliente</span>
<span class="val text-dark" [title]="detailData.cliente">{{ detailData.cliente || '-' }}</span>
</div>
@ -1712,6 +1712,10 @@
<span class="lbl">Usuário</span>
<span class="val">{{ detailData.usuario || '-' }}</span>
</div>
<div class="info-item span-2" *ngIf="isClientRestricted">
<span class="lbl">Centro de Custos</span>
<span class="val text-dark">&nbsp;</span>
</div>
<div class="info-item">
<span class="lbl">Item</span>
<span class="val">{{ detailData.item }}</span>
@ -1724,6 +1728,10 @@
<span class="lbl">Tipo de Chip</span>
<span class="val">{{ detailData.tipoDeChip || '-' }}</span>
</div>
<div class="info-item" *ngIf="isClientRestricted">
<span class="lbl">Franquia Line</span>
<span class="val">{{ formatFranquia(detailData.franquiaLine) }}</span>
</div>
</div>
</div>
</div>

View File

@ -4,9 +4,12 @@
<div class="left-content fade-in-up">
<div class="brand-header mb-4">
<div class="brand-logo">
<i class="bi bi-layers-fill"></i>
<span>LineGestão</span>
<div class="brand-logo" aria-label="Line Gestão">
<img src="linegestao-logo.png" alt="Line Gestão" class="login-logo-symbol" />
<div class="login-wordmark">
<div class="login-wordmark__line">Line</div>
<div class="login-wordmark__movel">Gestão</div>
</div>
</div>
</div>

View File

@ -62,14 +62,86 @@
margin-bottom: 32px;
.brand-logo {
display: flex;
display: inline-flex;
align-items: center;
gap: 10px;
font-size: 20px;
font-weight: 700;
color: var(--text-main);
gap: 12px;
min-width: 0;
}
i { color: var(--brand-blue); font-size: 24px; }
.login-logo-symbol {
width: 54px;
height: 54px;
object-fit: contain;
flex: 0 0 auto;
filter: drop-shadow(0 8px 14px rgba(106, 13, 173, 0.2));
}
.login-wordmark {
display: inline-flex;
flex-direction: column;
line-height: 0.92;
min-width: 0;
--scale: 0.31;
}
.login-wordmark__line {
font-family: "Poppins", "Nunito", system-ui, -apple-system, Segoe UI, Roboto, Arial, sans-serif;
font-weight: 800;
font-size: calc(96px * var(--scale));
letter-spacing: -0.02em;
white-space: nowrap;
background: linear-gradient(
180deg,
#c8c3ff 0%,
#7a6cff 26%,
#4b3fe6 52%,
#2b21c8 74%,
#120a78 100%
);
-webkit-background-clip: text;
background-clip: text;
color: transparent;
}
.login-wordmark__movel {
font-family: "Poppins", "Nunito", system-ui, -apple-system, Segoe UI, Roboto, Arial, sans-serif;
font-weight: 700;
font-size: calc(34px * var(--scale));
letter-spacing: -0.01em;
white-space: nowrap;
margin-left: calc(0.33em * var(--scale));
margin-top: calc(-6px * var(--scale));
background: linear-gradient(
180deg,
#aeb8c7 0%,
#6b778d 50%,
#3f4b60 100%
);
-webkit-background-clip: text;
background-clip: text;
color: transparent;
}
@media (max-width: 1366px) {
.login-logo-symbol {
width: 48px;
height: 48px;
}
.login-wordmark {
--scale: 0.27;
}
}
@media (max-width: 576px) {
.login-logo-symbol {
width: 44px;
height: 44px;
}
.login-wordmark {
--scale: 0.24;
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB