Files
WebinarNotes/.obsidian/plugins/webinar-dash/styles.css
meels 70b9e2a44f fix: find the width cap by measuring, not by class name
Measured chain from live preview showed the cap on .cm-content at 700px,
while .cm-sizer - the element closest() matched first - is already
uncapped at 1680px. The class-name shortcut therefore locked onto the
wrong element and returned before the fallback walk could find the real
one, so the cap survived and the container query correctly collapsed the
grid to one column.

widenHost now always measures computed max-width outward from the
dashboard's parent. The decision is extracted as firstCappedIndex and
tested against the real measured chains for both live preview and
reading view, so a class-name assumption cannot silently break it again.
Adds .cm-content to the CSS fallback.
2026-07-28 16:12:53 +02:00

248 lines
9.6 KiB
CSS

.webinar-dash {
--wd-ink-000: #ffffff; --wd-ink-050: #f7f7f7; --wd-ink-100: #ececec;
--wd-ink-200: #d9d9d9; --wd-ink-400: #8a8a8a; --wd-ink-500: #5e5e5e;
--wd-ink-700: #262626; --wd-ink-900: #0a0a0a; --wd-ink-999: #000000;
--wd-red-500: #e1261c; --wd-red-600: #c31c14;
--wd-bg: var(--wd-ink-000);
--wd-bg-subtle: var(--wd-ink-050);
--wd-fg: var(--wd-ink-999);
--wd-fg-2: var(--wd-ink-700);
--wd-fg-3: var(--wd-ink-500);
--wd-fg-4: var(--wd-ink-400);
--wd-border: var(--wd-ink-200);
--wd-border-strong: var(--wd-ink-999);
--wd-border-subtle: var(--wd-ink-100);
--wd-accent: var(--wd-red-500);
--wd-accent-press: var(--wd-red-600);
--wd-accent-on: #ffffff;
--wd-ok: #0a8a3f;
--wd-warn: #c68a00;
--wd-danger: var(--wd-red-500);
--wd-mono: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
--wd-sans: "Inter", ui-sans-serif, system-ui, -apple-system, "Helvetica Neue", Arial, sans-serif;
font-family: var(--wd-sans);
color: var(--wd-fg);
display: flex;
flex-direction: column;
gap: 16px;
/* Past roughly this width the two panes stop reading as a pair and table
rows get hard to track across. Cap the whole dashboard, not just the
grid, so the toolbar stays flush with the panes below it. */
max-width: 1600px;
/* Makes this element the reference for the @container query further down,
so the grid collapses on the pane's width rather than the window's. */
container-type: inline-size;
}
.theme-dark .webinar-dash {
--wd-bg: var(--wd-ink-900);
--wd-bg-subtle: #161616;
--wd-fg: var(--wd-ink-000);
--wd-fg-2: var(--wd-ink-200);
--wd-fg-3: var(--wd-ink-400);
--wd-fg-4: var(--wd-ink-500);
--wd-border: var(--wd-ink-700);
--wd-border-strong: #b8b8b8;
--wd-border-subtle: #161616;
/* Accent tracks the installed theme at .obsidian/themes/tesanti/theme.css,
whose dark section reads "Black canvas, same signal red": --accent-h/-s/-l
are declared once at :root and never redeclared under .theme-dark, and only
the hover state lifts (#c31c14 light, #ff4d43 dark). Match that exactly. */
--wd-accent: var(--wd-red-500);
--wd-accent-press: #ff4d43;
--wd-accent-on: #ffffff;
/* Status tokens are separate from the brand accent by design-system rule, and
here they carry small text in a dense table. #e1261c on near-black is about
3.8:1, under AA for small text, so these lift where the accent does not. */
--wd-ok: #2fbf6a;
--wd-warn: #e0a516;
--wd-danger: #ff5c50;
}
/* ------------------------------------------------------------------
Escape Obsidian's readable-line-length cap.
With "Readable line length" on (the default), Obsidian caps note
content at --file-line-width, roughly 700px. That is right for prose
and wrong for a two-pane dashboard, which gets squeezed into a column.
:has() scopes this to the sizer that actually contains a dashboard, so
every other note in the vault keeps its readable width. Both selectors
are needed: reading view sizes on .markdown-preview-sizer, live preview
on .cm-sizer.
If you would rather not rely on this, the alternatives are Settings ->
Editor -> Readable line length (off, but that widens every note), or
adding `cssclasses: wide-dash` to the note's frontmatter and swapping
the :has() selectors below for `.wide-dash .markdown-preview-sizer`.
The plugin also lifts this cap inline in `widenHost()`, which is the path
that actually carries the load — an inline style cannot lose a specificity
fight. These rules are the belt-and-braces copy, and they need !important
because Obsidian's own rule qualifies the sizer with the view class and so
outranks a bare `.markdown-preview-sizer:has(...)`.
------------------------------------------------------------------ */
.markdown-preview-sizer:has(.webinar-dash),
.markdown-preview-view.is-readable-line-width .markdown-preview-sizer:has(.webinar-dash),
.markdown-source-view.mod-cm6 .cm-content:has(.webinar-dash),
.markdown-source-view.mod-cm6 .cm-sizer:has(.webinar-dash) {
max-width: none !important;
}
.wd-grid {
display: grid;
grid-template-columns: minmax(0, 38fr) minmax(0, 62fr);
gap: 24px;
}
.wd-grid > * { min-width: 0; }
.wd-bar {
display: flex;
align-items: center;
gap: 12px;
flex-wrap: wrap;
border: 1px solid var(--wd-border);
border-radius: 4px;
padding: 8px 12px;
background: var(--wd-bg-subtle);
}
.wd-btn-ghost {
background: transparent;
color: var(--wd-fg);
border-color: var(--wd-border-strong);
}
.wd-btn-ghost:hover {
background: var(--wd-bg-muted, var(--wd-bg-subtle));
border-color: var(--wd-border-strong);
}
/* Collapse to one column on the width that actually matters — the pane's,
not the window's. A media query measures the window, so a wide window
with the dashboard in a narrow split pane would keep two cramped
columns. The container query below responds to the pane itself; the
media query stays as a floor for a genuinely narrow window. */
@container (max-width: 820px) {
.wd-grid { grid-template-columns: minmax(0, 1fr); }
}
@media (max-width: 820px) {
.wd-grid { grid-template-columns: minmax(0, 1fr); }
}
.wd-pane { display: flex; flex-direction: column; gap: 20px; }
.wd-eyebrow {
font-family: var(--wd-mono); font-size: 11px; line-height: 1;
letter-spacing: 0.12em; text-transform: uppercase;
color: var(--wd-fg-3); font-weight: 500;
display: flex; align-items: center; gap: 8px;
}
.wd-eyebrow::before {
content: ""; width: 5px; height: 5px; flex: none; background: var(--wd-accent);
}
.wd-block { display: flex; flex-direction: column; gap: 12px; }
.wd-row {
display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
border: 1px solid var(--wd-border); border-radius: 4px;
padding: 12px 12px 12px 16px; background: var(--wd-bg);
}
.wd-row + .wd-row { margin-top: -1px; }
.wd-row-main { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.wd-row-name {
font-size: 14px; font-weight: 600;
overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.wd-mono {
font-family: var(--wd-mono); font-size: 11px; color: var(--wd-fg-3);
font-variant-numeric: tabular-nums;
}
.wd-btn {
display: inline-flex; align-items: center; gap: 6px; flex: none;
font-family: var(--wd-sans); font-size: 13px; font-weight: 600;
padding: 6px 12px; border-radius: 6px; cursor: pointer;
border: 1px solid var(--wd-accent); background: var(--wd-accent);
color: var(--wd-accent-on);
transition: background 120ms cubic-bezier(0.2, 0, 0, 1);
}
.wd-btn:hover { background: var(--wd-accent-press); border-color: var(--wd-accent-press); }
.wd-btn:focus-visible { outline: 2px solid var(--wd-accent); outline-offset: 2px; }
.wd-btn[disabled] {
opacity: 0.45; cursor: not-allowed;
background: transparent; color: var(--wd-fg-3); border-color: var(--wd-border);
}
.wd-btn svg { width: 14px; height: 14px; flex: none; }
.wd-done { display: flex; flex-direction: column; }
.wd-done-row {
display: flex; align-items: baseline; gap: 12px; padding: 5px 0;
border-bottom: 1px solid var(--wd-border-subtle); font-size: 13px;
}
.wd-done-row:last-child { border-bottom: 0; }
.wd-done-name {
color: var(--wd-fg-2);
overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.wd-note { font-size: 12px; color: var(--wd-fg-3); }
.wd-error {
font-size: 13px; color: var(--wd-danger);
border: 1px solid var(--wd-danger); border-radius: 4px; padding: 12px;
}
@media (prefers-reduced-motion: reduce) {
.webinar-dash * { transition-duration: 0.01ms !important; }
}
.wd-meter { display: flex; gap: 2px; height: 8px; width: 100%; }
.wd-meter > i { display: block; height: 100%; }
.wd-seg-covered { background: var(--wd-ok); }
.wd-seg-partial { background: var(--wd-warn); }
.wd-seg-absent { background: var(--wd-danger); }
.wd-key { display: flex; flex-wrap: wrap; gap: 16px; font-size: 12px; color: var(--wd-fg-2); }
.wd-key > span { display: inline-flex; align-items: center; gap: 6px; }
.wd-key i { width: 8px; height: 8px; flex: none; }
.wd-tbl { width: 100%; border-collapse: collapse; font-size: 13px; }
.wd-tbl th {
font-family: var(--wd-mono); font-size: 10px; letter-spacing: 0.1em;
text-transform: uppercase; color: var(--wd-fg-3); font-weight: 500;
text-align: left; padding: 0 12px 8px 0;
border-bottom: 1px solid var(--wd-border-strong);
}
.wd-tbl td {
padding: 6px 12px 6px 0; border-bottom: 1px solid var(--wd-border-subtle);
vertical-align: baseline;
}
.wd-grp td {
padding-top: 16px; border-bottom: 1px solid var(--wd-border-strong);
font-family: var(--wd-mono); font-size: 10px; letter-spacing: 0.1em;
text-transform: uppercase; color: var(--wd-fg); font-weight: 500;
}
.wd-stat { display: inline-flex; align-items: center; gap: 5px; font-size: 12px; font-weight: 600; }
.wd-stat svg { width: 13px; height: 13px; flex: none; }
.wd-covered { color: var(--wd-ok); }
.wd-partial { color: var(--wd-warn); }
.wd-absent { color: var(--wd-danger); }
.wd-pin { font-family: var(--wd-mono); font-size: 10px; color: var(--wd-fg-4); }
.wd-status { font-family: var(--wd-mono); font-size: 11px; flex: none; }
.wd-status-running { color: var(--wd-warn); }
.wd-status-done { color: var(--wd-ok); }
.wd-status-failed { color: var(--wd-danger); }
.wd-output {
flex-basis: 100%;
width: 100%;
font-family: var(--wd-mono); font-size: 11px; white-space: pre-wrap;
max-height: 220px; overflow: auto; margin-top: 8px;
border: 1px solid var(--wd-border); border-radius: 4px; padding: 8px;
color: var(--wd-fg-2);
}