// Verso Lumière — modern card-based project dashboard theme. // // The outer element carries both project-ds-nav-page + website-redesign // (for sidebar/navbar CSS) and project-list-lumiere (our styling hook). // Everything here is additive or override-only — zero impact on Classic themes. // ── Brand colours ────────────────────────────────────────────────────────── $lum-teal: #2a9d8f; $lum-teal-dark: #21867a; $lum-blue: #3d7ebf; $lum-text: #1a2e3b; $lum-text-sub: #64748b; $lum-text-muted: #94a3b8; $lum-border: #e2eaf2; // Grainy SVG noise tile (fractalNoise, greyscale, stitched for seamless tiling). $lum-noise: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='200' height='200'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.75' numOctaves='4' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)' opacity='0.28'/%3E%3C/svg%3E"); .project-list-lumiere { // ══════════════════════════════════════════════════════════════════════════ // NAVBAR // ══════════════════════════════════════════════════════════════════════════ .navbar-default { border-bottom: none !important; box-shadow: 0 1px 0 rgba(0, 0, 0, 0.06), 0 2px 8px rgba(0, 0, 0, 0.04); background-color: #ffffff !important; // Teal-to-blue gradient accent stripe at the very top &::before { content: ''; position: absolute; top: 0; left: 0; right: 0; height: 3px; background: linear-gradient(90deg, $lum-teal 0%, $lum-blue 100%); z-index: 10; } // Nav link hover — shared base .navbar-nav > li > .nav-link, .navbar-nav > li > .dropdown-toggle { border-radius: 8px !important; transition: background-color 0.15s ease, color 0.15s ease, border-color 0.15s ease; border: 1px solid transparent !important; &:hover, &:focus, &.show { background-color: rgba($lum-teal, 0.09) !important; color: $lum-teal !important; border-color: rgba($lum-teal, 0.18) !important; } } // Account button — slightly more prominent (has a resting tint) .nav-item-account > .dropdown-toggle { background-color: rgba($lum-teal, 0.06) !important; color: $lum-text !important; font-weight: 500; &:hover, &:focus, &.show { background-color: rgba($lum-teal, 0.14) !important; color: $lum-teal !important; border-color: rgba($lum-teal, 0.25) !important; } } // Admin button .subdued > .dropdown-toggle { color: $lum-text-sub !important; font-weight: 500; } .navbar-title { color: $lum-text !important; font-weight: 600; } } // ══════════════════════════════════════════════════════════════════════════ // SIDEBAR — shell // ══════════════════════════════════════════════════════════════════════════ .project-list-sidebar-wrapper-react { background: #ffffff !important; border-right: 1px solid $lum-border; } // ══════════════════════════════════════════════════════════════════════════ // SIDEBAR — New Project button // ══════════════════════════════════════════════════════════════════════════ // New Project button in the sidebar only (not in the header actions row) .project-list-sidebar-wrapper-react .new-project-dropdown { padding-bottom: 0.75rem; } // When the button appears inline next to the search bar, strip extra spacing .lumiere-header-actions .new-project-dropdown { padding-bottom: 0; display: flex; align-items: center; } .new-project-dropdown { .new-project-button.btn { width: 100%; background: linear-gradient(135deg, $lum-teal 0%, $lum-blue 100%) !important; border: none !important; color: #ffffff !important; font-weight: 600; border-radius: 10px !important; box-shadow: 0 2px 8px rgba($lum-teal, 0.25); transition: box-shadow 0.18s ease, filter 0.18s ease; &:hover, &:focus { filter: brightness(1.08); box-shadow: 0 4px 14px rgba($lum-teal, 0.38) !important; color: #ffffff !important; } &::after { border-top-color: rgba(255, 255, 255, 0.8); } } } // ══════════════════════════════════════════════════════════════════════════ // SIDEBAR — filter list // ══════════════════════════════════════════════════════════════════════════ .project-list-wrapper ul.project-list-filters { > li > button { border-radius: 8px; padding: 0.45rem 0.75rem; font-size: 0.875rem; font-weight: 500; color: $lum-text-sub; transition: background-color 0.15s ease, color 0.15s ease; } > li:hover button { background-color: rgba($lum-teal, 0.07) !important; color: $lum-teal; } > li.active button { background: $lum-teal !important; color: #ffffff !important; font-weight: 600; } .dropdown-header { font-size: 0.7rem; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase; color: $lum-teal !important; padding: 0.85rem 0.75rem 0.35rem; } > li.tag { button.tag-name { border-radius: 8px; font-size: 0.83rem; color: $lum-text-sub; display: flex; align-items: center; gap: 0.45rem; &:hover { color: $lum-teal; } } .tag-menu button.dropdown-toggle { border-radius: 50%; transition: background-color 0.15s ease; &:hover, &:active, &[aria-expanded='true'] { background-color: rgba($lum-teal, 0.1) !important; color: $lum-teal; } } } hr { border-color: $lum-border; } } // ══════════════════════════════════════════════════════════════════════════ // SIDEBAR — lower section // ══════════════════════════════════════════════════════════════════════════ .ds-nav-sidebar-lower { border-top: none !important; padding-top: 0.75rem; } .ds-nav-icon-dropdown .dropdown-toggle { border-radius: 50% !important; color: $lum-text-sub !important; transition: background-color 0.15s ease, color 0.15s ease, box-shadow 0.15s ease; &:hover { background-color: rgba($lum-teal, 0.09) !important; color: $lum-teal !important; box-shadow: 0 0 0 3px rgba($lum-teal, 0.12); } &.show { background-color: rgba($lum-teal, 0.15) !important; color: $lum-teal !important; box-shadow: 0 0 0 3px rgba($lum-teal, 0.18); } } .ds-nav-verso-logo { // No border-top here — .ds-nav-sidebar-lower already has one padding-top: 0.6rem; margin-top: 0.25rem; transition: filter 0.2s ease; &:hover { filter: brightness(1.1) drop-shadow(0 1px 4px rgba($lum-teal, 0.2)); } } .theme-toggle-radios { background-color: rgba($lum-teal, 0.07); } .theme-toggle-radio input:checked + label { background-color: $lum-teal !important; color: #ffffff; .material-symbols { color: #ffffff; } } // ══════════════════════════════════════════════════════════════════════════ // NOTIFICATIONS — Lumière palette // ══════════════════════════════════════════════════════════════════════════ .notification { border-radius: 10px; box-shadow: 0 1px 4px rgba(0, 0, 0, 0.05); // Warning: solid amber-tinted white so the teal page background can't bleed // through. !important needed to beat :root [data-theme='default'] specificity. &.notification-type-warning { background-color: #fffbf0 !important; border-color: rgba(217, 119, 6, 0.35) !important; .notification-icon { color: #b45309 !important; } } // Info: solid blue-tinted white for the same reason &.notification-type-info { background-color: #f0f6fd !important; border-color: rgba($lum-blue, 0.28) !important; .notification-icon { color: $lum-blue !important; } } // Action buttons (e.g. "Send confirmation code") — neutral slate-grey, // rounded-square to match the Lumière button style. .notification-cta .btn-secondary { background-color: rgba(100, 116, 139, 0.10) !important; border-color: rgba(100, 116, 139, 0.28) !important; color: $lum-text !important; border-radius: 8px !important; &:hover, &:focus { background-color: rgba(100, 116, 139, 0.18) !important; border-color: rgba(100, 116, 139, 0.38) !important; color: $lum-text !important; } } } // ══════════════════════════════════════════════════════════════════════════ // MAIN CONTENT AREA — grainy gradient background // // Three layers, back to front: // 1. Solid base colour (#fafbff — cool off-white) // 2. Two soft radial-gradient "orbs" (teal top-right, blue bottom-left), // rendered fixed so they stay in the corner as the user scrolls. // 3. SVG feTurbulence noise tile (200×200, repeating, scrolls with content) // at 6% opacity — the "grain" effect seen in Linear / Raycast / UmbrelOS. // ══════════════════════════════════════════════════════════════════════════ .project-ds-nav-content { // Grainy gradient: noise tile on top, two strong radial orbs below. // Using scroll (not fixed) so the gradient renders correctly inside the // overflow:auto scroll container. background-image: #{$lum-noise}, radial-gradient(circle 700px at 110% -80px, rgba($lum-teal, 0.60) 0%, transparent 100%), radial-gradient(circle 600px at -120px 110%, rgba($lum-blue, 0.45) 0%, transparent 100%); background-size: 200px 200px, cover, cover; background-repeat: repeat, no-repeat, no-repeat; background-color: #e8f5f2; } // ── Page header ──────────────────────────────────────────────────────────── .lumiere-header { display: flex; align-items: center; justify-content: space-between; gap: 1rem; margin-bottom: 1.75rem; flex-wrap: wrap; } // Title + zoom control grouped on the left .lumiere-title-row { display: flex; align-items: center; gap: 0.75rem; flex-wrap: wrap; } .lumiere-header-actions { display: flex; align-items: center; gap: 0.75rem; flex-shrink: 0; flex-wrap: wrap; } // Search bar — wide enough to show the full placeholder (relaxed on mobile) form.project-search .form-control { min-width: 360px; @media (max-width: 767px) { min-width: 0; } } .lumiere-title { font-family: Georgia, 'Times New Roman', 'DejaVu Serif', serif !important; font-size: 2rem !important; font-weight: 700 !important; color: $lum-text !important; line-height: 1.15 !important; margin: 0 !important; } // ── Empty state ───────────────────────────────────────────────────────── .lumiere-empty { color: $lum-text-sub; font-size: 0.95rem; margin-top: 2rem; } // ── Selection bar (appears when projects are selected) ──────────────────── .lumiere-selection-bar { display: flex; align-items: center; gap: 0.75rem; padding: 0.6rem 1rem; margin-bottom: 1rem; background: rgba($lum-teal, 0.08); border: 1px solid rgba($lum-teal, 0.22); border-radius: 10px; flex-wrap: wrap; } .lumiere-selection-bar-left { display: flex; align-items: center; gap: 0.6rem; flex-shrink: 0; } .lumiere-selection-count { font-size: 0.875rem; font-weight: 600; color: $lum-teal; white-space: nowrap; } .lumiere-selection-deselect { margin-left: auto; font-size: 0.8rem; color: $lum-text-sub; background: none; border: none; padding: 0.2rem 0.4rem; cursor: pointer; border-radius: 4px; flex-shrink: 0; &:hover { color: $lum-text; background: rgba(0, 0, 0, 0.06); } } // ── Card grid ───────────────────────────────────────────────────────────── .lumiere-card-grid { --lum-card-scale: 1; display: grid; grid-template-columns: repeat(auto-fill, minmax(calc(180px * var(--lum-card-scale)), 1fr)); gap: 1.5rem; margin-top: 0.5rem; } // ── Zoom control (S / M / L card-size picker) ───────────────────────────── .lumiere-zoom-control { display: flex; align-items: center; background: rgba(255, 255, 255, 0.6); border: 1px solid $lum-border; border-radius: 7px; padding: 2px; gap: 1px; flex-shrink: 0; } .lumiere-zoom-btn { background: none; border: none; border-radius: 5px; padding: 3px 9px; font-size: 0.72rem; font-weight: 700; color: $lum-text-sub; cursor: pointer; line-height: 1; transition: background-color 0.12s ease, color 0.12s ease; letter-spacing: 0.05em; &:hover { background: rgba($lum-teal, 0.1); color: $lum-teal; } &.active { background: #fff; color: $lum-teal; box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12); } } // ── Card wrapper (checkbox + link) ──────────────────────────────────────── .lumiere-card-wrapper { position: relative; } // Checkbox overlay: top-left corner of the card, low opacity by default. // Becomes fully opaque on hover, on focus, and for all cards when any is // selected (:has(input:checked) on the grid). .lumiere-card-checkbox { position: absolute; top: 10px; left: 10px; z-index: 2; opacity: 0.35; transition: opacity 0.15s ease; input[type='checkbox'] { width: 16px; height: 16px; cursor: pointer; accent-color: $lum-teal; } } .lumiere-card-wrapper:hover .lumiere-card-checkbox, .lumiere-card-wrapper:focus-within .lumiere-card-checkbox { opacity: 1; } // When any card in the grid is checked, show all checkboxes fully .lumiere-card-grid:has(input[type='checkbox']:checked) .lumiere-card-checkbox { opacity: 1; } // Selected card: blue ring on solid white — clearly distinct from the teal page bg .lumiere-card-wrapper:has(input[type='checkbox']:checked) .lumiere-card { border-color: rgba($lum-blue, 0.65); background: rgba(255, 255, 255, 0.96); box-shadow: 0 0 0 3px rgba($lum-blue, 0.22), 0 4px 12px rgba(0, 0, 0, 0.10); } // ── Individual card ─────────────────────────────────────────────────────── // Card container is now a
; the clickable area is .lumiere-card-link .lumiere-card { display: flex; flex-direction: column; border-radius: 10px; background: rgba(255, 255, 255, 0.82); backdrop-filter: blur(8px); -webkit-backdrop-filter: blur(8px); border: 1px solid rgba(255, 255, 255, 0.6); box-shadow: 0 2px 8px rgba(0, 0, 0, 0.07); transition: transform 0.18s ease, box-shadow 0.18s ease; overflow: hidden; &:hover, &:focus-within { transform: translateY(-3px); box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12); } } // The anchor covers thumb + body, with no underline or color bleed .lumiere-card-link { display: flex; flex-direction: column; flex: 1; text-decoration: none; color: inherit; &:hover, &:focus-visible { text-decoration: none; color: inherit; } } // Action strip — icon buttons that fade in when the card is hovered .lumiere-card-actions { display: flex; align-items: center; justify-content: center; gap: 2px; padding: 3px 6px 5px; border-top: 1px solid rgba($lum-teal, 0.10); opacity: 0; transition: opacity 0.15s ease; // Recolour OLIconButton's action-btn class for the Lumière palette .action-btn { color: $lum-text-muted !important; border-radius: 6px !important; &:hover, &:focus { color: $lum-teal !important; background: rgba($lum-teal, 0.09) !important; } } } .lumiere-card:hover .lumiere-card-actions, .lumiere-card:focus-within .lumiere-card-actions { opacity: 1; } // ── Card thumbnail ──────────────────────────────────────────────────────── .lumiere-card-thumb { position: relative; height: calc(130px * var(--lum-card-scale, 1)); display: flex; align-items: center; justify-content: center; overflow: hidden; &::after { content: ''; position: absolute; top: 0; right: 0; width: 0; height: 0; border-style: solid; border-width: 0 28px 28px 0; border-color: transparent rgba(255, 255, 255, 0.3) transparent transparent; z-index: 2; } } // Thumbnail image — shown when the project has a cached compiled PDF page. // Falls back to the gradient + initial when the image 404s or is loading. // The counter-transform on hover keeps the image visually stationary while // the card rises beneath it (matching the card's translateY(-3px) lift). .lumiere-card-thumb-img { position: absolute; top: 14px; left: 12px; right: 12px; bottom: 0; width: calc(100% - 24px); height: calc(100% - 14px); object-fit: cover; object-position: top center; border-radius: 5px 5px 0 0; z-index: 1; transition: transform 0.18s ease; box-shadow: 0 2px 8px rgba(0, 0, 0, 0.18); } .lumiere-card:hover .lumiere-card-thumb-img, .lumiere-card:focus-within .lumiere-card-thumb-img { transform: translateY(3px); } .lumiere-card-initial { font-family: Georgia, 'Times New Roman', 'DejaVu Serif', serif; font-size: 3rem; font-weight: 700; color: rgba(255, 255, 255, 0.75); line-height: 1; user-select: none; position: relative; z-index: 0; } .lumiere-card--latex .lumiere-card-thumb { background: linear-gradient(135deg, #4caf7d 0%, #098842 100%); } .lumiere-card--typst .lumiere-card-thumb { background: linear-gradient(135deg, #4dc8bf 0%, #239dad 100%); } .lumiere-card--quarto .lumiere-card-thumb { background: linear-gradient(135deg, #6b9ec3 0%, #447099 100%); } .lumiere-card--quarto-slides .lumiere-card-thumb { background: linear-gradient(135deg, #f09aaa 0%, #e4637c 100%); } // ── Card body ───────────────────────────────────────────────────────────── .lumiere-card-body { display: flex; flex-direction: column; gap: 0.35rem; padding: 0.85rem 0.9rem 0.9rem; flex: 1; } .lumiere-card-name { font-size: 0.875rem; font-weight: 600; color: $lum-text; line-height: 1.3; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; } .lumiere-card-meta { display: flex; align-items: center; gap: 0.4rem; flex-wrap: wrap; } .lumiere-card-owner { font-size: 0.72rem; color: $lum-text-sub; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 100px; } .lumiere-card-date { font-size: 0.72rem; color: $lum-text-muted; margin-top: auto; } // ── Format badges ───────────────────────────────────────────────────────── .lumiere-format-badge { display: inline-block; font-size: 0.65rem; font-weight: 600; letter-spacing: 0.03em; text-transform: uppercase; padding: 0.15em 0.5em; border-radius: 4px; line-height: 1.5; } .lumiere-format-badge--latex { background: rgba(#e6f4ec, 0.9); color: #098842; } .lumiere-format-badge--typst { background: rgba(#e0f7f5, 0.9); color: #239dad; } .lumiere-format-badge--quarto { background: rgba(#e8eef5, 0.9); color: #447099; } .lumiere-format-badge--quarto-slides { background: rgba(#fde8ec, 0.9); color: #e4637c; } // ── Card tags ───────────────────────────────────────────────────────────── // Dots live inside .lumiere-card-meta so they add zero extra height. .lumiere-card-tag-dot { flex-shrink: 0; width: 8px; height: 8px; border-radius: 50%; display: inline-block; cursor: default; } // ── XS compact list view ───────────────────────────────────────────────── // Activated via .lumiere-card-grid--compact (cardScale === 0). // Uses ProjectCardCompact which reuses the classic table cell components // (FormatCell, OwnerCell, LastUpdatedCell, ActionsCell) laid out in a // CSS Grid so every row aligns like a proper table. .lumiere-card-grid--compact { display: flex; flex-direction: column; gap: 0.25rem; margin-top: 0.5rem; } .lumiere-compact-row { display: grid; // checkbox | name+tags | format | owner | date | actions grid-template-columns: 28px 1fr 96px 120px 150px auto; align-items: center; column-gap: 0.85rem; padding: 0.45rem 0.75rem; background: rgba(#edf7f5, 0.82); backdrop-filter: blur(8px); -webkit-backdrop-filter: blur(8px); border: 1px solid rgba($lum-teal, 0.18); border-radius: 7px; box-shadow: 0 1px 4px rgba($lum-teal, 0.06); transition: background-color 0.15s ease, border-color 0.15s ease, box-shadow 0.15s ease; &:hover { background: rgba(#e4f4f1, 0.96); border-color: rgba($lum-teal, 0.35); box-shadow: 0 2px 10px rgba($lum-teal, 0.10); } } // Override classic project-format-badge colors so the XS compact view // shows the same soft Lumière palette as the card-based views. .project-format-badge { border-radius: 4px; font-size: 0.65rem; font-weight: 600; letter-spacing: 0.03em; text-transform: uppercase; padding: 0.15em 0.5em; line-height: 1.5; border: none; white-space: nowrap; } .project-format-badge-latex { background-color: rgba(#e6f4ec, 0.9); color: #098842; border: none; } .project-format-badge-typst { background-color: rgba(#e0f7f5, 0.9); color: #239dad; border: none; } .project-format-badge-quarto { background-color: rgba(#e8eef5, 0.9); color: #447099; border: none; } .project-format-badge-quarto-slides { background-color: rgba(#fde8ec, 0.9); color: #e4637c; border: none; } .lumiere-compact-checkbox { display: flex; align-items: center; input[type='checkbox'] { width: 16px; height: 16px; cursor: pointer; accent-color: $lum-teal; } } .lumiere-compact-name-cell { display: flex; align-items: center; gap: 0.4rem; overflow: hidden; min-width: 0; } .lumiere-compact-name { font-size: 0.875rem; font-weight: 600; color: $lum-text; text-decoration: none; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; &:hover, &:focus { color: $lum-teal; text-decoration: none; } } .lumiere-compact-owner { font-size: 0.8rem; color: $lum-text-sub; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .lumiere-compact-date { font-size: 0.8rem; color: $lum-text-muted; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } // On desktop, the meta wrapper is invisible to grid layout — its children // participate as direct grid items, preserving the 6-column alignment. .lumiere-compact-meta { display: contents; } .lumiere-compact-actions { display: flex; align-items: center; gap: 1px; .action-btn { color: $lum-text-muted !important; border-radius: 6px !important; opacity: 0; transition: opacity 0.12s ease, color 0.12s ease, background-color 0.12s ease; &:hover, &:focus { color: $lum-teal !important; background: rgba($lum-teal, 0.09) !important; } } // ⋮ dropdown toggle — restyled from the table variant to match Lumière .dropdown-table-button-toggle { padding: 0.2rem 0.35rem; border-radius: 6px; background: transparent; border: none; color: $lum-text-muted; line-height: 1; transition: background-color 0.15s ease, color 0.15s ease; &:hover, &:focus, &[aria-expanded='true'] { background: rgba($lum-teal, 0.09); color: $lum-teal; outline: none; } } } .lumiere-compact-row:hover .lumiere-compact-actions .action-btn, .lumiere-compact-row:focus-within .lumiere-compact-actions .action-btn { opacity: 1; } // ── Mobile layout overrides ──────────────────────────────────────────────── @media (max-width: 767px) { // Stack the header vertically so nothing overflows the viewport width. // Without this, lumiere-header-actions (flex-shrink:0) forces the flex // container wider than the screen. .lumiere-header { flex-direction: column; align-items: stretch; gap: 0.5rem; } .lumiere-header-actions { width: 100%; flex-shrink: 1; min-width: 0; form.project-search { flex: 1; min-width: 0; } } // Compact row: 2-line layout // Row 1: [checkbox] [name+tags] [⋮ action] // Row 2: [checkbox] [format · owner · date] // ActionsDropdown (single ⋮ button) is shown via d-md-none; ActionsCell // (many icon buttons) is hidden on mobile, so the auto column stays tiny. .lumiere-compact-row { grid-template-columns: 28px 1fr auto; grid-template-rows: auto auto; row-gap: 0.2rem; .lumiere-compact-checkbox { grid-column: 1; grid-row: 1 / 3; align-self: center; } .lumiere-compact-name-cell { grid-column: 2; grid-row: 1; } .lumiere-compact-actions { grid-column: 3; grid-row: 1; align-self: center; opacity: 1; .action-btn { opacity: 1; } } // Meta wrapper becomes a flex row spanning the second line .lumiere-compact-meta { display: flex; align-items: center; gap: 0.4rem; flex-wrap: wrap; grid-column: 2 / 4; grid-row: 2; } } // Card tile grid: M = 2 tiles/row, L = 1 tile/row. // --lum-card-scale inline var is suppressed on mobile (isMobile=true in JS), // so the CSS custom property here wins for thumbnail sizing. .lumiere-card-grid:not(.lumiere-card-grid--compact) { grid-template-columns: repeat(2, 1fr); gap: 0.75rem; --lum-card-scale: 0.85; &.lumiere-card-grid--mobile-1col { grid-template-columns: 1fr; --lum-card-scale: 1.3; } } } // ── Touch devices: card actions always visible (no hover cursor on phones) ── @media (hover: none) { .lumiere-card-actions { opacity: 1; } } // ── Mobile toolbar: filter pills + zoom control ─────────────────────────── .lumiere-mobile-toolbar { align-items: center; gap: 0.5rem; width: 100%; padding: 0.25rem 0 0.5rem; flex-shrink: 0; } .lumiere-mobile-filters { overflow-x: auto; display: flex; gap: 0.45rem; flex: 1; min-width: 0; scrollbar-width: none; -ms-overflow-style: none; &::-webkit-scrollbar { display: none; } } .lumiere-mobile-zoom { flex-shrink: 0; } .lumiere-mobile-filter-pill { flex-shrink: 0; padding: 0.3rem 0.8rem; border-radius: 20px; font-size: 0.8rem; font-weight: 500; border: 1.5px solid $lum-border; background: rgba(255, 255, 255, 0.7); color: $lum-text-sub; cursor: pointer; white-space: nowrap; transition: border-color 0.15s ease, color 0.15s ease, background-color 0.15s ease; line-height: 1.4; &.active { background: $lum-teal; border-color: $lum-teal; color: #fff; font-weight: 600; } &:hover:not(.active), &:focus:not(.active) { border-color: rgba($lum-teal, 0.55); color: $lum-teal; background: rgba($lum-teal, 0.07); } } // ── Selection bar — tool buttons ────────────────────────────────────────── .lumiere-selection-bar { .btn-toolbar { gap: 4px; } .btn-group { gap: 2px; } .btn-secondary, .btn.btn-secondary { background-color: rgba(255, 255, 255, 0.7) !important; border-color: rgba($lum-teal, 0.28) !important; color: $lum-text !important; border-radius: 8px !important; font-size: 0.82rem; transition: background-color 0.15s ease, border-color 0.15s ease, color 0.15s ease; &:hover, &:focus, &.show { background-color: rgba($lum-teal, 0.12) !important; border-color: rgba($lum-teal, 0.45) !important; color: $lum-teal !important; } } .dropdown-menu { border: 1px solid $lum-border; border-radius: 10px; box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1); .dropdown-header { font-size: 0.7rem; font-weight: 700; letter-spacing: 0.07em; text-transform: uppercase; color: $lum-teal; padding-top: 0.6rem; } .dropdown-item:hover, .dropdown-item:focus { background-color: rgba($lum-teal, 0.07); color: $lum-teal; } } } } // ── Tooltip — prevent hover-stealing from card lift animation ───────────────── // Bootstrap tooltips are purely informational. pointer-events: none ensures // they never steal :hover from the card beneath them (which would cause the // translateY lift to flicker when hovering over a tag dot). .tooltip { pointer-events: none; } // ── Footer — Lumière override ───────────────────────────────────────────────── // Pale teal canvas with noise grain, 2px teal→blue accent stripe at top. // Left col: serif author credit. Right col: monospace/uppercase meta links. // !important beats :root [data-theme='default'] .project-ds-nav-page footer.site-footer. .project-list-lumiere footer.site-footer { position: relative; .site-footer-content > .row { align-items: center; } background-color: #edf7f4 !important; background-image: #{$lum-noise} !important; background-size: 200px 200px !important; background-repeat: repeat !important; border-top: none !important; color: #64748b !important; // Teal-to-blue gradient stripe matching the navbar accent &::before { content: ''; position: absolute; top: 0; left: 0; right: 0; height: 2px; background: linear-gradient(90deg, $lum-teal 0%, $lum-blue 100%); pointer-events: none; } a { color: #64748b !important; text-decoration: none; transition: color 0.15s ease; &:hover { color: $lum-teal !important; } } // Author credit — warm serif for a human touch .col-lg-9 .site-footer-items > li:first-child a { font-family: Georgia, 'Times New Roman', 'DejaVu Serif', serif; color: $lum-text !important; font-weight: 500; } // Meta links (AGPL, source code) — subtle monospace/uppercase treatment .col-lg-3 { font-family: ui-monospace, 'SFMono-Regular', 'Fira Code', Consolas, monospace; text-transform: uppercase; letter-spacing: 0.07em; color: $lum-text-muted !important; a { color: $lum-text-muted !important; &:hover { color: $lum-teal !important; } } } // Pipe separators .text-muted { color: #b8d4cf !important; } --link-color: #64748b; --link-hover-color: #{$lum-teal}; --link-visited-color: #64748b; } // ── Global Lumière rules (apply to every page when data-lumiere is set) ──── // These cover pages that don't carry .project-list-lumiere (404, settings). // min-height on html (not body) so the gradient fills the viewport without // adding artificial height that would push the footer below the fold. html:has(body[data-lumiere='true']) { min-height: 100vh; } [data-lumiere='true'] { background: linear-gradient(160deg, #f0faf8 0%, #e4f4f1 50%, #daeef5 100%); // Navbar: white background with teal accent stripe. // Override CSS custom properties used by navbar.scss — no hard-coded // class selectors needed, and position:absolute from base CSS is kept. .navbar-default { --navbar-bg: #ffffff; --navbar-link-color: #{$lum-text-sub}; --navbar-link-hover-color: #{$lum-teal}; --navbar-link-hover-bg: rgba(42, 157, 143, 0.08); --navbar-link-border-color: transparent; --navbar-link-hover-border-color: rgba(42, 157, 143, 0.2); --navbar-subdued-color: #{$lum-text}; --navbar-subdued-hover-color: #{$lum-teal}; --navbar-subdued-hover-bg: rgba(42, 157, 143, 0.08); --navbar-title-color: #{$lum-text}; --navbar-title-color-hover: #{$lum-teal}; border-bottom: none !important; box-shadow: 0 1px 0 rgba(0, 0, 0, 0.06), 0 2px 8px rgba(0, 0, 0, 0.04); &::before { content: ''; position: absolute; top: 0; left: 0; right: 0; height: 3px; background: linear-gradient(90deg, $lum-teal 0%, $lum-blue 100%); } } }