/**
 * UniHouse dashboard shell
 * ========================
 * Shared chrome for the agent and admin areas. Deliberately reuses the public
 * site's design language - white surfaces, #1a1a1a ink, Inter, 16px radii - so
 * moving between the marketing pages and the role areas feels like one product.
 */

* { margin: 0; padding: 0; box-sizing: border-box; }

body {
  font-family: 'Inter', -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  line-height: 1.6;
  color: #1a1a1a;
  background: #fafafa;
}

a { color: inherit; text-decoration: none; }
button { font-family: inherit; }

/* ---------- Surface tokens ----------
   One elevation scale for the whole shell. Cards used to be flat outlines on
   a flat page, which left a dashboard reading as a spreadsheet; a little
   depth separates "this is a surface" from "this is the page behind it".
   Kept in ink rather than a colour so the role areas still match the
   marketing site. */
:root {
  --uh-line: #ececec;
  --uh-line-soft: #f2f2f2;

  /* Resting, raised, lifted. Two shadows each: a wide soft one for depth and
     a tight one for the edge, which is what stops it looking like a blur. */
  --lift-1: 0 1px 2px rgba(16, 16, 16, 0.04);
  --lift-2: 0 4px 14px -6px rgba(16, 16, 16, 0.10), 0 1px 3px rgba(16, 16, 16, 0.04);
  --lift-3: 0 18px 38px -18px rgba(16, 16, 16, 0.26), 0 2px 8px rgba(16, 16, 16, 0.06);

  /* Dark tile behind an icon - the one place the shell goes solid ink. */
  --uh-tile: linear-gradient(140deg, #3d3d3d, #1a1a1a);
  --uh-tile-glow: 0 8px 18px -8px rgba(26, 26, 26, 0.45), inset 0 1px 0 rgba(255, 255, 255, 0.16);
}

/* ---------- Top bar ---------- */
.dash-nav {
  position: fixed;
  top: 0;
  width: 100%;
  background: #fff;
  border-bottom: 1px solid #f0f0f0;
  z-index: 1000;
  padding: 0.85rem 0;
}

.dash-nav-inner {
  max-width: 1400px;
  margin: 0 auto;
  padding: 0 1.5rem;
  display: flex;
  align-items: center;
  gap: 1.25rem;
}

.dash-logo {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  font-weight: 800;
  letter-spacing: 0.5px;
  flex-shrink: 0;
}

/* The real logo carries its own blue and orange, so it needs no ink tile
   behind it - a dark square would only fight the mark's own colours. */
.dash-logo-icon {
  width: 34px;
  height: 34px;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}

.dash-logo-icon img {
  width: 100%;
  height: 100%;
  object-fit: contain;
  display: block;
}

.dash-role-tag {
  font-size: 0.62rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.6px;
  background: #1a1a1a;
  color: #fff;
  border-radius: 5px;
  padding: 0.15rem 0.4rem;
}

.dash-nav-spacer { flex: 1; }

/* ---------- Tab bar (mirrors the mobile tab bar) ---------- */
.dash-tabs {
  position: fixed;
  top: 61px;
  width: 100%;
  background: #fff;
  border-bottom: 1px solid #f0f0f0;
  z-index: 999;
  overflow-x: auto;
  scrollbar-width: none;
}

.dash-tabs::-webkit-scrollbar { display: none; }

.dash-tabs-inner {
  max-width: 1400px;
  margin: 0 auto;
  padding: 0 1.5rem;
  display: flex;
  gap: 0.25rem;
}

.dash-tab {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.85rem 1rem;
  font-size: 0.9rem;
  font-weight: 500;
  color: #777;
  white-space: nowrap;
  border-bottom: 2px solid transparent;
  transition: color 0.2s, border-color 0.2s;
}

.dash-tab:hover { color: #1a1a1a; }

.dash-tab.active {
  color: #1a1a1a;
  font-weight: 600;
  border-bottom-color: #1a1a1a;
}

.dash-tab i { font-size: 0.9rem; }

.dash-tab-badge {
  background: #ef4444;
  color: #fff;
  font-size: 0.65rem;
  font-weight: 700;
  border-radius: 9px;
  min-width: 17px;
  height: 17px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0 4px;
}

/* ---------- Page shell ---------- */
.dash-main {
  max-width: 1400px;
  margin: 0 auto;
  padding: 8.5rem 1.5rem 3rem;
}

.dash-head {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 1rem;
  margin-bottom: 2rem;
}

.dash-head h1 {
  font-size: 1.9rem;
  font-weight: 800;
  letter-spacing: -0.5px;
}

.dash-head p { color: #888; font-size: 0.95rem; }

/* ---------- Stat cards ---------- */
.stat-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: 1rem;
  margin-bottom: 2.5rem;
}

.stat-card {
  position: relative;
  overflow: hidden;
  background: linear-gradient(165deg, #f7f7f7 0%, #fff 62%);
  border: 1px solid var(--uh-line);
  border-radius: 16px;
  padding: 1.4rem;
  box-shadow: var(--lift-2);
}

/* Ink edge along the top, fading out - reads as a card that starts here
   rather than a box that happens to have a border. */
.stat-card::before {
  content: '';
  position: absolute;
  inset: 0 0 auto 0;
  height: 3px;
  background: linear-gradient(90deg, #1a1a1a, #4a4a4a 45%, transparent 92%);
}

/* Ghosted disc in the corner. It sits behind the number and gives the card
   somewhere to breathe; on the linked cards it swells on hover. */
.stat-card::after {
  content: '';
  position: absolute;
  top: -58px;
  right: -58px;
  width: 158px;
  height: 158px;
  border-radius: 50%;
  background: radial-gradient(circle, rgba(26, 26, 26, 0.055), transparent 68%);
  pointer-events: none;
  transition: transform 0.45s var(--uh-ease-out);
}

.stat-card:hover::after { transform: scale(1.25); }

.stat-card-top,
.stat-value,
.stat-sub { position: relative; }

.stat-card-top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 0.75rem;
}

.stat-label {
  font-size: 0.76rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.5px;
  color: #999;
}

.stat-icon {
  width: 38px;
  height: 38px;
  border-radius: 12px;
  background: var(--uh-tile);
  color: #fff;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 0.88rem;
  box-shadow: var(--uh-tile-glow);
}

/* The number is the point of the card, so it gets the size and a graded
   fill that keeps it from reading as flat black at this weight. */
.stat-value {
  font-size: 2.2rem;
  font-weight: 800;
  line-height: 1.1;
  letter-spacing: -1.4px;
  color: #1a1a1a;
  background: linear-gradient(135deg, #1a1a1a 0%, #5c5c5c 100%);
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
}

.stat-sub { font-size: 0.8rem; color: #999; margin-top: 0.15rem; }

.stat-card.loading .stat-value {
  color: transparent;
  background: linear-gradient(90deg, #f2f2f2 25%, #e9e9e9 37%, #f2f2f2 63%);
  background-size: 400% 100%;
  -webkit-background-clip: border-box;
  background-clip: border-box;
  animation: dash-shimmer 1.4s ease infinite;
  border-radius: 6px;
  max-width: 80px;
}

@keyframes dash-shimmer {
  0% { background-position: 100% 50%; }
  100% { background-position: 0 50%; }
}

/* ---------- Panels ---------- */
.panel {
  background: #fff;
  border: 1px solid var(--uh-line);
  border-radius: 18px;
  margin-bottom: 1.75rem;
  overflow: hidden;
  box-shadow: var(--lift-1);
}

.panel-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: 1.1rem 1.4rem;
  border-bottom: 1px solid #f2f2f2;
}

.panel-head h2 {
  font-size: 1rem;
  font-weight: 700;
  display: flex;
  align-items: center;
  gap: 0.55rem;
}

.panel-head h2 i { color: #999; font-size: 0.9rem; }

.panel-body { padding: 1.4rem; }
.panel-body.flush { padding: 0; }

/* ---------- Quick actions ---------- */
.action-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(170px, 1fr));
  gap: 0.85rem;
}

.action-card {
  position: relative;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  padding: 1.1rem;
  border: 1px solid var(--uh-line);
  border-radius: 14px;
  background: linear-gradient(160deg, #f7f7f7 0%, #fff 72%);
  cursor: pointer;
  text-align: left;
  box-shadow: var(--lift-1);
  transition: border-color 0.2s, transform 0.2s, box-shadow 0.2s;
}

/* A light sweeps across the tile on hover. It is the one flourish here that
   is purely decorative, so it is short and stays under reduced motion. */
.action-card::after {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(105deg, transparent 34%, rgba(255, 255, 255, 0.62) 50%, transparent 66%);
  transform: translateX(-120%);
  transition: transform 0.62s var(--uh-ease-out);
  pointer-events: none;
}

.action-card:hover::after { transform: translateX(120%); }

.action-card:hover {
  border-color: #1a1a1a;
  transform: translateY(-3px);
  box-shadow: var(--lift-3);
}

.action-card i {
  position: relative;
  width: 38px;
  height: 38px;
  border-radius: 12px;
  background: var(--uh-tile);
  color: #fff;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 0.9rem;
  box-shadow: var(--uh-tile-glow);
  transition: transform 0.2s var(--uh-ease-out);
}

.action-card:hover i { transform: scale(1.08) rotate(-6deg); }

.action-card strong,
.action-card span { position: relative; }

.action-card strong { font-size: 0.92rem; font-weight: 600; }
.action-card span { font-size: 0.8rem; color: #999; }

/* ---------- Tables ---------- */
.table-wrap { overflow-x: auto; }

table.dash-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.9rem;
  min-width: 640px;
}

.dash-table th {
  text-align: left;
  font-size: 0.72rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.5px;
  color: #999;
  padding: 0.8rem 1.4rem;
  border-bottom: 1px solid #f2f2f2;
  background: #fcfcfc;
}

.dash-table td {
  padding: 0.9rem 1.4rem;
  border-bottom: 1px solid #f6f6f6;
  vertical-align: middle;
}

.dash-table tr:last-child td { border-bottom: none; }
.dash-table tbody tr:hover { background: #fcfcfc; }

.cell-main { font-weight: 600; }
.cell-sub { font-size: 0.8rem; color: #999; }

/* ---------- Pills ---------- */
.pill {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  font-size: 0.72rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.4px;
  padding: 0.28rem 0.65rem;
  border-radius: 20px;
  background: #f0f0f0;
  color: #666;
  white-space: nowrap;
}

.pill.green { background: #e6f7ec; color: #1b7a45; }
.pill.amber { background: #fff5e0; color: #96650a; }
.pill.red { background: #fdeaea; color: #b3261e; }
.pill.blue { background: #eef4ff; color: #1a56b8; }

/* ---------- Buttons ---------- */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  border: 1px solid #e5e5e5;
  background: #fff;
  color: #1a1a1a;
  border-radius: 10px;
  padding: 0.6rem 1rem;
  font-size: 0.88rem;
  font-weight: 600;
  cursor: pointer;
  transition: border-color 0.2s, background 0.2s;
}

.btn:hover:not(:disabled) { border-color: #1a1a1a; }
.btn:disabled { opacity: 0.55; cursor: not-allowed; }

.btn.primary { background: #1a1a1a; color: #fff; border-color: #1a1a1a; }
.btn.primary:hover:not(:disabled) { background: #333; }
.btn.danger { color: #b3261e; border-color: #f0cccc; }
.btn.danger:hover:not(:disabled) { border-color: #b3261e; }
.btn.sm { padding: 0.4rem 0.7rem; font-size: 0.8rem; }

/* ---------- States ---------- */
.state {
  text-align: center;
  padding: 3rem 1.5rem;
  color: #888;
}

.state i { font-size: 2.1rem; color: #ddd; display: block; margin-bottom: 0.85rem; }
.state h3 { font-size: 1.05rem; color: #444; font-weight: 700; margin-bottom: 0.3rem; }
.state p { font-size: 0.9rem; max-width: 380px; margin: 0 auto; }

.notice {
  display: flex;
  align-items: flex-start;
  gap: 0.75rem;
  border-radius: 12px;
  padding: 0.9rem 1.1rem;
  font-size: 0.88rem;
  line-height: 1.55;
  margin-bottom: 1.5rem;
}

.notice i { margin-top: 0.15rem; }
.notice.amber { background: #fff8e6; border: 1px solid #ffe9b0; color: #7a5c00; }
.notice.red { background: #fdeaea; border: 1px solid #f7cfcf; color: #b3261e; }
.notice.blue { background: #eef4ff; border: 1px solid #d3e2ff; color: #1a56b8; }
.notice.green { background: #e6f7ec; border: 1px solid #c6ecd5; color: #1b7a45; }

.hidden { display: none !important; }

/* ---------- Responsive ---------- */
@media (max-width: 768px) {
  .dash-main { padding: 8rem 1rem 2.5rem; }
  .dash-head h1 { font-size: 1.5rem; }
  .dash-nav-inner, .dash-tabs-inner { padding: 0 1rem; }
  .stat-grid { grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); }
  .stat-value { font-size: 1.5rem; }
  .dash-tab span.label { display: none; }
  .dash-tab { padding: 0.85rem 0.9rem; }
}

/* ==========================================================================
   Motion and feedback
   ==========================================================================
   Shared "feel" layer for the student area (and anything else on the dash
   shell). Three jobs: say something is coming (skeletons), say something
   arrived (entrance), say something happened (toasts, press, pop).

   Everything here is opt-in via a class except the table row entrance, so
   existing screens keep working untouched. All of it collapses under
   prefers-reduced-motion at the bottom of this section.
   ========================================================================== */

:root {
  --uh-ease: cubic-bezier(0.22, 0.61, 0.36, 1);
  --uh-ease-out: cubic-bezier(0.16, 1, 0.3, 1);
  --uh-dur: 0.22s;
  --uh-stagger: 38ms;
}

/* ---------- Skeletons ----------
   Same shimmer the stat cards already used, pulled out so any shape can
   borrow it. Skeletons keep layout height so nothing jumps on swap. */
.skel {
  background: linear-gradient(90deg, #f2f2f2 25%, #e9e9e9 37%, #f2f2f2 63%);
  background-size: 400% 100%;
  animation: dash-shimmer 1.4s ease infinite;
  border-radius: 6px;
  color: transparent !important;
  user-select: none;
}

.skel-line { height: 0.68rem; margin: 0.28rem 0; }
.skel-line.wide { width: 82%; }
.skel-line.mid { width: 58%; }
.skel-line.narrow { width: 34%; }
.skel-thumb { width: 52px; height: 52px; border-radius: 10px; flex-shrink: 0; }
.skel-pill { width: 68px; height: 1.35rem; border-radius: 20px; }
.skel-btn { width: 64px; height: 1.9rem; border-radius: 10px; display: inline-block; }

/* Skeleton table rows reuse the real table so column widths settle early. */
.dash-table tr.skel-row td { padding: 0.9rem 1.4rem; }
.dash-table tr.skel-row .skel-cell { display: flex; align-items: center; gap: 0.75rem; }

/* ---------- Entrance ----------
   .uh-in on any element; set --i for a staggered index. Capped so a long
   list never leaves the reader waiting on the tail. */
@keyframes uh-in {
  from { opacity: 0; transform: translateY(7px); }
  to { opacity: 1; transform: none; }
}

.uh-in {
  animation: uh-in 0.34s var(--uh-ease-out) backwards;
  animation-delay: calc(var(--i, 0) * var(--uh-stagger));
}

/* Table rows stagger without needing per-row inline styles. */
.dash-table tbody tr:not(.skel-row) {
  animation: uh-in 0.3s var(--uh-ease-out) backwards;
}
.dash-table tbody tr:nth-child(1) { animation-delay: 0ms; }
.dash-table tbody tr:nth-child(2) { animation-delay: 34ms; }
.dash-table tbody tr:nth-child(3) { animation-delay: 68ms; }
.dash-table tbody tr:nth-child(4) { animation-delay: 102ms; }
.dash-table tbody tr:nth-child(5) { animation-delay: 136ms; }
.dash-table tbody tr:nth-child(6) { animation-delay: 170ms; }
.dash-table tbody tr:nth-child(7) { animation-delay: 204ms; }
.dash-table tbody tr:nth-child(8) { animation-delay: 238ms; }
.dash-table tbody tr:nth-child(n + 9) { animation-delay: 260ms; }

/* Row leaving after an optimistic delete. */
@keyframes uh-row-out {
  to { opacity: 0; transform: translateX(26px); }
}
.dash-table tbody tr.uh-leaving {
  animation: uh-row-out 0.24s var(--uh-ease) forwards;
  pointer-events: none;
}

/* Every dash screen boots the same way: a #bootState spinner is hidden and
   #content is un-hidden. Animating the reveal here means all 21 screens get
   the fade without a line of HTML changing. */
#content:not(.hidden) {
  animation: uh-in 0.32s var(--uh-ease-out);
}

/* ---------- Toasts ----------
   Stacked, dismissible, and no longer wiping the previous message: two
   things happening back to back should read as two things. */
.uh-toasts {
  position: fixed;
  bottom: 1.5rem;
  left: 50%;
  transform: translateX(-50%);
  z-index: 10000;
  display: flex;
  flex-direction: column-reverse;
  align-items: center;
  gap: 0.5rem;
  pointer-events: none;
  width: max-content;
  max-width: min(92vw, 460px);
}

@keyframes uh-toast-in {
  from { opacity: 0; transform: translateY(14px) scale(0.96); }
  to { opacity: 1; transform: none; }
}

@keyframes uh-toast-out {
  to { opacity: 0; transform: translateY(6px) scale(0.97); }
}

.uh-toast {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  background: #1e1e1e;
  color: #fff;
  padding: 0.8rem 1.1rem;
  border-radius: 11px;
  font-size: 0.9rem;
  font-weight: 500;
  line-height: 1.4;
  box-shadow: 0 10px 34px rgba(0, 0, 0, 0.32);
  pointer-events: auto;
  cursor: pointer;
  animation: uh-toast-in 0.28s var(--uh-ease-out);
}

.uh-toast.success { background: #1b7a45; }
.uh-toast.error { background: #b3261e; }
.uh-toast.leaving { animation: uh-toast-out 0.2s ease forwards; }
.uh-toast i { font-size: 0.85rem; opacity: 0.9; flex-shrink: 0; }

/* An undo affordance turns a destructive tap into a recoverable one. */
.uh-toast .uh-undo {
  margin-left: 0.35rem;
  background: rgba(255, 255, 255, 0.16);
  border: none;
  color: inherit;
  font: inherit;
  font-weight: 700;
  padding: 0.22rem 0.6rem;
  border-radius: 7px;
  cursor: pointer;
}
.uh-toast .uh-undo:hover { background: rgba(255, 255, 255, 0.28); }

/* ---------- Top progress bar ----------
   For navigations and saves that outlast a button spinner. */
.uh-progress {
  position: fixed;
  top: 0;
  left: 0;
  height: 2px;
  width: 0;
  background: #1a1a1a;
  z-index: 10001;
  transition: width 0.25s var(--uh-ease), opacity 0.3s ease 0.15s;
}
.uh-progress.done { opacity: 0; }

/* ---------- Press, hover and focus ----------
   Pointer feedback on everything already clickable. */
.btn { transition: border-color var(--uh-dur), background var(--uh-dur), transform 0.09s ease; }
.btn:active:not(:disabled) { transform: translateY(1px) scale(0.985); }

.action-card:active { transform: translateY(0) scale(0.985); }

.stat-card {
  transition: border-color var(--uh-dur), transform var(--uh-dur), box-shadow var(--uh-dur);
}
a.stat-card:hover {
  border-color: #dcdcdc;
  transform: translateY(-5px);
  box-shadow: var(--lift-3);
}
a.stat-card:active { transform: translateY(0) scale(0.99); }
.stat-card .go { transition: transform var(--uh-dur); }
a.stat-card:hover .go { transform: translateX(3px); }

.dash-table tbody tr { transition: background 0.15s ease; }

.filter-chip { transition: background 0.18s, color 0.18s, border-color 0.18s, transform 0.09s ease; }
.filter-chip:active { transform: scale(0.96); }

/* Keyboard users get the same clarity mouse users do. */
:focus-visible {
  outline: 2px solid #1a1a1a;
  outline-offset: 2px;
  border-radius: 8px;
}

/* ---------- Pop ----------
   For a state flip the user just caused: saving, favouriting, rating. */
@keyframes uh-pop {
  0% { transform: scale(1); }
  42% { transform: scale(1.32); }
  100% { transform: scale(1); }
}
.uh-pop { animation: uh-pop 0.34s var(--uh-ease); }

/* An optimistic row is live but not yet confirmed by the server. */
.uh-pending { opacity: 0.55; transition: opacity 0.2s ease; }

/* ---------- Reduced motion ----------
   Keep every signal, drop the movement. Skeletons stay as flat blocks so
   "still loading" is still legible without the shimmer. */
@media (prefers-reduced-motion: reduce) {
  .uh-in,
  .uh-pop,
  .uh-toast,
  #content:not(.hidden),
  .dash-table tbody tr,
  .dash-table tbody tr.uh-leaving {
    animation: none !important;
  }
  .skel,
  .stat-card.loading .stat-value {
    animation: none !important;
    background: #eee !important;
  }
  .uh-toast.leaving { display: none; }
  .action-card::after { display: none; }
  .stat-card:hover::after,
  .action-card:hover i,
  a.stat-card:hover,
  .action-card:hover,
  .btn:active:not(:disabled),
  .action-card:active,
  a.stat-card:active,
  .filter-chip:active {
    transform: none !important;
  }
  * { transition-duration: 0.01ms !important; }
}
