/*
  Visual language pulled from https://infinite-trails.com/: near-black
  background, orange accent, sharp corners (no border-radius anywhere),
  adidas webfonts (adihausregular for copy, adiBlack for headlines/CTAs).
  Mobile-first; the grid/layout progressively enhances at wider breakpoints.
*/

@font-face {
  font-family: adihausregular;
  src: url("../fonts/adihausregular.woff2") format("woff2"),
       url("../fonts/adihausregular.woff") format("woff"),
       url("../fonts/adihausregular.ttf") format("truetype");
  font-weight: normal;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: adiBlack;
  src: url("../fonts/adineuePRO-BlackWeb.woff2") format("woff2"),
       url("../fonts/adineuePRO-BlackWeb.woff") format("woff"),
       url("../fonts/adineuePRO-BlackWeb.ttf") format("truetype");
  font-weight: normal;
  font-style: normal;
  font-display: swap;
}

:root {
  --bg: #020101;
  --bg-raised: #141414;
  --bg-card: #1a1a1a;
  --border: #2c2c2c;
  --text: #f5f5f5;
  --text-muted: #a8a8a8;
  --accent: #e35431;
  --accent-hover: #ff6a44;
  --success-bg: #16342a;
  --success-border: #2aa379;
  --error: #e35431;
  --font-heading: adiBlack, "Arial Narrow", Arial, "Helvetica Neue", Helvetica, sans-serif;
  --font-body: adihausregular, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
}

* {
  box-sizing: border-box;
}

html, body {
  margin: 0;
  padding: 0;
}

/* No rounded corners anywhere, matching infinite-trails.com - iOS/Safari in
   particular applies its own rounded chrome to form controls unless the
   native appearance is explicitly turned off. */
button,
input,
textarea,
select {
  appearance: none;
  -webkit-appearance: none;
  border-radius: 0;
}

/* visible checkboxes (e.g. "select all") get a sharp custom box with the
   arrow as the checked-state mark, instead of the native OS checkmark */
input[type="checkbox"] {
  width: 18px;
  height: 18px;
  border: 2px solid var(--text-muted);
  background: transparent;
  position: relative;
  flex-shrink: 0;
  vertical-align: middle;
}

input[type="checkbox"]:checked {
  background: var(--accent);
  border-color: var(--accent);
}

input[type="checkbox"]:checked::after {
  content: "";
  position: absolute;
  inset: 0;
  background-image: url("../img/arrow.svg");
  background-repeat: no-repeat;
  background-position: center;
  background-size: 9px 9px;
  transform: rotate(180deg);
}

body {
  background: var(--bg);
  color: var(--text);
  font-family: var(--font-body);
  font-size: 15px;
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
  /* this is a browsing/tapping UI, not text content - without this, iOS in
     particular will happily start a text-selection (the blue highlight bar)
     from an ordinary tap or a press-and-hold gesture anywhere on the page */
  -webkit-user-select: none;
  user-select: none;
  -webkit-tap-highlight-color: transparent;
}

/* ...except actual text-entry fields, which should keep normal selection */
input[type="text"],
input[type="password"] {
  -webkit-user-select: text;
  user-select: text;
}

h1, h2, h3 {
  font-family: var(--font-heading);
  font-weight: 400;
  text-transform: uppercase;
  letter-spacing: 0.02em;
  margin: 0 0 0.5em;
}

a {
  color: var(--accent);
}

button {
  cursor: pointer;
  font-family: var(--font-body);
}

/* ---------- icons ---------- */

.icon-arrow {
  display: inline-block;
  background-image: url("../img/arrow.svg");
  background-repeat: no-repeat;
  background-position: center;
  background-size: contain;
  flex-shrink: 0;
}

/* ---------- buttons ---------- */
/* Outline-button pattern matching infinite-trails.com's CTAs (e.g. "Meet
   all partners"): transparent background, 2px solid border, uppercase
   adiBlack text, sharp corners. Fills solid on hover for feedback. */

.btn-primary {
  display: inline-block;
  background: transparent;
  color: var(--accent);
  border: 2px solid var(--accent);
  padding: 0.75em 1.8em;
  font-family: var(--font-heading);
  font-weight: 400;
  text-transform: uppercase;
  letter-spacing: 0.02em;
  font-size: 0.9em;
  text-align: center;
  text-decoration: none;
  transition: background-color 0.15s ease, color 0.15s ease;
}

.btn-primary:hover,
.btn-primary:focus-visible {
  background: var(--accent);
  color: var(--bg);
}

.btn-primary[hidden] {
  display: none;
}

.btn-secondary {
  display: inline-block;
  background: transparent;
  color: var(--text);
  border: 2px solid var(--border);
  padding: 0.6em 1.6em;
  font-family: var(--font-heading);
  font-weight: 400;
  text-transform: uppercase;
  letter-spacing: 0.02em;
  text-decoration: none;
  font-size: 0.85em;
  transition: border-color 0.15s ease, color 0.15s ease;
}

.btn-secondary:hover,
.btn-secondary:focus-visible {
  border-color: var(--text);
}

.btn-link {
  display: inline-block;
  color: var(--text-muted);
  text-decoration: underline;
  margin-top: 0.75em;
  font-size: 0.9em;
}

/* ---------- login page ---------- */

/* .page-login is min-height:100vh flex-column (not .login-shell itself) so
   the footer, which sits after .login-shell as its own flex item, is
   accounted for instead of pushing the page to 100vh + footer height and
   causing an unnecessary scrollbar. */
.page-login {
  min-height: 100vh;
  display: flex;
  flex-direction: column;
}

.login-shell {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 32px 20px;
}

.login-card {
  width: 100%;
  max-width: 420px;
  text-align: center;
}

.login-logo {
  max-width: 220px;
  width: 60%;
  height: auto;
  margin: 0 auto 24px;
  display: block;
}

.login-card h1 {
  font-size: 1.6em;
  margin-bottom: 1em;
}

.login-form {
  text-align: left;
  background: var(--bg-card);
  border: 1px solid var(--border);
  padding: 24px;
}

.login-form label {
  display: block;
  font-size: 0.8em;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--text-muted);
  margin-bottom: 6px;
}

.login-form input[type="text"],
.login-form input[type="password"] {
  width: 100%;
  background: #0c0c0c;
  border: 1px solid var(--border);
  color: var(--text);
  padding: 0.75em 0.9em;
  font-size: 1em;
  margin-bottom: 16px;
  font-family: var(--font-body);
}

.login-form input.has-error {
  border-color: var(--error);
}

.login-form .btn-primary {
  width: 100%;
  border-width: 2px;
}

.error-message {
  color: var(--accent-hover);
  font-size: 0.85em;
  margin: -8px 0 16px;
}

.login-status {
  margin-bottom: 16px;
}

.apply-note {
  margin-top: 24px;
  font-size: 0.85em;
  color: var(--text-muted);
}

.apply-note a {
  color: var(--text);
}

/* ---------- gallery shell ---------- */

.site-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 20px 16px;
  border-bottom: 1px solid var(--border);
  position: sticky;
  top: 0;
  background: var(--bg);
  z-index: 10;
  transition: padding 0.25s ease;
}

.site-header .brand img {
  height: 68px;
  display: block;
  transition: height 0.25s ease;
}

.site-header.is-scrolled {
  padding: 10px 16px;
}

.site-header.is-scrolled .brand img {
  height: 32px;
}

.site-title {
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  font-family: var(--font-heading);
  font-size: 0.75em;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  color: var(--text);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  /* leaves room for the logo/logout on a 320px-wide viewport regardless of
     how wide those end up being */
  max-width: 42vw;
  pointer-events: none;
}

.site-footer {
  display: flex;
  justify-content: center;
  gap: 20px;
  padding: 20px 16px calc(20px + env(safe-area-inset-bottom));
  border-top: 1px solid var(--border);
}

/* The gallery page's action bar is fixed to the viewport bottom (see the
   comment above .action-bar in gallery.php) and would otherwise cover the
   footer whenever the page is scrolled all the way down - reserve enough
   extra space for it to clear, regardless of whether the folder currently
   shown via AJAX nav has files (the body class is set once per full page
   load, not per folder). */
.page-gallery .site-footer {
  padding-bottom: calc(84px + env(safe-area-inset-bottom));
}

.site-footer a {
  color: var(--text-muted);
  text-decoration: none;
  font-size: 0.8em;
}

.site-footer a:hover {
  color: var(--text);
}

.logout-link {
  color: var(--text-muted);
  text-decoration: none;
  font-size: 0.85em;
  text-transform: uppercase;
  letter-spacing: 0.04em;
}

.breadcrumb {
  padding: 12px 16px;
  font-size: 0.85em;
  color: var(--text-muted);
  overflow-x: auto;
  white-space: nowrap;
  /* on overflow, anchor to the END (current folder) rather than the start:
     flipping the scroll container to rtl makes its resting scroll position
     show the right edge, so ancestors run off-screen to the left instead of
     the current folder running off-screen to the right on mobile. The
     actual breadcrumb items are re-flipped to ltr below so they still read
     left-to-right. */
  direction: rtl;
}

.breadcrumb-track {
  direction: ltr;
  unicode-bidi: isolate;
  display: inline-block;
}

.breadcrumb a {
  color: var(--text-muted);
  text-decoration: none;
}

.breadcrumb a:last-of-type {
  color: var(--text);
}

.breadcrumb .sep {
  display: inline-block;
  width: 7px;
  height: 7px;
  margin: 0 10px;
  vertical-align: middle;
  transform: rotate(180deg);
  opacity: 0.4;
}

.banner-ready {
  margin: 0 16px 16px;
  padding: 14px 16px;
  background: var(--success-bg);
  border: 1px solid var(--success-border);
  font-size: 0.9em;
}

.banner-ready a {
  color: #7ee9c4;
  font-weight: 700;
}

.empty-state {
  padding: 40px 16px;
  text-align: center;
  color: var(--text-muted);
}

.search-bar {
  padding: 0 16px;
}

.search-input-wrap {
  position: relative;
}

.search-input {
  width: 100%;
  padding: 10px 40px 10px 12px;
  background: var(--bg-card);
  border: 1px solid var(--border);
  color: var(--text);
  font-family: var(--font-body);
  font-size: 0.95em;
}

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

.search-input:focus-visible {
  outline: 1px solid var(--accent);
  outline-offset: 2px;
}

/* the browser's native search-cancel button renders in its own accent
   color (blue on WebKit) that clashes with this app's palette - hidden in
   favor of the custom .search-clear button below */
.search-input::-webkit-search-cancel-button,
.search-input::-webkit-search-decoration {
  -webkit-appearance: none;
  appearance: none;
}

.search-clear {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  width: 40px;
  background: transparent;
  border: none;
  color: var(--text);
  font-size: 1.3em;
  line-height: 1;
  cursor: pointer;
  padding: 0;
}

.search-clear:hover,
.search-clear:focus-visible {
  color: var(--accent);
}

.search-status {
  padding: 16px 16px 0;
}

.search-summary {
  color: var(--text-muted);
  font-size: 0.85em;
  margin: 0;
}

.search-filters {
  display: flex;
  flex-wrap: wrap;
  gap: 16px;
  padding: 12px 16px 0;
}

.search-filter-group {
  display: flex;
  gap: 4px;
}

.search-filter-group a {
  padding: 4px 10px;
  border: 1px solid var(--border);
  color: var(--text-muted);
  text-decoration: none;
  font-size: 0.8em;
  text-transform: uppercase;
  letter-spacing: 0.03em;
}

.search-filter-group a.is-active {
  border-color: var(--accent);
  color: var(--text);
}

/* year picker is a native <select> rather than a row of pills, since the
   list of years only ever grows (one more added every year this event
   runs) - a row of buttons would keep demanding more horizontal space
   indefinitely, while a dropdown stays a single line regardless. The
   global `select { appearance: none; }` reset (see the top of this file)
   already strips the native arrow, so a small custom chevron is drawn via
   background-image here instead. */
.search-year-select {
  padding: 4px 26px 4px 10px;
  background-color: var(--bg-card);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6' viewBox='0 0 10 6'%3E%3Cpath d='M1 1l4 4 4-4' stroke='%23a8a8a8' stroke-width='1.5' fill='none' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 10px center;
  border: 1px solid var(--border);
  color: var(--text);
  font-family: var(--font-body);
  font-size: 0.8em;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  cursor: pointer;
}

.search-year-select:focus-visible {
  outline: 1px solid var(--accent);
  outline-offset: 2px;
}

.tile-path {
  display: block;
  color: var(--text-muted);
  font-size: 0.75em;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* ---------- gallery navigation transition ---------- */
/* A large arrow flashes in via opacity at the centre of the screen between
   folder changes - pointing right when moving into a child folder, left
   when moving back up to a parent. Kept short so it never feels like a
   wait, just a quick directional cue for where you just went. */

#galleryMain {
  opacity: 1;
  transition: opacity 0.12s ease;
}

#galleryMain.is-transitioning {
  opacity: 0.4;
}

.nav-sweep {
  position: fixed;
  inset: 0;
  z-index: 50;
  display: flex;
  align-items: center;
  justify-content: center;
  pointer-events: none;
}

.nav-sweep .icon-arrow {
  width: 26vw;
  height: 26vw;
  max-width: 130px;
  max-height: 130px;
  opacity: 0;
}

.nav-sweep.sweep-forward .icon-arrow {
  transform: rotate(180deg);
  animation: arrow-flash 0.3s ease-out;
}

.nav-sweep.sweep-back .icon-arrow {
  transform: rotate(0deg);
  animation: arrow-flash 0.3s ease-out;
}

@keyframes arrow-flash {
  0% {
    opacity: 0;
  }
  30% {
    opacity: 0.95;
  }
  70% {
    opacity: 0.95;
  }
  100% {
    opacity: 0;
  }
}

/* ---------- file/folder grid ---------- */

.grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 12px;
  padding: 4px 16px 120px;
}

@media (min-width: 480px) {
  .grid {
    grid-template-columns: repeat(3, 1fr);
  }
}

@media (min-width: 720px) {
  .grid {
    grid-template-columns: repeat(4, 1fr);
    gap: 16px;
  }
}

@media (min-width: 1000px) {
  .grid {
    grid-template-columns: repeat(6, 1fr);
  }

  .site-title {
    font-size: 23px;
  }
}

.tile {
  position: relative;
  /* establishes a proper stacking context so ::before's negative z-index
     below is scoped to this tile, instead of potentially escaping behind
     sibling tiles or the grid's own background */
  isolation: isolate;
  background: var(--bg-card);
  border: 1px solid var(--border);
  overflow: hidden;
  display: flex;
  flex-direction: column;
}

/* faint watermark on every tile, matching how infinite-trails.com uses this
   graphic: flush with the right edge, full tile height, pointing right
   to left (its native, unrotated orientation). A *positioned* z-index:0
   element still paints above ordinary static content regardless of DOM
   order - it needs a negative z-index to actually sit behind the
   thumb/icon/name, which is why .tile above needs its own stacking
   context (so -1 stays contained here rather than escaping to a parent). */
.tile::before {
  content: "";
  position: absolute;
  inset: 0;
  background-image: url("../img/arrow.svg");
  background-repeat: no-repeat;
  background-position: right center;
  background-size: auto 100%;
  opacity: 0.07;
  pointer-events: none;
  z-index: -1;
}

.tile-dir {
  align-items: center;
  justify-content: center;
  text-align: center;
  text-decoration: none;
  color: var(--text);
  aspect-ratio: 1 / 1;
  gap: 10px;
  padding: 12px;
}

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

/* sharp solid tag with the arrow as the design element - deliberately not a
   literal folder-with-tab shape, to suit the CI's sharp/graphic language */
.icon-folder {
  width: 40px;
  height: 40px;
  background: var(--accent);
  display: flex;
  align-items: center;
  justify-content: center;
}

.icon-folder .icon-arrow {
  width: 13px;
  height: 13px;
  transform: rotate(180deg);
}

/* "Back" tile reuses the folder tile look, but the arrow points the other
   way - same rotate(0)/rotate(180) convention as .nav-sweep's
   sweep-back/sweep-forward transition. */
.tile-back .icon-folder .icon-arrow {
  transform: rotate(0deg);
}

.tile-dir .tile-name {
  font-size: 0.8em;
  word-break: break-word;
  color: var(--text);
}

.tile-updated {
  position: absolute;
  left: 8px;
  bottom: 6px;
  font-size: 0.65em;
  color: var(--text-muted);
  pointer-events: none;
}

.tile-file {
  padding-top: 6px;
}

.tile-file input.file-select {
  position: absolute;
  opacity: 0;
  pointer-events: none;
}

.tile-link {
  display: flex;
  flex-direction: column;
  text-decoration: none;
  color: var(--text);
  padding: 6px 8px 10px;
}

.tile-thumb {
  aspect-ratio: 1 / 1;
  background-color: #0c0c0c;
  /* generic document glyph shown behind the <img>; a real (opaque) thumbnail
     fully covers it, so it only shows through for file types we can't
     rasterize a preview for (thumb.php then serves a transparent pixel) */
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23444' stroke-width='1.5'%3E%3Cpath d='M6 2h9l5 5v15a1 1 0 0 1-1 1H6a1 1 0 0 1-1-1V3a1 1 0 0 1 1-1z'/%3E%3Cpath d='M15 2v5h5'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: center;
  background-size: 34%;
  overflow: hidden;
  display: flex;
  align-items: center;
  justify-content: center;
  margin-bottom: 8px;
}

.tile-thumb img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

.tile-name {
  font-size: 0.78em;
  word-break: break-word;
  line-height: 1.3;
  max-height: 2.6em;
  overflow: hidden;
}

.tile-size {
  font-size: 0.72em;
  color: var(--text-muted);
  margin-top: 4px;
}

.tile-select-toggle {
  position: absolute;
  /* aligned to sit flush with .tile-thumb's actual top-right corner:
     .tile's 1px border + .tile-file's 6px padding-top + .tile-link's own
     6px padding-top (top), and .tile's 1px border + .tile-link's 8px
     padding-right (right) - keep in sync if any of those change */
  top: 13px;
  right: 9px;
  width: 26px;
  height: 26px;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
}

.checkbox-visual {
  width: 24px;
  height: 24px;
  border: 2px solid rgba(255, 255, 255, 0.6);
  background: rgba(0, 0, 0, 0.35);
  display: flex;
  align-items: center;
  justify-content: center;
}

.checkbox-visual .icon-arrow {
  width: 10px;
  height: 10px;
  transform: rotate(180deg);
  opacity: 0;
  transition: opacity 0.1s ease;
}

.file-select:checked ~ .tile-select-toggle .checkbox-visual,
.lightbox-select.is-selected .checkbox-visual {
  background: var(--accent);
  border-color: var(--accent);
}

.file-select:checked ~ .tile-select-toggle .checkbox-visual .icon-arrow,
.lightbox-select.is-selected .checkbox-visual .icon-arrow {
  opacity: 1;
}

.file-select:checked ~ .tile-link {
  outline: 2px solid var(--accent);
  outline-offset: -2px;
}

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

.action-bar {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 10px 16px;
  padding-bottom: calc(10px + env(safe-area-inset-bottom));
  background: var(--bg-raised);
  border-top: 1px solid var(--border);
  z-index: 20;
}

.action-bar-info {
  display: flex;
  flex-direction: column;
  gap: 3px;
  min-width: 0;
  flex: 1;
}

.select-all {
  font-size: 0.85em;
  color: var(--text-muted);
  display: flex;
  align-items: center;
  gap: 6px;
  white-space: nowrap;
}

.selection-summary {
  font-size: 0.78em;
  color: var(--text-muted);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.action-bar .btn-primary {
  flex-shrink: 0;
  padding: 0.7em 1.3em;
  font-size: 0.8em;
}

/* ---------- lightbox ---------- */

.lightbox {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.92);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 100;
  padding: 24px;
}

.lightbox[hidden] {
  display: none;
}

.lightbox-image {
  max-width: 100%;
  max-height: 100%;
  object-fit: contain;
  touch-action: pan-y;
  user-select: none;
  -webkit-user-drag: none;
  /* stops iOS Safari's own long-press "Save Image" callout from competing
     with the press-and-hold zoom gesture below */
  -webkit-touch-callout: none;
  cursor: zoom-in;
  transition: transform 0.18s ease;
}

.lightbox-image.is-zoomed {
  cursor: zoom-out;
}

.lightbox-close,
.lightbox-nav {
  position: absolute;
  border: none;
  background-color: rgba(255, 255, 255, 0.12);
  background-repeat: no-repeat;
  background-position: center;
  background-image: url("../img/arrow.svg");
}

.lightbox-close:hover,
.lightbox-nav:hover {
  background-color: rgba(255, 255, 255, 0.22);
}

.lightbox-close {
  top: 16px;
  right: 16px;
  width: 44px;
  height: 44px;
  background-size: 14px 14px;
  transform: rotate(-90deg);
}

.lightbox-nav {
  top: 50%;
  width: 48px;
  height: 48px;
  background-size: 16px 16px;
  transform: translateY(-50%);
}

.lightbox-prev {
  left: 12px;
}

.lightbox-next {
  right: 12px;
  transform: translateY(-50%) rotate(180deg);
}

@media (min-width: 720px) {
  .lightbox-prev {
    left: 24px;
  }

  .lightbox-next {
    right: 24px;
  }
}

.lightbox-filename {
  position: absolute;
  left: 50%;
  bottom: 76px;
  transform: translateX(-50%);
  color: #fff;
  font-family: var(--font-body);
  font-size: 0.85em;
  white-space: nowrap;
  text-shadow: 0 1px 3px rgba(0, 0, 0, 0.8);
  pointer-events: none;
}

@media (min-width: 720px) {
  .lightbox-filename {
    left: 24px;
    bottom: 24px;
    transform: none;
  }
}

.lightbox-select[hidden] {
  display: none;
}

.lightbox-select {
  position: absolute;
  left: 50%;
  bottom: 24px;
  transform: translateX(-50%);
  display: flex;
  align-items: center;
  gap: 10px;
  border: 1px solid var(--border);
  background: rgba(20, 20, 20, 0.85);
  color: #fff;
  padding: 0.6em 1.2em 0.6em 0.7em;
  font-size: 0.9em;
  font-family: var(--font-body);
}

.lightbox-select .checkbox-visual {
  border-color: rgba(255, 255, 255, 0.6);
}

.lightbox-select.is-selected {
  border-color: var(--accent);
  background: rgba(227, 84, 49, 0.18);
}

/* ---------- zip processing page ---------- */

.zip-processing {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 100vh;
  padding: 24px;
}

.processing-card {
  max-width: 420px;
  width: 100%;
  text-align: center;
}

.progress {
  background: var(--bg-card);
  border: 1px solid var(--border);
  height: 14px;
  overflow: hidden;
  margin: 20px 0 10px;
}

.progress-bar {
  height: 100%;
  background: var(--accent);
  width: 0%;
  transition: width 0.3s ease;
}

.muted {
  color: var(--text-muted);
  font-size: 0.85em;
}
