/* public/css/custom.css - Minimal overrides for TailwindCSS */

/* ─── Code Playground panes ──────────────────────────────────────────────── */
/* Below lg the three editors are a tabbed interface (one pane at a time);
   from lg up all three stack vertically and are always visible.
   Driven by an explicit media query rather than Tailwind's `hidden` +
   `lg:block`, because those two utilities have equal specificity and the
   cascade order would otherwise decide which wins. */
@media (max-width: 1023.98px) {
  .cp-pane[hidden-sm] { display: none; }
}
@media (min-width: 1024px) {
  .cp-pane { display: block !important; }
}

/* ─── Site logo ──────────────────────────────────────────────────────────── */
/* The mark is a full-colour icon with a transparent background, so it needs
   no dark-mode treatment — the previous invert() + hue-rotate assumed a
   monochrome logo and turned this one into a negative. */
.site-logo {
  height: 32px;
  width: 32px;
  display: block;
  object-fit: contain;
}

/* ─── Form controls ──────────────────────────────────────────────────────── */
/* The focus ring is also expressed by the .field component class; this rule
   covers inputs in views that have not been migrated to it yet. */
textarea,
input[type="text"],
input[type="number"] {
  transition: border-color .15s ease, box-shadow .15s ease;
}
textarea:focus,
input[type="text"]:focus,
input[type="number"]:focus {
  border-color: #7A2E3C;
  box-shadow: 0 0 0 3px rgba(122, 46, 60, .15);
}
textarea[readonly] {
  background-color: #F4F2EE;
  cursor: default;
}
.dark textarea[readonly] {
  background-color: #121110;
}

/* ─── Disclosure chevrons ────────────────────────────────────────────────── */
details > summary {
  -webkit-user-select: none;
  user-select: none;
}
details[open] > summary { margin-bottom: 0; }
details > summary span {
  display: inline-block;
  transition: transform .2s ease;
}
details[open] > summary span { transform: rotate(180deg); }

/* ─── Tool cards ─────────────────────────────────────────────────────────── */
.tool-card {
  transition: transform .15s ease, box-shadow .15s ease;
}
.tool-card:hover {
  transform: translateY(-2px);
  box-shadow: 0 8px 24px -4px rgba(28, 26, 24, 0.10);
}
.dark .tool-card:hover {
  box-shadow: 0 10px 25px rgba(0, 0, 0, .35);
}

/* ─── Mobile menu ────────────────────────────────────────────────────────── */
/* Collapsed by height rather than `hidden` so the open/close is animatable;
   header.ejs toggles `.active`. max-height is generous because the menu is
   scrollable — the previous 600px silently truncated most of the list. */
#mobile-menu {
  max-height: 0;
  overflow: hidden;
  transition: max-height .3s ease;
}
#mobile-menu.active {
  max-height: 80vh;
  overflow-y: auto;
}

/* ─── Inline code styling ────────────────────────────────────────────────── */
code {
  background-color: #F4F2EE;
  color: #2A2724;
  padding: 0.1em 0.35em;
  border-radius: 0.3em;
  font-size: 0.875em;
  font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, monospace;
}
/* Previously missing, which left inline code near-black on near-black. */
.dark code {
  background-color: #121110;
  color: #F4F2EE;
}

/* ─── Toast notification ─────────────────────────────────────────────────── */
#ts-toast {
  pointer-events: none;
  opacity: 1;
}

/* ─── Scrollbar (Webkit) — subtle ────────────────────────────────────────── */
::-webkit-scrollbar { width: 6px; height: 6px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb { background: #D6D2CA; border-radius: 3px; }
::-webkit-scrollbar-thumb:hover { background: #A8A29A; }

/* ─── Sticky sidebar ad layout ──────────────────────────────────────────── */
.ad-sidebar-container {
  position: relative;
  width: 320px;
  flex-shrink: 0;
  margin-left: 2rem;
}

.ad-sidebar-sticky {
  position: sticky;
  top: 1.5rem;
  transition: all 0.3s ease;
}

/* Container with sidebar */
.content-with-sidebar {
  display: flex;
  align-items: flex-start;
  max-width: 1400px;
  margin: 0 auto;
}

.content-main {
  flex: 1;
  min-width: 0;
  /* The narrower 1000px cap exists only to leave room for the 352px ad
     sidebar. That sidebar renders solely when AdSense is fully configured, so
     without it the cap was paying rent for a tenant that never moved in and
     left a dead gutter. _head.ejs adds .has-sidebar when the slot will render. */
  max-width: 1240px;
  margin-inline: auto;
}

.content-with-sidebar.has-sidebar .content-main {
  max-width: 1000px;
}

/* AdSense-friendly ad wrappers: clear label + reserved slot space */
.ad-label {
  margin-bottom: 0.5rem;
  text-align: center;
  font-size: 0.7rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: #7A756D;
}

.ad-slot-shell {
  width: 100%;
  margin: 0 auto;
  overflow: hidden;
}

.ad-slot-generic {
  min-height: 120px;
}

.ad-slot-banner {
  min-height: 100px;
}

.ad-slot-leaderboard {
  min-height: 90px;
}

.ad-slot-sidebar {
  min-height: 600px;
}

@media (max-width: 767px) {
  .ad-slot-banner {
    min-height: 50px;
  }

  .ad-slot-leaderboard {
    min-height: 50px;
  }
}

/* Responsive: hide sidebar on mobile/tablet */
@media (max-width: 1023px) {
  .ad-sidebar-container {
    display: none !important;
  }
}

/* ─── Piano keyboard (learn-piano) ───────────────────────────────────────── */
/* Key geometry is set inline per-key in the view; these rules cover the
   interaction states, which Tailwind utilities can't express. */
.piano-key {
  transition: background-color 90ms ease-out, transform 90ms ease-out;
  transform-origin: top center;
  user-select: none;
  -webkit-user-select: none;
  -webkit-tap-highlight-color: transparent;
}

.piano-key-white:hover { background-color: #f1f5f9; }
.piano-key-black:hover { background-color: #1f2937; }

/* Lesson highlight — the keys belonging to the selected scale/chord. */
.piano-key-white.piano-key-hint { background-color: #ede9fe; }
.piano-key-black.piano-key-hint { background-color: #5b21b6; }

/* Currently sounding — must win over the hint colour. */
.piano-key-white.piano-key-active,
.piano-key-white.piano-key-hint.piano-key-active {
  background-color: #a78bfa;
  transform: scaleY(0.985);
}
.piano-key-black.piano-key-active,
.piano-key-black.piano-key-hint.piano-key-active {
  background-color: #7c3aed;
  transform: scaleY(0.985);
}

.piano-key:focus-visible {
  outline: 2px solid #7A2E3C;
  outline-offset: -2px;
}

@media (prefers-reduced-motion: reduce) {
  .piano-key { transition: none; transform: none !important; }
}

/* ─── Print styles ───────────────────────────────────────────────────────── */
@media print {
  header, footer, .ad-slot, .ad-leaderboard, .ad-banner, .ad-sidebar-container, button { display: none !important; }
  body { background: white; }
}

/* ═══════════════════════════════════════════════════════════════════════════
   Interaction & type layer (Apple fluid-interface principles)

   Applies site-wide so tools and games share one feel. Notes reference the
   numbered sections of the apple-design guidance these rules come from.
   ═══════════════════════════════════════════════════════════════════════════ */

/* §1 Response — feedback on pointer-DOWN, not on release.
   The site previously had zero :active states: every button looked dead until
   its handler returned. Scale is compositor-only, so it costs nothing.
   Faster in (90ms) than out (140ms) — the press should feel immediate, the
   release can relax. */
button,
[role="button"],
.btn,
a.tool-card {
  transition: transform 140ms cubic-bezier(0.2, 0, 0.2, 1),
              background-color 140ms ease,
              box-shadow 140ms ease;
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation; /* removes the legacy ~300ms tap delay */
}
button:active,
[role="button"]:active,
.btn:active {
  transform: scale(0.97);
  transition-duration: 90ms;
}
/* Cards travel further, so they compress less — big surfaces that squash
   as hard as a small button read as flimsy. */
a.tool-card:active {
  transform: translateY(-1px) scale(0.995);
  transition-duration: 90ms;
}
/* Disabled controls must not appear to respond. */
button:disabled:active,
button[disabled]:active {
  transform: none;
}

/* §10 Gesture details — keyboard parity with the press state, and a visible
   focus ring that does not rely on colour alone. */
button:focus-visible,
[role="button"]:focus-visible,
a.tool-card:focus-visible,
input:focus-visible,
select:focus-visible {
  outline: 2px solid #7A2E3C;
  outline-offset: 2px;
}

/* §11 Frame-level smoothness — hint the compositor only where motion is
   actually imminent (on hover/press), never permanently: a standing
   will-change on every card would pin hundreds of needless layers. */
.tool-card:hover,
.tool-card:active {
  will-change: transform;
}

/* §12 Materials & depth — the sticky header becomes a translucent layer that
   content scrolls under, rather than an opaque strip that consumes the top of
   the viewport. The bright top edge reads as light catching the material. */
.site-header-material {
  background: rgba(255, 255, 255, 0.72);
  backdrop-filter: blur(20px) saturate(180%);
  -webkit-backdrop-filter: blur(20px) saturate(180%);
  border-bottom: 1px solid rgba(0, 0, 0, 0.06);
}
.dark .site-header-material {
  background: rgba(28, 26, 24, 0.72);
  border-bottom-color: rgba(255, 255, 255, 0.08);
}

/* §15 Typography — tracking and line-height now live in the fontSize tokens
   in tailwind.config.js, so `tracking-*` utilities can override them per
   element. Rules here would win over those utilities and were removed. */

/* Tabular figures for anything counting: scores, timers, live results. Without
   this, proportional digits make a ticking clock visibly jitter as glyph
   widths change (1 is narrower than 8). */
.tabular-nums,
#time, #score, #streak, #best, #wpm, #acc, #solved, #mult,
#found-count, #found-total, #attempt-no, #puzzle-no {
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum" 1;
}

/* §14 Reduced motion.
   The existing blanket rule crushes ALL durations to 0.01ms, which also kills
   colour and opacity feedback the guidance says to keep — a correct-answer
   flash becomes an instant jump with no perceptible change. Restore gentle,
   non-vestibular cross-fades: no travel, but state changes stay legible. */
@media (prefers-reduced-motion: reduce) {
  button, [role="button"], .btn, a.tool-card, .tool-card {
    transition: background-color 200ms ease, color 200ms ease,
                opacity 200ms ease, box-shadow 200ms ease !important;
    transform: none !important;
  }
  button:active, [role="button"]:active, .btn:active,
  a.tool-card:active, .tool-card:hover {
    transform: none !important;
  }
}

/* ─── Daily Word Guess board ─────────────────────────────────────────────── */
/* §8 — tiles flip as they are scored, so the row reads left-to-right instead
   of all five states popping at once. Transform + opacity only (§11). */
@keyframes wg-flip {
  0%   { transform: rotateX(0deg)  scale(1);    }
  50%  { transform: rotateX(90deg) scale(1.04); }
  100% { transform: rotateX(0deg)  scale(1);    }
}
.wg-tile { transform-style: preserve-3d; }
/* A typed-but-unsubmitted tile: present, but visibly not yet scored. */
.wg-filled {
  border-color: #9ca3af;
  animation: wg-pop 110ms cubic-bezier(0.2, 0, 0.2, 1);
}
.dark .wg-filled { border-color: #6b7280; }
@keyframes wg-pop {
  0%   { transform: scale(1);    }
  60%  { transform: scale(1.06); }
  100% { transform: scale(1);    }
}

/* ─── Anagram Challenge found-words ──────────────────────────────────────── */
/* §13 — the accepted word lands, so the score change has a visible cause. */
.ac-chip-new {
  animation: ac-land 200ms cubic-bezier(0.2, 0, 0.2, 1);
}
@keyframes ac-land {
  0%   { transform: scale(0.85); opacity: 0; }
  100% { transform: scale(1);    opacity: 1; }
}

/* §14 Reduced transparency — frost the material into a solid surface rather
   than leaving low-contrast text over a blur. */
@media (prefers-reduced-transparency: reduce) {
  .site-header-material {
    background: #ffffff;
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
  }
  .dark .site-header-material {
    background: #1C1A18;
  }
}

/* §14 Increased contrast — near-solid backgrounds with a defined border. */
@media (prefers-contrast: more) {
  .site-header-material {
    background: #ffffff;
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
    border-bottom: 1px solid #1C1A18;
  }
  .dark .site-header-material {
    background: #000000;
    border-bottom-color: #ffffff;
  }
  button:focus-visible, a.tool-card:focus-visible {
    outline-width: 3px;
  }
}
