/** * OpenStation — Content Graph window styles. * * Scoped to `.desktop-mode-content-graph`. Reads `os-variables` * tokens so the chrome adapts to the active theme. * * @since 0.8.2 */ .desktop-mode-content-graph { display: flex; flex-direction: column; width: 100%; height: 100%; background: var( --os-ui-surface, #f7f8fb ); color: var( --os-ui-fg, #1a1f2b ); font-family: var( --os-ui-font, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif ); } /* ---------- Toolbar ------------------------------------------------- */ .os-content-graph__toolbar { display: flex; align-items: center; gap: 12px; padding: 10px 14px; border-bottom: 1px solid var( --os-ui-border, #e2e6ec ); background: var( --os-ui-surface-elevated, #fff ); flex-wrap: wrap; } .os-content-graph__filters { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; } .os-content-graph__chip { display: inline-flex; align-items: center; gap: 6px; padding: 5px 10px; border: 1px solid var( --os-ui-border, #d8dde4 ); border-radius: 999px; background: transparent; color: var( --os-ui-fg-muted, #5a6473 ); font-size: 12px; cursor: pointer; transition: background 0.12s ease, border-color 0.12s ease, color 0.12s ease; } .os-content-graph__chip:hover { background: var( --os-ui-hover, rgba( 79, 139, 243, 0.08 ) ); color: var( --os-ui-fg, #1a1f2b ); } .os-content-graph__chip.is-active { border-color: var( --os-ui-accent, #2c6be5 ); background: var( --os-ui-accent-soft, rgba( 44, 107, 229, 0.12 ) ); color: var( --os-ui-accent-strong, #1f4ea8 ); } .os-content-graph__chip .dashicons { font-size: 14px; width: 14px; height: 14px; line-height: 14px; } .os-content-graph__chip-count { font-variant-numeric: tabular-nums; font-size: 11px; background: var( --os-ui-surface, #f1f3f7 ); padding: 1px 6px; border-radius: 999px; } /* * The count pill on an ACTIVE chip is a bright fill, and the chip's * own text colour is `--os-ui-accent-strong` — a light tint, by design, * because the chip body around it is a dark accent wash. The two meet * on this pill and cancel out (Nebula on 70% white is ~1.7:1). * * So the pill names its own text, exactly the way `--os-ui-ribbon-fg` * and `--os-ui-step-chip-fg` do for the other bright fills in the kit. * Unset it inherits the chip's colour, which is what a light theme * wants — there the chip text is already dark. */ .os-content-graph__chip.is-active .os-content-graph__chip-count { background: rgba( 255, 255, 255, 0.7 ); color: var( --os-ui-cg-chip-count-fg-active, inherit ); } .os-content-graph__search { position: relative; flex: 1; min-width: 220px; max-width: 320px; } .os-content-graph__search-input { width: 100%; padding: 6px 10px; border: 1px solid var( --os-ui-border, #d8dde4 ); border-radius: 6px; background: var( --os-ui-surface, #fff ); color: inherit; font-size: 13px; } .os-content-graph__search-input:focus { outline: none; border-color: var( --os-ui-accent, #2c6be5 ); box-shadow: 0 0 0 3px var( --os-ui-accent-soft, rgba( 44, 107, 229, 0.18 ) ); } .os-content-graph__search-results { position: absolute; top: calc( 100% + 4px ); left: 0; right: 0; margin: 0; padding: 4px; list-style: none; background: var( --os-ui-surface-elevated, #fff ); border: 1px solid var( --os-ui-border, #d8dde4 ); border-radius: 8px; box-shadow: 0 6px 18px rgba( 17, 24, 39, 0.08 ); z-index: 10; max-height: 300px; overflow-y: auto; } .os-content-graph__search-result { display: flex; align-items: center; justify-content: space-between; gap: 8px; width: 100%; padding: 6px 10px; background: transparent; border: 0; border-radius: 6px; color: inherit; cursor: pointer; text-align: left; font-size: 13px; } .os-content-graph__search-result:hover { background: var( --os-ui-hover, rgba( 79, 139, 243, 0.08 ) ); } .os-content-graph__search-title { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .os-content-graph__search-type { font-size: 11px; color: var( --os-ui-fg-muted, #6b7280 ); text-transform: uppercase; letter-spacing: 0.05em; } .os-content-graph__actions { display: flex; align-items: center; gap: 8px; margin-left: auto; } .os-content-graph__group-by { /* The os-select grows to its own intrinsic size; cap it so the action row stays compact on narrow windows. */ max-width: 180px; } .os-content-graph__btn { display: inline-flex; align-items: center; gap: 6px; padding: 5px 10px; border: 1px solid var( --os-ui-border, #d8dde4 ); border-radius: 6px; background: var( --os-ui-surface-elevated, #fff ); color: inherit; font-size: 12px; cursor: pointer; } .os-content-graph__btn:hover { background: var( --os-ui-hover, rgba( 79, 139, 243, 0.08 ) ); border-color: var( --os-ui-accent, #2c6be5 ); } .os-content-graph__btn .dashicons { font-size: 14px; width: 14px; height: 14px; line-height: 14px; } .os-content-graph__toolbar-status { margin-left: 8px; font-size: 11px; color: var( --os-ui-fg-muted, #6b7280 ); font-variant-numeric: tabular-nums; } /* ---------- Cluster labels (DOM overlay) -------------------------- */ .os-content-graph__group-labels { position: absolute; inset: 0; pointer-events: none; /* Sit above the canvas but below any toolbar / side panel. */ z-index: 2; overflow: hidden; } .os-content-graph__group-label { position: absolute; top: 0; left: 0; padding: 5px 12px; border-radius: 999px; background: var( --os-ui-cg-cluster-color, #2c6be5 ); color: var( --os-ui-fg-on-accent, #fff ); font-size: 14px; font-weight: 700; font-family: var( --os-ui-font, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif ); white-space: nowrap; box-shadow: 0 0 0 1.5px rgba( 255, 255, 255, 0.85 ), 0 1px 3px rgba( 0, 0, 0, 0.18 ); /* Translucent so nodes/edges behind the label remain visible. */ opacity: 0.85; /* Smooth the per-frame `style.opacity` and transform updates so the cluster labels glide instead of stutter during the grouping tween. */ transition: opacity 120ms ease-out; will-change: transform, opacity; } /* ---------- Body layout (stage + side panel) ----------------------- */ .os-content-graph__body { display: flex; flex: 1; min-height: 0; } /* ---------- Stage --------------------------------------------------- */ .os-content-graph__stage { position: relative; flex: 1; min-width: 0; min-height: 0; overflow: hidden; /* * Three layers, painted bottom-up: * 1. The theme surface fills the canvas (so PixiJS, which uses * `backgroundAlpha: 0`, lets it bleed through). * 2. Two soft theme-tinted radial vignettes give the canvas a * sense of depth without competing with the graph itself. * 3. A 24x24 dot grid at low alpha gives a subtle "graph paper" * texture, mirroring the categories-mindmap reference. */ background: radial-gradient( circle, rgba( 0, 0, 0, 0.06 ) 1px, transparent 1.5px ) 0 0 / 24px 24px, radial-gradient( ellipse at 28% 22%, rgba( 79, 139, 243, 0.08 ), transparent 60% ), radial-gradient( ellipse at 78% 80%, rgba( 176, 102, 215, 0.06 ), transparent 58% ), var( --os-ui-surface, #f7f8fb ); } .os-content-graph__canvas { display: block; width: 100%; height: 100%; } /* * Full-canvas loading wash. Resting state is invisible: the bundle * arms it on every graph fetch and adds `--visible` only once the * fetch has run long enough to be worth interrupting the board for * (see `src/content-graph/loading-overlay.ts`). A class rather than * `[hidden]` so the wash fades instead of popping. */ .os-content-graph__loading { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; /* * A translucent sheet of the stage's own surface, so it dims a * dark board as well as a light one. The literal is the pre-brand * light surface, kept as the floor if the token is missing. */ background: color-mix( in srgb, var( --os-ui-surface, #f7f8fb ) 72%, transparent ); pointer-events: none; z-index: 3; opacity: 0; visibility: hidden; transition: opacity 0.2s ease, visibility 0s linear 0.2s; } .os-content-graph__loading--visible { opacity: 1; visibility: visible; transition: opacity 0.2s ease; } .os-content-graph__loading[ hidden ] { display: none; } @media ( prefers-reduced-motion: reduce ) { .os-content-graph__loading { transition: none; } } /* ---------- Board notices (empty board, no threads yet) ----------- */ /* * owns the icon + copy; this is placement only. It * covers the (empty) canvas and lets pointer events through so the * stage still pans and the dot grid still reads as a board. */ .os-content-graph__empty { position: absolute; inset: 0; z-index: 2; pointer-events: none; } /* * "No threads yet" note. Top-left, out of the way of a small board * centred in the stage and of the side panel on the right. Real DOM * text over the canvas, so it is translatable and follows the theme * tokens like the rest of the chrome; pointer-events are off so a * pan that starts on it still pans the board. The bundle hides it * while a grouping is active, when the cluster labels need the space. */ .os-content-graph__hint { position: absolute; top: 12px; left: 12px; z-index: 2; max-width: 320px; padding: 10px 14px 12px; border: 1px solid var( --os-ui-border, #e2e6ec ); border-radius: 8px; background: var( --os-ui-surface-elevated, #fff ); color: var( --os-ui-fg-muted, #5a6473 ); box-shadow: 0 1px 3px rgba( 0, 0, 0, 0.08 ); font-size: 12px; line-height: 1.45; pointer-events: none; } .os-content-graph__hint-title { display: block; margin-bottom: 3px; color: var( --os-ui-fg, #1a1f2b ); font-size: 12.5px; font-weight: 600; } .os-content-graph__hint-body { margin: 0; } /* ---------- Right side panel: breadcrumb --------------------------- */ .os-content-graph__panel-breadcrumb { display: flex; align-items: center; padding: 8px 14px 0; min-height: 32px; } .os-content-graph__panel-breadcrumb[ hidden ] { display: none; } .os-content-graph__panel-breadcrumb-back { display: inline-flex; align-items: center; gap: 4px; background: transparent; border: 0; padding: 4px 8px 4px 4px; border-radius: 6px; cursor: pointer; color: var( --os-ui-fg-muted, #6b7280 ); font-size: 12px; font-weight: 500; max-width: 100%; min-width: 0; text-align: left; } .os-content-graph__panel-breadcrumb-back:hover { background: var( --os-ui-hover, rgba( 0, 0, 0, 0.05 ) ); color: var( --os-ui-fg, #1a1f2b ); } .os-content-graph__panel-breadcrumb-arrow { font-size: 16px; width: 16px; height: 16px; line-height: 16px; flex-shrink: 0; } .os-content-graph__panel-breadcrumb-label { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; } /* ---------- Right side panel --------------------------------------- */ .os-content-graph__panel { width: 320px; flex-shrink: 0; border-left: 1px solid var( --os-ui-border, #e2e6ec ); background: var( --os-ui-surface-elevated, #fff ); display: flex; flex-direction: column; overflow: hidden; /* * Subtle slide-in / slide-out when the panel opens or closes — * the outer container collapses its width while the inner frame * eases off to the right + fades, so the canvas reclaims the * space smoothly instead of the panel popping out of layout. */ transition: width 220ms cubic-bezier( 0.32, 0.72, 0, 1 ), border-left-width 220ms cubic-bezier( 0.32, 0.72, 0, 1 ), opacity 180ms ease-out; will-change: width, opacity; } .os-content-graph__panel[ hidden ], .os-content-graph__panel--closed { width: 0; opacity: 0; pointer-events: none; border-left-width: 0; } .os-content-graph__panel[ hidden ] { /* Initial PHP-rendered state — no transition on the very first * paint, otherwise the panel briefly slides in on page load. */ transition: none; } .os-content-graph__panel-frame { /* * Without these rules the body's `flex: 1; overflow-y: auto` * has nothing to constrain it — the body just grows to fit its * dossier content and the action buttons get clipped at the * bottom of the panel. Make the frame a flex column itself so * the body is forced to share the panel's height with the * breadcrumb and head, then scrolls the overflow. */ display: flex; flex-direction: column; flex: 1 1 0; min-height: 0; width: 320px; overflow: hidden; /* Slides + fades alongside the parent's width collapse so the * panel content visibly leaves to the right when closing. */ transition: transform 220ms cubic-bezier( 0.32, 0.72, 0, 1 ), opacity 180ms ease-out; } .os-content-graph__panel[ hidden ] .os-content-graph__panel-frame, .os-content-graph__panel--closed .os-content-graph__panel-frame { transform: translateX( 16% ); opacity: 0; } @media ( prefers-reduced-motion: reduce ) { .os-content-graph__panel, .os-content-graph__panel-frame { transition: none; } } .os-content-graph__panel-head { display: flex; align-items: flex-start; gap: 8px; padding: 14px 16px 10px; border-bottom: 1px solid var( --os-ui-border, #eef0f4 ); } .os-content-graph__panel-title-wrap { flex: 1; min-width: 0; } .os-content-graph__panel-title { margin: 0; font-size: 14px; font-weight: 600; line-height: 1.35; overflow-wrap: anywhere; } .os-content-graph__panel-meta { margin: 4px 0 0; font-size: 11px; color: var( --os-ui-fg-muted, #6b7280 ); text-transform: uppercase; letter-spacing: 0.06em; } .os-content-graph__panel-close { background: transparent; border: 0; color: var( --os-ui-fg-muted, #6b7280 ); cursor: pointer; padding: 2px; border-radius: 4px; flex-shrink: 0; } .os-content-graph__panel-close:hover { background: var( --os-ui-hover, rgba( 0, 0, 0, 0.05 ) ); color: inherit; } .os-content-graph__panel-body { flex: 1; min-height: 0; /* * The body is now a clipped stage that holds one or two * absolutely-positioned `__panel-page` children. During an iOS- * style navigation, the new page slides in over the old; both * are clipped here so the off-stage portion isn't visible. */ position: relative; overflow: hidden; padding: 0; } .os-content-graph__panel-page { position: absolute; inset: 0; overflow-y: auto; padding: 14px 16px 18px; display: flex; flex-direction: column; gap: 14px; background: var( --os-ui-surface-elevated, #fff ); /* * iOS navigation curve — quick out, slow in. 240ms matches * UIKit's default push/pop duration closely enough for the * reviewer-flagged "abrupt" feeling to ease. */ transition: transform 240ms cubic-bezier( 0.32, 0.72, 0, 1 ), opacity 200ms ease-out; will-change: transform, opacity; } /* * Forward push: new page enters from the right at full distance, the * outgoing page parallax-slides a fraction of the way to the left. * Back pop: mirrored — new page enters from the left at parallax * distance, current page slides off the right at full distance. */ .os-content-graph__page-from-right { transform: translateX( 100% ); } .os-content-graph__page-from-left { transform: translateX( -28% ); opacity: 0.55; } .os-content-graph__page-to-right { transform: translateX( 100% ); /* Keep the outgoing page above the incoming parallax shadow on * back so the slide reads as the user "removing" it. */ z-index: 2; } .os-content-graph__page-to-left { transform: translateX( -28% ); opacity: 0.55; } @media ( prefers-reduced-motion: reduce ) { .os-content-graph__panel-page { transition: none; } } .os-content-graph__panel-section-label { display: block; font-size: 10px; font-weight: 600; color: var( --os-ui-fg-muted, #6b7280 ); text-transform: uppercase; letter-spacing: 0.06em; margin-bottom: 4px; } .os-content-graph__panel-author { display: flex; flex-direction: column; gap: 4px; } .os-content-graph__panel-author[ hidden ] { display: none; } .os-content-graph__panel-author-row { display: flex; align-items: center; gap: 8px; } .os-content-graph__panel-avatar { width: 32px; height: 32px; border-radius: 50%; flex-shrink: 0; } .os-content-graph__panel-author-name { font-size: 13px; font-weight: 500; } .os-content-graph__panel-dates { display: flex; flex-direction: column; gap: 8px; } .os-content-graph__panel-dates[ hidden ] { display: none; } .os-content-graph__panel-date-row { display: flex; flex-direction: column; gap: 2px; } .os-content-graph__panel-date-value { font-size: 12px; color: var( --os-ui-fg, #1a1f2b ); font-variant-numeric: tabular-nums; } .os-content-graph__panel-stats { margin: 0; padding: 0; list-style: none; display: grid; grid-template-columns: repeat( auto-fill, minmax( 80px, 1fr ) ); gap: 4px; background: var( --os-ui-surface, #f7f8fb ); border: 1px solid var( --os-ui-border, #eef0f4 ); border-radius: 8px; padding: 8px; } .os-content-graph__panel-stats[ hidden ] { display: none; } .os-content-graph__panel-stat { display: flex; flex-direction: column; align-items: center; gap: 1px; } .os-content-graph__panel-stat-num { font-size: 16px; font-weight: 600; font-variant-numeric: tabular-nums; color: var( --os-ui-fg, #1a1f2b ); } .os-content-graph__panel-stat-label { font-size: 10px; color: var( --os-ui-fg-muted, #6b7280 ); text-transform: uppercase; letter-spacing: 0.04em; } .os-content-graph__panel-actions { display: flex; flex-direction: column; gap: 6px; } .os-content-graph__panel-actions[ hidden ] { display: none; } .os-content-graph__panel-actions .os-content-graph__btn { width: 100%; justify-content: center; } .os-content-graph__btn--primary { border-color: var( --os-ui-accent, #2c6be5 ); background: var( --os-ui-accent, #2c6be5 ); color: var( --os-ui-fg-on-accent, #fff ); } .os-content-graph__btn--primary:hover { background: var( --os-ui-accent-strong, #1f4ea8 ); border-color: var( --os-ui-accent-strong, #1f4ea8 ); } .os-content-graph__panel-loading { display: flex; justify-content: center; padding: 24px 0; } .os-content-graph__panel-loading[ hidden ] { display: none; } .os-content-graph__panel-empty { margin: 0; font-size: 12px; color: var( --os-ui-fg-muted, #6b7280 ); font-style: italic; } .os-content-graph__panel-empty[ hidden ] { display: none; } /* ---------- Contextual detail views (user / term / comment) -------- */ .os-content-graph__panel-detail-section { display: flex; flex-direction: column; gap: 4px; } .os-content-graph__panel-detail-head { display: flex; align-items: center; gap: 12px; } .os-content-graph__panel-detail-avatar--lg { width: 56px; height: 56px; border-radius: 50%; flex-shrink: 0; } .os-content-graph__panel-detail-handle { display: flex; flex-direction: column; gap: 2px; min-width: 0; } .os-content-graph__panel-detail-handle strong { font-size: 14px; font-weight: 600; overflow-wrap: anywhere; } .os-content-graph__panel-detail-handle span { font-size: 11px; color: var( --os-ui-fg-muted, #6b7280 ); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .os-content-graph__panel-detail-prose { margin: 0; font-size: 13px; line-height: 1.5; color: var( --os-ui-fg, #1a1f2b ); } .os-content-graph__panel-detail-link { font-size: 12px; color: var( --os-ui-accent, #2c6be5 ); text-decoration: none; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; display: inline-block; max-width: 100%; } .os-content-graph__panel-detail-link:hover { text-decoration: underline; } .os-content-graph__panel-detail-html { font-size: 13px; line-height: 1.5; color: var( --os-ui-fg, #1a1f2b ); background: var( --os-ui-surface, #f7f8fb ); border: 1px solid var( --os-ui-border, #eef0f4 ); border-radius: 6px; padding: 10px 12px; overflow-wrap: anywhere; } .os-content-graph__panel-detail-html p:first-child { margin-top: 0; } .os-content-graph__panel-detail-html p:last-child { margin-bottom: 0; } .os-content-graph__panel-detail-quote { margin: 0; padding: 10px 12px; border-left: 3px solid var( --os-ui-border, #d8dde4 ); background: var( --os-ui-surface, #f7f8fb ); border-radius: 0 6px 6px 0; display: flex; flex-direction: column; gap: 4px; } .os-content-graph__panel-detail-quote strong { font-size: 12px; font-weight: 600; } .os-content-graph__panel-detail-quote span { font-size: 12px; color: var( --os-ui-fg-muted, #4b5563 ); } .os-content-graph__panel-detail-thumb { display: flex; justify-content: center; background: var( --os-ui-surface, #f7f8fb ); border: 1px solid var( --os-ui-border, #eef0f4 ); border-radius: 8px; padding: 8px; max-height: 240px; overflow: hidden; } .os-content-graph__panel-detail-thumb img { max-width: 100%; max-height: 220px; object-fit: contain; border-radius: 4px; } .os-content-graph__panel-badges { display: flex; flex-wrap: wrap; gap: 4px; } .os-content-graph__panel-badge { display: inline-flex; align-items: center; padding: 2px 8px; font-size: 11px; font-weight: 500; border-radius: 999px; background: var( --os-ui-surface, #f1f3f7 ); color: var( --os-ui-fg-muted, #4b5563 ); border: 1px solid var( --os-ui-border, #e2e6ec ); } .os-content-graph__panel-badge--blue { background: rgba( 44, 107, 229, 0.12 ); color: var( --os-ui-accent-strong, #1f4ea8 ); border-color: rgba( 44, 107, 229, 0.35 ); } .os-content-graph__panel-badge--green { background: rgba( 44, 169, 122, 0.14 ); color: #1f7754; border-color: rgba( 44, 169, 122, 0.35 ); } .os-content-graph__panel-badge--amber { background: rgba( 232, 137, 58, 0.16 ); color: #8a5012; border-color: rgba( 232, 137, 58, 0.35 ); } .os-content-graph__panel-inline-meta { display: flex; flex-direction: column; gap: 6px; } .os-content-graph__panel-inline-meta-row { display: flex; align-items: baseline; gap: 8px; } .os-content-graph__panel-inline-meta-row .os-content-graph__panel-section-label { flex: 0 0 auto; margin-bottom: 0; } .os-content-graph__panel-chips { display: flex; flex-wrap: wrap; gap: 4px; margin: 0; padding: 0; list-style: none; } .os-content-graph__panel-chip { display: inline-flex; align-items: center; gap: 6px; padding: 3px 9px; font-size: 12px; border-radius: 999px; background: var( --os-ui-surface, #f1f3f7 ); border: 1px solid var( --os-ui-border, #e2e6ec ); } .os-content-graph__panel-chip-count { font-variant-numeric: tabular-nums; font-size: 11px; color: var( --os-ui-fg-muted, #6b7280 ); } .os-content-graph__panel-author-list { display: flex; flex-direction: column; gap: 6px; margin: 0; padding: 0; list-style: none; } .os-content-graph__panel-author-list-row { display: flex; align-items: center; gap: 8px; padding: 4px 0; } .os-content-graph__panel-author-list-row .os-content-graph__panel-avatar { width: 24px; height: 24px; border-radius: 50%; flex-shrink: 0; } .os-content-graph__panel-author-list-row .os-content-graph__panel-author-name { flex: 1 1 auto; font-size: 13px; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .os-content-graph__panel-milestones { display: flex; flex-direction: column; gap: 6px; } .os-content-graph__panel-milestone-row { display: flex; justify-content: space-between; gap: 8px; } .os-content-graph__panel-milestone-key { font-size: 12px; color: var( --os-ui-fg-muted, #6b7280 ); } .os-content-graph__panel-replies { display: flex; flex-direction: column; gap: 6px; margin: 0; padding: 0; list-style: none; } .os-content-graph__panel-reply { background: var( --os-ui-surface, #f7f8fb ); border: 1px solid var( --os-ui-border, #eef0f4 ); border-radius: 6px; padding: 8px 10px; } .os-content-graph__panel-reply header { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; margin-bottom: 4px; } .os-content-graph__panel-reply header strong { font-size: 12px; } .os-content-graph__panel-reply header span { font-size: 11px; color: var( --os-ui-fg-muted, #6b7280 ); } .os-content-graph__panel-reply p { margin: 0; font-size: 12px; line-height: 1.45; color: var( --os-ui-fg-muted, #4b5563 ); } .os-content-graph__panel-detail-loading { display: flex; align-items: center; gap: 8px; padding: 8px 0; font-size: 12px; color: var( --os-ui-fg-muted, #6b7280 ); } .os-content-graph__panel-stat-row { display: flex; flex-direction: column; gap: 2px; } @media ( max-width: 760px ) { .os-content-graph__panel { position: absolute; inset: auto 0 0 0; width: 100%; max-height: 60%; border-left: 0; border-top: 1px solid var( --os-ui-border, #e2e6ec ); box-shadow: 0 -8px 24px rgba( 17, 24, 39, 0.08 ); z-index: 4; } } /* ---------- Satellite tooltip -------------------------------------- */ .os-content-graph__tooltip { position: absolute; z-index: 5; display: flex; flex-direction: column; gap: 2px; max-width: 240px; padding: 6px 10px; background: var( --os-tooltip-bg, var( --os-ui-surface-elevated, #1a1f2b ) ); color: var( --os-tooltip-fg, var( --os-ui-fg-on-accent, #fff ) ); border-radius: 6px; box-shadow: 0 4px 14px rgba( 17, 24, 39, 0.18 ); font-size: 12px; pointer-events: none; } .os-content-graph__tooltip[ hidden ] { display: none; } .os-content-graph__tooltip strong { font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .os-content-graph__tooltip span { font-size: 11px; opacity: 0.85; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }