Files
fitme3070.pt/assets/css/backoffice.css
T

352 lines
13 KiB
CSS

/* Backoffice FitMe 3070: tokens da marca, casca (barra lateral, topbar, gaveta
em telemóvel) e acertos dos componentes. Carregado por includes/header.php
depois do Bootstrap. O Bootstrap nunca se edita: o que muda faz-se com
variáveis e com classes próprias (prefixo bo-). */
:root {
--bo-accent: #C2D500;
--bo-accent-rgb: 194,213,0;
--bo-dark: #0a0a0a;
--bo-dark-2: #151515;
--bo-surface: #eef0f4;
--bo-sidebar-w: 264px;
--bo-sidebar-w-mini: 80px;
--bo-topbar-h: 56px;
--bo-ease: .2s ease;
/* Texto da barra lateral (escura nos dois temas) */
--bo-nav-text: rgba(255,255,255,.62);
--bo-nav-text-muted: rgba(255,255,255,.5);
--bo-nav-line: rgba(255,255,255,.1);
--bo-nav-strong: #fff;
}
[data-bs-theme="dark"] { --bo-surface: #121416; }
body { background: var(--bo-surface); font-size: .925rem; }
a { color: var(--bs-emphasis-color); }
main { margin-left: var(--bo-sidebar-w); padding-top: calc(var(--bo-topbar-h) + 12px); }
/* ── Barra lateral ───────────────────────────────────────────────────────── */
/* Sem overflow aqui: o menu do utilizador sai da barra no modo mini.
Quem rola é só .bo-sidebar__nav; cabeçalho e utilizador ficam fixos. */
.sidebar {
position: fixed;
inset: 0 auto 0 0;
z-index: 100;
width: var(--bo-sidebar-w);
display: flex;
flex-direction: column;
background: var(--bo-dark);
}
/* Cabeçalho numa linha: [☰] [marca] [↗ site público] */
.bo-sidebar__head {
flex: none;
display: flex;
align-items: center;
gap: .5rem;
height: var(--bo-topbar-h);
padding: 0 .75rem;
border-bottom: 1px solid var(--bo-nav-line);
}
.bo-sidebar__toggle,
.bo-sidebar__site {
flex: none;
display: inline-flex;
align-items: center;
justify-content: center;
min-width: 40px;
min-height: 40px;
padding: 0;
border: 0;
border-radius: 8px;
background: transparent;
color: var(--bo-nav-text);
font-size: 1.25rem;
line-height: 1;
text-decoration: none;
transition: background var(--bo-ease), color var(--bo-ease);
}
.bo-sidebar__site { font-size: 1rem; }
.bo-sidebar__toggle:hover,
.bo-sidebar__site:hover { background: rgba(255,255,255,.08); color: var(--bo-nav-strong); }
.bo-sidebar__brand {
flex: 1;
min-width: 0;
color: var(--bo-nav-strong);
font-weight: 700;
font-size: 1.05rem;
letter-spacing: .5px;
text-decoration: none;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.bo-sidebar__brand i { color: var(--bo-accent); }
/* Utilizador logo abaixo do cabeçalho */
.bo-sidebar__user {
flex: none;
padding: .6rem .75rem;
border-bottom: 1px solid var(--bo-nav-line);
}
.bo-user-menu {
width: 100%;
display: flex;
align-items: center;
gap: .6rem;
padding: .35rem .45rem;
border: 1px solid var(--bo-nav-line);
border-radius: 8px;
background: transparent;
color: var(--bo-nav-strong);
text-align: left;
}
.bo-user-menu:hover,
.bo-user-menu.show { background: rgba(255,255,255,.08); color: var(--bo-nav-strong); }
.bo-user-menu::after { margin-left: auto; flex: none; }
.bo-user-menu__avatar {
flex: none;
width: 32px;
height: 32px;
display: inline-flex;
align-items: center;
justify-content: center;
border-radius: 50%;
background: var(--bo-accent);
color: var(--bo-dark);
font-size: .8rem;
font-weight: 700;
}
.bo-user-menu__text { min-width: 0; display: flex; flex-direction: column; align-items: flex-start; line-height: 1.25; }
.bo-user-menu__name { max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: .85rem; font-weight: 600; }
.bo-user-menu__text .badge { font-size: .62rem; font-weight: 600; }
.bo-sidebar__user .dropdown-menu { min-width: 14rem; z-index: 1110; }
/* Lista de navegação: a única parte que rola */
.bo-sidebar__nav {
flex: 1;
min-height: 0;
overflow-y: auto;
overscroll-behavior: contain;
padding: .5rem 0 1rem;
display: flex;
flex-direction: column;
gap: 2px;
}
.sidebar .bo-nav-item {
position: relative;
display: flex;
align-items: center;
gap: .6rem;
min-height: 40px;
padding: .5rem 1.25rem;
border-left: 3px solid transparent;
color: var(--bo-nav-text);
font-size: .875rem;
transition: background var(--bo-ease), color var(--bo-ease), border-color var(--bo-ease);
}
.sidebar .bo-nav-item i { flex: none; width: 1.25rem; text-align: center; font-size: 1.05rem; }
.sidebar .bo-nav-item:hover { color: var(--bo-nav-strong); background: rgba(255,255,255,.06); border-left-color: rgba(255,255,255,.2); }
.sidebar .bo-nav-item.active { color: var(--bo-nav-strong); background: rgba(var(--bo-accent-rgb),.12); border-left-color: var(--bo-accent); }
.sidebar .bo-nav-item.active i { color: var(--bo-accent); }
.sidebar .bo-nav-item--primary i { font-size: 1.25rem; }
/* Indentação = cadeia de dados: filhos de um grupo, e de um subgrupo. */
.sidebar .bo-nav-item--sub { padding-left: 2.3rem; font-size: .84rem; }
.sidebar .bo-nav-item--sub2 { padding-left: 3.2rem; font-size: .84rem; }
.bo-nav-item__label { min-width: 0; }
.sidebar .bo-nav-item:focus-visible,
.bo-nav-group__label:focus-visible,
.bo-sidebar__toggle:focus-visible,
.bo-sidebar__site:focus-visible,
.bo-user-menu:focus-visible,
.bo-sidebar__brand:focus-visible { outline: 2px solid var(--bo-accent); outline-offset: -2px; }
/* Grupos recolhíveis */
.bo-nav-group { margin-top: .25rem; }
.bo-nav-group__label {
display: flex;
align-items: center;
gap: .6rem;
width: 100%;
padding: .55rem 1.25rem;
border: 0;
background: transparent;
color: var(--bo-nav-text-muted);
font-family: inherit;
font-size: .68rem;
font-weight: 700;
letter-spacing: .14em;
text-align: left;
text-transform: uppercase;
cursor: pointer;
}
.bo-nav-group__label:hover { color: var(--bo-nav-strong); background: rgba(255,255,255,.04); }
.bo-nav-group__icon { flex: none; width: 1.25rem; text-align: center; font-size: 1.1rem; letter-spacing: 0; }
.bo-nav-group__text { flex: 1; min-width: 0; }
.bo-nav-group__chevron { font-size: .75rem; letter-spacing: 0; transition: rotate var(--bo-ease); }
.bo-nav-group__label[aria-expanded="false"] .bo-nav-group__chevron { rotate: -90deg; }
.bo-nav-group--sub > .bo-nav-group__label { padding-left: 1.9rem; }
/* Corpo recolhível: grelha 1fr -> 0fr anima a altura sem JavaScript a medir. */
.bo-nav-group__body {
display: grid;
grid-template-rows: 1fr;
transition: grid-template-rows var(--bo-ease), visibility var(--bo-ease);
}
.bo-nav-group__inner {
min-height: 0;
overflow: hidden;
display: flex;
flex-direction: column;
gap: 2px;
}
/* Fechado = classe (clique no grupo da página ativa) ou chave no atributo do
<html> posto pelo script do <head> antes da pintura. O grupo da página ativa
só fecha por clique (.is-closed), nunca pelo estado guardado. visibility
tira os links fechados da ordem de tabulação. Grupo novo = chave nova aqui. */
:is(.bo-nav-group.is-closed,
html[data-bo-groups~="gestao"] .bo-nav-group[data-group="gestao"]:not(.has-active),
html[data-bo-groups~="site"] .bo-nav-group[data-group="site"]:not(.has-active),
html[data-bo-groups~="horarios"] .bo-nav-group[data-group="horarios"]:not(.has-active),
html[data-bo-groups~="comercial"] .bo-nav-group[data-group="comercial"]:not(.has-active),
html[data-bo-groups~="legal"] .bo-nav-group[data-group="legal"]:not(.has-active),
html[data-bo-groups~="utilizadores"] .bo-nav-group[data-group="utilizadores"]:not(.has-active),
html[data-bo-groups~="sistema"] .bo-nav-group[data-group="sistema"]:not(.has-active)) > .bo-nav-group__body {
grid-template-rows: 0fr;
visibility: hidden;
}
/* Véu por trás da gaveta em telemóvel */
.sidebar-backdrop { display: none; position: fixed; inset: 0; z-index: 1090; background: rgba(0,0,0,.45); }
.sidebar-backdrop.show { display: block; }
/* ── Topbar ──────────────────────────────────────────────────────────────── */
.topbar {
position: fixed;
top: 0;
left: var(--bo-sidebar-w);
right: 0;
z-index: 99;
height: var(--bo-topbar-h);
padding: 0 1.5rem;
display: flex;
align-items: center;
gap: .5rem;
background: var(--bs-body-bg);
border-bottom: 1px solid var(--bs-border-color);
}
.bo-topbar__tools { display: flex; align-items: center; gap: .5rem; margin-left: auto; }
.menu-toggle {
display: none;
width: 44px;
height: 44px;
padding: 0;
border: 1px solid var(--bs-border-color);
border-radius: 8px;
background: var(--bs-body-bg);
color: var(--bs-body-color);
font-size: 1.35rem;
line-height: 1;
align-items: center;
justify-content: center;
}
.theme-toggle { min-width: 44px; min-height: 44px; }
/* ── Marca nos componentes ───────────────────────────────────────────────── */
.badge-role-sysadmin { background: var(--bo-accent); color: var(--bo-dark); }
.badge-role-admin { background: var(--bo-accent); color: var(--bo-dark); opacity: .85; }
.badge-role-staff { background: #6f42c1; }
.badge-role-client { background: #adb5bd; color: #212529; }
.btn-outline-primary { color: var(--bo-accent); border-color: var(--bo-accent); }
.btn-outline-primary:hover { background: var(--bo-accent); border-color: var(--bo-accent); color: var(--bo-dark); }
.btn-primary { background: var(--bo-accent); border-color: var(--bo-accent); color: var(--bo-dark); }
.btn-primary:hover { background: #a8ba00; border-color: #a8ba00; color: var(--bo-dark); }
.card { border: none; box-shadow: 0 1px 3px rgba(0,0,0,.04); }
[data-bs-theme="dark"] .table-light { --bs-table-bg: var(--bs-tertiary-bg); --bs-table-color: var(--bs-body-color); }
/* Summernote (WYSIWYG): alinhado com o aspeto do backoffice */
.note-editor.note-frame { border-color: #ced4da; border-radius: .375rem; }
.note-editor .note-editing-area .note-editable { font-size: .95rem; }
.note-editor.note-frame.note-focused { border-color: var(--bo-accent); box-shadow: 0 0 0 .2rem rgba(var(--bo-accent-rgb), .25); }
.note-toolbar { background: var(--bs-tertiary-bg); }
.note-btn.btn-primary { background: var(--bo-accent); border-color: var(--bo-accent); color: var(--bo-dark); }
/* ── Telemóvel: barra lateral em gaveta ──────────────────────────────────── */
@media (max-width: 991.98px) {
.sidebar {
transform: translateX(-100%);
transition: transform .25s ease;
z-index: 1100;
box-shadow: 2px 0 18px rgba(0,0,0,.3);
}
.sidebar.open { transform: translateX(0); }
main { margin-left: 0; }
.topbar { left: 0; padding: 0 .75rem; }
.menu-toggle { display: inline-flex; }
/* Tabelas largas rolam dentro do cartão em vez de alargar a página */
main .card > .card-body { overflow-x: auto; -webkit-overflow-scrolling: touch; }
}
@media (max-width: 575.98px) {
/* Cabeçalhos de página (título + botões) empilham em vez de transbordar */
main .d-flex.justify-content-between.align-items-center { flex-wrap: wrap; gap: .5rem; }
/* 16px nos campos: o iOS não faz zoom ao focar */
.form-control, .form-select { font-size: 16px; }
/* Margens confortáveis em telemóvel */
/* !important: .p-3 é uma utilitária do Bootstrap e tem !important de origem */
.p-3 { padding: .85rem !important; }
}
/* ── Modo mini (só ecrã grande; classe posta no <html> pelo script do <head>) ── */
@media (min-width: 992px) {
html.bo-mini { --bo-sidebar-w: var(--bo-sidebar-w-mini); }
html.bo-mini .bo-sidebar__head {
flex-direction: column;
justify-content: center;
height: auto;
padding: .5rem 0;
gap: .25rem;
}
html.bo-mini .bo-sidebar__brand { display: none; }
html.bo-mini .bo-sidebar__user { padding: .5rem; }
html.bo-mini .bo-user-menu { justify-content: center; padding: .25rem; }
html.bo-mini .bo-user-menu__text,
html.bo-mini .bo-user-menu::after { display: none; }
html.bo-mini .bo-sidebar__nav { padding: .5rem 0; }
html.bo-mini .sidebar .bo-nav-item,
html.bo-mini .sidebar .bo-nav-item--sub,
html.bo-mini .sidebar .bo-nav-item--sub2 { justify-content: center; padding: .5rem; }
html.bo-mini .bo-nav-item__label { display: none; }
html.bo-mini .bo-nav-item__badge {
position: absolute;
top: 2px;
right: 8px;
margin: 0;
padding: .15em .4em;
font-size: .6rem;
}
/* Categoria no mini: sigla de texto (data-short), sem ícone nem chevron. */
html.bo-mini .bo-nav-group__label,
html.bo-mini .bo-nav-group--sub > .bo-nav-group__label { justify-content: center; padding: .55rem .25rem; font-size: 0; }
html.bo-mini .bo-nav-group__label::before { content: attr(data-short); font-size: .66rem; font-weight: 700; letter-spacing: .08em; }
html.bo-mini .bo-nav-group__text,
html.bo-mini .bo-nav-group__icon,
html.bo-mini .bo-nav-group__chevron { display: none; }
}
/* ── Navegação sem piscar: só o conteúdo faz fade; barra e topbar ficam ── */
@media (prefers-reduced-motion: no-preference) {
@view-transition { navigation: auto; }
.sidebar { view-transition-name: bo-sidebar; }
.topbar { view-transition-name: bo-topbar; }
::view-transition-old(root),
::view-transition-new(root) { animation-duration: .14s; }
}
@media (prefers-reduced-motion: reduce) {
.sidebar,
.sidebar .bo-nav-item,
.bo-nav-group__body,
.bo-nav-group__chevron { transition: none; }
}