/* Toolbar above the listing */ .browse-root { flex: 1; display: flex; flex-direction: column; min-height: 0; overflow: hidden; } .browse-table-wrap { flex: 1; overflow: auto; min-height: 0; } .toolbar { display: flex; align-items: center; gap: 1rem; padding: 0.6rem 1rem; background: var(--bg-secondary); border-bottom: 1px solid var(--border); flex-shrink: 0; flex-wrap: wrap; } /* Breadcrumb path. The root node is a 🏠 link to "/" (online) or the FS handle name (offline). Each segment is a clickable link in server mode that re-navigates the browser; in FS-API mode they render as plain spans because we don't keep ancestor handles. */ .breadcrumbs { flex: 1; min-width: 0; overflow-x: auto; overflow-y: hidden; white-space: nowrap; font-family: Consolas, Monaco, monospace; font-size: 0.9rem; color: var(--text-muted); padding: 0.1rem 0; /* Hide the scrollbar but keep horizontal scroll for very deep paths */ scrollbar-width: thin; } .breadcrumbs .bc-link { color: var(--primary); text-decoration: none; padding: 0.1rem 0.25rem; border-radius: 3px; } .breadcrumbs .bc-link:hover { background: var(--bg-hover, rgba(0,0,0,0.05)); text-decoration: underline; } .breadcrumbs .bc-link--current { color: var(--text); font-weight: 500; cursor: default; } .breadcrumbs .bc-link--current:hover { background: transparent; text-decoration: none; } .breadcrumbs .bc-sep { color: var(--text-muted); margin: 0 0.05rem; } .breadcrumbs .bc-root { display: inline-flex; align-items: center; line-height: 1; } .bc-home-icon { width: 1rem; height: 1rem; display: block; color: currentColor; } .toolbar__count { font-size: 0.8rem; color: var(--text-muted); white-space: nowrap; } /* Auto-filter rows in . Two rows — one targets file rows (📄 icon, with file-name + ext inputs), one targets folder rows (📁 icon, with folder-name input). The icons make it visually obvious which row controls which kind of filter. The rows are non-sticky (only the sortable header row sticks) — keeps the stack-positioning math out of the picture and accepts that filters scroll out of view on long lists. */ .browse-table thead .filter-row th { position: static; padding: 0.25rem 0.6rem; background: var(--bg-secondary); border-bottom: 1px solid var(--border); cursor: default; font-weight: normal; z-index: 0; } .browse-table thead .filter-row th:hover { background: var(--bg-secondary); } .filter-row__icon { display: inline-block; width: 1.2rem; text-align: center; margin-right: 0.3rem; vertical-align: middle; font-size: 0.95rem; color: var(--text-muted); } .column-filter { width: calc(100% - 1.5rem); padding: 0.2rem 0.4rem; border: 1px solid var(--border); border-radius: 3px; background: var(--bg); color: var(--text); font-size: 0.8rem; font-family: Consolas, Monaco, monospace; box-sizing: border-box; } .filter-row th.col-name .column-filter { width: calc(100% - 1.7rem); /* leave space for the icon */ } .column-filter:focus { outline: 1px solid var(--primary); outline-offset: -1px; } /* Table — folders + files in a tree */ .browse-table { width: 100%; border-collapse: collapse; font-size: 0.9rem; background: var(--bg); /* No flex:1 — tables don't reliably distribute extra height across rows the way flex columns do. With few rows we'd get tall rows that shrink as more children are loaded. The wrap div handles scrolling instead. */ } .browse-table tbody tr { /* Pin rows to a deterministic height so table layout never redistributes vertical space across them. */ line-height: 1.4; } .browse-table thead th { position: sticky; top: 0; background: var(--bg-secondary); border-bottom: 1px solid var(--border); text-align: left; padding: 0.5rem 0.75rem; font-weight: 600; color: var(--text); user-select: none; z-index: 1; } .browse-table th.sortable { cursor: pointer; } .browse-table th.sortable:hover { background: var(--bg-hover, #e8e8e8); } .sort-arrow { display: inline-block; width: 0.7rem; color: var(--text-muted); font-size: 0.7rem; margin-left: 0.2rem; } .browse-table th.sort-asc .sort-arrow::after { content: "▲"; color: var(--text); } .browse-table th.sort-desc .sort-arrow::after { content: "▼"; color: var(--text); } .browse-table tbody td { padding: 0.3rem 0.75rem; border-bottom: 1px solid var(--border); vertical-align: middle; } .browse-table tbody tr:hover { background: var(--bg-hover, #f6faff); } /* Tree-row — name cell with indent + chevron */ .tree-name { display: flex; align-items: center; gap: 0.4rem; min-width: 0; } .tree-name__indent { flex: 0 0 auto; } .tree-name__chevron { width: 1rem; text-align: center; color: var(--text-muted); cursor: pointer; user-select: none; flex: 0 0 1rem; line-height: 1; } .tree-name__chevron--leaf { visibility: hidden; } .tree-name__chevron::before { content: "▶"; font-size: 0.65rem; } .tree-row.expanded > td .tree-name__chevron::before { content: "▼"; } .tree-name__icon { flex: 0 0 1.1rem; text-align: center; color: var(--text-muted); font-size: 1rem; line-height: 1; } .tree-name__label { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--text); } .tree-name__label.is-folder { font-weight: 500; } .tree-name__label.is-file { cursor: pointer; color: var(--primary); text-decoration: none; } .tree-name__label.is-file:hover { text-decoration: underline; } /* Numeric columns right-aligned */ .col-size, .col-date { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; color: var(--text-muted); } .col-ext { color: var(--text-muted); font-family: Consolas, Monaco, monospace; font-size: 0.85rem; } /* Loading row */ .tree-row--loading td { color: var(--text-muted); font-style: italic; padding: 0.5rem 1rem 0.5rem calc(0.75rem + 2.4rem); }