/* ============================================================
   desktop.css — UWS 2026
   Tablet + desktop layer for the mobile-first PWA.

   STRATEGY
   Every rule in this file lives inside a media query with a
   `min-width` of 768px or greater. Nothing here can reach a phone:
   below 768px the app renders exactly as it did before this sheet
   existed. There are no new class names and no markup changes —
   this is a pure re-layout of the existing shell.

   LOAD ORDER MATTERS. This sheet must be linked AFTER app.css and
   features.css. Most rules override base declarations at identical
   specificity and win only on source order.

   BREAKPOINTS
     >= 768px   TABLET   Bottom nav stays. Content column ~760px,
                         grids go 2–3 up, headings step up a size.
                         Hover + focus affordances start here.
     >= 1025px  DESKTOP  Bottom nav becomes a 232px fixed left
                         sidebar; header becomes a full-width top
                         bar; content column ~1100px; real
                         multi-column layouts.
     >= 1440px  WIDE     Content column ~1240px, directory 3-up.

   ADDING THINGS
   Put new work in the section banner for the breakpoint it belongs
   to, not at the end of the file. Hover rules go in the
   `(hover: hover) and (pointer: fine)` block so touch tablets never
   get stuck in a hover state. Layout tokens are declared at the top
   of the >= 768px block.

   NOT DONE HERE
   Admin pages (assets/css/admin.css) are already desktop-oriented
   and are deliberately untouched. There is no dark theme — see the
   note at the bottom of this file for why.
   ============================================================ */


/* ============================================================
   >= 768px — TABLET
   Bottom nav is still a bottom nav. Just more room.
   ============================================================ */
@media (min-width: 768px) {

    /* ── Layout tokens ───────────────────────────────────────
       Declared here rather than in a bare :root so that nothing
       in this file can leak below the tablet breakpoint.       */
    :root {
        --uws-sidebar-w:   232px;
        --uws-content-max: 1100px;
        --uws-tablet-max:  760px;
        --uws-gutter:      24px;
        --uws-prose:       72ch;
    }

    /* ── Shell ───────────────────────────────────────────── */
    .app-header-inner {
        max-width: var(--uws-tablet-max);
        padding: 16px var(--uws-gutter);
    }

    .app-content {
        max-width: var(--uws-tablet-max);
        padding: 26px var(--uws-gutter) 16px;
    }

    /* Bottom nav: stop the five links stretching to the screen
       edges on a wide tablet — centre them instead. */
    .app-nav      { justify-content: center; }
    .app-nav-link { flex: 0 1 132px; }

    /* ── Type scale — headings only, body copy is unchanged ── */
    .page-title       { font-size: 26px; }
    .page-subtitle    { font-size: 14px; margin-bottom: 24px; }
    .home-greeting-hi { font-size: 26px; }
    .speaker-hero-name,
    .person-hero-name { font-size: 23px; }
    .venue-hero-name  { font-size: 24px; }
    .sheet-title      { font-size: 21px; }
    .empty-card-title { font-size: 19px; }

    /* ── Grids: 2–3 up ──────────────────────────────────────── */
    .speaker-grid,
    .sponsor-grid            { grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: 14px; }
    .home-tiles              { grid-template-columns: repeat(3, 1fr); gap: 12px; }
    .dinner-restaurants-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; }
    .venue-amenities-grid    { grid-template-columns: repeat(auto-fit, minmax(120px, 1fr)); }

    /* ── Breathing room ─────────────────────────────────────── */
    .schedule-row  { gap: 16px; padding: 16px 18px; }
    /* :not() guards keep the flush modifiers at zero padding —
       this sheet loads last, so a bare .ux-card would beat them. */
    .ux-card:not(.ux-card--flush),
    .venue-card:not(.venue-card--no-pad),
    .poll-card,
    .survey-q      { padding: 20px 22px; }
    .msg-bubble    { max-width: 68%; }
    .certificate   { padding: 48px 44px; }
}


/* ============================================================
   FOCUS AFFORDANCES — moved to app.css
   ============================================================
   These rules used to live here, inside `@media (min-width: 768px)`.
   That was a mistake: it meant nobody on a phone got a focus ring
   at any time. Keyboard access is not a screen-size feature —
   attendees pair Bluetooth keyboards to phones, iPads run Magic
   Keyboard below this breakpoint, and Switch Control and
   VoiceOver's focus cursor both rely on a visible indicator. WCAG
   2.4.7 applies at every width.

   They now live in app.css, unconditionally, so they apply
   everywhere. Nothing was lost — `:focus-visible` already
   withholds the ring from plain touch and mouse interaction, which
   is what made the media query look unnecessary on mobile in the
   first place.
   ============================================================ */


/* ============================================================
   >= 768px — DESKTOP AFFORDANCES: HOVER
   Guarded so a touch tablet never inherits a sticky hover state.
   ============================================================ */
@media (min-width: 768px) and (hover: hover) and (pointer: fine) {

    /* Cards lift */
    .home-tile:hover,
    .speaker-card:hover,
    .sponsor-card:hover,
    .dir-row:hover,
    .msg-thread:hover,
    .resource-card:hover,
    .checkin-log-row:hover,
    a.ux-card:hover {
        transform: translateY(-2px);
        box-shadow: var(--card-shadow-hover);
    }

    /* List rows tint instead of lifting */
    .more-item:hover,
    .venue-transport-item:hover { background: var(--blue-light); }

    /* Buttons darken */
    .ux-btn:hover:not(:disabled),
    .sched-btn:hover:not(:disabled),
    .msg-send:hover:not(:disabled),
    .btn-feedback-submit:hover:not(:disabled),
    .push-banner-enable:hover:not(:disabled),
    .a2hs-close-btn:hover {
        filter: brightness(0.93);
    }

    /* Inputs / choice controls pick up the accent border */
    .poll-option:hover:not(:disabled),
    .survey-choice:hover,
    .qa-vote:hover,
    .nps-btn:hover:not(.is-chosen),
    .dir-filter:hover:not(.is-active),
    .qa-session-tab:hover:not(.is-active) {
        border-color: var(--blue-bright);
    }

    /* :not(:focus) so hovering a focused field can't grey out the
       accent border those components set on :focus. */
    .dir-search input:hover:not(:focus),
    .qa-textarea:hover:not(:focus),
    .survey-text:hover:not(:focus),
    .session-feedback-comment:hover:not(:focus),
    .msg-composer textarea:hover:not(:focus) { border-color: #C7D2E8; }

    .venue-map-floor-btn:hover:not(.is-active) { background: #DCE7FF; }

    /* Anything clickable should say so */
    .home-tile,
    .speaker-card,
    .sponsor-card,
    .dir-row,
    .msg-thread,
    .more-item { cursor: pointer; }
}


/* ============================================================
   >= 1025px — DESKTOP
   The big change: bottom nav becomes a left sidebar.

   Why 1025 and not 1024: the iPad Pro 12.9" reports exactly 1024px
   in PORTRAIT. At 1024 it was picking up the full desktop shell —
   232px sidebar plus a content column sized for a real monitor —
   on a tablet held upright, with no mouse. Held sideways it is
   1366px and still gets the desktop layout, which is correct.
   One pixel keeps portrait tablets on the tablet tier where the
   bottom nav and the 760px column belong.
   ============================================================ */
@media (min-width: 1025px) {

    /* --nav-h is what every bottom-anchored element measures from
       (body padding, toasts, banners, the message composer, and an
       inline style in includes/footer.php). Zeroing it here
       re-anchors all of them in one move now that the nav is a
       sidebar; the explicit rules further down then place the ones
       that need a real desktop position. */
    :root {
        --nav-h: 0px;
        --header-h: 72px;
    }

    /* ── Read-only preview: the header gets taller ──────────
       includes/impersonation.php renders its banner INSIDE .app-header so
       it stays put while the page scrolls. That makes the header taller,
       but the sidebar below is pinned to `top: var(--header-h)` — a flat
       72px — so it kept starting at the old height and its top edge covered
       the logo.

       Declared on `body`, not `:root`, on purpose: the class lives on
       <body>, and custom properties inherit, so every descendant that reads
       --header-h (the sidebar) picks up this value instead. Setting it on
       :root would not work, because :root cannot see a class on body.

       36px matches .imp-banner-inner's min-height in features.css. If that
       changes, change this too. */
    body.is-impersonating {
        --header-h: 108px;   /* 72 + 36 */
    }

    /* ── Body: swap bottom clearance for left clearance ────── */
    body {
        padding-bottom: 40px;
        padding-left: var(--uws-sidebar-w);
    }

    /* index.php / register.php render their own full-bleed shell
       with no nav — never indent them. */
    body.auth-page { padding-left: 0; }

    /* Same guard for any other page that skips includes/header.php
       (certificate.php). Progressive: browsers without :has() are
       unaffected, and those pages don't link this sheet today. */
    @supports selector(:has(*)) {
        body:not(:has(> .app-nav)) { padding-left: 0; }
    }

    /* ── Header: full-width top bar ─────────────────────────── */
    /* The negative margin pulls the bar back across the body's new
       left padding so it spans the whole viewport and sits above
       the sidebar. Its inner content still starts at the far left. */
    .app-header { margin-left: calc(-1 * var(--uws-sidebar-w)); }

    .app-header-inner {
        max-width: none;
        margin: 0;
        padding: 14px 28px;
        min-height: 44px;   /* 44 + 14 + 14 = --header-h */
        gap: 20px;
    }

    .app-header-user   { font-size: 14px; gap: 10px; }
    .app-header-avatar { width: 36px; height: 36px; font-size: 13px; }

    /* ── Nav: fixed left sidebar ────────────────────────────── */
    .app-nav {
        top: var(--header-h);
        bottom: 0;
        left: 0;
        right: auto;
        width: var(--uws-sidebar-w);
        flex-direction: column;
        align-items: stretch;
        justify-content: flex-start;
        gap: 4px;
        padding: 18px 14px 24px;
        border-top: none;
        border-right: 1px solid rgba(0,0,0,0.07);
        box-shadow: 1px 0 20px rgba(5,54,123,0.06);
        overflow-y: auto;
    }

    .app-nav-link {
        flex: 0 0 auto;
        flex-direction: row;
        align-items: center;
        justify-content: flex-start;
        gap: 14px;
        padding: 12px 14px;
        border-radius: 12px;
        color: var(--text-muted);
        transition: background 0.15s ease, color 0.15s ease;
    }

    .app-nav-link.nav-active {
        color: var(--blue-dark);
        background: var(--blue-light);
    }

    .nav-icon { width: 20px; height: 20px; }
    .app-nav-link.nav-active .nav-icon { transform: none; }

    .nav-label {
        font-size: 14px;
        font-weight: 700;
        letter-spacing: 0;
        line-height: 1.2;
    }

    /* Active indicator moves from a top bar to a left edge bar,
       sitting in the sidebar's own gutter. */
    .app-nav-link.nav-active::before {
        top: 50%;
        left: -10px;
        transform: translateY(-50%);
        width: 3px;
        height: 24px;
        border-radius: 0 4px 4px 0;
    }

    /* ── Desktop-only shortcuts from the More page ──────────── */
    .app-nav-link.nav-desktop-only {
        display: flex;
    }
    .nav-desktop-divider {
        display: block;
        margin: 8px 0 4px;
    }

    /* ── Log out: pinned to the bottom of the sidebar, visually
       separated from the primary destinations above it. Hidden
       below desktop width (mobile/tablet keep it on More only). */
    .app-nav-link--logout {
        display: flex;
        margin-top: auto;
        color: #dc2626;
        border-top: 1px solid rgba(0,0,0,0.07);
        padding-top: 16px;
    }

    .app-nav-link--logout:hover {
        background: rgba(220,38,38,0.08);
        color: #dc2626;
    }

    /* ── Content column ─────────────────────────────────────── */
    .app-content {
        max-width: var(--uws-content-max);
        padding: 32px 40px 48px;
    }

    .page-title    { font-size: 30px; }
    .page-subtitle { font-size: 14.5px; margin-bottom: 26px; }
    .day-section   { margin-top: 34px; }
    .day-label     { font-size: 12px; }

    /* ── Multi-column ───────────────────────────────────────── */
    /* Directory: flex column -> 2-up grid. The A/B/C separators are
       siblings of the rows, so they must span the full row. */
    .dir-list {
        display: grid;
        grid-template-columns: repeat(2, minmax(0, 1fr));
        gap: 12px;
        align-items: start;
    }
    .dir-letter {
        grid-column: 1 / -1;
        margin: 18px 0 2px 4px;
        font-size: 13px;
    }

    /* Bigger cards, not merely more of them: ~4 across at 1100. */
    .speaker-grid,
    .sponsor-grid { grid-template-columns: repeat(auto-fill, minmax(228px, 1fr)); gap: 16px; }
    .speaker-card,
    .sponsor-card { padding: 24px 18px; }
    .speaker-card-name,
    .sponsor-name { font-size: 15px; }
    .sponsor-logo { height: 76px; }

    .home-tiles      { grid-template-columns: repeat(4, 1fr); gap: 14px; }
    .home-tile       { padding: 18px; }
    .home-tile-label { font-size: 14.5px; }

    /* More hub: two columns inside the same card. The divider rules
       assume an even item count; with an odd count the last row's
       neighbour keeps a hairline, which reads fine. */
    .more-group { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); }
    .more-item  { padding: 16px 18px; }
    .more-item:nth-child(odd)        { border-right: 1px solid var(--border); }
    .more-item:nth-last-child(-n+2)  { border-bottom: none; }

    .venue-amenities-grid { grid-template-columns: repeat(auto-fit, minmax(120px, 1fr)); gap: 12px; }

    /* ── Breathing room, NOT more columns ───────────────────── */
    .qa-item    { padding: 18px 20px; gap: 16px; margin-bottom: 12px; }
    .qa-text    { font-size: 15px; max-width: var(--uws-prose); }
    .qa-answer  { padding: 12px 14px; max-width: var(--uws-prose); }
    .qa-composer,
    .poll-card,
    .survey-q,
    .ux-card:not(.ux-card--flush),
    .venue-card:not(.venue-card--no-pad),
    .lead-scan-panel { padding: 22px 24px; }

    .ce-row          { padding: 16px 18px; gap: 16px; margin-bottom: 12px; }
    .ce-row-title    { font-size: 15px; }
    .ce-total        { padding: 34px 24px; }

    .msg-thread-list,
    .checkin-log     { gap: 12px; }
    .msg-thread      { padding: 16px 18px; gap: 16px; }
    .msg-bubble      { max-width: 60%; }

    .sessions-summary { padding: 16px 22px; }
    .empty-card,
    .ux-empty         { padding: 56px 32px; }
    .empty-card-desc,
    .ux-empty-desc    { max-width: 380px; margin-left: auto; margin-right: auto; }
    .speaker-bio      { font-size: 15px; max-width: var(--uws-prose); }

    /* ── Agenda: one column, but roomier ────────────────────── */
    .schedule-row        { gap: 20px; padding: 18px 22px; margin-bottom: 12px; }
    .schedule-time       { min-width: 84px; width: 84px; padding: 10px 8px; }
    .schedule-time-start { font-size: 15px; }
    .schedule-time-end   { font-size: 11px; }
    .schedule-title      { font-size: 17px; margin-bottom: 7px; }
    .schedule-chip       { font-size: 12px; padding: 4px 10px; }
    .schedule-chip svg   { width: 12px; height: 12px; }

    .session-detail      { padding-top: 16px; margin-top: 14px; }
    .session-detail-desc {
        font-size: 14.5px;
        line-height: 1.7;
        max-width: var(--uws-prose);
    }
    .session-feedback-comment { max-width: var(--uws-prose); }

    /* Speaker pills wrap side by side instead of stacking. */
    .session-detail-speakers { flex-direction: row; flex-wrap: wrap; gap: 10px; }
    .session-speaker-pill    { flex: 0 1 300px; }

    /* ── Venue ──────────────────────────────────────────────── */
    .venue-hero      { padding: 40px 28px 34px; }
    .venue-hero-name { font-size: 26px; }
    .venue-action-btn { padding: 14px 16px; font-size: 14px; }

    /* ── Re-anchored fixed / sticky chrome ──────────────────── */
    /* The composer used to sit on top of the bottom nav. */
    .msg-composer { bottom: 0; padding: 14px 0 18px; }

    /* Toasts move to the bottom-right corner. */
    .ux-toast {
        left: auto;
        right: 32px;
        bottom: 28px;
        transform: translateY(12px);
        max-width: 420px;
    }
    .ux-toast.is-visible { transform: translateY(0); }

    .network-toast {
        left: auto;
        right: 32px;
        bottom: 28px;
        transform: translateY(20px);
    }
    .network-toast--show { transform: translateY(0); }

    .push-banner {
        left: auto;
        right: 32px;
        bottom: 24px;
        width: 420px;
        transform: none;
        animation: none;
    }

    /* Sign-out sheet becomes a centred dialog, not a bottom sheet. */
    .sheet-overlay { align-items: center; padding: 0; }
    .sheet-card {
        border-radius: 20px;
        max-width: 420px;
        padding: 32px 32px 28px;
        animation: none;
    }

    /* ── Capped media ───────────────────────────────────────── */
    /* A 1000px-wide camera preview is unusable, not impressive. */
    .scanner-shell { max-width: 420px; }

    /* Fixed print-sized certificate, centred in the column. */
    .certificate {
        width: 760px;
        max-width: 100%;
        margin-left: auto;
        margin-right: auto;
    }

    .badge-card,
    .badge-tip-card { max-width: 420px; }
}


/* ============================================================
   >= 1440px — WIDE
   ============================================================ */
@media (min-width: 1440px) {

    :root { --uws-content-max: 1240px; }

    .app-content { padding: 36px 48px 56px; }

    .dir-list { grid-template-columns: repeat(3, minmax(0, 1fr)); }

    .speaker-grid,
    .sponsor-grid { grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); gap: 18px; }

    .home-tiles { gap: 16px; }

    .app-header-inner { padding: 14px 40px; }
}


/* ============================================================
   REDUCED MOTION
   Scoped to >= 768px because this sheet is contractually forbidden
   from changing anything below the tablet breakpoint. The phone
   equivalent belongs in app.css — it is missing there today.

   Deliberately NOT silenced: .btn-spinner / .ux-btn-spinner, which
   communicate that a request is in flight.
   ============================================================ */
@media (min-width: 768px) and (prefers-reduced-motion: reduce) {

    .schedule-row,
    .home-tile,
    .speaker-card,
    .sponsor-card,
    .dir-row,
    .msg-thread,
    .resource-card,
    .notif-card,
    .more-item,
    .app-nav-link,
    .nav-icon,
    .ux-btn,
    .pill-btn,
    .sched-btn,
    .primary-link-btn,
    .poll-option,
    .poll-option-fill,
    .qa-vote,
    .rating-star,
    .survey-star,
    .detail-chevron,
    .dinner-restaurant-card,
    .dinner-restaurant-icon,
    .dinner-submit-btn,
    .dinner-reset-btn,
    .venue-action-btn,
    .venue-map-floor-btn,
    .a2hs-backdrop,
    .a2hs-sheet,
    .sheet-card,
    .ux-toast,
    .network-toast,
    .push-banner {
        transition: none;
        animation: none;
    }

    /* Looping decoration */
    .skeleton,
    .ux-live-dot { animation: none; }

    /* Cancel the hover lifts declared above (and the ones already in
       app.css) — selectors match theirs so source order decides. */
    .home-tile:hover,
    .speaker-card:hover,
    .sponsor-card:hover,
    .dir-row:hover,
    .msg-thread:hover,
    .resource-card:hover,
    .checkin-log-row:hover,
    a.ux-card:hover,
    .schedule-row:hover,
    .notif-card:hover,
    .dinner-restaurant-card:hover,
    .dinner-submit-btn:hover,
    .primary-link-btn:hover,
    .venue-action-btn--primary:hover,
    .pill-btn.add:hover:not(:disabled) {
        transform: none;
    }
}


/* ============================================================
   DARK MODE — NOW IMPLEMENTED, AND NOT FROM HERE
   ============================================================
   This block used to carry a long note explaining why a dark
   theme could not be added. That note prescribed the fix:

     "The real fix is to rework the base palette into semantic
      tokens in app.css first; this file can then add nothing at
      all, because the theme will come for free at every width."

   That is exactly what was done, and the prediction held — this
   file needs nothing.

   What changed:
     1. app.css :root gained --surface-sunken and --surface-input
        alongside the existing --card-bg, and a
        @media (prefers-color-scheme: dark) block that swaps every
        surface, border and text token.
     2. The ~30 components that hard-coded #fff / #F3F4F6 /
        #FBFCFE / #FAFBFF as a *background* now read those tokens.
        Hard-coded #fff as a *foreground* was left alone — white
        text on the brand gradient is correct in both themes.
     3. features.css re-tints the five accent pairs for dark, using
        low-alpha rgba washes so one tint composites correctly over
        the card, the page and sunken chips alike.
     4. Two surfaces stay literally white by design and say so at
        their definitions: .badge-qr-wrap (jsQR runs with
        inversionAttempts: 'dontInvert', so a dark plate would stop
        badges scanning) and .certificate (it gets printed).

   Anything dark-theme-related belongs in app.css or features.css.
   Adding it here would mean phones never get it.
   ============================================================ */
