/* 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 posto pelo script do 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 pelo script do ) ── */ @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; } }