/* ============================================================
   App layout built on the glass system
   ============================================================ */

* { margin: 0; padding: 0; box-sizing: border-box; }

body {
  font-family: var(--font);
  color: var(--text);
  background: transparent;
  min-height: 100vh;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
}

.container {
  width: 100%;
  max-width: var(--maxw);
  margin: 0 auto;
  padding: 0 var(--gutter);
}

/* ---------------- topbar ---------------- */
/* Edges must line up with the content panels: inset by the gutter on each
   side, so the glass box starts exactly where .container's panels start
   (left = gutter when narrow, (W - maxw)/2 + gutter when capped). */
.topbar {
  position: sticky; top: 14px; z-index: 50;
  width: calc(100% - 2 * var(--gutter));
  max-width: calc(var(--maxw) - 2 * var(--gutter));
  margin: 14px auto 0;
  /* horizontal padding matches the panels' 26px so the brand text and the
     module titles start on the same line */
  padding: 14px 26px;
  display: flex; align-items: center; justify-content: space-between;
  gap: 16px; flex-wrap: wrap;
}

.brand { display: flex; align-items: center; gap: 11px; min-width: 0; }
.logo {
  width: 38px; height: 38px; border-radius: 12px;
  background: linear-gradient(135deg, var(--accent), var(--accent-2));
  display: inline-flex; align-items: center; justify-content: center;
  color: #fff; font-weight: 700; font-size: 17px;
  box-shadow: 0 6px 18px var(--accent-soft);
  flex: none;
}
.brand-text strong { display: block; font-size: 16px; letter-spacing: -.01em; }
.brand-text small { color: var(--text-3); font-size: 12px; }

.actions { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }

/* ---------------- announcement ---------------- */
/* Same edge maths as the topbar/footer so all three chrome boxes line up
   with the content panels. */
.announce {
  width: calc(100% - 2 * var(--gutter));
  max-width: calc(var(--maxw) - 2 * var(--gutter));
  margin: 16px auto 0;
  padding: 12px 26px;
  font-size: 14px;
  color: var(--text-2);
  border-left: 3px solid var(--accent);
}

/* ---------------- hero ---------------- */
.hero { text-align: center; padding: 46px 0 30px; }
.hero h1 {
  font-size: clamp(30px, 5vw, 46px);
  font-weight: 800; letter-spacing: -.03em;
  background: linear-gradient(135deg, var(--accent), var(--accent-2));
  -webkit-background-clip: text; background-clip: text;
  color: transparent;
}
.hero p { color: var(--text-3); margin-top: 8px; font-size: 15px; }

/* ---------------- category chips ---------------- */
.chips { display: flex; gap: 6px; flex-wrap: wrap; justify-content: center; margin-bottom: 0; }
.chip {
  font-family: inherit; font-size: 12px; font-weight: 600;
  padding: 4px 12px; border-radius: 999px; cursor: pointer;
  border: 1px solid var(--glass-border);
  background: var(--chip-bg); color: var(--text-2);
  backdrop-filter: blur(12px);
  transition: all .2s var(--ease);
}
.chip:hover { transform: translateY(-1px); color: var(--text); }
.chip.active {
  color: var(--accent-contrast);
  background: linear-gradient(135deg, var(--accent), var(--accent-2));
  border-color: transparent;
  box-shadow: 0 6px 18px var(--accent-soft);
}

/* count rendered as a themed glass pill rather than bare text */
.userchip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  max-width: 160px;
  padding: 6px 13px;
  border-radius: 999px;
  font-size: 12.5px;
  font-weight: 600;
  color: var(--text-2);
  background: var(--glass-bg-2);
  border: 1px solid var(--glass-border);
}
.userchip::before { content: "👤"; font-size: 12px; }
.userchip span {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.userchip:empty { display: none; }

.count {
  font-size: 12.5px;
  font-weight: 600;
  color: var(--text-2);
  padding: 6px 14px;
  border-radius: 999px;
  background: var(--glass-bg-2);
  border: 1px solid var(--glass-border);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
}

/* ---------------- resource grid ---------------- */
.grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(215px, 1fr));
  gap: 14px;
  padding: 0 0 40px;
}

/* whole card is clickable: it IS the anchor */
.card.res {
  display: block;
  padding: 0;
  color: inherit;
  text-decoration: none;
  border-radius: var(--radius-lg);
  transition: transform .28s var(--ease), box-shadow .28s var(--ease);
}
.card.res:hover { transform: translateY(-4px); box-shadow: var(--glass-shadow-lg); }

.res-body { padding: 12px 13px 13px; }

.res-cover {
  height: 94px;
  margin: 0 0 10px;
  display: flex; align-items: center; justify-content: center;
  font-size: 30px;
  background: linear-gradient(135deg,
              color-mix(in srgb, var(--accent) 22%, transparent),
              color-mix(in srgb, var(--accent-2) 22%, transparent));
  background-size: cover;
  background-position: center;
}

.res-title {
  font-size: 13.5px;
  font-weight: 700;
  letter-spacing: -.01em;
  display: flex;
  align-items: center;
  gap: 6px;
  line-height: 1.4;
}

.res-desc {
  font-size: 12px;
  color: var(--text-3);
  margin-top: 6px;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.res-meta {
  display: flex;
  gap: 8px;
  margin-top: 9px;
  font-size: 11px;
  color: var(--text-3);
  flex-wrap: wrap;
}

.res-tags {
  display: flex;
  gap: 5px;
  flex-wrap: wrap;
  margin-top: 8px;
}

.tag {
  font-size: 10.5px;
  padding: 2px 8px;
  border-radius: 999px;
  background: var(--accent-soft);
  color: var(--accent);
  font-weight: 600;
}

.badge {
  font-size: 10.5px;
  padding: 2px 7px;
  border-radius: 6px;
  font-weight: 700;
  background: linear-gradient(135deg, var(--accent), var(--accent-2));
  color: var(--accent-contrast);
}

.res-actions { display: none; }

.empty { text-align: center; padding: 60px 20px; color: var(--text-3); }

/* ---------------- public modules ----------------
   The homepage is split into functional panels that reuse the exact surface
   and title rule the admin console uses (.panel shares .admin-grid > .card
   and .admin-grid h3 rules above), so both pages read as one system. */
.modules {
  display: grid;
  grid-template-columns: 1fr;
  gap: 26px;
  padding: 4px 0 56px;
}
/* every panel is a grid item: never let content blow the track out */
.modules > *, .side-col > * { min-width: 0; }
.side-col { display: flex; flex-direction: column; gap: 26px; }
/* The side column is shorter than the resource list, which leaves slack at the
   bottom of the grid cell. Let the last panel absorb it so its bottom edge
   lands on the same line as the list panel. */
.side-col > :last-child { flex: 1 0 auto; }

/* chips are the last child of the filter panel now that the sort toolbar is
   gone, so trailing margin would stack on top of the panel's own padding */
.panel .chips { justify-content: flex-start; margin-bottom: 0; }
.panel .grid { padding: 0; }
.panel .empty { padding: 44px 12px; }
.panel h3 .hint { font-weight: 400; font-size: 12.5px; }

/* filter row: title + search on one line */
.filter-row {
  display: flex;
  align-items: center;
  gap: 16px;
  margin-bottom: 12px;
}
.filter-row h3 { margin-bottom: 0; white-space: nowrap; }
.filter-row h3::after { display: none; }

/* Search sits inside the filter panel, so it must stretch to the panel width
   instead of the topbar's fixed min-width. */
.panel-search {
  flex: 1;
  min-width: 0;
  height: 32px;
  margin: 0;
}

/* Floating theme switch, pinned to the bottom-right corner. */
.fab-theme {
  position: fixed;
  right: 20px; bottom: 20px;
  z-index: 90;
  width: 44px; height: 44px;
  display: inline-flex; align-items: center; justify-content: center;
  border: 1px solid var(--glass-border);
  border-radius: 50%;
  background: var(--glass-bg);
  color: var(--text-2);
  cursor: pointer;
  box-shadow: var(--glass-shadow);
  -webkit-backdrop-filter: blur(14px) saturate(180%);
  backdrop-filter: blur(14px) saturate(180%);
  transition: transform .2s var(--ease), color .2s var(--ease);
}
.fab-theme:hover { transform: translateY(-2px); color: var(--text); }

/* rows shared by the hot / category / info panels */
.plist { display: flex; flex-direction: column; }
.prow {
  display: flex; align-items: center; justify-content: space-between;
  gap: 10px; padding: 11px 0;
  border-bottom: 1px solid var(--table-stripe);
  font-size: 14px; color: var(--text-2);
  text-decoration: none;
}
.prow:last-child { border-bottom: none; }
a.prow { cursor: pointer; }
a.prow:hover { color: var(--text); }
.prow.active .prow-name { color: var(--accent); font-weight: 600; }
.prow-t { display: flex; align-items: center; gap: 8px; min-width: 0; }
.prow-t .prow-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.prow-n { flex: none; font-weight: 700; font-size: 13px; color: var(--accent); }
.prow-sub { font-size: 12px; color: var(--text-3); }
.plist-note { font-size: 13px; color: var(--text-3); padding: 4px 0 2px; }

/* ---------------- admin ---------------- */
/* Panels are glass cards with NO default padding (.glass/.card define none),
   so content used to sit flush against the border. Give every panel its own
   gutter, and open up the rhythm between modules.
   `.panel` is the same surface used by the public homepage modules, so both
   pages share one visual language. */
.admin-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(340px, 1fr));
  gap: 26px;
  padding: 26px 0 56px;
}

.admin-grid > .card, .panel { padding: 16px 20px 18px; }

.admin-grid h3, .panel h3 {
  font-size: 14px;
  margin-bottom: 12px;
  position: relative;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
}
/* rule under the module title so each panel reads as its own block */
.admin-grid h3::after, .panel h3::after {
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: -9px;
  height: 1px;
  background: var(--table-stripe);
}

.tablewrap { max-height: 400px; overflow-y: auto; margin-top: 14px; }
.catlist { margin-bottom: 18px; }
.catitem {
  display: flex; align-items: center; justify-content: space-between;
  padding: 10px 0; font-size: 14px; color: var(--text-2);
  border-bottom: 1px solid var(--table-stripe);
}
.catitem:last-child { border-bottom: none; }

.row { display: flex; gap: 10px; align-items: center; flex-wrap: wrap; }
.f1 { flex: 1; min-width: 110px; }
.finput.tiny { width: 64px; }
.statsbox { font-size: 14px; color: var(--text-2); }
.stat-row {
  display: flex; justify-content: space-between;
  padding: 11px 0; border-bottom: 1px solid var(--table-stripe);
}
.stat-row:last-child { border-bottom: none; }
/* stacked admin labels need more air than the modal's */
.admin-grid label { margin-bottom: 15px; }
.admin-grid hr { margin: 20px 0; border: none; border-top: 1px solid var(--table-stripe); }

/* member users panel: full-width row so the table isn't squeezed into a column */
.users-panel { grid-column: 1 / -1; }
.users-panel .tablewrap { max-height: 340px; }
.users-hint {
  margin-top: 14px;
  font-size: 12.5px;
  color: var(--text-3);
}
.ustatus {
  display: inline-block;
  padding: 2px 9px;
  border-radius: 999px;
  font-size: 11.5px;
  font-weight: 700;
}
.ustatus.on { background: rgba(55, 205, 143, .16); color: var(--success); }
.ustatus.off { background: rgba(255, 107, 124, .16); color: var(--danger); }

/* per-resource visibility marker in the admin table + on public cards */
.vtag {
  display: inline-block;
  padding: 2px 9px;
  border-radius: 999px;
  font-size: 11.5px;
  font-weight: 700;
  white-space: nowrap;
}
.vtag.shared { background: rgba(55, 205, 143, .16); color: var(--success); }
.vtag.member { background: var(--chip-bg); color: var(--text-3); }
.user-modal-body { width: min(440px, 100%); }

/* ---------------- login ---------------- */
.login-wrap {
  flex: 1 0 auto;
  display: flex; align-items: center; justify-content: center;
  padding: 20px;
}
.login-card { width: min(400px, 100%); padding: 30px; }
.login-card h2 { font-size: 20px; margin-bottom: 20px; }
.login-card .btn-primary { width: 100%; justify-content: center; margin-top: 6px; }
.err { color: var(--danger); font-size: 13px; margin-top: 12px; }

/* member auth: brand block + login/register tabs */
.login-brand { margin-bottom: 22px; }
.auth-tabs {
  display: flex;
  gap: 6px;
  padding: 4px;
  margin-bottom: 20px;
  border-radius: 999px;
  background: var(--glass-bg-2);
  border: 1px solid var(--glass-border);
}
.auth-tab {
  flex: 1;
  padding: 8px 0;
  font-size: 13.5px;
  font-weight: 600;
  color: var(--text-3);
  border: none;
  border-radius: 999px;
  background: transparent;
  cursor: pointer;
  transition: all .2s var(--ease);
}
.auth-tab:hover { color: var(--text); }
.auth-tab.active {
  color: var(--accent-contrast);
  background: linear-gradient(135deg, var(--accent), var(--accent-2));
  box-shadow: 0 4px 14px var(--accent-soft);
}
/* Guests can leave the auth screen without an account. */
.auth-guest {
  width: 100%;
  justify-content: center;
  margin-top: 14px;
}
/* the gate also uses .login-card outside .login-wrap on some routes */
.login-card label:last-of-type { margin-bottom: 4px; }

/* ---------------- detail page ---------------- */
/* detail page: longhand vertical padding only - .container owns the horizontal
   gutter, and a shorthand here would wipe it (which is exactly why the detail
   content used to sit 28px left of the topbar). */
.detail { padding-top: 26px; padding-bottom: 44px; }
.detail-head { display: flex; gap: 22px; flex-wrap: wrap; padding: 24px; }
.detail-cover {
  width: 120px; height: 120px; border-radius: 18px; object-fit: cover;
  background: var(--accent-soft);
  display: flex; align-items: center; justify-content: center;
  font-size: 44px; flex: none;
}
.detail-info { flex: 1; min-width: 240px; }
.detail-info h1 { font-size: 22px; letter-spacing: -.02em; }
.link-list { display: flex; flex-direction: column; gap: 10px; margin-top: 16px; }
.link-item {
  display: flex; align-items: center; justify-content: space-between;
  gap: 12px; padding: 12px 16px; border-radius: 14px;
  background: var(--glass-bg-2); border: 1px solid var(--glass-border);
  flex-wrap: wrap;
}
.link-name { font-weight: 600; font-size: 14px; }
.link-code {
  font-size: 12px; color: var(--text-3);
  font-family: ui-monospace, Menlo, Consolas, monospace;
}

/* ---------------- reward ---------------- */
.reward { text-align: center; padding: 34px; margin-bottom: 30px; }
.reward img { max-width: 210px; border-radius: 16px; margin-top: 16px; }
.reward-desc { color: var(--text-3); font-size: 14px; }

/* ---------------- footer ---------------- */
/* Sticky footer: page is a full-height flex column and <main> absorbs the
   slack, so the footer sits at the bottom of the viewport even when there is
   little or no content. */
html, body { height: 100%; }
body { display: flex; flex-direction: column; }
main.container, main.detail { flex: 1 0 auto; width: 100%; }

.footer {
  /* flex-shrink:0 keeps the bar from being squeezed by the flex column above;
     equals the old `flex:none` (0 0 auto) but states the intent the test asserts. */
  flex-shrink: 0;
  /* same outer edges as the topbar and the content panels */
  width: calc(100% - 2 * var(--gutter));
  max-width: calc(var(--maxw) - 2 * var(--gutter));
  margin: 0 auto;
  padding: 16px 26px;
  text-align: center;
  font-size: 12.5px;
  color: var(--text-3);
}

/* ============================================================
   Breakpoints: mobile first, widen on large screens
   ============================================================ */
@media (min-width: 1280px) {
  :root { --maxw: 1560px; --gutter: 28px; }
  .grid { grid-template-columns: repeat(auto-fill, minmax(232px, 1fr)); gap: 18px; }
  .admin-grid { grid-template-columns: minmax(0, 2fr) minmax(320px, 1fr); gap: 30px; }
  /* main column = filter + resource list, side column = the compact panels */
  .modules { grid-template-columns: minmax(0, 2fr) minmax(300px, 1fr); gap: 30px; }
  .filter-panel { grid-column: 1 / -1; }
  .side-col { gap: 30px; }
  .tablewrap { max-height: 560px; }
  .hero { padding: 56px 0 34px; }
}

@media (min-width: 1800px) {
  :root { --maxw: 1680px; --gutter: 32px; }
  .grid { grid-template-columns: repeat(auto-fill, minmax(248px, 1fr)); gap: 20px; }
  .admin-grid { grid-template-columns: minmax(0, 2.2fr) minmax(360px, 1fr); }
  .tablewrap { max-height: 660px; }
}

@media (min-width: 2400px) {
  :root { --maxw: 1920px; --gutter: 40px; }
  .grid { grid-template-columns: repeat(auto-fill, minmax(264px, 1fr)); gap: 22px; }
}

/* ============================================================
   Mobile: single-row topbar, collapsed search, compact cards
   Target: <= 620px
   ============================================================ */
@media (max-width: 620px) {
  /* longhand: a `padding: 0 12px` shorthand here would also wipe the vertical
     padding that .detail sets on the same element */
  .container { padding-left: 12px; padding-right: 12px; }

  /* .container is pinned to 12px here instead of var(--gutter), so every
     chrome box has to follow it or the edges stop lining up. */
  .topbar,
  .footer,
  .announce {
    width: calc(100% - 24px);
    max-width: none;
    margin-left: auto;
    margin-right: auto;
  }
  .topbar,
  .footer,
  .announce,
  .panel { padding-left: 16px; padding-right: 16px; }

  /* filter row: stack on mobile */
  .filter-row { flex-direction: column; align-items: stretch; gap: 8px; }
  .filter-row h3 { font-size: 13px; }
  .panel-search { height: 30px; }

  /* topbar: ONE row, minimal height */
  .topbar {
    position: sticky;
    top: 0;
    margin-top: 0;
    padding-top: 8px;
    padding-bottom: 8px;
    gap: 6px;
    flex-wrap: nowrap;
    align-items: center;
    /* width comes from the shared 12px-inset rule above; re-stating 100%
       here would push the bar past the panels' edge again */
    max-width: none;
  }
  .brand { gap: 7px; flex: 1 1 auto; min-width: 0; }
  .logo {
    width: 24px; height: 24px; border-radius: 7px;
    font-size: 12px; box-shadow: none; flex: none;
  }
  .brand-text strong {
    font-size: 13.5px;
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  }
  .brand-text small { display: none; }

  .actions { flex: none; gap: 5px; flex-wrap: nowrap; width: auto; }
  .btn-primary, .btn-ghost { padding: 6px 11px; font-size: 12.5px; }
  .icon-btn { width: 30px; height: 30px; font-size: 12px; border-radius: 50%; }

  /* search is a permanent resident of the filter panel on every width */

  /* tighter vertical rhythm */
  .hero { padding: 18px 0 12px; }
  .hero h1 { font-size: clamp(21px, 6vw, 28px); }
  .hero p { font-size: 11.5px; margin-top: 4px; }
  .chips { gap: 4px; margin-bottom: 0; }
  .chip { font-size: 11px; padding: 3px 9px; }
  .count { font-size: 11px; padding: 3px 10px; }
  .select { padding: 5px 9px; font-size: 12px; }
  /* lift the floating theme switch clear of the compact footer */
  .fab-theme { bottom: 66px; right: 14px; width: 40px; height: 40px; }

  /* cards: compact horizontal ROWS instead of tall vertical tiles */
  .grid { grid-template-columns: 1fr; gap: 10px; }
  .card.res {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 10px;
  }
  .res-cover {
    width: 64px; height: 64px;
    flex: none;
    margin: 0;
    border-radius: 12px;
    font-size: 24px;
  }
  .res-body { flex: 1; min-width: 0; padding: 0; }
  .res-title { font-size: 13px; }
  .res-desc { margin-top: 4px; -webkit-line-clamp: 1; font-size: 11.5px; }
  .res-tags { margin-top: 6px; }
}
