/* =========================================================
   RESPONSIVE — TABLET
   ========================================================= */

@media (max-width: 1100px) {
  .app {
    /* Same var(--sidebar-width) as the base rule (css/layout.css) —
       collapse/resize (css/sidebar.css) apply uniformly across
       tablet and desktop widths, not just desktop; only the mobile
       drawer breakpoint below is a genuinely different layout model. */
    grid-template-columns:
      var(--sidebar-width)
      minmax(0, 1fr);
  }

  .player {
    /* Same pattern as the base rule: outer columns capped to content,
       middle column is the one 1fr track so .left/.right-controls
       stay pinned to the true edges instead of centering as a block.
       Right column needs to fit 3 icon buttons (lyrics/queue/mute)
       plus the volume slider — 220px left ~2px of headroom, so
       widened to 260px.

       The middle column's own minmax(250px, 1fr) — was minmax(0, 1fr)
       — is load-bearing, not decorative: with no real minimum, the
       grid algorithm satisfies the two *capped* outer columns' full
       preferred width first and only gives the flexible middle
       column whatever's left, which shrinks it far more aggressively
       than the outer columns as viewport width drops. Caught by the
       larger --tap-md/--icon-md transport controls (see docs/PRODUCT.md's
       "Icon sizes") needing ~244px of real room here — below ~870px
       this column was shrinking to ~220px, and the transport row
       started overlapping .left's track title on one side and
       .right-controls on the other. 250px is that measured need with
       a small buffer, not an arbitrary round number. */
    grid-template-columns:
      minmax(180px, 320px)
      minmax(250px, 1fr)
      minmax(120px, 260px);
  }

  .search {
    width: min(320px, 35vw);
  }
}

/* =========================================================
   MOBILE
   ========================================================= */

@media (max-width: 767px) {
  /* Touch targets grow here, not the icons themselves — this is the
     one breakpoint where touch (not mouse) is the primary input, and
     both Apple's HIG (44×44pt) and Material Design (48×48dp) call for
     bigger tap targets specifically for touch, not just "smaller
     screen." A --tap-md redefinition here (rather than per-selector
     overrides, unlike the typography scale elsewhere in this file) is
     deliberate: every icon-only button should grow together, uniformly,
     which is exactly the kind of scale-wide change custom properties
     exist for — typography's per-selector overrides handle the
     opposite case, where different text needs different treatment.
     Icon glyph sizes are untouched: padding absorbing the difference
     is the actual HIG/Material guidance, not a bigger glyph. */
  :root {
    --tap-md: 44px;
    --tap-lg: 52px;
  }

  body {
    overflow-x: hidden;
  }

  .app {
    min-height: 100vh;

    display: flex;
    flex-direction: column;

    gap: 10px;
    padding: 10px;
    /* Clears the mobile player's real (2-row, ~142px) height + its
       8px floating offset from the viewport edge — 105px was sized
       for the single-row desktop bar and let the fixed-position
       player overlap the last track row. */
    padding-bottom: 168px;
  }

  /* Sidebar becomes an off-canvas drawer instead of disappearing
     outright — it was previously unreachable below this breakpoint,
     with no way to get to Search/Liked Songs/playlists at all. */
  .sidebar {
    position: fixed;
    top: 0;
    left: 0;
    bottom: 0;

    z-index: 1100;

    width: min(300px, 84vw);

    border-radius: 0;

    transform: translateX(-100%);

    transition: transform 0.25s ease;
  }

  .sidebar.open {
    transform: translateX(0);
  }

  /* Collapse (rail mode) and resize are desktop/tablet-only concepts
     — the mobile drawer is a temporary overlay, not a persistent
     column with a width worth remembering or shrinking to icons.
     .sidebar.collapsed needs restating here at matching specificity
     (2 classes, same as its definition in css/sidebar.css) since a
     bare .sidebar rule wouldn't be specific enough to win over it —
     without this, resizing the window down to mobile width while
     collapsed would leave the drawer stuck at rail width instead of
     the drawer's own full min(300px, 84vw). */
  .sidebar.collapsed {
    width: min(300px, 84vw);
    min-width: 0;
    max-width: none;

    padding-left: 14px;
    padding-right: 14px;
  }

  .sidebar-collapse-btn,
  .sidebar-resize-handle {
    display: none;
  }

  .sidebar.collapsed .brand {
    display: flex;
  }

  .sidebar.collapsed .brand-word,
  .sidebar.collapsed .nav-label-text,
  .sidebar.collapsed .playlist-name,
  .sidebar.collapsed .library-toolbar {
    display: block;
  }

  .sidebar.collapsed .playlist-text {
    display: flex;
  }

  /* .library-sort-menu specifically must stay hidden even though the
     rule above restates everything else back to visible at mobile
     width — showing a leftover open dropdown here would float over
     the drawer with nothing sensible to anchor to. */
  .sidebar.collapsed .library-sort-menu {
    display: none;
  }

  .sidebar.collapsed .nav a {
    justify-content: flex-start;

    gap: 12px;
    padding-left: 12px;
    padding-right: 12px;

    border-left: 3px solid transparent;
  }

  .sidebar.collapsed .nav a.active {
    border-left-color: var(--pink);
  }

  .sidebar.collapsed .playlist-item {
    justify-content: flex-start;

    gap: 12px;
    padding-left: 10px;
    padding-right: 10px;

    border-left: 3px solid transparent;
  }

  .sidebar.collapsed .playlist-item.active {
    border-left-color: var(--pink);
  }

  /* The rail-mode underline indicator must not carry over either —
     it was positioned for a centered icon with no label. */
  .sidebar.collapsed .nav a.active::after,
  .sidebar.collapsed .playlist-item.active::after {
    display: none;
  }

  .header .menu-toggle {
    display: inline-flex;
  }

  /* display:none/block, not opacity — same fix as the queue panel
     (see its comment in player.css): a confirmed real bug in one
     tested environment left an opacity-transitioned "open" state
     rendering as invisible/inert despite every computed style and
     matched CSSOM rule checking out correctly. display toggling
     has no equivalent failure mode. */
  .sidebar-backdrop {
    display: none;

    position: fixed;
    inset: 0;

    z-index: 1090;

    background: rgba(20, 17, 33, 0.4);
  }

  .sidebar-backdrop.open {
    display: block;
  }

  .main {
    width: 100%;

    overflow: visible;
  }

  .header {
    min-height: 52px;
  }

  .nav-controls {
    display: none;
  }

  .header-right {
    width: 100%;
  }

  .search {
    width: 100%;
  }

  .content {
    display: flex;
    flex-direction: column;

    overflow: visible;
  }

  .left-col {
    overflow: visible;
  }

  .hero {
    min-height: 120px;

    padding: 15px;
    gap: 14px;
  }

  .cover {
    width: 82px;
    height: 82px;

    font-size: 21px;
  }

  .hero h1 {
    /* Display, scaled down for the width — not a new token, the
       hero title is still the one Display-role element, just smaller. */
    font-size: 22px;
  }

  .hero p {
    font-size: var(--fs-body-sm);
  }

  .player {
    left: 8px;
    right: 8px;
    bottom: 8px;

    width: auto;
    /* Base .player hard-codes height:92px for the single-row desktop
       layout — this is 2 rows (info+icons, then transport+seek), so
       a fixed height clipped the second row outright instead of
       just looking cramped. auto + min-height (still enforcing a
       sane minimum touch target) is what actually fits the content. */
    height: auto;
    min-height: 92px;

    grid-template-columns: 1fr auto;

    gap: 8px;
    padding: 10px 12px;

    border-radius: var(--radius-lg);
  }

  .player .controls {
    grid-column: 1 / -1;
    grid-row: 2;
  }

  .player .left {
    grid-column: 1;
    grid-row: 1;
  }

  .right-controls {
    grid-column: 2;
    grid-row: 1;
  }

  .right-controls input[type="range"] {
    display: none;
  }

  /* Non-functional for now (see index.html) and the tightest control
     to lose — dropping it keeps the touch targets that matter
     (queue, mute) comfortably spaced instead of cramming in a third. */
  #lyricsBtn {
    display: none;
  }

  .cover-sm {
    width: 46px;
    height: 46px;
  }

  .progress {
    width: 100%;
  }

  /* The queue panel anchors above the player bar via an inline
     `bottom` set in JS (queue-panel.js measures the bar's real
     height — it's no longer a fixed constant at this breakpoint).
     Only the horizontal fit needs a mobile override here. */
  .queue-panel {
    right: 8px;
    left: 8px;
    width: auto;
  }
}

/* =========================================================
   VERY SMALL SCREENS
   ========================================================= */

@media (max-width: 480px) {
  .app {
    padding: 7px;
    /* Same clearance reasoning as the 767px breakpoint above — the
       player bar's own height doesn't shrink further at this width. */
    padding-bottom: 168px;
  }

  .hero {
    min-height: 105px;
    padding: 12px;
  }

  .cover {
    width: 68px;
    height: 68px;
  }

  .hero h1 {
    font-size: 19px; /* Display, scaled down further still */
  }

  /* Play stays: it's the main action on a playlist, and tapping a row
     is not an obvious substitute. Only the description goes. */
  .hero p {
    display: none;
  }

  .hero-play {
    padding: 8px 18px 8px 14px;

    font-size: var(--fs-body);
  }

  .hero-secondary-btn {
    padding: 8px 14px;
  }

  .track {
    min-height: 58px;

    gap: 8px;
    padding: 7px;
  }

  .track .idx {
    width: 20px;
  }

  .track img {
    width: 42px;
    height: 42px;
  }

  .track .time {
    display: none;
  }

  .track .title {
    font-size: var(--fs-body);
  }

  .track .sub {
    font-size: var(--fs-label);
  }

  /* Tapping the row already plays it; a ▶ per row just squeezed
     the title. The button stays in the DOM (the row click uses it). */
  .track .actions .play-btn {
    display: none;
  }

  .track .actions {
    width: 40px;
  }

  .player-title {
    max-width: 150px;
  }
}

/* =========================================================
   PHONE LAYOUT: tab bar + mini player + full-screen Now Playing
   (js/mobile-player.js)
   ========================================================= */

.tab-bar,
.player-collapse-btn {
  display: none;
}

@media (max-width: 767px) {
  :root {
    --tab-bar-height: calc(58px + env(safe-area-inset-bottom));
    --mini-player-height: 60px;
  }

  /* The tab bar replaces the ☰ drawer as the way around the app. */
  .header .menu-toggle {
    display: none;
  }

  .app {
    padding-bottom: calc(var(--tab-bar-height) + var(--mini-player-height) + 24px);
  }

  /* ---------- Tab bar ---------- */

  .tab-bar {
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;

    z-index: 1000;

    height: var(--tab-bar-height);

    display: flex;

    padding-bottom: env(safe-area-inset-bottom);

    background: linear-gradient(to top, var(--bg) 70%, rgba(var(--bg-rgb), 0.85));
    backdrop-filter: blur(12px);
  }

  /* Fades the list out behind the floating mini player, so rows
     don't show through the gap between it and the tab bar. */
  .tab-bar::before {
    content: "";

    position: absolute;
    left: 0;
    right: 0;
    bottom: 100%;

    height: calc(var(--mini-player-height) + 12px);

    background: linear-gradient(to top, var(--bg) 30%, transparent);

    pointer-events: none;
  }

  .tab-bar-item {
    flex: 1;

    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;

    gap: 4px;

    border: none;

    background: transparent;
    color: var(--text-muted);

    font: inherit;
    font-size: var(--fs-label);
    font-weight: 600;

    cursor: pointer;
  }

  .tab-bar-item svg {
    width: 22px;
    height: 22px;
  }

  .tab-bar-item.is-active {
    color: var(--text);
  }

  .tab-bar-item.is-active svg {
    color: var(--pink);
  }

  /* ---------- Mini player ---------- */

  .player:not(.is-expanded) {
    left: 8px;
    right: 8px;
    bottom: calc(var(--tab-bar-height) + 4px);

    height: var(--mini-player-height);
    min-height: 0;

    display: flex;
    align-items: center;

    gap: 8px;
    padding: 8px 8px 8px 8px;

    border-radius: 12px;

    overflow: hidden;

    cursor: pointer;
  }

  .player:not(.is-expanded) .left {
    flex: 1;

    min-width: 0;

    gap: 10px;
  }

  .player:not(.is-expanded) .cover-sm {
    width: 44px;
    height: 44px;

    border-radius: var(--radius-sm);
  }

  .player:not(.is-expanded) .player-title {
    font-size: var(--fs-body);
  }

  .player:not(.is-expanded) .player-artist {
    font-size: var(--fs-body-sm);
  }

  /* Only play/pause stays; everything else lives in Now Playing. */
  .player:not(.is-expanded) .controls {
    display: contents;
  }

  .player:not(.is-expanded) .control-buttons > :not(#playPauseBtn, #nextBtn),
  .player:not(.is-expanded) .right-controls,
  .player:not(.is-expanded) .time-current,
  .player:not(.is-expanded) .time-duration,
  .player:not(.is-expanded) .seek-tooltip {
    display: none;
  }

  .player:not(.is-expanded) .control-buttons {
    order: 2;
  }

  .player:not(.is-expanded) #playPauseBtn,
  .player:not(.is-expanded) #nextBtn {
    width: 40px;
    height: 40px;

    background: transparent;
    color: var(--text);
  }

  /* Progress: a hairline along the bottom edge of the mini player. */
  .player:not(.is-expanded) .progress {
    position: absolute;
    left: 10px;
    right: 10px;
    bottom: 0;

    width: auto;
    padding: 0;
  }

  .player:not(.is-expanded) .bar {
    height: 2px;

    pointer-events: none;
  }

  /* ---------- Full-screen Now Playing ---------- */

  .player.is-expanded {
    inset: 0;

    z-index: 1200;

    width: auto;
    height: auto;
    min-height: 100dvh;

    display: flex;
    flex-direction: column;

    gap: 20px;
    padding: 12px 24px calc(24px + env(safe-area-inset-bottom));

    border-radius: 0;

    background:
      radial-gradient(120% 70% at 50% 0%, var(--tint), transparent 70%),
      var(--bg);

    transition: --tint 500ms var(--ease-out);

    animation: now-playing-in var(--dur-slow) var(--ease-out);
  }

  @keyframes now-playing-in {
    from {
      transform: translateY(40px);
      opacity: 0;
    }
  }

  body.player-expanded {
    overflow: hidden;
  }

  .player.is-expanded .player-collapse-btn {
    align-self: stretch;

    display: flex;
    align-items: center;
    justify-content: center;

    position: relative;

    gap: 6px;
    padding: 8px;

    border: none;

    background: transparent;
    color: var(--text-muted);

    font: inherit;
    font-size: var(--fs-label);
    font-weight: var(--fw-label);
    letter-spacing: var(--ls-label);
    text-transform: uppercase;

    cursor: pointer;
  }

  .player.is-expanded .player-collapse-btn svg {
    position: absolute;
    left: 0;

    width: 26px;
    height: 26px;

    color: var(--text);
  }

  .player.is-expanded .left {
    flex: 1;

    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    grid-template-rows: 1fr auto;
    align-content: center;

    gap: 24px 12px;
  }

  .player.is-expanded .cover-sm {
    grid-column: 1 / -1;
    justify-self: center;

    width: min(82vw, 360px, 46dvh);
    height: auto;
    aspect-ratio: 1;

    border-radius: 14px;

    box-shadow: 0 24px 60px rgba(0, 0, 0, 0.5);

    font-size: 48px;
  }

  .player.is-expanded .cover-sm svg {
    width: 30%;
    height: 30%;
  }

  .player.is-expanded .player-title {
    font-size: 20px;
    font-weight: 800;
  }

  .player.is-expanded .player-artist {
    font-size: var(--fs-body);
  }

  .player.is-expanded .player-like-btn {
    width: 44px;
    height: 44px;
  }

  .player.is-expanded .player-like-btn svg {
    width: 26px;
    height: 26px;
  }

  .player.is-expanded .controls {
    display: flex;
    flex-direction: column-reverse;

    gap: 16px;
  }

  .player.is-expanded .progress {
    width: 100%;
  }

  .player.is-expanded .bar {
    height: 4px;
  }

  .player.is-expanded .control-buttons {
    justify-content: space-between;
  }

  .player.is-expanded .control-buttons .btn {
    width: 48px;
    height: 48px;
  }

  .player.is-expanded #playPauseBtn {
    width: 68px;
    height: 68px;
  }

  .player.is-expanded #playPauseBtn svg {
    width: 30px;
    height: 30px;
  }

  /* Phones have hardware volume buttons; a mute icon here was a
     control that did less than the one on the side of the phone. */
  .player.is-expanded #volumeRange,
  .player.is-expanded #muteBtn {
    display: none;
  }

  .player.is-expanded .right-controls {
    justify-content: center;
  }
}

@media (max-width: 767px) and (prefers-reduced-motion: reduce) {
  .player.is-expanded {
    animation: none;
  }
}

@media (max-width: 767px) {
  /* Now Playing has room for long titles: wrap to two lines first. */
  .player.is-expanded .player-title,
  .player.is-expanded .player-artist {
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 2;

    white-space: normal;
  }
}

@media (max-width: 767px) {
  /* No mini player until something is loaded: an empty "Nothing
     playing" bar is just clutter above the tab bar. */
  .player:not(.is-expanded):has(.cover-sm.is-empty) {
    display: none;
  }
}

/* Touch screens keep :hover after a tap, so a tapped Shuffle or row
   button stayed highlighted as if it were switched on. */
@media (hover: none) {
  .control-buttons .btn:not(#playPauseBtn):not(.is-active):hover,
  .track .actions button:hover {
    background: transparent;
    color: var(--text-muted);
    transform: none;
  }

  .track .actions .save-btn.is-liked:hover {
    color: var(--pink);
  }
}
