:root {
  color-scheme: dark;

  /* ---- Surfaces ---- */
  --bg: #101114;
  --panel: #191b21;
  --text: #f4f4f5;
  --muted: #a1a1aa;
  --accent: #6d8cff;
  --border: #2d3038;

  /* Frosted glass. Two weights: the deep one for panels that float over
     content, the light one for bars that want the blur to read as glass. */
  --glass-deep: rgba(28, 30, 36, 0.62);
  --glass-light: rgba(255, 255, 255, 0.12);
  --glass-border: rgba(255, 255, 255, 0.18);

  /* Films laid over a surface: fills, hovers, hairlines. On a dark theme
     these lighten; on a light one the very same roles have to darken, which
     is why they are named for what they do rather than for their colour. */
  --film-1: rgba(255, 255, 255, 0.06);
  --film-2: rgba(255, 255, 255, 0.1);
  --film-3: rgba(255, 255, 255, 0.14);
  --film-4: rgba(255, 255, 255, 0.28);
  --film-5: rgba(255, 255, 255, 0.5);

  --field-bg: #111318;
  --tile-bg: #191b21;
  --overlay: rgba(8, 10, 16, 0.55);
  --shadow-ink-soft: rgba(0, 0, 0, 0.35);
  --shadow-ink-strong: rgba(0, 0, 0, 0.45);

  --danger: #e5484d;
  --danger-strong: #d8443c;
  --ok: #68d391;

  /* ---- Colour tags ----
     Stored by name, never by value: "blue" stays blue in both themes, and
     each theme carries the shade that holds its contrast against its own
     background. Nothing about this reaches the synced file. */
  --tag-blue: #6d8cff;
  --tag-teal: #4fd1e0;
  --tag-green: #68d391;
  --tag-yellow: #f2ce5a;
  --tag-orange: #f5a35c;
  --tag-red: #ff8080;
  --tag-pink: #f79ad3;
  --tag-purple: #b79cff;
  --tag-alpha: 0.2;
}

/* ---------- Light theme ----------

   "Frosted white": not a flat white but a very pale grey carrying the
   faintest blue, so it reads as clean paper rather than as a lightbulb --
   the blue is well below what the eye names as a colour, and only shows as
   coolness. Everything else is derived from it.

   The tag colours are not the dark ones lightened; they are chosen for
   contrast against a pale background, so a green tag on white is as legible
   as a green tag on black. Same names, same meaning, different shade. */
:root[data-theme="light"],
:root.is-light {
  color-scheme: light;

  --bg: #f4f6fa;
  --panel: #ffffff;
  --text: #14161c;
  --muted: #5c6270;
  --accent: #3f5fe0;
  --border: #dfe3ec;

  --glass-deep: rgba(255, 255, 255, 0.72);
  --glass-light: rgba(255, 255, 255, 0.66);
  --glass-border: rgba(20, 26, 45, 0.1);

  --film-1: rgba(20, 26, 45, 0.045);
  --film-2: rgba(20, 26, 45, 0.075);
  --film-3: rgba(20, 26, 45, 0.11);
  --film-4: rgba(20, 26, 45, 0.2);
  --film-5: rgba(20, 26, 45, 0.34);

  --field-bg: #ffffff;
  /* Plain white icons on a near-white page vanished into it. This is
     the same weight as the search field's fill, so a file tile sits on
     the page rather than being cut out of it. */
  --tile-bg: #e2e6ec;
  --overlay: rgba(28, 34, 54, 0.32);
  --shadow-ink-soft: rgba(20, 26, 45, 0.12);
  --shadow-ink-strong: rgba(20, 26, 45, 0.2);
  

  --danger: #d92d33;
  --danger-strong: #c0262c;
  --ok: #1e8f52;

  --tag-blue: #3f5fe0;
  --tag-teal: #0e8fa3;
  --tag-green: #1e8f52;
  --tag-yellow: #9a7400;
  --tag-orange: #c25a12;
  --tag-red: #cf3038;
  --tag-pink: #bd3d8e;
  --tag-purple: #6f4bd8;
  --tag-alpha: 0.14;
}

* { box-sizing: border-box; }
body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font: 16px system-ui, sans-serif;
  /* Switching theme should feel like a light coming on, not a cut. */
  transition: background 0.25s ease, color 0.25s ease;
}
.app { width: min(100% - 24px, 720px); margin: auto; }
.topbar { display: flex; align-items: center; justify-content: space-between; padding: 18px 0; }
h1, h2 { margin: 0; }
.toolbar { display: grid; gap: 10px; padding: 16px; background: var(--panel); border: 1px solid var(--border); border-radius: 20px; }
button { min-height: 44px; padding: 0 16px; border: 0; border-radius: 14px; background: var(--accent); color: white; font-weight: 600; }
input[type="file"] { width: 100%; }
.files { margin-top: 20px; }
#fileList { display: grid; gap: 8px; padding: 0; list-style: none; }
#fileList li { padding: 14px; background: var(--panel); border: 1px solid var(--border); border-radius: 16px; }
.hidden { display: none !important; }

.app-shell {
  min-height: 100dvh;
  display: grid;
  place-items: center;
  padding: 24px;
}

.screen {
  width: min(100%, 720px);
}

.screen-login {
  min-height: 100dvh;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: flex-start;
  padding-top: 11dvh;
}

body:has(#loginScreen:not(.hidden)) {
  overflow: hidden;
}

.login-card {
  width: min(100%, 360px);
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
}

.logo {
  width: 140px;
  height: 140px;
  object-fit: contain;
  margin-bottom: 24px;
}

.login-title {
  font-size: 1.75rem;
  font-weight: 700;
  margin: 0 0 28px;
  line-height: 1.25;
}

.field {
  width: 100%;
  margin-bottom: 14px;
}

.field input[type="text"],
.field input[type="password"] {
  width: 100%;
  min-height: 44px;
  font-size: 16px;
  padding: 0 14px;
  border-radius: 14px;
  border: 1px solid var(--border);
  background: var(--field-bg);
  color: var(--text);
}

.remember-me-field {
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  margin-top: 4px;
  font-size: 14px;
  color: var(--muted);
  cursor: pointer;
}

.remember-me-field input[type="checkbox"] {
  width: 18px;
  height: 18px;
  accent-color: var(--accent);
}

#loginButton {
  display: block;
  width: 100%;
  max-width: 240px;
  margin: 30px auto 0;
  border-radius: 999px;
  font-size: 18px;
}

.message {
  min-height: 22px;
  margin-top: 12px;
  color: var(--muted);
}

.message.error {
  color: #ff7b7b;
}

.message.success {
  color: var(--ok);
}

/* ---------- App screen (post-login) ---------- */

.screen-app {
  position: fixed;
  inset: 0;
  display: flex;
  flex-direction: column;
  background: var(--bg);
}

.app-body {
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
}

.nav-tab {
  border: 0;
  background: none;
  color: var(--muted);
  font: inherit;
  cursor: pointer;
  padding: 0;
}

.nav-tab.active {
  color: var(--accent);
}

/* Side nav: desktop only */

.side-nav {
  display: none;
}

.side-nav-tabs {
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.side-nav-tabs .nav-tab {
  display: block;
  width: 100%;
  text-align: left;
  padding: 10px 14px;
  border-radius: 14px;
  font-weight: 600;
  color: var(--text);
}

.side-nav-tabs .nav-tab.active {
  background: var(--panel);
  color: var(--accent);
}

.side-nav-parent {
  margin-top: 24px;
}

.side-nav-parent h3 {
  margin: 0 0 8px;
  padding: 0 14px;
  font-size: 12px;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--muted);
}

.parent-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 2px;
}

.parent-list li button {
  display: flex;
  align-items: center;
  gap: 8px;
  width: 100%;
  min-height: 0;
  text-align: left;
  padding: 8px 14px;
  border-radius: 14px;
  background: none;
  color: var(--muted);
  font-size: 14px;
  font-weight: 400;
}

.parent-list li button:disabled {
  opacity: 0.45;
  cursor: default;
}

.parent-list li button:not(:disabled):hover {
  background: var(--panel);
  color: var(--text);
}

.parent-list svg {
  width: 16px;
  height: 16px;
  flex-shrink: 0;
}

/* Main panel */

.main-panel {
  position: relative;
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  padding: 16px 16px 130px;
}

.pull-refresh-indicator {
  position: absolute;
  top: 6px;
  left: 50%;
  transform: translate(-50%, -40px);
  width: 34px;
  height: 34px;
  border-radius: 50%;
  display: grid;
  place-items: center;
  opacity: 0;
  color: var(--text);
  background: var(--glass-deep);
  backdrop-filter: blur(16px) saturate(160%);
  -webkit-backdrop-filter: blur(16px) saturate(160%);
  border: 1px solid var(--film-3);
  pointer-events: none;
  z-index: 5;
}

.pull-refresh-indicator svg {
  width: 18px;
  height: 18px;
}

.pull-refresh-indicator.visible {
  opacity: 1;
}

.pull-refresh-indicator.spinning svg {
  animation: pull-refresh-spin 0.7s linear infinite;
}

@keyframes pull-refresh-spin {
  to {
    transform: rotate(360deg);
  }
}

.search-row {
  margin-bottom: 14px;
}

.search-bar {
  display: flex;
  align-items: center;
  gap: 10px;
  background: var(--film-2);
  backdrop-filter: blur(16px) saturate(160%);
  -webkit-backdrop-filter: blur(16px) saturate(160%);
  border: 1px solid var(--film-3);
  border-radius: 999px;
  padding: 10px 16px;
}

.search-bar input {
  flex: 1;
  min-width: 0;
  border: 0;
  background: none;
  color: var(--text);
  font-size: 16px;
  outline: none;
}

.search-bar input::placeholder {
  color: var(--muted);
}

.search-icon {
  width: 20px;
  height: 20px;
  color: var(--muted);
  flex-shrink: 0;
}

.breadcrumb {
  display: flex;
  align-items: center;
  flex-wrap: nowrap;
  overflow-x: auto;
  gap: 4px;
  margin-bottom: 12px;
  padding-bottom: 2px;
}

.crumb {
  border: 0;
  background: none;
  color: var(--muted);
  font-size: 14px;
  white-space: nowrap;
  padding: 4px 2px;
}

.crumb:last-child {
  color: var(--text);
  font-weight: 600;
}

.crumb-sep {
  color: var(--muted);
  font-size: 14px;
}

.file-grid {
  display: grid;
  /* minmax(0, 1fr), not 1fr. A grid item's automatic minimum size is its
     min-content width, so a plain 1fr track refuses to go narrower than the
     widest thing inside it. The search hits are the only tiles carrying a
     folder path (.tile-where, set to nowrap), and one long path was enough
     to push all three columns wider than the screen -- the grid slid off to
     the right instead of ellipsising the path. */
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 16px 8px;
  min-height: 160px;
  align-content: start;
  -webkit-touch-callout: none;
  -webkit-user-select: none;
  user-select: none;
}

.grid-tile {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
  border: 0;
  background: none;
  color: var(--text);
  padding: 6px;
  min-height: 96px;
  /* The other half of the fix above: the track may shrink, so the tile has
     to be willing to shrink with it. */
  min-width: 0;
  max-width: 100%;
}

.tile-icon {
  width: 48px;
  height: 48px;
  display: grid;
  place-items: center;
  border-radius: 16px;
}

.tile-icon.is-folder {
  background: rgba(109, 140, 255, 0.18);
  color: var(--accent);
}

.tile-icon.is-file {
  background: var(--tile-bg);
  color: var(--muted);
}

.tile-icon.is-add {
  background: none;
  border: 2px dashed var(--border);
  color: var(--muted);
  transition: border-color 0.15s ease, color 0.15s ease;
}

.add-tile:hover .tile-icon.is-add,
.add-tile:active .tile-icon.is-add {
  border-color: var(--accent);
  color: var(--accent);
}

.add-tile .tile-name {
  color: var(--muted);
}

/* ---------- Drag & drop ---------- */

.grid-tile {
  touch-action: manipulation;
}

/* Enabled only while a drag is running, so tiles glide aside to make room
   instead of teleporting. */
.file-grid.drag-active .grid-tile {
  transition: transform 0.22s cubic-bezier(0.32, 0.72, 0.35, 1);
}

/* Held down long enough to start a drag: the tile lifts, the way an app
   icon does before you move it. */
.grid-tile.lifted .tile-icon {
  transform: scale(1.12);
  transition: transform 0.18s cubic-bezier(0.32, 0.72, 0.35, 1);
  box-shadow: 0 8px 20px var(--shadow-ink-soft);
}

/* The original tile, while its copy rides under the finger/cursor. */
.grid-tile.drag-source {
  opacity: 0;
  pointer-events: none;
}

/* Carried, but still where it was: used where the grid does not rearrange,
   so nothing appears to leave the screen. */
.grid-tile.is-carried {
  opacity: 0.4;
  pointer-events: none;
}

.drag-ghost {
  position: fixed;
  z-index: 90;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
  padding: 6px;
  margin: 0;
  border: 0;
  background: none;
  color: var(--text);
  pointer-events: none;
  transform-origin: center;
  animation: drag-ghost-pop 0.18s cubic-bezier(0.32, 0.72, 0.35, 1) forwards;
  filter: drop-shadow(0 12px 24px var(--shadow-ink-strong));
}

@keyframes drag-ghost-pop {
  from { transform: scale(1); }
  to { transform: scale(1.1); }
}

.drag-ghost .tile-icon {
  width: 48px;
  height: 48px;
  display: grid;
  place-items: center;
  border-radius: 16px;
}

.drag-ghost .tile-icon svg {
  width: 26px;
  height: 26px;
}

.drag-ghost .tile-name {
  font-size: 12.5px;
  text-align: center;
  line-height: 1.2;
  max-width: 100%;
  overflow: hidden;
}

.drag-count {
  position: absolute;
  top: 0;
  right: 4px;
  min-width: 22px;
  height: 22px;
  padding: 0 6px;
  border-radius: 999px;
  background: var(--accent);
  color: #fff;
  font-size: 12px;
  font-weight: 800;
  display: grid;
  place-items: center;
}

/* Back arrow while items are hovering over it: hold here to go up a level. */
.back-btn.drag-hover {
  background: rgba(109, 140, 255, 0.45);
  border-color: rgba(109, 140, 255, 0.7);
  transform: scale(1.12);
  transition: transform 0.18s cubic-bezier(0.32, 0.72, 0.35, 1), background 0.18s ease;
}

/* Folder currently under the pointer -- release here to move the items in. */
.grid-tile.drop-target .tile-icon {
  transform: scale(1.22);
  background: rgba(109, 140, 255, 0.4);
  color: #fff;
  box-shadow: 0 0 0 3px rgba(109, 140, 255, 0.5);
  transition: transform 0.18s cubic-bezier(0.32, 0.72, 0.35, 1), background 0.18s ease, box-shadow 0.18s ease;
}

/* ---------- Selection mode ---------- */

.grid-tile.is-selected .tile-icon {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

.grid-tile.selectable {
  position: relative;
}

.grid-tile.selectable::after {
  content: "";
  position: absolute;
  top: 2px;
  left: 50%;
  margin-left: 12px;
  width: 20px;
  height: 20px;
  border-radius: 50%;
  border: 2px solid var(--film-5);
  background: var(--field-bg);
  transition: background 0.15s ease, border-color 0.15s ease;
}

/* ---------- Colour tags ---------- */

.tile-icon.is-tinted {
  background: color-mix(in srgb, var(--tag) calc(var(--tag-alpha) * 100%), transparent);
  color: var(--tag);
}

/* Sits directly above the action capsule, left-aligned with it. */
.color-bar {
  position: fixed;
  left: 16px;
  right: 16px;
  transform: translateY(8px);
  bottom: calc(88px + env(safe-area-inset-bottom));
  z-index: 45;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  padding: 12px 16px;
  border-radius: 999px;
  background: var(--glass-light);
  backdrop-filter: blur(22px) saturate(180%);
  -webkit-backdrop-filter: blur(22px) saturate(180%);
  border: 1px solid var(--glass-border);
  box-shadow: 0 10px 30px var(--shadow-ink-soft);
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.2s ease, transform 0.2s cubic-bezier(0.32, 0.72, 0.35, 1);
}

.color-bar.open {
  opacity: 1;
  transform: translateY(0);
  pointer-events: auto;
}

.color-bar.hidden {
  display: none;
}

/* On a phone the bar spans the screen and the swatches spread out to fill
   it. On a desktop that same rule left them scattered across a metre of
   glass, so there the bar shrinks to fit its contents and they sit close
   together, the way they do on the phone. */
@media (min-width: 620px) {
  .color-bar {
    left: 50%;
    right: auto;
    width: max-content;
    justify-content: center;
    gap: 12px;
    padding: 12px 18px;
    transform: translate(-50%, 8px);
  }

  .color-bar.open {
    transform: translate(-50%, 0);
  }
}

.color-dot {
  width: 26px;
  height: 26px;
  padding: 0;
  border-radius: 50%;
  border: 1px solid var(--film-4);
  background: var(--tag, #ffffff);
  flex-shrink: 0;
  min-height: 0;
  cursor: pointer;
}

/* White alone says nothing -- it looks like a colour called white. The
   diagonal stroke is what makes it read as "none". */
.color-dot.is-reset {
  position: relative;
  overflow: hidden;
}

.color-dot.is-reset::after {
  content: "";
  position: absolute;
  left: -20%;
  right: -20%;
  top: 50%;
  height: 2px;
  transform: translateY(-50%) rotate(-45deg);
  background: var(--danger);
  border-radius: 2px;
}

.theme-btn svg { width: 20px; height: 20px; }

/* The mode's name, said once and then withdrawn.

   It sits to the left of the button and takes no space when silent, so the
   toolbar does not shift as it comes and goes. */
.theme-label {
  margin-right: 2px;
  font-size: 13px;
  font-weight: 600;
  color: var(--muted);
  white-space: nowrap;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.28s ease;
}

.theme-label.is-showing { opacity: 1; }

/* Once emptied it must give its place back as well: a transparent-but-present
   span still claims the flex row's gap and shifts the round buttons. */
.theme-label:empty { display: none; }

/* Switched again while it was still fading: the transition is turned off for
   that instant so the old word vanishes outright, and the new one starts its
   fade from nothing rather than from whatever was left on screen. */
.theme-label.is-cut { transition: none; }

@media (max-width: 380px) {
  .theme-label { display: none; }
}

/* Keeps the moon and the sun on the same footing as the other round glass
   buttons rather than inventing a third size. */
.theme-btn {
  flex-shrink: 0;
}

/* ---------- Password reveal ---------- */

.field-password {
  position: relative;
}

.field-password input {
  padding-right: 52px;
}

.reveal-btn {
  position: absolute;
  right: 6px;
  top: 50%;
  transform: translateY(-50%);
  width: 40px;
  height: 40px;
  min-height: 0;
  padding: 0;
  display: grid;
  place-items: center;
  border: 0;
  border-radius: 50%;
  background: none;
  color: var(--muted);
  cursor: pointer;
}

.reveal-btn svg { width: 20px; height: 20px; }

.reveal-btn:hover,
.reveal-btn:active {
  color: var(--text);
  background: var(--film-1);
}

/* ---------- Edge swipes ----------

   The panel follows the finger, so the movement itself is the animation --
   there is no second copy of the screen to render, and nothing is held in
   memory for it. Transitions are off while the finger is down (the position
   IS the finger) and back on when it lifts, so the spring-back is smooth. */
.main-panel,
.move-sheet {
  will-change: transform;
  /* (the sheet's own touch-action is set below) */
}

/* Vertical panning belongs to the browser; horizontal belongs to us. Without
   saying so, the browser claims a sideways drag as a pan of its own and cuts
   the pointer stream off after a single move -- the swipe then starts and
   instantly dies. */
.main-panel {
  touch-action: pan-y;
}

/* The sheet is the exception: there the vertical direction is ours too, and
   leaving it to the browser is precisely why it would follow the finger a
   little and then spring back instead of closing -- the browser claimed the
   gesture and cancelled ours.

   Naming only the grabber and the header was not enough: a finger landing in
   the gap between them lands on the sheet itself, which still deferred. So
   the whole sheet defers to us, and the one part that genuinely scrolls --
   the list of folders -- gets vertical panning back. */
.move-sheet {
  touch-action: none;
}

.move-grid {
  touch-action: pan-y;
}

.main-panel {
  transition: transform 0.26s cubic-bezier(0.32, 0.72, 0.35, 1);
}

.main-panel.edge-dragging,
.move-sheet.edge-dragging {
  transition: none;
}

/* ---------- The back button, breathing ----------

   While something is being dragged, the back arrow becomes a place to drop
   it -- carry an item there and it goes up a level. Nothing said so.

   A slow breath is the hint: it takes four seconds, so it registers as an
   invitation rather than an alarm, and the glass lightens very slightly at
   the top of each breath, as though the light had caught it. It runs only
   while something is actually being carried. */
@keyframes back-breathe {
  0%, 100% {
    transform: scale(1);
    background: var(--film-2);
    border-color: var(--film-3);
  }
  50% {
    transform: scale(1.16);
    background: var(--film-4);
    border-color: var(--film-4);
  }
}

.drag-carrying .back-btn:not(.hidden) {
  animation: back-breathe 4s ease-in-out infinite;
}

/* Reached with a second finger, or hovered: it stops breathing and simply
   lights up, because at that point the hint has done its job. */
.drag-carrying .back-btn.drag-hover {
  animation: none;
}

@media (prefers-reduced-motion: reduce) {
  .drag-carrying .back-btn:not(.hidden) {
    animation: none;
    background: var(--film-4);
  }
}

/* Files shown in the move picker: there to identify the folder, not to be
   chosen, so they read as background rather than as options. */
.grid-tile.is-context {
  opacity: 0.4;
  cursor: default;
}

/* ---------- Shared tab selection ----------

   One action, so one target: a single round button where the tab bar was,
   large enough to be unmissable and red enough to be unmistakable. */
.share-selection-bar {
  position: fixed;
  left: 0;
  right: 0;
  /* About three quarters of a button higher than the files toolbar sits:
     down at the very bottom it was awkward to reach past. */
  bottom: calc(68px + env(safe-area-inset-bottom));
  z-index: 40;
  display: flex;
  justify-content: center;
  pointer-events: none;
}

.share-selection-bar.hidden { display: none; }

.share-revoke {
  pointer-events: auto;
  width: 68px;
  height: 68px;
  border-radius: 50%;
  display: grid;
  place-items: center;
  padding: 0;
  min-height: 0;
  border: 1px solid var(--glass-border);
  background: color-mix(in srgb, var(--danger) 92%, transparent);
  backdrop-filter: blur(22px) saturate(180%);
  -webkit-backdrop-filter: blur(22px) saturate(180%);
  box-shadow: 0 10px 30px var(--shadow-ink-soft);
  color: #fff;
}

.share-revoke svg { width: 28px; height: 28px; }

.share-revoke {
  transition: transform 0.18s cubic-bezier(0.32, 0.72, 0.35, 1),
              background 0.18s ease, box-shadow 0.18s ease;
}

/* Carrying shares over it: the bin opens up to take them. */
.share-revoke.is-receiving {
  transform: scale(1.28);
  background: var(--danger);
  box-shadow: 0 14px 40px color-mix(in srgb, var(--danger) 45%, transparent);
}

.share-revoke:disabled {
  opacity: 0.4;
}

/* On a desktop the navigation lives down the side, so it never has to make
   way -- the button simply sits at the bottom of the panel. */
@media (min-width: 860px) {
  .share-selection-bar {
    left: auto;
    right: 32px;
    bottom: calc(24px + env(safe-area-inset-bottom));
    justify-content: flex-end;
  }
}

/* One name, one variable, both themes. The swatch in the palette and the
   tint on a file read from the same place, so they can never drift apart. */
.tile-icon.is-tinted[data-tag="blue"],
.color-dot[data-color="blue"] { --tag: var(--tag-blue); }
.tile-icon.is-tinted[data-tag="teal"],
.color-dot[data-color="teal"] { --tag: var(--tag-teal); }
.tile-icon.is-tinted[data-tag="green"],
.color-dot[data-color="green"] { --tag: var(--tag-green); }
.tile-icon.is-tinted[data-tag="yellow"],
.color-dot[data-color="yellow"] { --tag: var(--tag-yellow); }
.tile-icon.is-tinted[data-tag="orange"],
.color-dot[data-color="orange"] { --tag: var(--tag-orange); }
.tile-icon.is-tinted[data-tag="red"],
.color-dot[data-color="red"] { --tag: var(--tag-red); }
.tile-icon.is-tinted[data-tag="pink"],
.color-dot[data-color="pink"] { --tag: var(--tag-pink); }
.tile-icon.is-tinted[data-tag="purple"],
.color-dot[data-color="purple"] { --tag: var(--tag-purple); }

/* ---------- Selection action bar ---------- */

/* Capsule hard left, the round menu button hard right, so both sit under a
   thumb rather than bunched in the middle. */
.selection-bar {
  position: fixed;
  left: 16px;
  right: 16px;
  bottom: calc(18px + env(safe-area-inset-bottom));
  z-index: 40;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  pointer-events: none;
}

.selection-bar > * {
  pointer-events: auto;
}

.selection-bar.hidden {
  display: none;
}

.selection-actions {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 8px 10px;
  border-radius: 999px;
  /* Lighter, more translucent than .glass-panel so the blur actually reads
     as glass against the dark background instead of looking flat. */
  background: var(--glass-light);
  backdrop-filter: blur(22px) saturate(180%);
  -webkit-backdrop-filter: blur(22px) saturate(180%);
  border: 1px solid var(--glass-border);
  box-shadow: 0 10px 30px var(--shadow-ink-soft);
}

.sel-action {
  width: 54px;
  height: 50px;
  display: grid;
  place-items: center;
  padding: 0;
  min-height: 0;
  border: 0;
  border-radius: 999px;
  background: none;
  color: var(--text);
}

.sel-action svg {
  width: 26px;
  height: 26px;
}

.sel-action:disabled {
  opacity: 0.35;
}

/* Deliberately the largest control on the bar: it is the one reached for
   most, and a 52px circle was still being missed on a phone.
   Scoped to .selection-bar on purpose -- .glass-btn sets 40px further down
   the file, and at equal specificity the later rule wins, which is why this
   button stayed stubbornly small however large the number here was. */
.selection-bar .selection-more {
  width: 62px;
  height: 62px;
  flex-shrink: 0;
}

.selection-bar .selection-more svg {
  width: 27px;
  height: 27px;
}

.grid-tile.selectable.is-selected::after {
  content: "✓";
  border-color: var(--accent);
  background: var(--accent);
  color: #fff;
  font-size: 13px;
  font-weight: 800;
  line-height: 17px;
  text-align: center;
}

.tile-icon svg {
  width: 26px;
  height: 26px;
}

.tile-name {
  font-size: 12.5px;
  text-align: center;
  line-height: 1.2;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
  word-break: break-word;
}

/* Where a search hit lives, when it was found outside the open folder. */
.tile-where {
  font-size: 11px;
  color: var(--muted);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  /* Bound to the tile, never the other way round. max-width alone left the
     element free to claim its full nowrap width first. */
  min-width: 0;
  max-width: 100%;
  align-self: stretch;
  text-align: center;
}

/* The heading that separates this folder's matches from the rest. */
.grid-divider {
  grid-column: 1 / -1;
  margin: 10px 2px 2px;
  padding-top: 12px;
  border-top: 1px solid var(--border);
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.02em;
  color: var(--muted);
}

/* ---------- List view ----------

   Not a second grid: the same tiles, turned on their side. Everything that
   measures where a tile actually sits -- the drag, the folder hold, the
   custom order -- keeps working without knowing which layout is on. */
.file-grid.list-view {
  grid-template-columns: minmax(0, 1fr);
  gap: 8px;
}

.file-grid.list-view .grid-tile {
  flex-direction: row;
  align-items: center;
  justify-content: flex-start;
  gap: 14px;
  /* Deliberately roomy: a thin row is hard to aim at, and this one has to
     be grabbable enough to drag. */
  min-height: 62px;
  padding: 8px 12px;
  border-radius: 18px;
  background: var(--film-1);
  text-align: left;
}

.file-grid.list-view .grid-tile .tile-icon {
  width: 42px;
  height: 42px;
  flex-shrink: 0;
}

.file-grid.list-view .tile-name {
  flex: 1;
  min-width: 0;
  text-align: left;
  font-size: 14.5px;
  -webkit-line-clamp: 1;
}

.file-grid.list-view .tile-where {
  flex-shrink: 0;
  max-width: 40%;
  align-self: auto;
  text-align: right;
}

.file-grid.list-view .grid-tile.selectable::after {
  top: 50%;
  right: 14px;
  left: auto;
  margin-left: 0;
  transform: translateY(-50%);
}

.file-grid.list-view .grid-tile.selectable.is-selected::after {
  line-height: 17px;
}

.file-grid.list-view .add-tile {
  justify-content: center;
  background: none;
}

.loading-hint,
.empty-hint {
  margin-top: 24px;
  text-align: center;
  color: var(--muted);
  -webkit-touch-callout: none;
  -webkit-user-select: none;
  user-select: none;
}

.settings-panel {
  padding-top: 8px;
}

.settings-panel .hint {
  color: var(--muted);
  margin-top: 16px;
}

.setting-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 14px 16px;
  margin-bottom: 18px;
  border-radius: 20px;
  background: var(--film-1);
  border: 1px solid var(--border);
  cursor: pointer;
}

.setting-label {
  display: grid;
  gap: 3px;
  font-size: 15px;
  font-weight: 600;
}

.setting-label small {
  font-size: 12.5px;
  font-weight: 400;
  color: var(--muted);
}

/* Sync state, sitting under its description: a quiet grey line normally,
   picking up colour only when it has something to report. */
/* Which file this share dialog is about -- essential once several files are
   shared one after another and the dialog reappears with a new subject. */
.share-target {
  margin: -6px 0 14px;
  font-size: 13.5px;
  color: var(--muted);
  overflow-wrap: anywhere;
}

.setting-status {
  margin-top: 2px;
  font-size: 12px;
  font-weight: 500;
}

.setting-status.is-ok { color: var(--ok); }
.setting-status.is-error { color: #ff8080; }
.setting-status.is-busy { color: var(--accent); }

.setting-label code {
  padding: 1px 4px;
  border-radius: 4px;
  background: var(--film-2);
  font-size: 11.5px;
}

.setting-row input[type="checkbox"] {
  width: 20px;
  height: 20px;
  flex-shrink: 0;
  accent-color: var(--accent);
}

/* ---------- Drag files in ---------- */

.drop-overlay {
  position: fixed;
  inset: 0;
  z-index: 70;
  display: grid;
  place-items: center;
  padding: 24px;
  background: var(--overlay);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  /* The overlay must never eat the drag events it is reacting to. */
  pointer-events: none;
}

.drop-overlay.hidden { display: none; }

.drop-card {
  display: grid;
  justify-items: center;
  gap: 14px;
  padding: 32px 40px;
  border-radius: 28px;
  border: 2px dashed var(--film-5);
  text-align: center;
}

.drop-card svg { width: 40px; height: 40px; }

.drop-card p {
  margin: 0;
  font-size: 15.5px;
  font-weight: 600;
}

/* ---------- Upload progress ---------- */

.upload-panel {
  position: fixed;
  left: 16px;
  right: 16px;
  bottom: calc(90px + env(safe-area-inset-bottom));
  z-index: 45;
  display: grid;
  gap: 8px;
  padding: 14px 16px;
  border-radius: 22px;
}

.upload-panel.hidden { display: none; }

@media (min-width: 900px) {
  .upload-panel {
    left: auto;
    right: 24px;
    bottom: 24px;
    width: 340px;
  }
}

.upload-head {
  display: flex;
  align-items: center;
  gap: 10px;
}

.upload-title {
  flex: 1;
  font-size: 14.5px;
  font-weight: 700;
}

.upload-percent {
  font-size: 14.5px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  color: var(--accent);
}

.upload-cancel {
  width: 30px;
  height: 30px;
  flex-shrink: 0;
}

.upload-cancel svg { width: 15px; height: 15px; }

.upload-name {
  margin: 0;
  font-size: 12.5px;
  color: var(--muted);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.upload-track {
  height: 6px;
  border-radius: 999px;
  background: var(--glass-light);
  overflow: hidden;
}

.upload-fill {
  height: 100%;
  width: 0%;
  border-radius: 999px;
  background: var(--accent);
  transition: width 0.2s ease;
}

/* The folder a drop would land in, highlighted like a drag target. */
.grid-tile.drop-into .tile-icon {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
}

/* On a phone the version is shown in the strip above the tab bar, so the
   copy inside the panel would be the second one on the same screen. */
@media (max-width: 859px) {
  .app-version { display: none; }
}

.app-version {
  margin-top: 18px;
  font-size: 12px;
  color: var(--muted);
  text-align: center;
  user-select: text;
}

#settingsPanel #logoutButton {
  width: auto;
  min-width: 140px;
  display: block;
  margin-left: auto;
  margin-right: auto;
}

.upload-fab {
  position: fixed;
  right: 18px;
  bottom: 84px;
  width: 56px;
  height: 56px;
  border-radius: 50%;
  font-size: 28px;
  line-height: 1;
  display: grid;
  place-items: center;
  padding: 0;
  box-shadow: 0 6px 18px var(--shadow-ink-soft);
}

/* Quota label: mobile only, sits above the floating tab bar */

.quota-label {
  position: fixed;
  left: 0;
  right: 0;
  bottom: calc(98px + env(safe-area-inset-bottom));
  text-align: center;
  font-size: 12.5px;
  font-weight: 600;
  color: var(--muted);
  pointer-events: none;
}

/* Bottom tab bar: mobile only, floating rounded glass pill */

.bottom-tabs {
  display: flex;
  position: fixed;
  left: 50%;
  bottom: calc(18px + env(safe-area-inset-bottom));
  transform: translateX(-50%);
  width: auto;
  gap: 4px;
  background: var(--glass-deep);
  backdrop-filter: blur(22px) saturate(160%);
  -webkit-backdrop-filter: blur(22px) saturate(160%);
  border: 1px solid var(--film-2);
  box-shadow: 0 10px 30px var(--shadow-ink-soft);
  border-radius: 999px;
  padding: 10px 18px;
}

.bottom-tabs .nav-tab {
  flex: 0 0 auto;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 3px;
  min-height: 0;
  line-height: 1;
  font-size: 10.5px;
  font-weight: 600;
  padding: 4px 12px;
}

.bottom-tabs .nav-tab svg {
  width: 22px;
  height: 22px;
  display: block;
  margin: 0 auto;
}

/* ---------- Glass / liquid-glass surfaces ---------- */

.glass-panel {
  background: var(--glass-deep);
  backdrop-filter: blur(22px) saturate(160%);
  -webkit-backdrop-filter: blur(22px) saturate(160%);
  border: 1px solid var(--film-2);
  box-shadow: 0 10px 30px var(--shadow-ink-soft);
}

.glass-btn {
  width: 40px;
  height: 40px;
  border-radius: 50%;
  display: grid;
  place-items: center;
  padding: 0;
  min-height: 0;
  color: var(--text);
  background: var(--film-2);
  backdrop-filter: blur(16px) saturate(160%);
  -webkit-backdrop-filter: blur(16px) saturate(160%);
  border: 1px solid var(--film-3);
}

.glass-btn svg {
  width: 20px;
  height: 20px;
}

/* ---------- App top bar ---------- */

.app-topbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  min-height: 40px;
  margin-bottom: 14px;
}

.topbar-title {
  flex: 1;
  /* A shade larger, with a little air between the letters -- it is the
     first thing read on the screen, so it carries the tone. */
  font-size: 25px;
  font-weight: 800;
  letter-spacing: 0.02em;
  text-align: center;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.back-btn.hidden + .topbar-title {
  text-align: left;
}

.quota-label-top {
  display: none;
  font-size: 13px;
  font-weight: 600;
  color: var(--muted);
  white-space: nowrap;
}

/* The +, hamburger and Mégse buttons share one slot: + and hamburger sit
   side by side, and the (absolutely positioned) Mégse button fades in over
   them in selection mode, so nothing jumps in the layout. */
.topbar-actions {
  position: relative;
  display: flex;
  align-items: center;
  gap: 8px;
  flex-shrink: 0;
}

.topbar-actions .glass-btn {
  transition: opacity 0.22s ease, transform 0.22s cubic-bezier(0.32, 0.72, 0.35, 1);
}

.selection-mode .topbar-actions .add-btn,
.selection-mode .topbar-actions .menu-btn {
  opacity: 0;
  transform: scale(0.7);
  pointer-events: none;
}

/* Round glass "done" button with a blue tick, sitting exactly where the
   + and hamburger buttons were. */
.confirm-btn {
  position: absolute;
  right: 0;
  top: 50%;
  color: var(--accent);
  opacity: 0;
  transform: translateY(-50%) scale(0.7);
  pointer-events: none;
}

.selection-mode .confirm-btn {
  opacity: 1;
  transform: translateY(-50%) scale(1);
  pointer-events: auto;
}

/* Left-hand "Összes" / "Kijelölés törlése" toggle. order:-1 floats it to
   the far left while keeping backButton next to the title in the markup,
   so the title's alignment rule still works. */
.select-all-btn {
  order: -1;
  display: none;
  min-height: 0;
  padding: 7px 14px;
  border-radius: 999px;
  border: 1px solid var(--film-3);
  background: var(--film-2);
  backdrop-filter: blur(16px) saturate(160%);
  -webkit-backdrop-filter: blur(16px) saturate(160%);
  color: var(--text);
  font: inherit;
  font-size: 13.5px;
  font-weight: 600;
  white-space: nowrap;
  flex-shrink: 0;
}

.selection-count {
  display: none;
  flex: 1;
  text-align: center;
  font-size: 14px;
  font-weight: 700;
  color: var(--text);
  white-space: nowrap;
}

.selection-mode .select-all-btn,
.selection-mode .selection-count {
  display: block;
}

/* Scoped to the main panel: the move picker has its own top bar with the
   same classes, and it must stay usable while selection mode is active. */
.selection-mode .main-panel > .app-topbar > .back-btn,
.selection-mode .main-panel > .app-topbar > .topbar-title,
.selection-mode .quota-label-top {
  display: none;
}

/* The action bar takes the tab capsule's place while selecting. */
.selection-mode .bottom-tabs,
.selection-mode .quota-label {
  display: none;
}

/* ---------- Grid tile selection / rename ---------- */

.grid-tile.selected .tile-icon {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

.tile-rename-input {
  width: 100%;
  font-size: 12.5px;
  text-align: center;
  background: var(--panel);
  color: var(--text);
  border: 1px solid var(--accent);
  border-radius: 8px;
  padding: 2px 4px;
}

/* ---------- Sheets / modals ---------- */

.sheet-overlay {
  position: fixed;
  inset: 0;
  /* Above the floating selection bar (40) and colour bar (45): on mobile the
     dialogs sit at the bottom of the screen, right where those float. */
  z-index: 60;
  display: flex;
  align-items: flex-end;
  justify-content: center;
  background: var(--shadow-ink-strong);
}

@media (min-width: 860px) {
  .sheet-overlay {
    align-items: center;
  }
}

/* ---------- "+" liquid-glass morphing menu ---------- */

.add-menu {
  position: fixed;
  z-index: 70;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  padding: 8px;
  gap: 2px;
  transition:
    left 0.3s cubic-bezier(0.32, 0.72, 0.35, 1),
    top 0.3s cubic-bezier(0.32, 0.72, 0.35, 1),
    width 0.3s cubic-bezier(0.32, 0.72, 0.35, 1),
    height 0.3s cubic-bezier(0.32, 0.72, 0.35, 1),
    border-radius 0.3s cubic-bezier(0.32, 0.72, 0.35, 1);
}

.add-menu.hidden {
  display: none;
}

.add-menu-item {
  display: flex;
  align-items: center;
  gap: 12px;
  width: 100%;
  min-height: 42px;
  padding: 10px 12px;
  border-radius: 17px;
  background: none;
  border: 0;
  color: var(--text);
  font: inherit;
  font-size: 14.5px;
  font-weight: 600;
  white-space: nowrap;
  flex-shrink: 0;
  opacity: 0;
  transition: opacity 0.15s ease, background 0.15s ease;
}

.add-menu.open .add-menu-item {
  opacity: 1;
  transition-delay: 0.1s;
}

.add-menu-item svg {
  width: 20px;
  height: 20px;
  flex-shrink: 0;
}

.add-menu-item:hover,
.add-menu-item:active {
  background: var(--film-2);
}

/* An unavailable action stays visible and greyed rather than vanishing, so
   the menu keeps its shape and it is obvious that the action exists but
   needs a selection first. */
.add-menu.open .add-menu-item:disabled,
.add-menu-item:disabled {
  opacity: 0.35;
  cursor: default;
}

.add-menu-item:disabled:hover,
.add-menu-item:disabled:active {
  background: none;
}

.menu-label {
  padding: 4px 12px 6px;
  font-size: 11.5px;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--muted);
  white-space: nowrap;
  opacity: 0;
  transition: opacity 0.15s ease;
}

.add-menu.open .menu-label {
  opacity: 1;
  transition-delay: 0.1s;
}

.menu-divider {
  height: 1px;
  margin: 4px 8px;
  background: var(--film-2);
  flex-shrink: 0;
  opacity: 0;
  transition: opacity 0.15s ease;
}

.add-menu.open .menu-divider {
  opacity: 1;
  transition-delay: 0.1s;
}

.menu-check {
  width: 20px;
  flex-shrink: 0;
  text-align: center;
  color: var(--accent);
  font-weight: 800;
}

.sort-option.active .menu-check::before,
.share-sort-option.is-active .menu-check::before {
  content: "✓";
}

.modal {
  width: 100%;
  max-width: 360px;
  margin: 0 12px 12px;
  border-radius: 24px;
  padding: 20px;
}

.confirm-text {
  margin: 0 0 10px;
  color: var(--muted);
  font-size: 14px;
}

.confirm-list {
  list-style: none;
  margin: 0 0 4px;
  padding: 0;
  max-height: 190px;
  overflow-y: auto;
  display: grid;
  gap: 4px;
}

.confirm-list li {
  padding: 8px 10px;
  border-radius: 14px;
  background: var(--film-1);
  font-size: 13.5px;
  word-break: break-all;
}

.modal-btn.danger-btn {
  background: var(--danger-strong);
  color: #fff;
}

.more-menu button.danger {
  color: #ff7b7b;
}

/* ---------- Move picker ---------- */

.move-picker {
  position: fixed;
  inset: 0;
  z-index: 80;
}

.move-picker.hidden {
  display: none;
}

.move-backdrop {
  position: absolute;
  inset: 0;
  background: var(--shadow-ink-strong);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  opacity: 0;
  transition: opacity 0.3s ease;
}

.move-picker.open .move-backdrop {
  opacity: 1;
}

/* Mobile: rises from the bottom, leaving the status bar visible. */
.move-sheet {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  top: 52px;
  display: flex;
  flex-direction: column;
  padding: 8px 16px 0;
  border-radius: 26px 22px 0 0;
  background: var(--bg);
  box-shadow: 0 -12px 40px var(--shadow-ink-strong);
  transform: translateY(100%);
  transition: transform 0.34s cubic-bezier(0.32, 0.72, 0.35, 1);
}

.move-picker.open .move-sheet {
  transform: translateY(0);
}

/* While a finger is dragging the sheet down we set transform inline. */
.move-picker.dragging .move-sheet {
  transition: none;
}

.move-grabber {
  width: 38px;
  height: 5px;
  margin: 2px auto 8px;
  border-radius: 999px;
  background: var(--film-4);
  flex-shrink: 0;
}

.move-topbar {
  flex-shrink: 0;
}

.move-confirm {
  min-height: 0;
  padding: 9px 18px;
  border: 0;
  border-radius: 999px;
  background: var(--accent);
  color: #fff;
  font: inherit;
  font-size: 15px;
  font-weight: 700;
  white-space: nowrap;
  flex-shrink: 0;
}

.move-grid {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  align-content: start;
  padding-bottom: 86px;
}

.move-count-wrap {
  position: absolute;
  left: 0;
  right: 0;
  bottom: calc(16px + env(safe-area-inset-bottom));
  display: flex;
  justify-content: center;
  pointer-events: none;
}

.move-count {
  padding: 12px 22px;
  border-radius: 999px;
  font-size: 14px;
  font-weight: 700;
}

/* Desktop: a centred rounded panel over a blurred background. */
@media (min-width: 860px) {
  .move-picker {
    display: grid;
    place-items: center;
  }

  .move-picker.hidden {
    display: none;
  }

  .move-sheet {
    position: relative;
    inset: auto;
    width: min(680px, 92vw);
    height: min(680px, 86vh);
    border-radius: 26px;
    padding: 8px 20px 0;
    transform: translateY(24px) scale(0.98);
    opacity: 0;
    transition: transform 0.28s cubic-bezier(0.32, 0.72, 0.35, 1), opacity 0.28s ease;
  }

  .move-picker.open .move-sheet {
    transform: translateY(0) scale(1);
    opacity: 1;
  }

  .move-grabber {
    display: none;
  }
}

@media (min-width: 860px) {
  .modal {
    margin: 0 12px;
  }
}

.modal h3 {
  margin: 0 0 14px;
}

.modal input[type="text"] {
  width: 100%;
  min-height: 44px;
  font-size: 16px;
  padding: 0 14px;
  border-radius: 14px;
  border: 1px solid var(--border);
  background: var(--field-bg);
  color: var(--text);
  margin-bottom: 16px;
}

.modal-actions {
  display: flex;
  gap: 10px;
}

/* Three answers do not fit side by side on a phone -- at that width they
   stack, newest-first, so the safe option is nearest the thumb. */
@media (max-width: 460px) {
  .modal-actions:has(#confirmAlt:not(.hidden)) {
    flex-direction: column-reverse;
  }
}

.modal-btn {
  flex: 1;
  background: var(--film-2);
  color: var(--text);
}

/* A primary action that cannot be taken -- an unopenable file type -- reads
   as visibly off rather than merely unresponsive. */
.detail-primary:disabled {
  opacity: 0.4;
  background: var(--film-2);
  color: var(--muted);
  cursor: default;
}

.modal-btn.primary {
  background: var(--accent);
  color: white;
}

.share-cancel {
  width: 100%;
  margin-top: 12px;
  background: var(--film-1);
  color: var(--muted);
}

/* ---------- File details sheet ---------- */

.detail-panel {
  position: relative;
  width: 100%;
  max-width: 380px;
  margin: 0 12px 12px;
  border-radius: 28px;
  padding: 28px 20px 20px;
  text-align: center;
}

@media (min-width: 860px) {
  .detail-panel {
    margin: 0 12px;
  }
}

.detail-close {
  position: absolute;
  top: 12px;
  right: 12px;
  width: 30px;
  height: 30px;
  border-radius: 50%;
  background: var(--film-2);
  color: var(--muted);
  min-height: 0;
  padding: 0;
}

.detail-icon {
  width: 64px;
  height: 64px;
  margin: 0 auto 14px;
  border-radius: 20px;
  background: var(--panel);
  color: var(--muted);
  display: grid;
  place-items: center;
}

.detail-icon svg {
  width: 32px;
  height: 32px;
}

.detail-name {
  margin: 0 0 16px;
  font-size: 16px;
  word-break: break-word;
}

.detail-info {
  list-style: none;
  margin: 0 0 20px;
  padding: 0;
  display: grid;
  gap: 8px;
  text-align: left;
}

.detail-info li {
  display: flex;
  justify-content: space-between;
  gap: 10px;
  font-size: 13px;
  color: var(--muted);
  border-bottom: 1px solid var(--border);
  padding-bottom: 8px;
}

.detail-info li span:first-child {
  flex-shrink: 0;
}

/* Long values -- a share URL especially -- have to wrap inside the card
   instead of running off the edge of the screen. */
.detail-info li span:last-child {
  color: var(--text);
  text-align: right;
  min-width: 0;
  overflow-wrap: anywhere;
  word-break: break-word;
}

.detail-actions {
  display: flex;
  gap: 10px;
  align-items: center;
}

.detail-primary {
  flex: 1;
  min-width: 0;
  border-radius: 999px;
}

.detail-round {
  flex-shrink: 0;
}

.more-menu {
  margin-top: 10px;
  display: grid;
  gap: 4px;
}

.more-menu button {
  background: var(--film-1);
  color: var(--text);
  border-radius: 16px;
}

/* ---------- Share sheet ---------- */

/* Full-width, like the buttons under it. */
#shareCreateBtn {
  display: block;
  width: 100%;
  border-radius: 999px;
}

.share-field {
  display: grid;
  gap: 6px;
  margin-bottom: 16px;
  text-align: left;
}

.share-field span {
  font-size: 13px;
  color: var(--muted);
}

.share-field select {
  min-height: 44px;
  border-radius: 14px;
  border: 1px solid var(--border);
  background: var(--field-bg);
  color: var(--text);
  padding: 0 10px;
  font-size: 16px;
}

/* One rounded field across the whole row. The chain at its head is the copy
   button: putting the action inside the field leaves the link all the width
   there is, instead of surrendering a third of it to a button. */
.share-result {
  margin-top: 16px;
  display: flex;
  align-items: center;
  gap: 0;
  min-height: 48px;
  border-radius: 18px;
  border: 1px solid var(--border);
  background: var(--field-bg);
  overflow: hidden;
}

.share-copy {
  display: grid;
  place-items: center;
  width: 46px;
  align-self: stretch;
  flex-shrink: 0;
  padding: 0;
  min-height: 0;
  border: 0;
  border-right: 1px solid var(--border);
  border-radius: 0;
  background: var(--film-1);
  color: var(--text);
  cursor: pointer;
  transition: background 0.15s ease, color 0.15s ease;
}

.share-copy svg { width: 19px; height: 19px; }

.share-copy:hover,
.share-copy:active {
  background: var(--glass-light);
}

.share-copy.is-copied {
  background: rgba(104, 211, 145, 0.22);
  color: var(--ok);
}

/* Matched with the same weight as `.modal input[type="text"]`, and placed
   after it, so the field really does give up its own border and rounding.
   Without that it kept them, and the link appeared inside a second box. */
.share-result input[type="text"] {
  flex: 1;
  width: auto;
  min-width: 0;
  align-self: stretch;
  min-height: 0;
  margin: 0;
  border: 0;
  border-radius: 0;
  background: none;
  color: var(--text);
  padding: 0 12px;
  font-size: 13px;
}

@media (min-width: 860px) {
  .app-body {
    flex-direction: row;
  }

  .side-nav {
    display: flex;
    flex-direction: column;
    width: 240px;
    flex-shrink: 0;
    padding: 24px 12px;
    border-right: 1px solid var(--border);
    order: 2;
  }

  .main-panel {
    order: 1;
    padding: 28px 32px 96px;
  }

  .file-grid {
    grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
  }

  .bottom-tabs {
    display: none;
  }

  .quota-label {
    display: none;
  }

  .quota-label-top {
    display: inline-flex;
    align-items: center;
  }
}