/* ============================================================================
   Roxyon File Manager — Hetzner-style dark theme
   ----------------------------------------------------------------------------
   Everything is driven by the custom properties below. Drop this token block
   into the panel's global stylesheet and delete it from here, and the file
   manager inherits the rest of Roxyon automatically — no component restyling.
   ========================================================================= */

:root {
  /* Surfaces — a pure neutral ramp, hsl(0, 0%, L). The previous values carried a
     faint blue cast (#16191d is hsl(210, 15%, 10%)), which fought the red accent:
     a warm brand colour on cool grey reads slightly dirty. At zero saturation the
     red is the only chroma on screen, which is what makes it register. */
  --rx-bg:           hsl(0, 0%, 11%);   /* #1c1c1c — app background          */
  --rx-surface:      hsl(0, 0%, 15%);   /* #262626 — toolbar, header, sidebar */
  --rx-surface-2:    hsl(0, 0%, 19%);   /* #303030 — hover                    */
  --rx-surface-3:    hsl(0, 0%, 24%);   /* #3d3d3d — active, meter track      */
  --rx-overlay:      hsl(0, 0%, 17%);   /* #2b2b2b — menus, dialogs           */

  --rx-border:       hsl(0, 0%, 28%);
  --rx-border-soft:  hsl(0, 0%, 21%);
  --rx-border-focus: hsl(0, 0%, 42%);

  /* Text lightness chosen against --rx-surface: 12.7:1, 6.7:1 and 3.8:1. The dim
     tone is for non-essential metadata only — it is below AA for body copy. */
  --rx-text:         hsl(0, 0%, 92%);
  --rx-text-muted:   hsl(0, 0%, 68%);
  --rx-text-dim:     hsl(0, 0%, 50%);

  /* Hetzner red. Used only for primary actions and destructive confirmation —
     if it appears more than twice on screen it has stopped meaning anything. */
  --rx-accent:       #d50c2d;
  --rx-accent-hover: hsl(349, 89%, 52%);
  --rx-accent-dim:   rgba(213, 12, 45, 0.16);

  /* Folder glyphs. NOT the exact brand red: #d50c2d on --rx-surface is 2.8:1,
     under the 3:1 WCAG floor for graphical objects, and a 16px icon is exactly
     the case that floor exists for. Same hue, lifted to 3.5:1. */
  --rx-folder:       hsl(349, 72%, 55%);

  /* Complement of the accent (hue 349 -> 169), for anything that must read as
     neutral progress rather than as a brand moment: quota bars, upload bars,
     info toasts. Blue next to this red looked like two competing brands. */
  --rx-teal:         hsl(174, 45%, 48%);

  /* Kept so existing rules referencing --rx-blue do not break; both now resolve
     to the same complement. Remove once nothing points at it. */
  --rx-blue:         var(--rx-teal);

  --rx-green:        #3fb950;
  --rx-amber:        #d29922;
  --rx-red:          #f85149;

  --rx-radius:       6px;
  --rx-radius-sm:    4px;

  /* Overridden to 44px under (pointer: coarse) — see the touch block. */
  --rx-row-h:        34px;

  --rx-font: -apple-system, BlinkMacSystemFont, "Segoe UI", Inter, Roboto, sans-serif;
  --rx-mono: ui-monospace, "SF Mono", "JetBrains Mono", Menlo, Consolas, monospace;

  --rx-shadow: 0 8px 28px rgba(0, 0, 0, 0.55);

  /* Grid track template, overridden per breakpoint so the row markup never has to
     change: check, name, size, perms, modified. */
  --rx-cols: 28px 1fr 110px 96px 150px;
}

* { box-sizing: border-box; }

body.rx-fm-body {
  margin: 0;
  background: var(--rx-bg);
  color: var(--rx-text);
  font: 13px/1.5 var(--rx-font);
  -webkit-font-smoothing: antialiased;
}

/* ---------------------------------------------------------------- layout */

.rx-fm {
  /* Flex column, NOT grid-template-rows.
     
     Positional tracks were wrong here: three of this element's children are
     conditional — the job progress bar, the search banner, the truncation
     notice — so "the body is the third row" stops being true the moment any
     of them appears. What actually happened was the banner claiming the 1fr
     track while .rx-fm__body collapsed to its content height.
     
     With flex there is nothing positional to get wrong: whatever is present
     sizes to its content, and the body takes the remainder. */
  display: flex;
  flex-direction: column;

  /* 100%, not 100vh — the component is embedded in the console and its height
     comes from the mount element, not the viewport. 100vh overflowed the panel
     by exactly the height of the console chrome above it. */
  height: 100%;
  min-height: 0;
  background: var(--rx-bg);
}

/* Every direct child that is not the body holds its natural height. */
.rx-fm > .rx-toolbar,
.rx-fm > .rx-crumbs,
.rx-fm > .rx-job,
.rx-fm > .rx-banner,
.rx-fm > .rx-status {
  flex: 0 0 auto;
}

.rx-fm__body {
  display: grid;
  grid-template-columns: 232px 1fr;

  /* flex:1 claims the leftover space; min-height:0 is what allows it to SHRINK
     below its content, without which the inner scroll container never scrolls
     and the grid pushes the status bar off-screen instead. */
  flex: 1 1 auto;
  min-height: 0;
}

/* Responsive rules live in one block at the end of this file. */

/* --------------------------------------------------------------- toolbar */

.rx-toolbar {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 8px 12px;
  background: var(--rx-surface);
  border-bottom: 1px solid var(--rx-border);

  /* Scrolls rather than wrapping, at every width. Without this the buttons are
     simply wider than a 900px viewport and push the whole document sideways —
     the page gains a horizontal scrollbar and the grid's right-hand columns go
     off-screen, which is not obviously a toolbar problem when you see it. */
  overflow-x: auto;
  scrollbar-width: none;
}

.rx-toolbar::-webkit-scrollbar { display: none; }

.rx-toolbar__spacer { flex: 1; }

.rx-btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  height: 30px;
  padding: 0 11px;
  background: var(--rx-surface-2);
  color: var(--rx-text);
  border: 1px solid var(--rx-border);
  border-radius: var(--rx-radius-sm);
  font: 500 12.5px/1 var(--rx-font);
  cursor: pointer;
  white-space: nowrap;
  transition: background .12s ease, border-color .12s ease;
}

.rx-btn:hover:not(:disabled) { background: var(--rx-surface-3); border-color: var(--rx-border-focus); }
.rx-btn:active:not(:disabled) { transform: translateY(1px); }

/* Disabled buttons stay visible rather than vanishing: a toolbar that changes
   shape as the selection changes makes targets move under the cursor. */
.rx-btn:disabled { opacity: .38; cursor: default; }

.rx-btn--primary { background: var(--rx-accent); border-color: var(--rx-accent); color: #fff; }
.rx-btn--primary:hover:not(:disabled) { background: var(--rx-accent-hover); border-color: var(--rx-accent-hover); }

.rx-btn--danger:hover:not(:disabled) { background: var(--rx-accent-dim); border-color: var(--rx-accent); color: var(--rx-red); }

.rx-btn--icon { padding: 0; width: 30px; justify-content: center; }

.rx-btn svg { width: 14px; height: 14px; flex: none; }

.rx-sep { width: 1px; height: 18px; background: var(--rx-border); margin: 0 3px; }

/* ------------------------------------------------------------ breadcrumb */

.rx-crumbs {
  display: flex;
  align-items: center;
  gap: 2px;
  padding: 7px 12px;
  background: var(--rx-bg);
  border-bottom: 1px solid var(--rx-border-soft);
  font-size: 12.5px;
  overflow-x: auto;
  scrollbar-width: none;
}

.rx-crumbs::-webkit-scrollbar { display: none; }

.rx-crumb {
  padding: 3px 7px;
  color: var(--rx-text-muted);
  border-radius: var(--rx-radius-sm);
  cursor: pointer;
  white-space: nowrap;
}

.rx-crumb:hover { background: var(--rx-surface-2); color: var(--rx-text); }
.rx-crumb--last { color: var(--rx-text); font-weight: 500; cursor: default; }
.rx-crumb--last:hover { background: none; }
.rx-crumb__sep { color: var(--rx-text-dim); user-select: none; }

/* Drop target while dragging files over a breadcrumb — moving "up" is the most
   common drag destination and is otherwise impossible to hit. */
.rx-crumb--dropping { background: var(--rx-accent-dim); color: var(--rx-text); box-shadow: inset 0 0 0 1px var(--rx-accent); }

/* --------------------------------------------------------------- sidebar */

.rx-sidebar {
  background: var(--rx-surface);
  border-right: 1px solid var(--rx-border);
  padding: 10px 8px;
  overflow-y: auto;
}

.rx-sidebar__label {
  padding: 6px 8px 4px;
  font-size: 10.5px;
  font-weight: 600;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--rx-text-dim);
}

.rx-sidebar__item {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 6px 8px;
  border-radius: var(--rx-radius-sm);
  color: var(--rx-text-muted);
  cursor: pointer;
  font-size: 12.5px;
}

.rx-sidebar__item:hover { background: var(--rx-surface-2); color: var(--rx-text); }
.rx-sidebar__item--active { background: var(--rx-surface-3); color: var(--rx-text); }
.rx-sidebar__item svg { width: 15px; height: 15px; color: var(--rx-text-dim); flex: none; }

/* Quota meter. Turns amber at 80% and red at 95% — the customer should find out
   they are nearly full from the sidebar, not from a failed upload. */
.rx-quota { margin-top: auto; padding: 12px 8px 4px; display: flex; flex-direction: column; gap: 11px; }
.rx-quota__meter { min-width: 0; }
.rx-quota__bar { height: 4px; background: var(--rx-surface-3); border-radius: 2px; overflow: hidden; }
.rx-quota__fill { height: 100%; background: var(--rx-teal); border-radius: 2px; transition: width .3s ease; }
.rx-quota__fill--warn { background: var(--rx-amber); }
.rx-quota__fill--full { background: var(--rx-red); }

.rx-quota__text {
  display: flex; justify-content: space-between; gap: 8px;
  margin-top: 6px; font-size: 11px; color: var(--rx-text-dim);
}
.rx-quota__label { color: var(--rx-text-muted); white-space: nowrap; }
.rx-quota__value { white-space: nowrap; }

/* The status-bar copy of the meter. Hidden until the sidebar is dropped — see
   the responsive block. */
.rx-quota--inline { display: none; margin: 0; padding: 0; gap: 0; }
.rx-quota--inline .rx-quota__meter { display: flex; align-items: center; gap: 8px; }
.rx-quota--inline .rx-quota__bar { width: 76px; flex: none; }
.rx-quota--inline .rx-quota__text { margin-top: 0; }
.rx-quota--inline .rx-quota__label { display: none; }

/* Only the primary meter goes in the status bar. A phone status bar cannot hold
   three of them, and the sidebar — where they all live — is one breakpoint away. */
.rx-quota--inline .rx-quota__meter:not(:first-child) { display: none; }

/* [hidden] must beat the display rules above, otherwise an unmetered account
   shows an empty bar instead of nothing. */
.rx-quota[hidden] { display: none; }

/* ------------------------------------------------------------------ grid */

.rx-grid {
  position: relative;
  min-height: 0;
  display: flex;
  flex-direction: column;
  outline: none;
}

.rx-grid__head {
  display: grid;
  grid-template-columns: var(--rx-cols, 28px 1fr 110px 96px 150px);
  align-items: center;
  height: 30px;
  padding: 0 12px;
  background: var(--rx-surface);
  border-bottom: 1px solid var(--rx-border);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: .04em;
  text-transform: uppercase;
  color: var(--rx-text-dim);
  user-select: none;
}

.rx-grid__th { cursor: pointer; padding: 0 6px; display: flex; align-items: center; gap: 4px; }
.rx-grid__th:hover { color: var(--rx-text-muted); }
.rx-grid__th--num { justify-content: flex-end; }
.rx-grid__sort { font-size: 9px; }

/* The scroll container. Virtualisation renders only the visible slice into
   .rx-grid__pane, which is absolutely positioned inside a spacer whose height
   equals rowCount * rowHeight — so the native scrollbar stays accurate for
   400,000 rows without 400,000 DOM nodes. */
.rx-grid__scroll { flex: 1; overflow-y: auto; overflow-x: hidden; position: relative; }
.rx-grid__spacer { position: relative; width: 100%; }
.rx-grid__pane { position: absolute; top: 0; left: 0; right: 0; will-change: transform; }

.rx-row {
  display: grid;
  grid-template-columns: var(--rx-cols, 28px 1fr 110px 96px 150px);
  align-items: center;
  height: var(--rx-row-h);
  padding: 0 12px;
  border-bottom: 1px solid var(--rx-border-soft);
  cursor: default;
  user-select: none;
  contain: strict;
}

.rx-row:hover { background: var(--rx-surface-2); }
.rx-row--selected { background: var(--rx-accent-dim); }
.rx-row--selected:hover { background: rgba(213, 12, 45, .2); }

/* Keyboard cursor is a separate concept from selection — you can move the
   cursor with arrows without changing the selection (Ctrl+arrows). */
.rx-row--cursor { box-shadow: inset 2px 0 0 var(--rx-accent); }
.rx-row--cut { opacity: .45; }

.rx-row__cell { padding: 0 6px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.rx-row__cell--num { text-align: right; font-variant-numeric: tabular-nums; color: var(--rx-text-muted); }
.rx-row__cell--mode { font-family: var(--rx-mono); font-size: 11.5px; color: var(--rx-text-muted); text-align: right; }

.rx-row__name { display: flex; align-items: center; gap: 8px; min-width: 0; }
.rx-row__name span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.rx-row__icon { width: 16px; height: 16px; flex: none; }

.rx-icon--dir  { color: var(--rx-folder); }
.rx-icon--file { color: var(--rx-text-dim); }
.rx-icon--link { color: var(--rx-amber); }
.rx-icon--code { color: var(--rx-green); }
.rx-icon--img  { color: #c07ce8; }
.rx-icon--zip  { color: var(--rx-amber); }

.rx-row--broken .rx-row__name span { color: var(--rx-red); text-decoration: line-through; }
.rx-link-target { color: var(--rx-text-dim); font-size: 11.5px; }

.rx-check {
  width: 14px; height: 14px;
  border: 1px solid var(--rx-border-focus);
  border-radius: 3px;
  background: var(--rx-surface-2);
  cursor: pointer;
  position: relative;
}
.rx-check--on { background: var(--rx-accent); border-color: var(--rx-accent); }
.rx-check--on::after {
  content: ''; position: absolute; left: 4px; top: 1px;
  width: 4px; height: 8px; border: solid #fff; border-width: 0 2px 2px 0;
  transform: rotate(45deg);
}

/* ---------------------------------------------------------- drag & states */

.rx-grid--dragover::after {
  content: '';
  position: absolute; inset: 0;
  border: 2px dashed var(--rx-accent);
  background: var(--rx-accent-dim);
  pointer-events: none;
  border-radius: var(--rx-radius);
}

.rx-empty, .rx-loading {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 8px; padding: 64px 20px; color: var(--rx-text-dim); text-align: center;
}
.rx-empty svg { width: 40px; height: 40px; opacity: .4; }

.rx-banner--search {
  background: var(--rx-surface-2);
  border-bottom: 1px solid var(--rx-border);
  color: var(--rx-text);
  gap: 12px;
  padding: 8px 12px;
}

.rx-banner--search .rx-btn { height: 26px; padding: 0 10px; font-size: 12px; }

.rx-banner {
  display: flex; align-items: center; gap: 8px;
  padding: 7px 12px;
  background: rgba(210, 153, 34, .1);
  border-bottom: 1px solid rgba(210, 153, 34, .3);
  color: var(--rx-amber);
  font-size: 12px;
}

/* -------------------------------------------------------------- statusbar */

.rx-status {
  display: flex; align-items: center; gap: 14px;
  height: 28px; padding: 0 12px;
  background: var(--rx-surface);
  border-top: 1px solid var(--rx-border);
  font-size: 11.5px;
  color: var(--rx-text-dim);
}
.rx-status__spacer { flex: 1; }

/* --------------------------------------------------------------- uploads */

.rx-uploads {
  position: fixed; right: 16px; bottom: 16px;
  width: 348px; max-height: 62vh;
  display: flex; flex-direction: column;
  background: var(--rx-surface-2);
  border: 1px solid var(--rx-border);
  border-radius: var(--rx-radius);
  box-shadow: var(--rx-shadow);
  overflow: hidden;
  z-index: 60;
}
.rx-uploads[hidden] { display: none; }

.rx-uploads__head {
  display: flex; align-items: center; gap: 8px;
  padding: 9px 12px;
  background: var(--rx-surface-3);
  border-bottom: 1px solid var(--rx-border);
  font-size: 12.5px; font-weight: 600;
}
.rx-uploads__list { overflow-y: auto; padding: 4px 0; }

.rx-upload { padding: 7px 12px; border-bottom: 1px solid var(--rx-border-soft); }
.rx-upload:last-child { border-bottom: none; }
.rx-upload__top { display: flex; align-items: center; gap: 8px; margin-bottom: 5px; }
.rx-upload__name { flex: 1; font-size: 12px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.rx-upload__pct { font-size: 11px; color: var(--rx-text-dim); font-variant-numeric: tabular-nums; }
.rx-upload__bar { height: 3px; background: var(--rx-surface-3); border-radius: 2px; overflow: hidden; }
.rx-upload__fill { height: 100%; background: var(--rx-teal); border-radius: 2px; transition: width .2s ease; }
.rx-upload--done .rx-upload__fill  { background: var(--rx-green); }
.rx-upload--error .rx-upload__fill { background: var(--rx-red); }
.rx-upload--paused .rx-upload__fill { background: var(--rx-amber); }
.rx-upload__meta { margin-top: 4px; font-size: 10.5px; color: var(--rx-text-dim); }

/* ------------------------------------------------------------------ jobs */

.rx-job {
  display: flex; align-items: center; gap: 10px;
  padding: 6px 12px;
  background: var(--rx-surface-2);
  border-bottom: 1px solid var(--rx-border);
  font-size: 12px;
}

/* Any explicit `display` on a class beats the UA sheet's `[hidden] { display: none }`,
   so every element toggled via the hidden attribute needs this companion rule. Without
   it the progress bar sits there permanently, empty. */
.rx-job[hidden] { display: none; }
.rx-job__bar { flex: 1; height: 3px; background: var(--rx-surface-3); border-radius: 2px; overflow: hidden; }
.rx-job__fill { height: 100%; background: var(--rx-accent); transition: width .2s ease; }

/* ----------------------------------------------------------- context menu */

.rx-menu {
  position: fixed;
  min-width: 196px;
  padding: 4px;
  background: var(--rx-overlay);
  border: 1px solid var(--rx-border-focus);
  border-radius: var(--rx-radius);
  box-shadow: var(--rx-shadow);
  z-index: 100;
}
.rx-menu__item {
  display: flex; align-items: center; gap: 9px;
  padding: 6px 9px;
  border-radius: var(--rx-radius-sm);
  font-size: 12.5px;
  cursor: pointer;
  color: var(--rx-text);
}
.rx-menu__item:hover { background: var(--rx-surface-3); }
.rx-menu__item--danger { color: var(--rx-red); }
.rx-menu__item--danger:hover { background: var(--rx-accent-dim); }
.rx-menu__item[aria-disabled="true"] { opacity: .35; pointer-events: none; }
.rx-menu__item svg { width: 14px; height: 14px; opacity: .75; }
.rx-menu__key { margin-left: auto; font-size: 10.5px; color: var(--rx-text-dim); font-family: var(--rx-mono); }
.rx-menu__sep { height: 1px; background: var(--rx-border); margin: 4px 2px; }

/* --------------------------------------------------------------- dialogs */

.rx-backdrop {
  position: fixed; inset: 0;
  background: rgba(0, 0, 0, .62);
  display: flex; align-items: center; justify-content: center;
  z-index: 90;
  padding: 20px;
}

.rx-dialog {
  width: 100%; max-width: 440px;
  background: var(--rx-surface-2);
  border: 1px solid var(--rx-border-focus);
  border-radius: var(--rx-radius);
  box-shadow: var(--rx-shadow);
  overflow: hidden;
}
.rx-dialog--wide { max-width: min(1080px, 94vw); height: min(780px, 88vh); display: flex; flex-direction: column; }
.rx-dialog__head { padding: 13px 16px; border-bottom: 1px solid var(--rx-border); font-size: 13.5px; font-weight: 600; }
.rx-dialog__body { padding: 16px; }
.rx-dialog__body--flush { padding: 0; flex: 1; min-height: 0; display: flex; flex-direction: column; }
.rx-dialog__foot { display: flex; justify-content: flex-end; gap: 8px; padding: 12px 16px; border-top: 1px solid var(--rx-border); background: var(--rx-surface); }

.rx-field { margin-bottom: 13px; }
.rx-field:last-child { margin-bottom: 0; }
.rx-label { display: block; margin-bottom: 5px; font-size: 11.5px; font-weight: 500; color: var(--rx-text-muted); }

.rx-input, .rx-select {
  width: 100%; height: 32px;
  padding: 0 10px;
  background: var(--rx-bg);
  border: 1px solid var(--rx-border);
  border-radius: var(--rx-radius-sm);
  color: var(--rx-text);
  font: 13px var(--rx-font);
}
.rx-input:focus, .rx-select:focus { outline: none; border-color: var(--rx-accent); box-shadow: 0 0 0 2px var(--rx-accent-dim); }
.rx-input--mono { font-family: var(--rx-mono); }
.rx-hint { margin-top: 5px; font-size: 11px; color: var(--rx-text-dim); }
.rx-error { margin-top: 6px; font-size: 11.5px; color: var(--rx-red); }

/* Permission matrix. A 3x3 grid of checkboxes beats a raw octal box for the
   90% of customers who do not think in octal, with the numeric value shown
   live for the ones who do. */
.rx-perms { display: grid; grid-template-columns: 76px repeat(3, 1fr); gap: 7px; align-items: center; font-size: 12px; }
.rx-perms__head { color: var(--rx-text-dim); font-size: 11px; text-transform: uppercase; letter-spacing: .04em; }
.rx-perms__octal { font-family: var(--rx-mono); font-size: 15px; color: var(--rx-accent); }

/* ---------------------------------------------------------------- editor */

.rx-editor { flex: 1; min-height: 0; display: flex; flex-direction: column; }
.rx-editor__bar {
  display: flex; align-items: center; gap: 10px;
  padding: 7px 12px;
  background: var(--rx-surface);
  border-bottom: 1px solid var(--rx-border);
  font-size: 11.5px; color: var(--rx-text-dim);
}
.rx-editor__host { flex: 1; min-height: 0; overflow: hidden; }
.rx-editor__host .cm-editor { height: 100%; font-size: 13px; }
.rx-editor__host .cm-scroller { font-family: var(--rx-mono); }
.rx-editor__dot { width: 6px; height: 6px; border-radius: 50%; background: var(--rx-amber); }

/* ---------------------------------------------------------------- toasts */

/* Mounted on <body>, not inside the component.
   
   position:fixed resolves against the nearest ancestor with a transform,
   filter or will-change — and a console page has plenty of those. Combined
   with overflow:hidden on the mount element, toasts were being positioned
   relative to a clipped box and never appeared at all. Attaching to <body>
   removes the whole class of problem.
   
   z-index sits above typical modal ranges so an error is not hidden behind
   the dialog that caused it. */
.rx-toasts {
  position: fixed;
  top: 14px;
  left: 50%;
  transform: translateX(-50%);
  display: flex;
  flex-direction: column;
  gap: 7px;
  z-index: 2147483000;
  pointer-events: none;
}

.rx-toast { pointer-events: auto; }
.rx-toast {
  display: flex; align-items: center; gap: 9px;
  padding: 9px 14px;
  background: var(--rx-overlay);
  border: 1px solid var(--rx-border-focus);
  border-left: 3px solid var(--rx-teal);
  border-radius: var(--rx-radius);
  box-shadow: var(--rx-shadow);
  font-size: 12.5px;
  animation: rx-slide .18s ease;
}
.rx-toast--error   { border-left-color: var(--rx-red); }
.rx-toast--success { border-left-color: var(--rx-green); }

@keyframes rx-slide { from { opacity: 0; transform: translateY(-8px); } to { opacity: 1; transform: none; } }

/* Respect the OS setting — animation here is decoration, never information. */
@media (prefers-reduced-motion: reduce) {
  * { animation-duration: .01ms !important; transition-duration: .01ms !important; }
}

/* ------------------------------------------------------------ scrollbars */

.rx-grid__scroll::-webkit-scrollbar,
.rx-uploads__list::-webkit-scrollbar,
.rx-sidebar::-webkit-scrollbar { width: 10px; }

.rx-grid__scroll::-webkit-scrollbar-thumb,
.rx-uploads__list::-webkit-scrollbar-thumb,
.rx-sidebar::-webkit-scrollbar-thumb {
  background: var(--rx-surface-3);
  border: 2px solid var(--rx-bg);
  border-radius: 5px;
}
.rx-grid__scroll::-webkit-scrollbar-thumb:hover { background: var(--rx-border-focus); }


/* ==========================================================================
   RESPONSIVE
   --------------------------------------------------------------------------
   One block, mobile rules last, so every override is in one place instead of
   scattered next to the component it modifies.

   The grid is driven entirely by --rx-cols, so dropping a column is a token
   change plus one display:none — the row markup is identical at every width
   and virtual scrolling is untouched.
   ======================================================================== */

/* Shown only below the narrow breakpoint. */
.rx-only-narrow { display: none; }

/* ---- 1024px: the perms column is the first to go. Octal modes matter to
   maybe one customer in fifty, and they can still reach them through the
   Permissions dialog. */
@media (max-width: 1024px) {
  :root { --rx-cols: 28px 1fr 100px 132px; }

  .rx-grid__head .rx-grid__th:nth-child(4),
  .rx-row .rx-row__cell:nth-child(4) { display: none; }
}

/* ---- 860px: no room for a sidebar next to a usable listing. The quota meter
   moves into the status bar rather than disappearing — running out of space is
   exactly the thing a customer needs to see on a phone. */
@media (max-width: 860px) {
  .rx-fm__body { grid-template-columns: 1fr; }
  .rx-sidebar  { display: none; }

  .rx-quota--inline { display: flex; }

  /* The full path is the first thing worth losing when the bar gets tight. */
  .rx-status [data-status-path] { display: none; }
}

/* ---- 700px: phone territory. Modified drops too; name gets everything left. */
@media (max-width: 700px) {
  :root { --rx-cols: 34px 1fr 84px; }

  .rx-grid__head .rx-grid__th:nth-child(5),
  .rx-row .rx-row__cell:nth-child(5) { display: none; }

  .rx-only-narrow { display: inline-flex; }

  /* The toolbar becomes a single horizontally-scrolling strip rather than
     wrapping onto three lines and eating half the viewport. Upload, Search,
     Refresh and More stay; the rest are reachable through More, which is why
     that button exists. */
  .rx-toolbar { padding: 8px 10px; gap: 5px; }
  .rx-toolbar__spacer { flex: 0 0 auto; width: 4px; }

  .rx-toolbar [data-act="upload-folder"],
  .rx-toolbar [data-act="mkdir"],
  .rx-toolbar [data-act="newfile"],
  .rx-toolbar [data-act="compress"],
  .rx-toolbar [data-act="rename"],
  .rx-toolbar [data-act="perms"],
  .rx-toolbar [data-act="paste"],
  .rx-toolbar .rx-sep { display: none; }

  /* Breadcrumbs already scroll; keep the tail visible, since the deepest
     segment is the one you are in. */
  .rx-crumbs { padding: 6px 10px; }

  /* Dialogs go effectively full-screen. A 440px modal centred in a 390px
     viewport is a modal with its buttons off both edges. */
  .rx-dialog {
    max-width: none;
    width: 100%;
    height: 100%;
    max-height: none;
    border-radius: 0;
  }

  .rx-dialog--wide {
    max-width: none;
    width: 100%;
    height: 100%;
  }

  .rx-backdrop { padding: 0; align-items: stretch; }

  /* The uploads panel is fixed at 348px, which overflows a phone. */
  .rx-uploads {
    left: 0;
    right: 0;
    bottom: 0;
    width: auto;
    max-height: 48vh;
    border-radius: 0;
  }

  .rx-menu { min-width: 216px; }

  /* Toasts span the width instead of being a narrow pill in the middle. */
  .rx-toasts { left: 10px; right: 10px; transform: none; }

  .rx-status { padding: 0 10px; gap: 10px; }
}

/* ---- 420px: drop Size as well; on a 4-inch screen the name is the only
   column that earns its place. */
@media (max-width: 420px) {
  :root { --rx-cols: 34px 1fr; }

  .rx-grid__head .rx-grid__th:nth-child(3),
  .rx-row .rx-row__cell:nth-child(3) { display: none; }
}

/* ---- Touch input, independent of width: a tablet in landscape is wide and
   still has fingers. 34px rows are a 24px target after padding; 44px is the
   platform minimum on both iOS and Android. */
@media (pointer: coarse) {
  :root { --rx-row-h: 44px; }

  .rx-btn { height: 36px; padding: 0 13px; }
  .rx-btn--icon { width: 36px; }

  .rx-check { width: 18px; height: 18px; }
  .rx-check--on::after { left: 6px; top: 2px; width: 4px; height: 9px; }

  .rx-menu__item { padding: 10px 12px; }
  .rx-crumb { padding: 6px 9px; }
  .rx-sidebar__item { padding: 9px 8px; }

  /* Hover styling is meaningless without a hover state and sticks after a tap. */
  .rx-row:hover { background: none; }
  .rx-row--selected:hover { background: var(--rx-accent-dim); }
}
