/* Custom and Supplementary Styles for Kana Learner - Mobile & Desktop */

@import url('https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@400;500;600;700;800&family=Noto+Sans+JP:wght@400;500;700&display=swap');

:root {
  --primary: #2563eb;
  --primary-hover: #1d4ed8;
  --accent-cherry: #ec4899;
}

body {
  font-family: 'Plus Jakarta Sans', system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  -webkit-font-smoothing: antialiased;
  -webkit-tap-highlight-color: transparent;
}

.font-japanese {
  font-family: 'Noto Sans JP', 'Hiragino Sans', 'Hiragino Kaku Gothic ProN', 'Yu Gothic Medium', Meiryo, sans-serif;
}

/* Mobile Safe Areas */
.pb-safe {
  padding-bottom: calc(env(safe-area-inset-bottom, 0px) + 0.5rem);
}

.pt-safe {
  padding-top: env(safe-area-inset-top, 0px);
}

/* Touch Ergonomics - Prevent accidental double-tap zoom */
button, select, input, .touch-manipulation {
  touch-action: manipulation;
}

/* 3D Flip Card Styles */
.perspective-1000 {
  perspective: 1000px;
}

.transform-style-3d {
  transform-style: preserve-3d;
}

.backface-hidden {
  backface-visibility: hidden;
  -webkit-backface-visibility: hidden;
}

.rotate-y-180 {
  transform: rotateY(180deg);
}

.flashcard-inner {
  transition: transform 0.4s cubic-bezier(0.4, 0, 0.2, 1);
  transform-style: preserve-3d;
}

.flashcard-inner.flipped {
  transform: rotateY(180deg);
}

/* Bottom Nav Active State (Mobile) */
.bottom-nav-btn {
  color: #64748b;
  transition: color 0.15s ease, transform 0.15s ease;
}

.dark .bottom-nav-btn {
  color: #94a3b8;
}

.bottom-nav-btn:active {
  transform: scale(0.92);
}

/* ==========================================================================
   App shell navigation
   --------------------------------------------------------------------------
   Three surfaces share one state class (`nav-active`) and one data attribute
   (`data-view`), so switchView() updates them from a single selector:
     .nav-link.nav-sidebar   — sidebar, >= 1024px
     .nav-link.nav-top       — horizontal strip in the header, 768–1023px
     .bottom-nav-btn         — fixed bottom bar, < 768px
   Below 768px the wide header controls are dropped, which is what stops the
   app bar overflowing on a phone in portrait.
   ========================================================================== */

.nav-active {
  background-color: #2563eb;
  color: #ffffff !important;
  box-shadow: 0 4px 12px rgba(37, 99, 235, 0.25);
}

/* The sidebar items carry Tailwind's `hover:bg-slate-100`. On a touch device a
   tapped item stays hovered, so that hover background replaced the active blue
   while the label kept its forced white colour — white on near-white, i.e. the
   selected entry looked unstyled. Pin the active background against hover. */
.nav-active:hover,
.nav-active:focus,
.nav-active:focus-visible {
  background-color: #2563eb !important;
  color: #ffffff !important;
}

/* The bottom bar is a flat icon strip, so its active state is colour, not fill. */
.bottom-nav-btn.nav-active {
  background-color: transparent;
  box-shadow: none;
  color: #2563eb !important;
}

.dark .bottom-nav-btn.nav-active {
  color: #60a5fa !important;
}

/* Sidebar collapse. Collapsing leaves an icon rail, so every view stays
   reachable on a narrow tablet while reclaiming horizontal space. */
.app-sidebar {
  transition: width 0.2s ease;
}

/* The sidebar refuses to render until its breakpoint is known, so there is never
   a flash of the pinned layout inside the overlay layout (or vice versa). */
.app-sidebar[data-sidebar-ready="false"] {
  display: none !important;
}

/* Width is owned here rather than by a Tailwind utility. `!w-60` is emitted with
   `!important`, which outranks even an inline style, so the collapse could never
   take effect while the utility was present. */
.app-sidebar {
  width: 15rem;
}

.app-sidebar.is-collapsed {
  width: 4.5rem;
}

/* Width transition only while pinned: transitioning position/inset/display on the
   overlay path animates the wrong properties and looks like a glitch. */
.app-sidebar:not(.is-overlay) {
  transition: width 0.2s ease;
}

/* --- Below lg: the sidebar ONLY exists as a slide-in overlay -----------------
   The overlay state is also reachable by resizing (rotating a tablet) while the
   hamburger menu is open, and the resize handler is debounced, so for a moment a
   stale overlay state can coexist with a desktop-width viewport. Scoping the
   overlay to this breakpoint means the worst case is a sidebar that lays out
   flat instead of overlapping the page. */
@media (max-width: 1023.98px) {
  .app-sidebar {
    display: none;
  }

  .app-sidebar.is-overlay {
    position: fixed;
    inset: 0 auto 0 0;
    /* Sized relative to the viewport, not a fixed 272px. A fixed width covered
       76% of a 360px phone screen, which reads as the site being squeezed even
       though the overlay is out of flow and the content never moves. */
    /* Proportional on phones, capped for larger screens. A fixed 272px covered
       76% of a 360px screen; `min(20rem, 78vw)` gives ~281px at 360px (fits the
       longest label) and tops out at 320px so a tablet does not get a 600px
       drawer. */
    width: min(20rem, 78vw);
    max-width: min(20rem, 78vw);
    display: flex;
    flex-direction: column;
    z-index: 50;
    box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.45);
  }
}

/* --- lg and up: the sidebar is part of the layout ---------------------------
   This is what makes a stale overlay state harmless: even if the overlay class
   is still applied, at desktop width the sidebar lays out pinned. Declared after
   the overlay rules so it wins at equal specificity. */
@media (min-width: 1024px) {
  .app-sidebar,
  .app-sidebar.is-overlay {
    display: flex;
    position: sticky;
    top: 4rem;
    height: calc(100vh - 4rem);
    flex-direction: column;
    flex-shrink: 0;
    z-index: 30;
    box-shadow: none;
  }

  .app-sidebar.is-overlay {
    inset: auto;
    max-width: none;
    width: 15rem;
  }
}

.app-sidebar.is-collapsed .nav-label,
.app-sidebar.is-collapsed .sidebar-brand-text,
.app-sidebar.is-collapsed .sidebar-footer-text {
  display: none;
}

.app-sidebar.is-collapsed .nav-link {
  justify-content: center;
  padding-left: 0;
  padding-right: 0;
}

/* Keep the nav scrollable on short landscape viewports so nothing is clipped. */
.app-sidebar .sidebar-nav {
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
}

/* Touch Action for Stylus/Drawing Canvas */
.canvas-container {
  touch-action: none;
}

/* Smooth transitions */
button, a {
  transition: all 0.15s ease-in-out;
}

/* Custom scrollbars */
::-webkit-scrollbar {
  width: 6px;
  height: 6px;
}

::-webkit-scrollbar-track {
  background: transparent;
}

::-webkit-scrollbar-thumb {
  background: #cbd5e1;
  border-radius: 9999px;
}

.dark ::-webkit-scrollbar-thumb {
  background: #334155;
}

/* ==========================================================================
   App bar must never widen the document
   --------------------------------------------------------------------------
   A flex item's automatic minimum size is its content width, so on a narrow
   phone the action buttons refused to shrink and pushed the sticky header —
   and with it the whole document — past the viewport. `min-width: 0` lets them
   compress; containing the overflow means any residual spill is clipped rather
   than becoming horizontal page scroll.
   ========================================================================== */
.app-bar-row {
  min-width: 0;
}

.app-bar-actions {
  min-width: 0;
  overflow: hidden;
}

.app-bar-actions > * {
  min-width: 0;
}

/* Icon-only controls have no text to truncate, so shrinking them turns the
   avatar and theme toggle into clipped slivers. Only the switcher may shrink. */
.app-bar-actions > #user-profile-btn,
.app-bar-actions > #theme-toggle,
.app-bar-actions > #faq-open-btn,
.app-bar-actions > #install-pwa-btn {
  flex-shrink: 0;
}

@media (max-width: 767px) {
  .app-bar-actions > button {
    padding-left: 0.3rem;
    padding-right: 0.3rem;
  }
}

/* The quick kana switcher is the most-used control, so it must not be clipped
   on a narrow phone. Tighten it rather than letting it overflow its container. */
@media (max-width: 420px) {
  [data-quick-switcher] > button {
    padding-left: 0.35rem;
    padding-right: 0.35rem;
    font-size: 0.68rem;
  }
  [data-quick-switcher] {
    flex-shrink: 1;
    min-width: 0;
    overflow: hidden;
  }
}

/* Horizontally scrolling chip rows need a visible cue, otherwise the clipped
   chip just looks broken. Mask fades the edge to signal "scroll for more". */
.scroll-fade-x {
  -webkit-mask-image: linear-gradient(to right, #000 calc(100% - 24px), transparent 100%);
  mask-image: linear-gradient(to right, #000 calc(100% - 24px), transparent 100%);
}


/* Overlay scrim must sit above the app bar (z-40) and the fixed bottom
   navigation (z-40) but below the slide-in sidebar (z-50). At an equal z-index
   the winner is decided by DOM order, which left the bottom bar painted on top
   of the scrim — so the page looked half-dimmed with the nav still active. */
.z-45 {
  z-index: 45;
}
