/*
ArozOS File Manager css file
This file is used to overwrite the default css
on segmentic ui (or formantic if it is later upgraded)
*/
/*
Color definations
*/
:root{
--dark_theme_toggle: #333333;
--dark_theme_toggle_text: rgb(218, 218, 218);
--white_theme_toggle: #dadada;
--white_theme_toggle_text: rgb(27, 27, 27);
}
body.whiteTheme {
--fileopr_btnTxt: rgb(226, 226, 226);
--fileopr_oprtxt: rgb(56, 52, 52);
--fileopr_btnhover: #f0f0f0;
--divider: #f0f0f0;
--navi_bgcolor: var(--body_background_secondary, #fcfcfc);
--navi_theme: var(--theme_color, #92cfe7);
--navi_theme_multiselect: #6c06ba;
--navi_txt: rgb(114, 114, 114);
--dropdown_bg: white;
--dropdown_txt: black;
--vroot_active_bg: #dadada;
--dir_item_color: rgb(78, 78, 78);
--text_active: #23cc28;
--dir_bg: #f5f5f5;
--dir_txt: rgb(44, 44, 44);
--dir_border: rgba(219, 226, 241, 0.7);
--dir_hover_text: #a3a3a3;
--dir_hover_background: #f3f3f3;
--dir_hover_active: #c9e7f1;
--normal_object_txt: #303030;
--hex_folder_txt: #2b9447;
--um_file_txt: #69aaff;
--folder_view_background: #ffffff;
--folder_view_share: #24cc29;
--fileobject_background_hover: #f2f2f2;
--fileobject_background_selected: #d2f2f7;
--fileobject_text_selected: black;
--address_text_border:#cfcfcf;
--address_text_background: white;
--popup_bg: white;
--popup_border: rgb(226, 226, 226);
--popup_header_bg: #ffffff;
--popup_header_txt: #1f2328;
--popup_btn_border: #dedede;
--popup_btn_hover: rgba(238, 238, 238, 0.932);
--popup_btn_primary_bg: #51aded;
--popup_btn_primary_txt: white;
--popup_btn_primary_bg_hover: #76c0f5;
--popup_btn_negative_bg: #ed5151;
--popup_btn_negative_txt: white;
--popup_btn_negative_bg_hover: #f57676;
--modulelist_bg: white;
--modulelist_hover: rgba(35, 35, 35, 0.06);
--contextmenu_background: #ffffff;
--contextmenu_hover: #f9f9f9;
--contextmenu_textcolor: rgb(78, 78, 78);
/* Transfer panel bars. The pale legacy greens/reds washed out against the
new card surface, so these are the saturated status colours. */
--upload_progressbar: var(--fs-accent);
--upload_progresstext: rgb(255, 255, 255);
--upload_progress_succ: #1e8e3e;
--upload_progress_failed: #d93025;
--fs-danger-soft: #fce8e6;
--open_with_selected: #51aded;
--open_with_selected_text: white;
--open_with_item_hover_background:rgba(35,35,35,0.14);
--popup_wrapper_background: rgba(15, 20, 30, 0.18);
--code_bg: #f7f7f9;
--code_txt: #bd4147;
--uploadtab_bg: #f5f5f5;
--uploadtab_txt: rgb(78, 78, 78);
--upload_bg: #ffffff;
}
body.darkTheme{
/*
Legacy variable set, re-sampled to match the palette in
shared/fs-theme.css so the parts of the UI that still read these
(popups, upload tab, context menu, file object rows) sit in the same
colour family as everything already ported to the --fs-* tokens.
*/
/* ao.css's own dark values are a neutral grey; pull them onto the sampled
palette so semantic-ui widgets inside this app match the rest of it. */
--body_background: var(--fs-bg);
--body_text: var(--fs-text);
--text_color: var(--fs-text);
--text_color_secondary: var(--fs-text-dim);
--fileopr_btnTxt: #e6e9ee;
--fileopr_oprtxt: #c7ced7;
--fileopr_btnhover: #2a3039;
--divider: #272c34;
/* Surfaces come from the sampled tokens, not ao.css's --body_background_*.
Those resolve to a neutral grey that is lighter than the file area, which
inverts the mockup's depth order (content darkest, chrome above it). */
--navi_bgcolor: var(--fs-bg);
--navi_theme: var(--theme_color, #272c34);
--navi_theme_multiselect: #4a9eff;
--navi_txt: #c7ced7;
--dropdown_bg: #1c2129;
--dropdown_txt: #e6e9ee;
--vroot_active_bg: #262b33;
--dir_item_color: #c7ced7;
--text_active: #4a9eff;
--dir_bg: #14181d;
--dir_txt: #e6e9ee;
--dir_border: #272c34;
--dir_hover_text: #9aa3ae;
--dir_hover_background: #1f242c;
--dir_hover_active: #1e2d40;
--normal_object_txt: #e6e9ee;
--hex_folder_txt: #5fd48b;
--um_file_txt: #7db8ff;
--folder_view_background: var(--fs-content-bg);
--folder_view_share: #3ecf6d;
--fileobject_background_hover: #1f242c;
--fileobject_background_selected: #17293f;
--fileobject_text_selected: #e6e9ee;
--address_text_border: #272c34;
--address_text_background: #1c2129;
--popup_bg: #1c2129;
--popup_border: #272c34;
--popup_header_bg: #1c2129;
--popup_header_txt: #e6e9ee;
--popup_btn_border: #323945;
--popup_btn_hover: #2a3039;
--popup_btn_primary_bg: #4a9eff;
--popup_btn_primary_txt: #0d1014;
--popup_btn_primary_bg_hover: #6bb0ff;
--popup_btn_negative_bg: #e5484d;
--popup_btn_negative_txt: #ffffff;
--popup_btn_negative_bg_hover: #f06a6e;
--modulelist_bg: transparent;
--modulelist_hover: rgba(122, 138, 160, 0.18);
--contextmenu_background: #1c2129;
--contextmenu_hover: #2a3039;
--contextmenu_textcolor: #e6e9ee;
--upload_progressbar: var(--fs-accent);
--upload_progresstext: #0d1014;
--upload_progress_succ: #3ecf6d;
--upload_progress_failed: #e5484d;
--fs-danger-soft: #3a2224;
--open_with_selected: #1e3450;
--open_with_selected_text: #e6e9ee;
--open_with_item_hover_background: rgba(122, 138, 160, 0.16);
--popup_wrapper_background: rgba(0, 0, 0, 0.38);
--code_bg: #12161b;
--code_txt: #ff8f93;
--uploadtab_bg: #16191f;
--uploadtab_txt: #e6e9ee;
--upload_bg: #1c2129;
}
body{
color:var(--body_text);
background-color:var(--body_background);
height:100%;
overflow: hidden;
}
h1, h2, h3, p, span, div, input, .dropdown { font-family: "Microsoft JhengHei","SimHei", "Apple LiGothic Medium", "STHeiti"}
html{
height:100%;
overflow:hidden;
}
/* force override of semantic button rule */
body.darkTheme .ui.icon.button{
color: var(--text_color) !important;
}
/*
Navigation Bar
The top bar of the interface
see subparts for more detail configs
*/
.navibar{
width:100%;
padding-left:12px;
padding-right:12px;
padding-top:6px;
padding-bottom:3px;
z-index: 99;
background-color:var(--navi_bgcolor);
border-bottom:2px solid var(--navi_theme);
}
.navibar.ctrl{
border-bottom:2px solid var(--navi_theme_multiselect);
}
.navibar.mobile{
padding-top: 0;
}
.button.standard{
box-shadow: 0 1px 1px 0px rgb(190, 190, 190);
border: 0px;
}
.button.standard:hover{
background-color:#82c2f0 !important;
color:white !important;
}
/*
File operation bar
*/
.navibar .fileOprBtn{
vertical-align: top;
border: 1px solid transparent;
cursor: pointer;
background-color: transparent;
text-align: center;
padding-bottom: 0.4em;
padding-top: 0.5em;
border-radius: 0.4em;
}
.navibar .fileOprBtn:hover{
border: 1px solid var(--fileopr_btnhover);
opacity: 0.8;
}
.navibar .fileOprBtn .opricon{
width: 46px;
}
.navibar .fileOprBtn .oprtxt{
color:var(--fileopr_oprtxt);
}
.navibar .twolines.fileOprBtn{
padding-top: 0.1em;
padding-bottom: 0.1em;
}
.navibar .twolines.fileOprBtn .opricon{
width: 40px;
}
.navibar .twolines.fileOprBtn .oprtxt{
font-size: 1em;
}
.navibar.mobile .fileOprBtn{
padding-bottom: 0.4em;
padding-top: 0.2em;
border-radius: 0.4em;
}
.navibar.mobile .fileOprBtn .opricon{
width: 36px;
}
.navibar.mobile .twolines.fileOprBtn .opricon{
width: 28px;
}
.navibar.mobile .twolines.fileOprBtn .oprtxt{
font-size: 0.7em;
}
.navibar .fileoprSmallBtn{
cursor: pointer;
border: 1px solid transparent;
color:var(--navi_txt);
background-color: transparent;
padding: 0.3em;
width: fit-content;
text-align: left;
}
.navibar .fileoprSmallBtn:hover{
opacity: 0.8;
border: 1px solid var(--divider);
border-radius: 0.4em;
}
.navibar.mobile .fileoprSmallBtn{
font-size: 0.9em;
padding: 0.2em;
}
.navibar .fileoprGroupDivider{
padding-right: 0.2em;
margin-right: 0.2em;
border-right: 1px solid var(--divider);
height: 80px;
}
.navibar.mobile .fileoprGroupDivider{
height: 64px;
}
.ui.selection.dropdown{
background-color: var(--dropdown_bg) !important;
color: var(--dropdown_txt) !important;
min-width: 11.5em !important;
}
/* special case when using in mobile sidebar */
#mobileSortDropdown .ui.selection.dropdown{
width: 100%;
border-radius: 0;
padding: 1em;
}
.ui.selection.dropdown .menu > .item{
border-top-color:var(--divider);
background-color: var(--dropdown_bg) !important;
color: var(--dropdown_txt) !important;
}
.ui.selection.active.dropdown .menu{
border: 1px solid var(--divider) !important;
}
.ui.selection.visible.dropdown > .text:not(.default){
color: var(--text_color_secondary) !important;
}
/* Mobile interface */
.fileoprBtnMobile{
position: relative;
width: 100%;
background-color: none;
padding: 0.5em;
padding-left: 1em;
cursor: pointer;
}
#mobileNaviBar{
height: 100vh !important;
overflow-y: auto !important;
}
#mobileNaviBar .fileoprBtnMobile{
border-bottom: 1px solid var(--divider);
}
.fileoprBtnMobile:hover{
background-color: var(--popup_btn_hover) !important;
}
.fileoprBtnMobile .opricon{
width: 30px;
display: inline-block;
vertical-align: middle;
margin-right: 0.4em;
}
.fileoprBtnMobile p{
display: inline-block;
vertical-align: middle;
}
.fileoprSmallBtnMobile{
cursor: pointer;
border: 1px solid transparent;
color:var(--navi_txt);
background-color: transparent;
padding: 0.5em;
padding-left: 1em;
width: 100%;
text-align: left;
}
#mobileNaviBar .fileoprSmallBtnMobile{
border-bottom: 1px solid var(--divider);
}
.fileoprSmallBtnMobile:hover{
background-color: var(--popup_btn_hover) !important;
}
/*
Address and search bar
*/
.navibarBtn{
cursor: pointer;
border: 1px solid transparent;
color:var(--navi_txt);
background-color: transparent;
padding: 0.3em;
display: inline-block;
border-radius: 0.4em;
padding-right: 0.1em;
padding-bottom: 0.4em;
margin-left: 0.2em;
}
.navibarBtn:hover{
opacity: 0.8;
border: 1px solid var(--divider);
}
.navibarBtn.disabled{
pointer-events: none;
opacity: 0.5;
user-select: none;
}
/* Special button for switching over to dark theme*/
.navibarBtn.DarkThemeToggle.inverted{
color:var(--dark_theme_toggle_text);
background-color: var(--dark_theme_toggle);
}
.navibarBtn.DarkThemeToggle{
color: var(--white_theme_toggle_text);
background-color: var(--white_theme_toggle);
}
.navibarBtn.DarkThemeToggle:hover{
border: 1px solid transparent;
}
.navibarBtn:hover{
opacity: 0.8;
}
/* View mode buttons */
.videmode.button{
color:var(--navi_txt) !important;
background-color: transparent;
}
.videmode.button:hover{
background-color: transparent;
opacity: 0.8;
}
.videmode.button:focus:not(#togglePropertiesViewBtn){
background-color: transparent !important;
}
.addressBar{
border-top: 1px solid var(--divider);
width:100%;
padding: 0.4em;
padding-left: 0;
padding-right: 0;
padding-top: 0.6em;
min-height: 35px;
margin-top:0.4em;
vertical-align: top;
display: flex;
position: relative;
}
.addressBar .divider{
color: var(--text_color_secondary) !important;
}
#pathDisplayField{
margin-left: 0.4em !important;
}
.addressText{
padding:5px;
border-radius: 0.5em;
/* border: 1px solid var(--address_text_border); */
flex-grow: 1;
background-color: var(--address_text_background);
}
#pathInputField{
margin-left: 0.4em !important;
font-size: 1rem;
height: 27px;
width: 100%;
}
#pathInputField input{
background-color: var(--address_text_background);
color: var(--text_color);
}
.selectable{
cursor:pointer;
}
.viewportBtns.mobile{
order: 2;
margin-left: auto !important;
height: 30px;
border-right: none;
margin-top: -10px;
}
/* Mobile file operation menus */
.mobileFileOprMenu{
position: fixed;
top: 0.6em;
right: 0.6em;
background-color: var(--navi_bgcolor);
border: none;
color: var(--text_color);
cursor: pointer;
width: 50px;
height: 50px;
padding-top: 4px;
padding-left: 10px;
border-radius: 0.4em;
}
.mobileFileOprMenu:hover{
opacity: 0.8;
}
.mobileFileOprMenuToggle{
padding: 1em;
border: 0px solid transparent;
color: var(--text_color);
border-bottom:2px solid var(--navi_theme);
text-align: right;
cursor: pointer;
}
.mobileFileOprMenuToggle .logo{
position: absolute;
top: 0.8em;
left: 0.5em;
width: 100px;
opacity: 0.6;
}
/*
Search bar
*/
.searchbar{
width:100%;
padding: 0.4em;
padding-left: 0;
padding-right: 0;
min-height: 35px;
margin-top:0.4em;
vertical-align: top;
display: flex;
align-items: center;
}
.searchbar .searInputBar{
flex-grow: 1;
}
.searchbar .navibarBtn.active{
color: var(--text_active);
font-weight: bold;
}
/*
Main Window scalling
*/
#mainWindow{
display: flex;
align-items:flex-start;
}
/*
Directory Sidebar
*/
#directorySidebar{
padding-top:1em;
padding-bottom: 1em;
overflow-y:auto;
padding-bottom:20px;
border-right:2px solid var(--dir_border);
background-color:var(--dir_bg);
color:var(--dir_txt);
/*
Starting size only. splitter.js rewrites width and min-width together as
the handle is dragged - min-width is what stops flexbox from shrinking
the pane, so it has to follow width down rather than pin it.
*/
width: 250px;
min-width: 250px;
flex: 0 0 auto;
scrollbar-width: thin;
}
.rightmargin.icon{
margin-right:8px !important;
}
.dir{
cursor:pointer;
}
.dir:not(.active):hover{
color: var(--dir_hover_text) !important;
}
.dir.active:hover{
background-color:var(--dir_hover_active);
}
.dir.item{
padding-top: 0.4em !important;
padding-bottom: 0.4em !important;
padding-left: 1.4em !important;
padding-right: 1.4em !important;
color:var(--dir_item_color);
}
.vroot.active{
background-color: var(--vroot_active_bg);
}
#selectInfo{
padding-left: 1.2em;
padding-right: 1.2em;
color: var(--text_color_secondary);
}
.pathDisplay{
cursor: text;
overflow:hidden;
white-space: nowrap;
text-align: left;
}
.measure {
position: absolute;
visibility: hidden;
left: -1000px;
top: -1000px;
}
/*
Folder Viewer (Main viewer)
*/
/*
Pane splitters
A 7px grab strip that straddles the border between two panes. The negative
side margins pull its own width back out of the flex line, so adding the
handle does not shift the layout by a pixel - it sits on top of the border
that was already there.
Hidden on the touch layout: splitter.js does not bind them there, and a
7px target is not a sensible touch affordance anyway.
*/
.fmSplitter{
flex: 0 0 auto;
align-self: stretch;
width: 7px;
margin-left: -3px;
margin-right: -4px;
position: relative;
z-index: 6;
cursor: col-resize;
background-color: transparent;
transition: background-color 0.12s ease;
}
.fmSplitter:hover,
.fmSplitter.dragging{
background-color: var(--fs-accent);
opacity: 0.55;
}
/*
While a handle is being dragged the pointer regularly ends up over the panes
either side of it. Without this the cursor flickers back to the default and
stray text gets selected on the way past.
*/
body.fmResizing{
cursor: col-resize;
user-select: none;
-webkit-user-select: none;
}
body.fmResizing *{
cursor: col-resize !important;
user-select: none;
-webkit-user-select: none;
}
#folderView{
flex-grow:1;
padding-left:2em;
padding-right:2em;
padding-top:1.4em;
overflow-y:auto;
background-color: var(--folder_view_background);
scrollbar-width: thin;
}
#folderList{
margin-bottom:1em;
}
.fileviewList{
position: relative;
}
/* Common spacing for list view and grid view */
.fileviewList .fileObject.item,.fileviewList .fileObject.card{
display:block !important;
cursor:pointer;
overflow-wrap: break-word !important;
user-select: none;
border: 1px solid var(--divider);
}
/*
Hidden entries, shown only when the user turns them on. Dimmed so they stay
distinguishable from ordinary content at a glance; they lift to full
strength on hover and while selected so they are still readable to work
with.
*/
.fileObject[data-hidden="true"]{
opacity: 0.45;
}
.fileObject[data-hidden="true"]:hover,
.fileObject[data-hidden="true"].selected{
opacity: 1;
}
.fileviewList .fileObject.item:hover,.fileviewList .fileObject.card:hover{
background-color: var(--fileobject_background_hover) !important;
}
.fileviewList .fileObject.item.selected, .fileviewList .fileObject.card.selected{
background-color: var(--fileobject_background_selected) !important;
color: var(--fileobject_text_selected) !important;
}
/* Filelist in list mode */
.fileviewList .fileObject.item{
padding: 0.8em;
padding-left: 1.2em;
padding-right: 1em;
}
.fileviewList .fileObject.item:first-child{
border-top-left-radius: 0.4em;
border-top-right-radius: 0.4em;
}
.fileviewList .fileObject.item:last-child{
border-bottom-left-radius: 0.4em;
border-bottom-right-radius: 0.4em;
}
.fileviewList .fileObject.item.selected.renaming{
padding-top: 0.6em !important;
padding-bottom: 0.6em !important;
}
.fileviewList .fileObject.item:not(:first-child) {
border-top: 0;
}
/* Filelist in grid mode.
Width is set by the status bar zoom slider (--fm-tile / inline style), so the
old fixed 148px !important is gone - it silently defeated the slider. */
.fileviewList .fileObject.card{
border-radius: 0.4em;
position: relative;
margin-bottom: 1em;
}
/*
Grid tiles are square at every width. aspect-ratio keeps the box square so
the responsive breakpoint no longer has to fight fixed pixel sizes.
Icons use contain so they are never distorted; a real thumbnail (marked by
.hasThumbnail from thumbnail.js) uses cover so it fills the square instead
of letterboxing.
display:block matters as much as the sizing here: an inline sits on
the text baseline, which leaves a few pixels of the container's background
showing as a grey strip under every thumbnail.
*/
.fileviewList .fileObject.card img{
display: block;
width: 100%;
aspect-ratio: 1 / 1;
height: auto;
object-fit: contain;
}
.fileviewList .fileObject.card.hasThumbnail img{
object-fit: cover;
object-position: center;
}
/*
The tinted plate behind an icon is there to give a bare glyph a surface. A
real thumbnail covers the whole square, so keeping the plate only risks it
peeking out along an edge.
*/
.fileviewList .fileObject.card.hasThumbnail .image{
background: transparent;
}
.fileviewList .fileObject.card .content{
padding-left: 1em;
padding-right: 1em;
padding-top: 1em;
padding-bottom: 0.4em;
}
/* Share icon overlay for card view */
.fileviewList .fileObject.card .image{
position: relative;
}
.fileviewList .fileObject.card .shareOverlay.visible{
position: absolute;
bottom: 0.4em;
left: 0.4em;
padding-top: 4px;
background-color: var(--navi_bgcolor);
height: 28px;
width: 28px;
border-radius: 0.4em;
border: 1px solid var(--divider);
box-shadow: 3px 1px 5px 1px rgba(158,158,158,0.2);
opacity: 0.9;
}
.fileviewList .fileObject.card .content .header{
font-size: 1.2em;
font-weight: 500;
color: var(--text_color);
}
.fileviewList .fileObject.card .content .meta{
font-size: 0.9em;
color: var(--text_color_secondary);
}
.fileviewList .fileObject.card .content .description{
font-size: 1em;
color: var(--text_color);
position: absolute;
bottom: 1em;
left: 1em;
}
/* fileview in detail mode */
.fileviewList .fileObject.details{
cursor:pointer;
user-select: none;
border: 1px solid var(--divider);
color: var(--text_color);
}
.fileviewList .fileObject.details:hover{
background-color:var(--fileobject_background_hover) !important;
}
.fileviewList .fileObject.details.selected{
background-color:var(--fileobject_background_selected) !important;
}
#folderView th{
color: var(--text_color);
}
.fileviewList .fileObject.details.selected.renaming td:first-child{
padding: inherit;
}
.fileviewList .detailTableContent tr td:first-child{
padding-left: 1em !important;
}
.fileviewList .fileObject.details .light-text{
color: var(--text_color_secondary);
}
/* Share button */
.sharebtn{
cursor: pointer;
border: 1px solid transparent;
background-color: transparent;
color: var(--folder_view_share);
margin-left: 4px;
margin-top: 1px;
}
/* Handle specific Chrome bug in rendering the share icon */
@media screen and (-webkit-min-device-pixel-ratio:0)
and (min-resolution:.001dpcm) {
.sharebtn{
padding: 0 !important;
}
}
.sharebtn:hover{
opacity: 0.5;
}
/*
Properties View
*/
#propertiesView{
/* Starting size only - see the note on #directorySidebar */
width: 300px;
min-width: 300px;
flex: 0 0 auto;
padding: 1em;
overflow-y: auto;
scrollbar-width: thin;
color: var(--text_color);
border-left: 1px solid var(--divider);
background-color: var(--folder_view_background);
}
/*
Permission grid in the properties panel. Compact enough to sit inside the
properties table cell without stretching the panel.
*/
#propertiesView .fmPermTable{
border-collapse: collapse;
width: auto;
font-size: 12px;
line-height: 1.3;
}
#propertiesView .fmPermTable th{
padding: 1px 7px 3px 7px;
font-weight: 400;
color: var(--fs-text-dim) !important;
text-align: center;
white-space: nowrap;
}
#propertiesView .fmPermTable td{
padding: 1px 7px;
text-align: center;
}
#propertiesView .fmPermTable td.fmPermWho{
padding-left: 0px;
padding-right: 10px;
text-align: left;
color: var(--fs-text-dim) !important;
white-space: nowrap;
}
/* Granted reads as present, denied as a quiet dash rather than a red cross */
#propertiesView .fmPermTable td.fmPermOn{
color: var(--upload_progress_succ) !important;
}
#propertiesView .fmPermTable td.fmPermOff{
color: var(--fs-text-faint) !important;
}
#propertiesView td, #propertiesView span, #propertiesView div{
color: var(--text_color);
}
/*
Context Menu
This is a complete rewrite / re-implement of the
ts contextmenu after migration
*/
/*
Styled to match the .fsMenu component in shared/fs-components.css so the
right click menu, the "..." menu and the sort menu all read as the same
control: rounded card, inset rows that round on hover, and icons a step
dimmer than the label text.
*/
.contextmenu{
position: fixed;
display: none;
width: 200px;
padding: 4px;
background-color: var(--contextmenu_background);
border: 1px solid var(--divider);
border-radius: 10px;
-webkit-box-shadow: 0px 8px 28px var(--fs-shadow);
-moz-box-shadow: 0px 8px 28px var(--fs-shadow);
box-shadow: 0px 8px 28px var(--fs-shadow);
z-index: 999;
max-height: calc(100vh - 16px);
overflow-y: auto;
}
.contextmenu.visible{
display: block;
}
.contextmenu .item{
display: flex;
align-items: center;
gap: 7px;
padding: 5px 7px;
border-radius: 6px;
cursor: pointer;
font-size: 13.5px;
white-space: nowrap;
color: var(--contextmenu_textcolor);
}
.contextmenu .item:hover{
background-color: var(--contextmenu_hover);
}
/* Label expands to fill the row so the trailing element is always right-aligned */
.contextmenu .item > span:not(.description){
flex-grow: 1;
}
/*
The rows carry semantic-ui font icons. Pin to a fixed box and push to the
trailing edge with margin-left: auto. Items that carry a .description
(Copy / Paste / Cut) hide their icon — the hotkey text is the indicator.
The colour needs !important: ao.css styles every and under a
themed body with a blanket rule whose :not() chain scores higher than any
reasonable selector here, so it would otherwise repaint the icons to the
same colour as the label and flatten the two-tone look.
*/
.contextmenu .item > i.icon{
width: 16px;
min-width: 16px;
height: auto;
margin-left: auto;
font-size: 14px;
text-align: center;
color: var(--fs-icon) !important;
opacity: 0.6;
}
/* Items that already show a hotkey — no icon needed */
.contextmenu .item.hasHotkey > i.icon {
display: none;
}
/* Keyboard hint, pushed to the trailing edge */
.contextmenu .description{
margin-left: auto;
color: var(--fs-text-faint) !important;
font-size: 12px;
}
.contextmenu .divider{
width: auto;
height: 1px;
margin: 3px;
background-color: var(--fs-line-soft);
border-bottom: 0px;
}
/*
Message box and popups
*/
/*
Toast
A dark pill centred along the bottom edge. It auto dismisses, and the
trailing button closes it early.
Colours are hardcoded to the toast tokens rather than the theme surfaces:
the pill floats above the content instead of belonging to it, so it stays
dark in the light theme too. That also means #msgbox has to win over the
blanket ao.css rule that paints every span and under a themed body,
which the id in the selector does without needing !important.
*/
#msgbox.msgbox{
position: fixed;
bottom: 24px;
left: 50%;
transform: translateX(-50%) translateY(10px);
z-index: 999;
display: flex;
align-items: center;
gap: 11px;
max-width: min(560px, calc(100% - 32px));
padding: 11px 10px 11px 18px;
border-radius: 999px;
background-color: var(--fs-toast-bg);
color: var(--fs-toast-fg);
box-shadow: 0px 6px 22px rgba(0, 0, 0, 0.35);
opacity: 0;
transition: opacity 0.18s ease, transform 0.18s ease;
/*
Belt and braces with the display:none that hideMsgBox sets after the
fade: while faded out the pill must never swallow clicks aimed at the
content beneath it, and that must not depend on a timer firing.
*/
pointer-events: none;
}
#msgbox.msgbox.visible{
opacity: 1;
transform: translateX(-50%) translateY(0px);
pointer-events: auto;
}
#msgbox.msgbox.error{
background-color: var(--fs-toast-error-bg);
color: var(--fs-toast-error-fg);
}
#msgbox .msgboxText{
flex: 1 1 auto;
min-width: 0px;
color: inherit;
font-size: 13.5px;
line-height: 1.45;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
#msgbox > i.icon{
flex: 0 0 auto;
width: 16px;
height: auto;
margin: 0px;
font-size: 15px;
text-align: center;
color: inherit;
opacity: 0.9;
}
#msgbox .closeMsgButton{
flex: 0 0 auto;
width: 26px;
height: 26px;
display: flex;
align-items: center;
justify-content: center;
border-radius: 50%;
cursor: pointer;
color: var(--fs-toast-dim);
}
#msgbox.msgbox.error .closeMsgButton{
color: var(--fs-toast-error-fg);
opacity: 0.85;
}
#msgbox .closeMsgButton:hover{
background-color: rgba(255, 255, 255, 0.14);
color: var(--fs-toast-fg);
}
#msgbox .closeMsgButton svg{
width: 15px;
height: 15px;
display: block;
}
/*
File operation dialogs
The embedded dialogs (overwrite, delete, rename, new file/folder, share,
open with). Drawn as a rounded card docked to the right edge rather than a
full bleed panel with a dark title bar.
The progress dialog that runs in a floatWindow over a websocket is a
separate page and is deliberately not restyled here.
*/
.popup{
position: fixed;
/*
Anchored to the bottom right and only as tall as its content: top is
deliberately auto, because pinning both top and bottom is what used to
stretch a three line confirmation over the full window height. The cap
keeps a long file list inside the viewport, and .popupcontent scrolls
once that cap is reached.
*/
top: auto;
right: 10px;
bottom: 10px;
/* Above the transfer panel (500), below the toast and context menu (999) */
z-index: 601;
width: 23em;
max-width: calc(100% - 20px);
max-height: calc(100% - 20px);
display: flex;
flex-direction: column;
overflow: hidden;
border: 1px solid var(--popup_border);
border-radius: 12px;
background-color: var(--popup_bg);
box-shadow: 0px 8px 28px var(--fs-shadow);
}
.popup.wide{
width: 44em;
}
/*
The header carries the card's own surface now. It used to be a dark bar with
an accent underline, which read as a separate title bar sitting on top of
the panel rather than part of one card.
*/
.popupheader{
flex: 0 0 auto;
display: flex;
align-items: center;
gap: 9px;
width: 100%;
height: auto;
padding: 12px 10px 12px 16px;
border-bottom: 1px solid var(--divider);
background-color: var(--popup_header_bg);
color: var(--popup_header_txt);
font-size: 14px;
}
/*
The title is a bare text node between the icon and the closer, so it cannot
be targeted directly - pushing the closer instead is what right aligns it.
*/
.popupheader > span{
flex: 1 1 auto;
min-width: 0px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.popupheader > i.icon{
flex: 0 0 auto;
width: 16px;
margin: 0px;
font-size: 15px;
text-align: center;
opacity: 0.85;
}
.popupcontent{
/*
Grows to its content and only shrinks when the card hits its cap.
min-height:0 is what lets it actually scroll then - a flex item's
default min-height:auto refuses to shrink below its content.
*/
flex: 0 1 auto;
min-height: 0;
height: auto;
padding: 14px 16px 16px 16px;
overflow-y: auto;
overflow-x: hidden;
scrollbar-width: thin;
color: var(--normal_object_txt);
}
.popupcontent p,
.popupcontent small{
color: var(--fs-text-dim) !important;
line-height: 1.5;
}
.popupcloser{
position: static;
flex: 0 0 auto;
width: 26px;
height: 26px;
display: flex;
align-items: center;
justify-content: center;
border-radius: 6px;
font-size: 100%;
cursor: pointer;
opacity: 0.75;
}
.popupcloser:hover{
background-color: var(--popup_btn_hover);
opacity: 1;
}
.popupcloser i.icon{
margin: 0px;
}
/* ---------- Option rows ---------- */
.popupbuttons{
display: flex;
align-items: center;
gap: 10px;
cursor: pointer;
padding: 10px 13px;
margin-bottom: 7px;
border: 1px solid var(--popup_btn_border);
border-radius: 9px;
font-size: 13.5px;
line-height: 1.35;
color: var(--normal_object_txt);
}
.popupbuttons > i.icon{
flex: 0 0 auto;
width: 16px;
height: auto;
margin: 0px;
font-size: 14px;
text-align: center;
opacity: 0.75;
}
.popupbuttons.primary{
background-color: var(--popup_btn_primary_bg);
border: 1px solid transparent;
color: var(--popup_btn_primary_txt) !important;
}
.popupbuttons.primary > i.icon{
color: var(--popup_btn_primary_txt) !important;
opacity: 1;
}
.popupbuttons.negative{
background-color: var(--popup_btn_negative_bg);
border: 1px solid transparent;
color: var(--popup_btn_negative_txt) !important;
}
.popupbuttons.negative > i.icon{
color: var(--popup_btn_negative_txt) !important;
opacity: 1;
}
.popupbuttons.disabled{
opacity: 0.4;
pointer-events: none;
}
.popupbuttons.primary.disabled{
opacity: 0.4;
pointer-events: none;
}
/* Rename dialog */
.renameinput input{
box-shadow: none;
border: 1px solid var(--divider);
padding-left: 0.4em;
padding-right: 0.4em;
padding-top: 0.2em;
padding-bottom: 0.2em;
width: 100%;
}
.renameinput input:focus {
outline: none !important;
border: 1px solid var(--navi_theme);
}
.allowHover:hover{
background-color:var(--popup_btn_hover);
}
.allowHover.primary:hover{
background-color:var(--popup_btn_primary_bg_hover);
}
.allowHover.negative:hover{
background-color:var(--popup_btn_negative_bg_hover);
}
.newFileFormat{
cursor:pointer;
}
.popupWrapper{
position:fixed;
top:0px;
left:0px;
width:100%;
height:100%;
/* Directly under .popup, so the scrim covers the transfer panel too */
z-index:600;
background-color: var(--popup_wrapper_background);
display:none;
}
/*
The scrim is much lighter than it used to be, and no longer blurs: the
mockup shows the file list plainly behind the card. Some dimming is kept
rather than none, because the wrapper still swallows clicks - an invisible
overlay that silently eats them would be worse than a faint one that
explains itself.
*/
/*
The Open With picker. Laid out like the standalone opener dialog
(SystemAO/file_system/defaultOpener.html): the WebApps that registered the
selected file's extension are listed first and everything else stays folded
behind the toggle row, so a long module list no longer buries the two apps
that can actually open the file.
The box grows with its content up to a cap rather than always standing 50vh
tall - a two app suggestion list used to leave most of the card empty.
*/
#openWithModuleList{
max-height:42vh;
overflow-y:auto;
overflow-x:hidden;
scrollbar-width: thin;
padding: 4px;
background-color: var(--modulelist_bg);
border: 1px solid var(--divider);
border-radius: 8px;
}
#openWithModuleList .ui.avatar.image, #openWithModuleList .ui.avatar.image img, #openWithModuleList .ui.avatar.image svg, #openWithModuleList .ui.avatar.images .image, #openWithModuleList .ui.avatar.images img, #openWithModuleList .ui.avatar.images svg{
flex: 0 0 auto;
width: 28px;
height: 28px;
margin: 0px;
border-radius: 0;
object-fit: contain;
}
.openWithSectionLabel{
padding: 6px 8px 4px 8px;
color: var(--fs-text-dim);
font-size: 12.5px;
}
#openWithModuleList .item{
padding: 8px 10px;
border-radius: 6px;
display: flex;
align-items: center;
gap: 10px;
}
#openWithModuleList .item .content{
flex: 1 1 auto;
min-width: 0px;
}
#openWithModuleList .item .header{
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
/* Hidden until the row is picked, so the list does not look pre-ticked */
#openWithModuleList .item .tick{
flex: 0 0 auto;
width: 20px;
text-align: center;
color: inherit;
visibility: hidden;
}
#openWithModuleList .item.selected .tick{
visibility: visible;
}
#openWithModuleList .item:hover{
background-color: var(--modulelist_hover) !important;
}
#openWithModuleList .item.selected{
background-color: var(--open_with_selected) !important;
color:var(--open_with_selected_text);
}
#openWithModuleList .item.selectable:hover{
background-color:var(--open_with_item_hover_background);
}
/* The one row that unfolds the WebApps which did not register this file type */
.openWithToggleRow{
display: flex;
align-items: center;
gap: 10px;
padding: 8px 10px;
margin-top: 4px;
border-top: 1px solid var(--divider);
border-radius: 6px;
color: var(--fs-text-dim);
cursor: pointer;
user-select: none;
}
.openWithToggleRow:hover{
background-color: var(--open_with_item_hover_background);
}
.openWithToggleRow i.icon{
flex: 0 0 auto;
width: 20px;
margin: 0px;
text-align: center;
}
.openWithEmptyNote{
padding: 14px 10px;
text-align: center;
color: var(--fs-text-dim);
font-size: 13px;
}
/*
New Item List
*/
.newfilelist{
border: 1px solid var(--divider);
border-radius: 0.4em;
margin-bottom: 0.6em;
}
.newfilelist .item{
padding: 0.6em;
}
.newfilelist .item:not(:last-child){
border-bottom: 1px solid var(--divider);
}
.newfilelist .item.selected{
background-color: var(--open_with_selected) !important;
color:var(--open_with_selected_text);
}
/*
Transfer panel
The floating upload / zip task card at the bottom right. Markup shell lives
in file_explorer.html, rows are drawn by js/explorer/uploadui.js.
*/
/*
Floats above the status bar rather than over it, so the tray buttons (the
upload list toggle included) stay clickable. --fm-statusbar-h is measured
by applyUploadPanelVisibility(); the fallback is the bar's usual height.
*/
#uploadTab{
position: fixed;
right: 8px;
bottom: calc(var(--fm-statusbar-h, 39px) + 10px);
width: 360px;
max-width: calc(100% - 32px);
background-color: var(--upload_bg);
border: 1px solid var(--divider);
border-radius: 12px;
box-shadow: 0px 8px 28px var(--fs-shadow);
overflow: hidden;
z-index: 500;
}
/* ---------- Header ---------- */
#uploadTab .uploadHeader{
display: flex;
align-items: center;
gap: 4px;
padding: 12px 10px 12px 16px;
background-color: var(--uploadtab_bg);
}
#uploadTab .uploadHeaderTitle{
flex: 1 1 auto;
min-width: 0px;
font-size: 15px;
color: var(--uploadtab_txt);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
#uploadTab .uploadHeaderBtn{
flex: 0 0 auto;
width: 28px;
height: 28px;
display: flex;
align-items: center;
justify-content: center;
border-radius: 6px;
cursor: pointer;
color: var(--fs-icon);
}
#uploadTab .uploadHeaderBtn:hover{
background-color: var(--fs-fill-hover);
}
#uploadTab .uploadHeaderBtn svg{
width: 17px;
height: 17px;
display: block;
}
/* ---------- Task list ---------- */
#uploadTab .uploadList{
padding: 0px 16px;
max-height: 300px;
overflow-y: auto;
overflow-x: hidden;
scrollbar-width: thin;
}
/*
Three rows: name, byte counter + status, progress bar. The action button
spans the first two so it centres against the text block while the bar
still runs the full width of the card.
*/
#uploadTab .uploadTask{
display: grid;
grid-template-columns: 1fr auto;
column-gap: 10px;
padding: 14px 0px 2px 0px;
}
#uploadTab .uploadTaskName{
grid-column: 1;
grid-row: 1;
font-size: 13.5px;
line-height: 1.45;
color: var(--normal_object_txt);
word-break: break-word;
overflow: hidden;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
}
#uploadTab .uploadTaskMeta{
grid-column: 1;
grid-row: 2;
display: flex;
align-items: center;
justify-content: space-between;
gap: 10px;
margin-top: 7px;
font-size: 12px;
color: var(--fs-text-dim);
}
#uploadTab .uploadTaskSize,
#uploadTab .uploadTaskStatus{
color: var(--fs-text-dim);
}
/*
A row with no byte counter has an empty size cell, and the flex gap after it
would indent whatever comes next - which is what the download link on a
finished download would otherwise be, sitting a notch right of the task name
*/
#uploadTab .uploadTaskSize:empty{
display: none;
}
/*
Byte counters update several times a second, so every glyph has to keep its
x position or the text is unreadable. Two things are needed: tabular figures
so "1" occupies the same advance as "8", and a fixed cell per part so a
changing digit count cannot push the neighbouring parts around.
Widths are in ch (the width of a digit at the current size), so they track
the font rather than assuming one.
*/
#uploadTab .uploadTaskSize,
#uploadTab .uploadSummaryText{
font-variant-numeric: tabular-nums;
-moz-font-feature-settings: "tnum";
-webkit-font-feature-settings: "tnum";
font-feature-settings: "tnum";
}
/* Right aligned: the ones column stays put as the value grows into 4 digits */
#uploadTab .uploadNum{
display: inline-block;
text-align: right;
}
/*
Left aligned and padded off the number, so the unit starts at a fixed x.
This one is a hard width, not a min-width: unit letters are not digit width
and differ from each other ("MB" is wider than "KB", which is wider than
"B"), so a min-width still lets the cell grow and shove everything after it
when a transfer crosses a unit boundary. The value is sized for the widest
unit rather than measured per string.
*/
#uploadTab .uploadUnit{
display: inline-block;
width: 4.4ch;
text-align: left;
padding-left: 4px;
}
#uploadTab .uploadSep{
display: inline-block;
width: 16px;
text-align: center;
}
/* The summary's overall percentage: its own right aligned cell, like the numbers */
#uploadTab .uploadPct{
display: inline-block;
min-width: 4ch;
margin-left: 8px;
text-align: right;
}
/*
Always the right hand end of the status line, whatever is to its left: a
byte counter, the download link of a finished download, or nothing at all.
An auto margin rather than the row's space-between, which only reaches the
edge when there happen to be two items on the line.
*/
#uploadTab .uploadTaskStatus{
flex: 0 0 auto;
margin-left: auto;
white-space: nowrap;
}
/*
The action column holds up to two controls: cancel, which only appears once
the transfer is paused, and the main pause/resume/retry button. Cancel is
deliberately hidden while uploading - the pause button is the one to reach
for, and putting a destructive control next to it invites misclicks.
*/
#uploadTab .uploadTaskActions{
grid-column: 2;
grid-row: 1 / span 2;
/*
Bottom rather than centre: the column spans the name and the status
line, and centring it hung the buttons between the two with a gap under
them. Ending the column lines their base up with the status text.
*/
align-self: end;
display: flex;
align-items: center;
gap: 2px;
}
#uploadTab .uploadTaskCancel{
display: none;
width: 28px;
height: 28px;
align-items: center;
justify-content: center;
border-radius: 50%;
cursor: pointer;
color: var(--fs-text-faint);
}
#uploadTab .uploadTask.paused .uploadTaskCancel{
/*
Shown by state class alone, so nothing has to rewrite this button on a
progress tick - which is what used to swallow clicks on its neighbour.
*/
display: flex;
}
#uploadTab .uploadTaskCancel:hover{
background-color: var(--fs-fill-hover);
color: var(--upload_progress_failed);
}
#uploadTab .uploadTaskCancel svg{
width: 22px;
height: 22px;
display: block;
pointer-events: none;
}
/*
The "Download again" link on a finished download.
A completed download row shows this instead of the tick: the browser may
have blocked the download that started on its own, and a tick would then be
the only thing on screen while nothing had actually been saved.
It lives in the status line rather than the button column, so it reads as
one row with the label opposite it - the link at the left of the line, and
"Completed" pinned to its right hand end.
*/
#uploadTab .uploadTaskDoneLink{
display: none;
white-space: nowrap;
color: var(--upload_progressbar);
cursor: pointer;
}
#uploadTab .uploadTask.withDoneLink .uploadTaskDoneLink{
display: inline-block;
}
#uploadTab .uploadTaskDoneLink:hover{
text-decoration: underline;
}
/* No control on a finished row - see renderUploadTask() */
#uploadTab .uploadTask.done .uploadTaskAction{
display: none;
}
#uploadTab .uploadTaskAction{
width: 30px;
height: 30px;
display: flex;
align-items: center;
justify-content: center;
border-radius: 50%;
cursor: pointer;
color: var(--upload_progressbar);
}
#uploadTab .uploadTaskAction svg{
width: 26px;
height: 26px;
display: block;
/*
The glyph must not be the event target. It is swapped out whenever the
task changes state, and a press that spans the swap would leave mousedown
and mouseup on two different elements - which produces no click at all.
Letting the pointer fall through to the button itself makes the whole
30px control clickable regardless of what the icon does underneath.
*/
pointer-events: none;
}
/* A failed row uses the "Retry" text link in the status line instead of the button */
#uploadTab .uploadTask.failed .uploadTaskAction{
display: none;
}
#uploadTab .uploadTaskRetry{
display: none;
flex: 0 0 auto;
white-space: nowrap;
color: var(--upload_progressbar);
cursor: pointer;
}
#uploadTab .uploadTask.failed .uploadTaskRetry{
display: inline-block;
margin-left: -2px;
}
#uploadTab .uploadTask.failed .uploadTaskRetry::before{
content: "";
display: inline-block;
width: 1px;
height: 12px;
margin-right: 10px;
vertical-align: -2px;
background-color: var(--fs-line);
}
#uploadTab .uploadTaskRetry:hover{
text-decoration: underline;
}
#uploadTab .uploadTaskAction:hover{
background-color: var(--fs-fill-hover);
}
/* ---------- Progress bar ---------- */
#uploadTab .uploadTaskBar{
grid-column: 1 / -1;
grid-row: 3;
height: 4px;
margin-top: 10px;
border-radius: 999px;
background-color: var(--fs-line);
overflow: hidden;
}
#uploadTab .uploadTaskBarFill{
width: 0%;
height: 100%;
border-radius: 999px;
background-color: var(--upload_progressbar);
transition: width 0.2s linear;
}
#uploadTab .uploadTask.done .uploadTaskBarFill{
background-color: var(--upload_progress_succ);
}
#uploadTab .uploadTask.failed .uploadTaskBarFill{
background-color: var(--upload_progress_failed);
}
#uploadTab .uploadTask.paused .uploadTaskBarFill{
background-color: var(--fs-text-faint);
}
/* A task with no announced total sweeps instead of filling */
#uploadTab .uploadTask.indeterminate .uploadTaskBarFill{
width: 40%;
transition: none;
animation: uploadSweep 1.4s ease-in-out infinite;
}
@keyframes uploadSweep {
0% { transform: translateX(-105%); }
100% { transform: translateX(255%); }
}
/* ---------- Summary row ---------- */
#uploadTab .uploadSummary{
display: flex;
align-items: center;
gap: 10px;
padding: 12px 16px;
margin-top: 6px;
border-top: 1px solid var(--divider);
}
#uploadTab .uploadSummaryIcon{
flex: 0 0 auto;
color: var(--fs-icon);
}
#uploadTab .uploadSummaryIcon svg{
width: 19px;
height: 19px;
display: block;
}
/* The filled part of the ring, sized by setUploadSummaryRing() */
#uploadTab .uploadSummaryIcon .taskProgressArc{
color: var(--upload_progressbar);
transition: stroke-dasharray 0.25s linear;
}
#uploadTab .uploadSummaryText{
flex: 1 1 auto;
min-width: 0px;
font-size: 12.5px;
color: var(--fs-text-dim);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
/* ---------- Footer buttons ---------- */
#uploadTab .uploadActions{
display: flex;
align-items: center;
gap: 10px;
padding: 4px 16px 16px 16px;
}
#uploadTab .uploadActionBtn{
display: flex;
align-items: center;
gap: 7px;
padding: 8px 14px;
border: 1px solid var(--popup_btn_border);
border-radius: 8px;
cursor: pointer;
font-size: 12.5px;
white-space: nowrap;
color: var(--normal_object_txt);
}
#uploadTab .uploadActionBtn:hover{
background-color: var(--fs-fill-hover);
}
#uploadTab .uploadActionBtn svg{
width: 15px;
height: 15px;
display: block;
color: var(--fs-icon);
}
#uploadTab .uploadActionBtn.primary{
margin-left: auto;
border-color: var(--upload_progressbar);
color: var(--upload_progressbar);
}
#uploadTab .uploadActionBtn.primary:hover{
background-color: var(--fs-accent-soft);
}
/*
Minimized card (#uploadTab.compact, see toggleUploadMinimize)
The same panel shrunk in place to its summary row: ring, running total and
the maximize / close buttons, which only exist on this view because the
header that normally carries the controls is hidden.
*/
#uploadTab .uploadCompactBtn{
display: none;
}
/*
Shrink to fit rather than a fixed width: the total's label differs in
length between locales, and it must never be cut off mid number.
*/
#uploadTab.compact{
width: auto;
min-width: 240px;
}
#uploadTab.compact .uploadHeader,
#uploadTab.compact .uploadList,
#uploadTab.compact .uploadActions{
display: none;
}
#uploadTab.compact .uploadSummary{
gap: 8px;
padding: 8px 8px 8px 14px;
margin-top: 0px;
border-top: none;
background-color: var(--uploadtab_bg);
}
#uploadTab.compact .uploadSummaryIcon svg{
width: 22px;
height: 22px;
}
/* Not allowed to shrink: the card grows with the text instead of clipping it */
#uploadTab.compact .uploadSummaryText{
flex: 0 0 auto;
overflow: visible;
font-size: 13px;
color: var(--uploadtab_txt);
}
#uploadTab.compact .uploadCompactBtn{
display: flex;
}
@media screen and (max-width: 500px) {
#uploadTab{
right: 12px;
left: 12px;
bottom: calc(var(--fm-statusbar-h, 37px) + 8px);
width: auto;
max-width: none;
}
#uploadTab.compact{
min-width: 0px;
}
.uploadList{
max-height: 40vh;
}
}
/*
Special message or exceptions
*/
.ui.themed.header{
color: var(--text_color);
}
.ui.themed.header .sub.header{
color: var(--text_color_secondary);
}
code{
background-color: var(--code_bg);
color: var(--code_txt);
line-height: 2.5;
padding: 0.1em;
padding-left: 0.4em;
padding-right: 0.4em;
border-radius: 0.2em;
}
/*
Legacy supports (Deprecated)
*/
.normal.object{
color:var(--normal_object_txt);
}
.hex.foldername{
color: var(--hex_folder_txt) !important;
}
.um.filename{
color: var(--um_file_txt) !important;
}
/*
Hot Search Related
*/
i.blue{
color: #345eeb;
}
.fileObject.hotSearchHighlight{
background-color: #d2f2f7 !important;
}
/*
Responsive
*/
@media (max-width:1035px) {
.viewportBtns{
display: block;
float: right;
}
}
@media (max-width:840px) {
.viewportBtns{
float: none;
}
.tabletAndDesktopOnly{
display:none !important;
}
.mobileFileOprMenu{
display:block !important;
}
.navibar.mobile .fileOprBtn{
padding-top: 0.1em;
padding-bottom: 0em;
}
.navibar.mobile .twolines.fileOprBtn{
padding-top: 0.1em;
padding-bottom: 0em;
}
.navibar.mobile .twolines.fileOprBtn .opricon{
width: 36px;
}
.navibar.mobile .twolines.fileOprBtn .oprtxt{
display:none !important;
}
.navibar.mobile .wideScreenOnly{
display:none;
}
.navibar.mobile .fileoprGroupDivider{
height: 42px;
}
.mobileFileOprMenu{
top: 0;
right: 0.4em;
margin-top: -0.2em;
}
}
@media (max-width:620px) {
#pathInputField{
width: 100%;
}
#pathInputField input{
margin-left: 0;
}
.ui.selection.dropdown{
min-width: 8em;
}
/*Directory sidebar, full width */
#directorySidebar{
width: 100%;
min-width: 100%;
}
/* grid mode preview */
.fileviewList .fileObject.card{
border-radius: 0.4em;
position: relative;
margin-bottom:1em;
width: calc(33% - 4px) !important;
min-width: 100px;
max-width: 148px;
}
/*
Dialogs centre in the viewport instead of hugging a corner.
Centred with inset:0 + margin:auto rather than a translate(-50%,-50%),
because these are shown with semantic's transition("slide left in") -
its keyframes set transform themselves, so a centring transform would be
dropped for the length of the animation and the card would visibly jump
into place at the end. Auto margins are untouched by the animation.
The auto margins need a definite height to resolve against, which is
what height:fit-content provides - plain auto height would stretch to
fill the insets instead.
*/
.popup{
right: 0;
bottom: 2em;
left: 0;
margin: auto;
width: calc(100% - 28px);
max-width: 420px;
height: -webkit-fit-content;
height: fit-content;
max-height: calc(100% - 40px);
}
/* Properties view, disable function in small display size*/
#propertiesView{
display:none !important;
}
#togglePropertiesViewBtn{
display:none !important;
}
/* ...and with no pane to resize, neither does its handle */
#fmPropsSplitter{
display:none !important;
}
}
@media (max-width:450px) {
.viewportBtns{
float: right;
}
}
/* ======================================================================
Redesigned navigation row and sidebar (Phase 2.3 / 2.4)
Colours come from shared/fs-theme.css, components from
shared/fs-components.css. Only layout lives here.
====================================================================== */
.navibar {
padding: 0 !important;
height: auto !important;
}
.fmNav {
display: flex;
align-items: center;
gap: 8px;
padding: 8px 12px;
position: relative;
background: var(--fs-bg);
border-bottom: 1px solid var(--fs-line);
}
.fmNavBtns {
display: flex;
align-items: center;
gap: 4px;
flex-shrink: 0;
}
.fmNav .fsIconBtn.disabled,
.fmNav .fsIconBtn:disabled {
opacity: 0.35;
pointer-events: none;
}
/* ---------- Breadcrumb pill ---------- */
.fmPathbar {
flex-grow: 1;
min-width: 0;
cursor: text;
padding-left: 4px;
padding-right: 0px;
}
.fmPathHome {
width: 26px;
height: 26px;
min-width: 26px;
border: none;
background: transparent;
border-radius: 6px;
padding: 4px;
color: var(--fs-icon);
cursor: pointer;
flex-shrink: 0;
}
.fmPathHome:hover { background: var(--fs-fill); color: var(--fs-text); }
.fmPathbar .pathDisplay {
flex-grow: 1;
min-width: 0;
overflow: hidden;
white-space: nowrap;
font-size: 14px;
margin: 0 !important;
color: var(--fs-text);
}
.fmPathbar .pathDisplay .section {
padding: 3px 7px;
border-radius: 6px;
cursor: pointer;
}
.fmPathbar .pathDisplay .section:hover { background: var(--fs-fill); }
.fmPathbar .pathDisplay .divider { color: var(--fs-text-faint); }
.fmPathInput {
display: flex;
align-items: center;
gap: 6px;
flex-grow: 1;
min-width: 0;
}
.fmPathInput input {
flex-grow: 1;
min-width: 0;
border: none;
outline: none;
background: transparent;
font-size: 14px;
font-family: inherit;
color: var(--fs-text);
padding: 4px 2px;
}
/* ---------- Search pill ---------- */
.fmSearch {
width: 240px;
flex-shrink: 0;
padding-right: 8px;
}
.fmSearch input {
flex-grow: 1;
min-width: 0;
border: none;
outline: none;
background: transparent;
font-size: 14px;
font-family: inherit;
color: var(--fs-text);
}
.fmSearchIcon {
width: 17px;
height: 17px;
flex-shrink: 0;
color: var(--fs-text-dim);
}
.fmSearchIcon svg { display: block; width: 100%; height: 100%; }
.fmCaseBtn {
border: none;
background: transparent;
color: var(--fs-text-dim);
font-size: 12px;
font-weight: 600;
border-radius: 5px;
padding: 3px 5px;
cursor: pointer;
flex-shrink: 0;
}
.fmCaseBtn:hover { background: var(--fs-fill); color: var(--fs-text); }
.fmCaseBtn.active { background: var(--fs-accent-soft); color: var(--fs-accent-strong); }
/* ---------- View toggle ---------- */
.fsViewToggle {
display: flex;
background: var(--fs-fill);
border-radius: 8px;
padding: 2px;
gap: 2px;
flex-shrink: 0;
}
.fsViewToggle button {
width: 30px;
height: 26px;
border: none;
background: transparent;
border-radius: 6px;
padding: 5px;
color: var(--fs-icon);
cursor: pointer;
}
.fsViewToggle button:hover { background: var(--fs-fill-hover); }
.fsViewToggle button.disabled,
.fsViewToggle button:disabled {
background: var(--fs-surface);
color: var(--fs-accent);
box-shadow: 0 1px 2px rgba(0,0,0,0.12);
pointer-events: none;
opacity: 1;
}
.fsViewToggle button svg { display: block; width: 100%; height: 100%; }
/* ---------- Overflow menu button ---------- */
.fsMoreBtn {
width: 32px;
height: 32px;
min-width: 32px;
border: 1px solid var(--fs-line);
background: var(--fs-surface);
border-radius: 8px;
padding: 7px;
color: var(--fs-text);
cursor: pointer;
flex-shrink: 0;
}
.fsMoreBtn:hover { background: var(--fs-fill); }
.fsMoreBtn.active {
background: var(--fs-accent-soft);
color: var(--fs-accent);
border-color: transparent;
}
.fsMoreBtn svg { display: block; width: 100%; height: 100%; }
.fmMoreMenu {
right: 12px;
top: 46px;
max-height: 70vh;
overflow-y: auto;
overflow-x: hidden;
}
.fmSortRow select {
flex-grow: 1;
border: 1px solid var(--fs-line);
border-radius: 6px;
background: var(--fs-surface);
color: var(--fs-text);
font-family: inherit;
font-size: 13px;
padding: 3px 6px;
outline: none;
}
.fmSortRow:hover { background: transparent; }
/* ---------- Sidebar ---------- */
#directorySidebar {
padding: 10px 8px 10px 10px !important;
background: var(--fs-bg);
border-right: 1px solid var(--fs-line);
}
.fsSideTitle {
font-size: 12px;
color: var(--fs-text-faint);
padding: 4px 8px;
margin-top: 4px;
}
.fsSideTitle:first-child { margin-top: 0; }
.fmSideGroup { margin-bottom: 6px; }
#directorySidebar .fsSideItem {
display: flex !important;
align-items: center;
gap: 10px;
padding: 5px 8px !important;
border-radius: 7px;
cursor: pointer;
white-space: nowrap;
overflow: hidden;
color: var(--fs-text);
margin: 0 !important;
}
#directorySidebar .fsSideItem:hover { background: var(--fs-fill); }
#directorySidebar .fsSideItem.active {
background: var(--fs-accent-soft);
color: var(--fs-accent-strong);
}
#directorySidebar .fsSideItem .fsSideIcon {
width: 20px;
height: 20px;
min-width: 20px;
}
#directorySidebar .fsSideItem .fsSideIcon svg { display: block; width: 100%; height: 100%; }
#directorySidebar .fsSideItem .fsSideLabel {
overflow: hidden;
text-overflow: ellipsis;
}
/*
Separates the mounted storage devices above from the special views below
them - the trash bin and anything that joins it later. Without it the two
kinds run together and the bin reads as another drive.
*/
#directorySidebar .fsSideDivider {
height: 1px;
background: var(--fs-line);
margin: 7px 8px;
}
#selectInfo {
font-size: 12px;
color: var(--fs-text-faint);
padding: 8px;
margin: 0;
}
/* ---------- Narrow windows ---------- */
@media only screen and (max-width: 900px) {
.fmSearch { width: 170px; }
}
@media only screen and (max-width: 720px) {
.fmSearch { display: none; }
}
/* ======================================================================
Redesigned file list, grid and status bar (Phase 2.5 - 2.8)
====================================================================== */
/* ---------- Shared row icon ---------- */
.fmRowIcon {
width: 20px;
height: 20px;
min-width: 20px;
display: inline-block;
vertical-align: middle;
flex-shrink: 0;
}
.fmRowIcon .fsSmallIcon { width: 100%; height: 100%; }
/* ---------- List view (single column) ---------- */
.fileviewList .fileObject.item {
display: flex !important;
align-items: center;
gap: 9px;
height: 38px;
padding: 0 14px 0 16px !important;
cursor: pointer;
border-bottom: 1px solid var(--fs-line-soft);
}
.fileviewList .fileObject.item .filename {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
/* ---------- Details view: the mockup's columned list ---------- */
#folderView.fmDetailsView {
padding-top: 0px;
border-top: 10px solid var(--folder_view_background);
}
#fmListHeader {
position: sticky;
top: 0;
z-index: 6;
background: var(--fs-bg);
border-bottom: 1px solid var(--fs-line);
}
.detailstable {
table-layout: fixed !important;
width: 100% !important;
margin: 0 !important;
border-collapse: collapse !important;
}
#fmListHeader th {
font-size: 13px !important;
font-weight: 400 !important;
color: var(--fs-text-dim) !important;
padding: 6px 8px !important;
text-align: left;
background: transparent !important;
border: none !important;
white-space: nowrap;
}
#fmListHeader th.fmSortable { cursor: pointer; }
#fmListHeader th.fmSortable:hover { background: var(--fs-fill) !important; }
#fmListHeader th.sorted { color: var(--fs-text) !important; }
.fmSortMark {
margin-left: 5px;
font-size: 11px;
color: var(--fs-text-dim);
}
.detailstable tr.fileObject.details { cursor: pointer; }
.detailstable tr.fileObject.details td {
padding: 6px 8px !important;
border: none !important;
border-bottom: 1px solid var(--fs-line-soft) !important;
font-size: 14px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
vertical-align: middle;
}
/*
The name cell must stay a real table-cell: display:flex on a