/* ============================================================================
 * UCDFS shared stylesheet
 *
 * The design system for the card-based applets: dashboard, attendance, comp.
 * Load it BEFORE a page's own <style> block so page rules win on conflict:
 *
 *     <link rel="stylesheet" href="/static/shared.css">
 *     <style> ...page-specific only... </style>
 *
 * The canvas tools (pt, harness) deliberately do NOT use this. They are
 * full-screen editors with their own visual language. They share shared.js only.
 *
 * Pages set their own content width with --page-max (default 1100px).
 * ========================================================================== */

:root {
  /* brand, sampled from ucdfs_logo.png */
  --ucd-navy:#15386e; --ucd-gold:#f6ca45;

  /* accents */
  --indigo:#4f46e5; --indigo-light:#818cf8; --indigo-bg:#eef2ff; --indigo-border:#c7d2fe;
  --purple:#7c3aed; --purple-bg:#f5f3ff; --purple-border:#ddd6fe;
  --green:#16a34a;  --green-bg:#f0fdf4;   --green-mid:#86efac;  --green-text:#14532d;
  --red:#dc2626;    --red-bg:#fff1f2;     --red-mid:#fca5a5;    --red-text:#7f1d1d;
  --amber:#d97706;  --amber-bg:#fffbeb;   --amber-border:#fcd34d;
  --teal:#0d9488;   --teal-bg:#f0fdfa;    --teal-border:#99f6e4;

  /* surfaces */
  --bg:#f1f5f9; --card:#fff; --text:#0f172a; --muted:#64748b; --border:#e2e8f0;
  --dark:#0f172a;

  --shadow-sm:0 1px 3px rgba(0,0,0,0.07), 0 1px 2px rgba(0,0,0,0.04);
  --shadow-md:0 4px 14px rgba(0,0,0,0.08), 0 2px 4px rgba(0,0,0,0.04);
  --shadow-lg:0 12px 28px rgba(0,0,0,0.1), 0 4px 10px rgba(0,0,0,0.06);

  --page-max:1100px;
}

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

body {
  font-family:-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
  background:var(--bg); color:var(--text); min-height:100vh;
  -webkit-tap-highlight-color:transparent;
}

/* ── Layout ────────────────────────────────────────────────────────────── */
.page { max-width:var(--page-max); margin:0 auto; padding:20px 16px 90px; }
@media (min-width:720px) { .page { padding:28px 32px 60px; } }

/* ── Header ────────────────────────────────────────────────────────────── */
header {
  background:var(--card); border-bottom:1px solid var(--border);
  box-shadow:var(--shadow-sm); position:sticky; top:0; z-index:20;
}
.header-inner {
  max-width:var(--page-max); margin:0 auto;
  padding:14px 16px; display:flex; align-items:center; gap:14px;
}
@media (min-width:720px) { .header-inner { padding:14px 32px; } }
.logo {
  width:40px; height:40px; background:var(--dark); border-radius:11px;
  display:flex; align-items:center; justify-content:center;
  font-size:1.15rem; flex-shrink:0; text-decoration:none;
}
.logo-purple { background:var(--purple); }
.logo-indigo { background:var(--indigo); }
a.logo { transition:transform .12s; }
a.logo:hover { transform:translateY(-2px); }

/* The swan mark. The source art already carries its navy field, so this is a
   plain image with the same rounding as the emoji .logo chips it sits beside. */
.logo-mark {
  width:40px; height:40px; border-radius:11px;
  flex-shrink:0; display:block;
}
.logo-mark-lg { width:76px; height:76px; border-radius:20px; margin:0 auto 16px; }
.header-text  { flex:1; min-width:0; }
.header-title { font-size:1rem; font-weight:700; line-height:1.2; }
.header-sub   { font-size:0.75rem; color:var(--muted); }

/* back-to-dashboard chevron, sits left of the logo on applet pages */
.back-link {
  display:flex; align-items:center; justify-content:center;
  width:32px; height:32px; border-radius:9px; flex-shrink:0;
  color:var(--muted); text-decoration:none; font-size:1rem;
  transition:background .12s, color .12s;
}
.back-link:hover { background:var(--bg); color:var(--text); }

/* ── Identity pill ─────────────────────────────────────────────────────── */
.name-pill {
  display:flex; align-items:center; gap:8px;
  background:var(--bg); border:1px solid var(--border);
  border-radius:999px; padding:6px 12px 6px 6px; flex-shrink:0;
}
.pill-avatar {
  width:28px; height:28px; border-radius:50%; background:var(--dark);
  color:#fff; font-size:0.6rem; font-weight:800;
  display:flex; align-items:center; justify-content:center; flex-shrink:0;
}
/* Your own photo, when you have one. UCDFS.renderPill() swaps the class. */
.pill-avatar-photo { background-size:cover; background-position:center; }
.pill-name   { font-size:0.825rem; font-weight:600; white-space:nowrap; }
.pill-change {
  font-size:0.7rem; color:var(--muted); cursor:pointer;
  padding:2px 6px; border-radius:5px; transition:background .12s;
}
.pill-change:hover { background:var(--border); }
@media (max-width:520px) { .pill-name { display:none; } }

/* ── Setup card (the "who are you?" gate) ──────────────────────────────── */
#setup {
  min-height:100vh; display:flex; align-items:center; justify-content:center;
  padding:24px;
}
.setup-card {
  background:var(--card); border-radius:24px; padding:40px 32px;
  box-shadow:var(--shadow-lg); border:1px solid var(--border);
  width:100%; max-width:400px; text-align:center;
}
.setup-logo { font-size:2.5rem; margin-bottom:14px; }
.setup-card h2 { font-size:1.4rem; font-weight:800; margin-bottom:6px; }
.setup-card p  { color:var(--muted); line-height:1.55; margin-bottom:28px; }
.name-row { display:flex; gap:10px; margin-bottom:12px; }
.setup-btn {
  width:100%; padding:14px; background:var(--dark); color:#fff;
  border:none; border-radius:14px; font-size:1rem; font-weight:700;
  cursor:pointer; box-shadow:var(--shadow-md);
  transition:transform .12s cubic-bezier(.34,1.56,.64,1), box-shadow .12s;
}
.setup-btn:hover  { transform:translateY(-2px); box-shadow:var(--shadow-lg); }
.setup-btn:active { transform:scale(.97); transition-duration:.05s; }

/* ── Inputs ────────────────────────────────────────────────────────────── */
.text-input {
  width:100%; padding:13px 15px; font-size:0.95rem;
  border:2px solid var(--border); border-radius:13px; outline:none;
  background:var(--card); font-family:inherit;
  transition:border-color .15s, box-shadow .15s;
}
.text-input:focus {
  border-color:var(--indigo); box-shadow:0 0 0 3px rgba(79,70,229,.12);
}

/* ── Buttons ───────────────────────────────────────────────────────────── */
.btn {
  display:flex; align-items:center; justify-content:center; gap:7px;
  padding:12px 18px; border:none; border-radius:13px;
  font-size:.9rem; font-weight:600; font-family:inherit; cursor:pointer;
  box-shadow:var(--shadow-md);
  transition:transform .12s cubic-bezier(.34,1.56,.64,1), box-shadow .12s;
}
.btn:hover   { transform:translateY(-2px); box-shadow:var(--shadow-lg); }
.btn:active  { transform:scale(.96); box-shadow:var(--shadow-sm); transition-duration:.05s; }
.btn:disabled{ opacity:.55; cursor:default; transform:none; }
.btn-full   { width:100%; }
.btn-purple { background:var(--purple); color:#fff; }
.btn-indigo { background:var(--indigo); color:#fff; }
.btn-dark   { background:var(--dark);   color:#fff; }
.btn-green  { background:var(--green);  color:#fff; }
.btn-ghost  { background:var(--bg); color:var(--muted); border:1px solid var(--border); box-shadow:none; }
.btn-sm     { padding:6px 12px; font-size:.78rem; box-shadow:var(--shadow-sm); }
.btn-xs     { padding:4px 9px;  font-size:.72rem; box-shadow:none; border-radius:8px; }

/* ── Labels ────────────────────────────────────────────────────────────── */
.section-label {
  font-size:.67rem; font-weight:800; text-transform:uppercase;
  letter-spacing:.09em; color:var(--muted); margin-bottom:9px;
}
.section-row { display:flex; align-items:center; justify-content:space-between; margin-bottom:9px; }
.section-row .section-label { margin-bottom:0; }

/* ── Avatars ───────────────────────────────────────────────────────────── */
.av { border-radius:50%; display:flex; align-items:center; justify-content:center;
      font-weight:800; flex-shrink:0; }
/* Applied by UCDFS.avatar() when a person has a photo. The element keeps its
   own sizing class and just swaps its fill, so a face and a set of initials
   occupy exactly the same space. A list must not reflow as photos load. */
.has-photo { background-size:cover; background-position:center; color:transparent; }
.av28 { width:28px; height:28px; font-size:.6rem; }
.av32 { width:32px; height:32px; font-size:.65rem; }
.av38 { width:38px; height:38px; font-size:.65rem; letter-spacing:.03em; }
.av-purple { background-color:var(--purple-bg); color:var(--purple); }
.av-indigo { background-color:var(--indigo-bg); color:var(--indigo); }
.av-green  { background-color:var(--green-mid); color:var(--green-text); }
.av-red    { background-color:var(--red-mid);   color:var(--red-text); }

/* ── Tabs ──────────────────────────────────────────────────────────────── */
.tabs { display:flex; gap:5px; background:var(--border); padding:4px; border-radius:14px; margin-bottom:24px; }
.tab {
  flex:1; padding:10px; border:none; border-radius:11px;
  font-size:.85rem; font-weight:600; font-family:inherit; cursor:pointer;
  background:transparent; color:var(--muted); transition:all .18s;
}
.tab.active { background:var(--card); color:var(--text); box-shadow:0 2px 8px rgba(0,0,0,.1); }

/* ── Filter chips ──────────────────────────────────────────────────────────
   A row of toggles that narrows what is already on screen. Used by the
   dashboard's subteam filter and the profiles directory, which is why it lives
   here rather than in either page.

   Chips FILTER, they never gate. Nothing a chip hides is unreachable. Clearing
   the filter always brings it back. A filter that permanently hides something
   someone needs is worse than no filter at all. */
.chips {
  display:flex; gap:7px; flex-wrap:wrap; align-items:center;
  margin-bottom:14px;
}
.chip {
  display:inline-flex; align-items:center; gap:6px;
  padding:6px 13px; border-radius:999px;
  background:var(--card); border:1px solid var(--border); color:var(--muted);
  font-size:.8rem; font-weight:600; font-family:inherit;
  cursor:pointer; white-space:nowrap;
  transition:background .13s, color .13s, border-color .13s, transform .13s;
}
.chip:hover  { border-color:var(--muted); color:var(--text); }
.chip:active { transform:scale(.96); }
.chip.active {
  background:var(--chip-accent, var(--dark)); border-color:var(--chip-accent, var(--dark));
  color:#fff;
}
.chip-count { font-size:.7rem; opacity:.7; font-variant-numeric:tabular-nums; }
/* Scrolls rather than wraps on a phone, so the row stays one line deep. */
@media (max-width:520px) {
  .chips { flex-wrap:nowrap; overflow-x:auto; padding-bottom:4px;
           scrollbar-width:none; }
  .chips::-webkit-scrollbar { display:none; }
}

/* ── Generic card ──────────────────────────────────────────────────────── */
.card {
  background:var(--card); border-radius:16px; border:1px solid var(--border);
  box-shadow:var(--shadow-sm);
}

/* ── Empty state ───────────────────────────────────────────────────────── */
.empty      { padding:36px 16px; text-align:center; }
.empty-icon { font-size:2rem; margin-bottom:8px; opacity:.4; }
.empty-text { color:var(--muted); font-size:.875rem; }

/* ── Footer note ───────────────────────────────────────────────────────── */
.foot {
  text-align:center; font-size:.72rem; color:var(--muted);
  padding-top:6px; line-height:1.6;
}

/* ── Spinner ───────────────────────────────────────────────────────────── */
@keyframes spin { to { transform:rotate(360deg); } }
.spinner {
  width:20px; height:20px; border:2.5px solid rgba(255,255,255,.5);
  border-top-color:#fff; border-radius:50%;
  animation:spin .6s linear infinite; display:inline-block;
}
.spinner-dark { border-color:var(--border); border-top-color:var(--indigo); }

/* ── Loading ring ──
   The dashboard's indicator, hoisted here so every applet shows the same thing
   while it waits instead of each inventing its own ⏳.

   In shared.css and NOT in shared.js's runtime CSS, which is where the other
   shared components live. The dashboard draws this on the first frame, before
   any script has run, and runtime CSS is injected by JS — so a ring that
   depended on it would appear a beat late on the one page whose whole point is
   that it does not. The cost is that the canvas tools, which load shared.js
   and deliberately not shared.css, cannot use this. They have their own look
   anyway.

   Two placements off one ring: .ring on its own sits wherever it is put (the
   dashboard drops it in a full-page veil), and .ring-block gives it the
   padding to stand in for a list that has not arrived. */
.ring { display:flex; align-items:center; justify-content:center; }
.ring-block { padding:44px 16px; }
.ring svg { display:block; animation:ring-spin 1.5s linear infinite; }
.ring circle {
  fill:none; stroke:var(--ring-accent, var(--indigo)); stroke-width:4; stroke-linecap:round;
  /* r=20, so the circumference is ~125.7 and the dasharray pairs below sum to
     it. The arc grows and shrinks as the whole thing turns, which is the bit
     that makes it read as working rather than as a timer. */
  animation:ring-dash 1.5s ease-in-out infinite;
}
@keyframes ring-spin { to { transform:rotate(360deg); } }
@keyframes ring-dash {
  0%   { stroke-dasharray:6 120;  stroke-dashoffset:0; }
  50%  { stroke-dasharray:80 46;  stroke-dashoffset:-18; }
  100% { stroke-dasharray:6 120;  stroke-dashoffset:-125; }
}
/* Rotation is the part that causes trouble for people who ask for less of it,
   so it goes and the ring stays: a still arc breathing in place still says
   "working", where nothing at all says "broken". */
@media (prefers-reduced-motion: reduce) {
  .ring svg { animation:none; }
  .ring circle { stroke-dasharray:80 46; animation:ring-fade 1.6s ease-in-out infinite; }
  @keyframes ring-fade { 0%,100% { opacity:1; } 50% { opacity:.35; } }
}

/* ── Toast ─────────────────────────────────────────────────────────────── */
.toast {
  position:fixed; bottom:28px; left:50%;
  transform:translateX(-50%) translateY(14px);
  background:var(--dark); color:#fff; padding:13px 20px; border-radius:16px;
  font-size:.875rem; font-weight:500; opacity:0;
  transition:opacity .2s, transform .2s cubic-bezier(.34,1.56,.64,1);
  pointer-events:none; max-width:calc(100vw - 32px); text-align:center;
  box-shadow:0 8px 24px rgba(0,0,0,.22); z-index:99;
}
.toast.show { opacity:1; transform:translateX(-50%) translateY(0); }
