Files
Verso/services/web/frontend/stylesheets/pages/editor/ide-lumiere.scss
T
claude 1814cba458
Build and Deploy Verso / deploy (push) Successful in 10m11s
fix(mobile): extend CSS breakpoints to cover Tor Browser spoofed viewport
Tor Browser sets viewport width to ~980px to resist fingerprinting, so
@media (max-width: 767px) never fires on a real phone using it. Add the
secondary condition (pointer: coarse) and (max-width: 1024px) — same
dual-check already used in JS — to all mobile CSS overrides in
ide-lumiere.scss and project-list-lumiere.scss. This activates the font
scaling, toolbar height increase, auto-zoom prevention, and project page
layout fixes on Tor Browser.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-19 08:24:29 +00:00

464 lines
15 KiB
SCSS

// Verso Lumière — editor chrome overrides.
// Scoped to body[data-lumiere='true'] — zero impact on Classic themes.
$lum-teal: #2a9d8f;
$lum-blue: #3d7ebf;
$lum-border: #daeae7;
// Same noise as the dashboard
$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.22'/%3E%3C/svg%3E");
// ── CSS variable overrides ─────────────────────────────────────────────────
[data-lumiere='true'] {
// Toolbar
--redesign-toolbar-background: #f4fbf9;
--redesign-toolbar-border-divider: #{$lum-border};
--redesign-toolbar-home-button-hover-background: rgba(42, 157, 143, 0.12);
--redesign-subdued-button-hover-background: rgba(42, 157, 143, 0.12);
--redesign-subdued-button-color: #1a2e3b;
// Rail icon strip
--ide-rail-background: #e8f5f2;
--ide-rail-border-colour: #{$lum-border};
--ide-rail-color: #2d5a52;
--ide-rail-link-background: transparent;
--ide-rail-link-hover-background: rgba(42, 157, 143, 0.15);
--ide-rail-link-hover-color: #{$lum-teal};
--ide-rail-link-active-color: #ffffff;
--ide-rail-link-active-background: #{$lum-teal};
--ide-rail-header-subdued-button-color: #2d5a52;
--ide-rail-header-subdued-button-hover-background: rgba(42, 157, 143, 0.15);
// File tree — transparent so the panel-group noise shows through
--file-tree-bg: transparent;
--file-tree-item-color: #1a2e3b;
--file-tree-icon-colour: #2a9d8f;
--file-tree-expand-button-color: #1a2e3b;
--file-tree-item-hover-bg: rgba(42, 157, 143, 0.10);
--file-tree-item-selected-bg: rgba(42, 157, 143, 0.20);
--file-tree-item-selected-color: #1a5c52;
// Compile/recompile button: teal instead of blue
--bg-accent-01: #{$lum-teal};
--bg-accent-02: #{$lum-teal};
--bg-accent-03: rgba(42, 157, 143, 0.15);
// Outline panel — transparent bg so the panel-group noise shows through
--outline-bg-color: transparent;
--outline-border-color: #{$lum-border};
--outline-header-hover-bg: rgba(42, 157, 143, 0.08);
--outline-item-hover-bg: rgba(42, 157, 143, 0.10);
--outline-line-guide-color: #{$lum-border};
--outline-container-color-bg: transparent;
--outline-content-color: #1a2e3b;
--outline-item-highlight-bg: rgba(42, 157, 143, 0.20);
--outline-item-highlight-color: #1a5c52;
--outline-item-highlight-font-weight: bold;
--outline-item-carat-color: #64748b;
// Panel resize handles
--editor-resizer-bg-color: #{$lum-border};
}
// ── Toolbar — gradient background + accent stripe ──────────────────────────
[data-lumiere='true'] .ide-redesign-toolbar {
position: relative;
// Exponential-ish teal wash: strong at top, nearly gone by mid-height
background:
linear-gradient(
180deg,
rgba(42, 157, 143, 0.20) 0%,
rgba(42, 157, 143, 0.09) 30%,
rgba(42, 157, 143, 0.03) 60%,
transparent 100%
),
#f7fdfc !important;
border-bottom: 1px solid $lum-border;
box-shadow: 0 2px 10px rgba(42, 157, 143, 0.10);
// 4px teal→blue gradient stripe at the very top
&::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
height: 4px;
background: linear-gradient(90deg, $lum-teal 0%, $lum-blue 100%);
pointer-events: none;
}
}
// ── Rail icon strip — grainy teal-tinted background ────────────────────────
[data-lumiere='true'] .ide-rail {
background: linear-gradient(180deg, #cceee8 0%, #daf2ee 100%);
border-right-color: $lum-border;
}
// Active tab bottom indicator: white dot on teal background
[data-lumiere='true'] .ide-rail-tab-link.open-rail::after {
background-color: rgba(255, 255, 255, 0.8);
}
// ── Rail panel (file tree / outline / search) — grainy gradient ───────────
[data-lumiere='true'] .file-tree-outline-panel-group {
background-image:
#{$lum-noise},
radial-gradient(ellipse 100% 60% at 100% 0%, rgba($lum-teal, 0.30) 0%, transparent 60%),
radial-gradient(ellipse 80% 50% at 0% 95%, rgba($lum-blue, 0.18) 0%, transparent 55%);
background-size: 200px 200px, cover, cover;
background-repeat: repeat, no-repeat, no-repeat;
background-color: #f4fbf9;
}
// Panel header bar inside rail panels
[data-lumiere='true'] .rail-panel-header {
background: linear-gradient(90deg, rgba($lum-teal, 0.12) 0%, transparent 80%);
border-bottom: 1px solid $lum-border;
}
[data-lumiere='true'] .rail-panel-title {
color: #1a5c52;
}
// File tree toolbar row
[data-lumiere='true'] .file-tree-toolbar {
border-bottom: 1px solid rgba($lum-teal, 0.15);
}
// ── CodeMirror toolbar buttons — rounded square style ─────────────────────
[data-lumiere='true'] .ol-cm-toolbar {
// Source editor formatting buttons (Bold, Italic, Link, etc.)
.ol-cm-toolbar-button {
border-radius: 7px !important;
transition: background-color 0.15s ease, color 0.15s ease, box-shadow 0.15s ease;
&:hover:not(:disabled) {
background-color: rgba(42, 157, 143, 0.10) !important;
color: $lum-teal !important;
}
&.active,
&[aria-pressed='true'] {
background-color: rgba(42, 157, 143, 0.18) !important;
color: $lum-teal !important;
}
}
// Toolbar group dividers
.ol-cm-toolbar-button-group {
gap: 2px;
}
}
// ── Toolbar action buttons (Share, Present, History, Layout, etc.) ─────────
// Targets the right-hand action area of the toolbar; covers OLButton (btn),
// subdued icon buttons, and the layout dropdown toggle.
[data-lumiere='true'] .ide-redesign-toolbar-actions {
.btn {
border-radius: 7px !important;
}
.ide-redesign-toolbar-button-subdued,
.ide-redesign-toolbar-button-icon {
border-radius: 7px !important;
&:hover:not(:disabled) {
background-color: rgba(42, 157, 143, 0.10) !important;
color: $lum-teal !important;
}
}
.layout-dropdown .dropdown-toggle {
border-radius: 7px !important;
}
}
// Also round the left-hand menu-bar subdued buttons (File, Edit, Help…)
[data-lumiere='true'] .ide-redesign-toolbar-menu {
.ide-redesign-toolbar-button-subdued,
.ide-redesign-toolbar-button-icon {
border-radius: 7px !important;
}
}
// ── PDF panel toolbar (Recompile, Logs, Download) ──────────────────────────
// The compile button and its neighbours live in .toolbar-pdf, not in the
// main ide-redesign-toolbar, so they need their own border-radius rule.
[data-lumiere='true'] .toolbar-pdf {
.btn {
border-radius: 7px !important;
}
}
// ── Settings modal ────────────────────────────────────────────────────────
// :has() scopes to only this modal so other editor modals are unaffected.
[data-lumiere='true'] .modal-content:has(.ide-settings-modal-body) {
border: 1px solid $lum-border;
border-radius: 14px;
overflow: hidden;
box-shadow: 0 8px 32px rgba($lum-teal, 0.14);
.modal-header {
position: relative;
background: linear-gradient(180deg, #e8f5f2 0%, #f8fffe 100%);
border-bottom: 1px solid $lum-border;
&::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
height: 3px;
background: linear-gradient(90deg, $lum-teal 0%, $lum-blue 100%);
}
}
.modal-title {
color: #1a5c52;
font-weight: 600;
}
}
[data-lumiere='true'] .ide-settings-tab-nav.nav {
background: linear-gradient(180deg, rgba($lum-teal, 0.04) 0%, transparent 100%);
border-right-color: $lum-border;
}
[data-lumiere='true'] .ide-settings-tab-link {
color: #1a2e3b;
&:visited { color: #1a2e3b; }
&.active {
color: $lum-teal;
background-color: rgba($lum-teal, 0.12);
font-weight: 600;
}
&:hover:not(.active) {
background-color: rgba($lum-teal, 0.07);
color: darken($lum-teal, 5%);
text-decoration: none;
}
}
[data-lumiere='true'] .ide-settings-section-title {
color: $lum-teal;
border-bottom-color: $lum-border;
}
[data-lumiere='true'] .ide-settings-tab-content {
.form-select:focus,
.form-control:focus {
border-color: rgba($lum-teal, 0.5);
box-shadow: 0 0 0 0.2rem rgba($lum-teal, 0.18);
}
}
// ── Compile button — teal gradient ────────────────────────────────────────
// .compile-button-group is a split button: main Recompile + dropdown arrow.
// Only the outer corners get rounded; the inner shared edge stays flat.
[data-lumiere='true'] .compile-button-group {
// Main (left) button: round left side, flat right side
.compile-button {
border-radius: 7px 0 0 7px !important;
}
// Dropdown arrow (right button): flat left side, round right side
.compile-dropdown-toggle {
border-radius: 0 7px 7px 0 !important;
}
// Teal gradient on the main compile button only
.compile-button.btn-primary {
background: linear-gradient(135deg, $lum-teal 0%, darken($lum-teal, 8%) 100%) !important;
border-color: darken($lum-teal, 10%) !important;
box-shadow: 0 2px 8px rgba($lum-teal, 0.35) !important;
&:hover,
&:focus {
background: linear-gradient(135deg, lighten($lum-teal, 4%) 0%, $lum-teal 100%) !important;
box-shadow: 0 4px 14px rgba($lum-teal, 0.45) !important;
}
}
// Dropdown toggle also gets the teal background (same button group, same color)
.compile-dropdown-toggle.btn-primary {
background: linear-gradient(135deg, darken($lum-teal, 5%) 0%, darken($lum-teal, 12%) 100%) !important;
border-color: darken($lum-teal, 10%) !important;
border-left-color: rgba(255, 255, 255, 0.2) !important;
box-shadow: 0 2px 8px rgba($lum-teal, 0.35) !important;
}
}
// ── Code / Visual editor toggle ────────────────────────────────────────────
// Replace the pill shape with rounded-square and add a sliding indicator that
// moves under the active tab instead of a simple background-color crossfade.
[data-lumiere='true'] .toggle-switch {
border-radius: 10px;
background-color: rgba($lum-teal, 0.07);
border: 1px solid rgba($lum-teal, 0.18);
padding: 3px;
position: relative;
// Sliding indicator — absolutely positioned under the active label
&::before {
content: '';
position: absolute;
top: 3px;
left: 3px;
// Each tab gets exactly half the inner area (enforced by flex: 1 below)
width: calc(50% - 3px);
height: calc(100% - 6px);
background: $lum-teal;
border-radius: 7px;
box-shadow: 0 2px 6px rgba($lum-teal, 0.35);
transition: transform 0.22s cubic-bezier(0.34, 1.56, 0.64, 1);
pointer-events: none;
z-index: 0;
}
// Slide the indicator right when Visual is active
&:has(input[value='rich-text']:checked)::before {
transform: translateX(100%);
}
// Force Code label and Visual span wrapper to equal width
> label.toggle-switch-label {
flex: 1;
}
> span {
flex: 1;
display: flex;
}
}
[data-lumiere='true'] .toggle-switch-label {
flex: 1;
border-radius: 7px;
position: relative;
z-index: 1;
color: $lum-teal;
transition: color 0.18s ease;
}
// Active tab: white text over the teal slider; remove built-in bg/shadow
[data-lumiere='true'] .toggle-switch-input:checked + .toggle-switch-label {
color: #fff;
background-color: transparent !important;
box-shadow: none !important;
}
// Disabled tab (Visual locked on non-.tex files)
[data-lumiere='true'] .toggle-switch-input:disabled + .toggle-switch-label {
color: rgba($lum-teal, 0.35);
}
// ── File tree — teal left-accent bar on selected item ─────────────────────
[data-lumiere='true'] .ide-redesign-main {
// Override vars declared at this same scope in file-tree.scss and outline.scss
// so the panel-group noise background shows through.
--file-tree-bg: transparent;
--outline-bg-color: transparent;
--outline-container-color-bg: transparent;
.file-tree:not(.multi-selected) ul.file-tree-list li.selected > .entity > .entity-name {
box-shadow: inset 2px 0 0 $lum-teal;
}
// linked-file badge uses background-color: var(--file-tree-bg); give it a teal tint
.linked-file-highlight {
background-color: rgba($lum-teal, 0.18) !important;
color: #0a4f43 !important;
}
// disconnected overlay would be invisible with transparent bg; restore a tinted fallback
.disconnected-overlay {
background-color: rgba(#f4fbf9, 0.92) !important;
}
}
// ── Panel resize handles — thin teal line, no dot grips ───────────────────
[data-lumiere='true'] .horizontal-resize-handle {
width: 4px !important;
transition: background-color 0.15s ease;
// Remove the dated dot-grip SVGs
&::before,
&::after {
content: none !important;
}
&.horizontal-resize-handle-enabled:hover {
background-color: rgba($lum-teal, 0.55);
}
}
[data-lumiere='true'] .vertical-resize-handle {
height: 4px;
transition: background-color 0.15s ease;
&::after {
content: none !important;
}
&.vertical-resize-handle-enabled:hover {
background-color: rgba($lum-teal, 0.55);
}
}
// Collapse toggle pill — wider than the 4px handle so the arrow icon is visible
[data-lumiere='true'] .custom-toggler {
width: 16px !important;
left: 50%;
transform: translateX(-50%);
border-radius: 4px;
background-color: rgba($lum-teal, 0.65);
&:hover {
background-color: $lum-teal;
}
}
// ── Mobile: scale up editor UI chrome so it's usable on a phone ───────────
// Bumps font-size tokens one step (12→14px, 14→16px, 16→18px) and increases
// the toolbar height. Scoped to .ide-redesign-main so only the editor page
// is affected. CodeMirror's own font size is controlled by user settings and
// is unaffected by these CSS custom properties.
//
// Two-condition query mirrors the JS dual-check in main-layout.tsx:
// (max-width: 767px) — standard mobile browsers
// (pointer: coarse) and (…1024px) — Tor Browser spoofs viewport to ~980px
// but does NOT spoof touch hardware
@media (max-width: 767px), (pointer: coarse) and (max-width: 1024px) {
[data-lumiere='true'] .ide-redesign-main {
--font-size-01: 0.875rem; // 14px (was 12px)
--font-size-02: 1rem; // 16px (was 14px)
--font-size-03: 1.125rem; // 18px (was 16px)
--toolbar-height: 48px; // was 40px
--toolbar-small-height: 40px; // was 32px
// Prevent iOS/Android auto-zoom when tapping into the editor.
// Browsers zoom any focused editable element whose font-size < 16px.
// `max(1rem, 1em)` honours the user's size setting if it is already ≥ 16px.
.cm-content {
font-size: max(1rem, 1em) !important;
}
}
}