/* TaskCat — the brand base every page on taskcat.dev shares.
   ------------------------------------------------------------------------
   Tokens, the page frame, the masthead with the Tasks Cat wordmark, buttons,
   list rows, empty states, and the pieces the login and account pages add.
   Catnnections layers its game on top of this in catnnections/app.css; the
   login and account pages use it as-is. One palette, one place:
   tools/check-contrast.mjs reads its ratios from THIS file and
   tools/build-cat.mjs asserts the favicon's colours against it.

   The four difficulty hues live here because they are the brand's colours as
   well as the game's. Purple means "hardest" wherever it appears.

   Dark mode is two blocks with identical values on purpose: the media query
   answers a system preference, the attribute answers the in-page toggle, and
   the toggle has to win in both directions. tools/check-contrast.mjs fails if
   the two blocks ever disagree.
*/

:root {
  --ink: #14161a;
  --ink-soft: #5b6270;
  --ink-faint: #6c737f;
  --ground: #fbfaf7;
  --surface: #ffffff;
  --tile: #eeedea;
  --tile-hover: #e5e4e0;
  --line: #d9d8d3;
  --line-strong: #b9b8b2;

  --yellow: #e3b93b;
  --green: #86ac4a;
  --blue: #7c9de0;
  --purple: #a86fbd;

  --yellow-fill: #f6df84;
  --green-fill: #b3d074;
  --blue-fill: #adc4ef;
  --purple-fill: #cf9fdd;

  --yellow-wash: #fdf6dd;
  --green-wash: #eef5e0;
  --blue-wash: #e9eefb;
  --purple-wash: #f5ebf9;

  /* Text-on-ground variants. The fills above are backgrounds and are far too
     light to be read as type on cream — these are the same hues walked dark
     until each clears 4.5:1. Never use a -fill token for text. */
  --yellow-ink: #8a7124;
  --green-ink: #607c35;
  --blue-ink: #5b73a4;
  --purple-ink: #9261a4;

  --danger: #c2452f;

  --cat-eye: #8ad17f;
  --cat-nose: #e58fa6;
  --cat-line: #8c8478;

  --radius: 10px;
  --radius-lg: 16px;
  --gap: 8px;
  --shadow: 0 1px 2px rgba(20, 22, 26, 0.06), 0 4px 12px rgba(20, 22, 26, 0.04);
  --dur: 220ms;
  --ease: cubic-bezier(0.2, 0.7, 0.3, 1);
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme='light']) {
    --ink: #ecedf0;
    --ink-soft: #a2a8b6;
    --ink-faint: #7f8693;
    --ground: #14161a;
    --surface: #1c1f25;
    --tile: #272b33;
    --tile-hover: #31353f;
    --line: #343943;
    --line-strong: #4a505c;

    --yellow-wash: #2e2a1c;
    --green-wash: #232c1e;
    --blue-wash: #1e2432;
    --purple-wash: #2a2033;

    --yellow-ink: #e3b93b;
    --green-ink: #86ac4a;
    --blue-ink: #7c9de0;
    --purple-ink: #a970be;
    --danger: #ce6856;
    --cat-eye: #7cf08a;

    --shadow: 0 1px 2px rgba(0, 0, 0, 0.4), 0 4px 14px rgba(0, 0, 0, 0.25);
  }
}

:root[data-theme='dark'] {
  --ink: #ecedf0;
  --ink-soft: #a2a8b6;
  --ink-faint: #7f8693;
  --ground: #14161a;
  --surface: #1c1f25;
  --tile: #272b33;
  --tile-hover: #31353f;
  --line: #343943;
  --line-strong: #4a505c;

  --yellow-wash: #2e2a1c;
  --green-wash: #232c1e;
  --blue-wash: #1e2432;
  --purple-wash: #2a2033;

  --yellow-ink: #e3b93b;
  --green-ink: #86ac4a;
  --blue-ink: #7c9de0;
  --purple-ink: #a970be;
  --danger: #ce6856;
  --cat-eye: #7cf08a;

  --shadow: 0 1px 2px rgba(0, 0, 0, 0.4), 0 4px 14px rgba(0, 0, 0, 0.25);
}

* { box-sizing: border-box; }

body {
  margin: 0;
  background: var(--ground);
  color: var(--ink);
  font: 400 16px/1.5 ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto,
    'Helvetica Neue', Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

.wrap {
  max-width: 560px;
  margin: 0 auto;
  padding: 20px 16px 64px;
}

/* ---- Masthead ---------------------------------------------------------- */

.masthead {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 18px;
}

.masthead-actions {
  display: flex;
  align-items: center;
  gap: 6px;
}
.account-user { display: flex; align-items: center; min-height: 44px; padding: 0 4px; }
/* Pre-account puzzles: same rows, plus one action to bring them along. */
.pending-actions { display: flex; align-items: center; gap: 12px; margin-top: 10px; }

.wordmark {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  font-size: 19px;
  font-weight: 800;
  letter-spacing: -0.02em;
  color: var(--ink);
  text-decoration: none;
}

/* The Tasks Cat rides currentColor, so she is black on the light ground and
   white on the dark one with no second asset. */
.wordmark-cat {
  width: 30px;
  height: 32px;
  flex: none;
  color: var(--ink);
  /* She swaps expression by swapping <use> targets, so soften the cut. */
  transition: opacity 160ms var(--ease);
}
.wordmark-tail { color: var(--ink-faint); font-weight: 600; }

/* ---- Buttons ----------------------------------------------------------- */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  min-height: 44px;
  min-width: 44px;
  padding: 0 16px;
  border-radius: 99px;
  border: 1.5px solid var(--line-strong);
  background: var(--surface);
  color: var(--ink);
  font-weight: 650; font-size: 14px; line-height: 1; font-family: inherit;
  letter-spacing: -0.01em;
  cursor: pointer;
  transition: background-color 140ms var(--ease), border-color 140ms var(--ease),
    transform 140ms var(--ease), opacity 140ms var(--ease);
}
@media (hover: hover) and (pointer: fine) {
  .btn:hover:not(:disabled) { background: var(--tile); }
}
.btn:focus-visible { outline: 3px solid var(--ink); outline-offset: 2px; }
.btn:active:not(:disabled) { transform: scale(0.97); }
.btn:disabled { opacity: 0.4; cursor: not-allowed; }
.btn svg { width: 18px; height: 18px; }

.btn-icon { padding: 0; width: 44px; }

.btn-quiet {
  border-color: transparent;
  background: transparent;
  color: var(--ink-soft);
}
.btn-quiet svg { width: 19px; height: 19px; }

/* Sign-in is chrome, not content: quiet text, full tap height. Sits after
   .btn on purpose; at equal specificity the later rule is the one that wins. */
.btn-text { padding: 0 12px; font-size: 13.5px; }

/* The primary button. In the game it is Submit, which app.css heats up as the
   stake grows; here it is just the one action a page most wants pressed. */
.btn-submit {
  background: var(--ink);
  color: var(--ground);
  border-color: var(--ink);
  padding: 0 22px;
  font-weight: 750;
}
@media (hover: hover) and (pointer: fine) {
  .btn-submit:hover:not(:disabled) { background: var(--ink); filter: brightness(1.15); }
}

.link-btn {
  border: 0;
  background: none;
  padding: 6px 2px;
  color: var(--ink-soft);
  font-weight: 600; font-size: 13px; line-height: 1; font-family: inherit;
  text-decoration: underline;
  text-underline-offset: 3px;
  cursor: pointer;
}
@media (hover: hover) and (pointer: fine) {
  .link-btn:hover { color: var(--ink); }
}
.link-btn:focus-visible { outline: 2px solid var(--ink); outline-offset: 2px; }

/* ---- List sections ------------------------------------------------------
   A run of rows under a small uppercase heading. Rows, not cards: the
   footprint scales with what is said, not with how many items there are.
   ------------------------------------------------------------------------ */

.my-puzzles { margin-top: 30px; }
.my-puzzles h2 {
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink-soft);
  margin: 0 0 8px;
}
/* A second heading follows a run of rows, so it needs its own breathing room. */
.my-puzzles h2:not(:first-child) {
  margin-top: 22px;
}
.puzzle-row {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 2px;
  border-bottom: 1px solid var(--line);
}
.puzzle-row a { color: var(--ink); font-weight: 650; font-size: 14.5px; text-decoration: none; flex: 1; }
/* An action on the row (Edit) is an <a> too, so it would inherit the title's
   `flex: 1` and eat half the row. An action sizes to its own word. */
.puzzle-row .link-btn { flex: none; }
@media (hover: hover) and (pointer: fine) {
  .puzzle-row a:hover { text-decoration: underline; }
}
.puzzle-row time { font-size: 12px; color: var(--ink-faint); }

.empty {
  padding: 26px 18px;
  text-align: center;
  color: var(--ink-soft);
  font-size: 14px;
  border: 1.5px dashed var(--line);
  border-radius: var(--radius);
}

/* A small secondary line: a date, a count, a caveat. */
.note { font-size: 12.5px; color: var(--ink-faint); }

.footer-bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  margin-top: 22px;
  padding-top: 16px;
  border-top: 1px solid var(--line);
}

/* ---- Login page --------------------------------------------------------- */

/* Clerk's card mounts inside. Its colours come from the tokens above via the
   appearance object that ../shared/auth.js derives at load; the CSS here only
   places it. */
.auth { margin-top: 28px; }
.auth-note {
  margin: 18px 4px 0;
  text-align: center;
  font-size: 13.5px;
  color: var(--ink-soft);
}

/* ---- Account page ------------------------------------------------------- */

.identity {
  display: flex;
  align-items: center;
  gap: 14px;
  flex-wrap: wrap;
  padding: 16px;
  margin-top: 6px;
  border-radius: var(--radius-lg);
  background: var(--surface);
  border: 1px solid var(--line);
  box-shadow: var(--shadow);
}
.identity-avatar {
  width: 48px;
  height: 48px;
  flex: none;
  border-radius: 50%;
  background: var(--tile);
  object-fit: cover;
}
.identity-who { flex: 1; min-width: 160px; }
.identity-name { margin: 0; font-size: 16px; font-weight: 750; letter-spacing: -0.01em; overflow-wrap: anywhere; }
.identity-email { font-size: 13px; color: var(--ink-soft); overflow-wrap: anywhere; }
.identity-actions { display: flex; gap: 6px; flex-wrap: wrap; }

/* Rows with a trailing action keep the same divider rhythm as plain rows. The
   44px button already gives the row its height, so the padding steps down. */
.puzzle-row.has-actions { padding: 4px 2px; }
.row-actions { display: flex; align-items: center; gap: 2px; margin-right: -8px; }

/* A row asking "really?": the question where the title was, the answer where
   the actions were. Danger colour is reserved for the button that acts. */
.puzzle-row.confirm { flex-wrap: wrap; gap: 8px 12px; padding: 8px 2px; }
.confirm-text { flex: 1; min-width: 220px; font-size: 14px; }
.puzzle-row.confirm .row-actions { gap: 6px; margin-right: 0; }
.note-danger { flex-basis: 100%; color: var(--danger); }
.btn-danger { border-color: var(--danger); color: var(--danger); }
@media (hover: hover) and (pointer: fine) {
  .btn-danger:hover:not(:disabled) { background: color-mix(in oklab, var(--danger) 10%, var(--surface)); }
}
.section-foot { display: flex; align-items: center; gap: 14px; margin-top: 12px; flex-wrap: wrap; }

.sr-only {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

@media (prefers-reduced-motion: reduce) {
  /* Not a blanket kill: every state change still reads, it just stops moving.
     Pages add their own rules for anything that needs a static substitute. */
  *, *::before, *::after {
    animation-duration: 1ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 90ms !important;
  }
}
