/* ============================================================
   Phones and tablets.

   Loaded last, so the desktop stylesheets never have to know a
   small screen exists. Three steps:

     <= 1040px  tablets and small laptops: wide grids narrow
     <=  820px  the phone shell: the navigation moves to the
                bottom of the screen and everything is one column
     <=  380px  the smallest phones still in use

   Two rules this file keeps to:

     1. Nothing is ever scrolled sideways. A wide table becomes a
        stack of small cards, a month grid becomes a list of the
        days that matter, and a row of buttons wraps in pairs.
     2. Anything you tap is at least 44px tall, and the things you
        tap most are near the bottom of the screen where a thumb
        reaches without shifting your grip.
   ============================================================ */


/* ============================================================
   Tablets and small laptops
   ============================================================ */
@media (max-width: 1040px) {
  .hero-inner { grid-template-columns: 1fr; }
  .dash-grid { grid-template-columns: 1fr 1fr; }
  .chat-wrap { grid-template-columns: 260px minmax(0, 1fr); }
  .chart-grid { grid-template-columns: 1fr; }
}

@media (max-width: 860px) {
  .app-shell { padding: 0; }
  .page-head { flex-direction: column; align-items: flex-start; gap: 10px; }
  .page-head .head-actions { width: 100%; }
  .card-head { flex-direction: column; align-items: flex-start; gap: 10px; }
  .card-head .head-actions { width: 100%; }

  .dash-grid, .chat-wrap { grid-template-columns: 1fr; }
  .budget-grid, .an-tiles, .org-ledger .org-figures, .demo-grid, .admin-club-grid {
    grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  }
  .events-grid, .member-grid, .activity-grid, .highlights-grid,
  .showcase-grid, .squad-grid, .vote-grid {
    grid-template-columns: 1fr;
  }
}


/* ============================================================
   The phone shell — 820px and under
   ============================================================ */
@media (max-width: 820px) {

  /* The bottom bar's height, quoted by everything that has to sit
     clear of it. `--sab` is the strip of screen under the bar on a
     phone with no home button. */
  :root {
    --mnav: 58px;
    --sab: env(safe-area-inset-bottom, 0px);
    --gutter: 14px;
  }

  html { -webkit-text-size-adjust: 100%; }
  body { overflow-x: hidden; }

  /* A stray wide child inside a flex or grid row is the usual cause of a
     page that scrolls sideways; these are the containers it hides in. */
  .app-shell, .page, .card, .flex, .stack, .head-actions, .info-strip { min-width: 0; }
  .card > *, .stack > * { min-width: 0; }


  /* ---------- top bar: one line, always ---------- */
  .topbar {
    position: sticky; top: 0; z-index: 40;
    width: 100%; margin: 0;
    border-radius: 0;
    border-left: 0; border-right: 0; border-top: 0;
    padding: 8px var(--gutter);
    gap: 10px;
    padding-top: calc(8px + env(safe-area-inset-top, 0px));
    /* A backdrop-filter makes an element the frame of reference for anything
       fixed inside it, which would trap the bottom bar in the header. The blur
       goes, and an opaque background takes over the job of separating the bar
       from whatever scrolls beneath it. */
    backdrop-filter: none; -webkit-backdrop-filter: none;
    background: var(--bg);
  }
  .brandline { gap: 9px; flex: 1 1 auto; min-width: 0; }
  .brandline .brand-logo img { height: 20px; width: auto; }
  .brand-sub strong { font-size: 14px; }
  .brand-sub span { display: none; }            /* "Member portal" is not news */

  .userbox { flex: 0 0 auto; gap: 8px; }
  .usermeta { display: none; }                  /* the avatar carries it */
  .userbox .avatar { width: 32px !important; height: 32px !important; font-size: 12px; }
  .userbox .btn { padding: 8px 11px; font-size: 12px; }


  /* ---------- the nav becomes the bar along the bottom ---------- */
  .nav {
    position: fixed; left: 0; right: 0; bottom: 0; z-index: 90;
    display: flex; flex-wrap: nowrap; gap: 0;
    padding: 4px 4px calc(4px + var(--sab));
    background: var(--topbar-bg, rgba(8, 12, 22, .93));
    border-top: 1px solid var(--border-strong, var(--border));
    backdrop-filter: blur(18px);
    box-shadow: 0 -8px 30px rgba(0, 0, 0, .28);
  }
  .nav a {
    flex: 1 1 0; min-width: 0;
    display: flex; flex-direction: column; align-items: center; justify-content: center;
    gap: 2px;
    padding: 6px 2px; border-radius: 14px;
    font-size: 10px; font-weight: 700; letter-spacing: 0;
    line-height: 1.1; white-space: nowrap;
    border: 0; background: none; transform: none;
  }
  .nav a:hover { transform: none; background: none; }
  .nav a.active {
    background: none; box-shadow: none; border: 0;
    color: var(--brand, #ff7a1a);
  }
  .nav .nav-ico {
    display: block; font-size: 17px; line-height: 1;
    /* the active tab is marked by its icon lifting into a filled pill,
       which reads at a glance better than a colour change alone */
    padding: 4px 12px; border-radius: 999px; transition: background .18s ease;
  }
  .nav a.active .nav-ico { background: color-mix(in srgb, var(--brand, #ff7a1a) 18%, transparent); }
  .nav .nav-txt {
    display: block; max-width: 100%;
    overflow: hidden; text-overflow: ellipsis;
  }
  .nav .badge { top: 0; right: 50%; margin-right: -26px; }

  /* content must not end up underneath the bar */
  .page {
    width: calc(100% - (var(--gutter) * 2));
    margin: 14px auto 0;
    padding-bottom: calc(var(--mnav) + var(--sab) + 26px);
  }
  .page.narrow { width: calc(100% - (var(--gutter) * 2)); }


  /* ---------- type and cards ---------- */
  .page-head h1, .page h1 { font-size: 25px; line-height: 1.12; }
  .page-head h2, .page h2 { font-size: 21px; }
  .page-head .sub, .sub { font-size: 13px; }
  .card, .card.glass { padding: 15px; border-radius: 20px; }
  .card h3 { font-size: 16px; }
  .stack { gap: 13px; }


  /* ---------- controls: pairs, never a lonely stray ---------- */
  .head-actions { gap: 8px; width: 100%; }
  .head-actions > .btn, .head-actions > .tab, .head-actions > label.btn {
    flex: 1 1 calc(50% - 4px); min-width: calc(50% - 4px);
    justify-content: center;
  }
  .head-actions > .btn:only-child { flex-basis: 100%; }
  .btn { min-height: 44px; padding: 11px 15px; }
  .btn-sm { min-height: 38px; padding: 9px 12px; font-size: 12.5px; }
  .btn-block { width: 100%; }
  /* a ghost button next to solid ones reads as stray text on a small screen */
  .btn-ghost { border-color: var(--border); background: rgba(255, 255, 255, .03); }

  /* a tab strip scrolls rather than stacking into a wall of pills */
  .tabs {
    flex-wrap: nowrap; overflow-x: auto;
    margin: 14px calc(var(--gutter) * -1) 14px;
    padding: 2px var(--gutter) 8px;
    scrollbar-width: none; -webkit-overflow-scrolling: touch;
  }
  .tabs::-webkit-scrollbar { display: none; }
  .tabs .tab { flex: 0 0 auto; }


  /* ---------- forms ---------- */
  /* 16px is the smallest size iOS will not zoom the page for */
  input, select, textarea { font-size: 16px !important; min-height: 44px; }
  textarea { min-height: 90px; }
  .field { min-width: 0; }
  .budget-row { grid-template-columns: 1fr; }
  .form-note { font-size: 12.5px; }


  /* ---------- tiles ---------- */
  .budget-grid, .an-tiles, .org-ledger .org-figures, .demo-grid,
  .admin-club-grid, .hero-side {
    grid-template-columns: 1fr 1fr; gap: 10px;
  }
  .stat-tile, .ac-tile, .hero-tile, .an-tile { padding: 12px; border-radius: 16px; }
  .stat-tile .value, .ac-num, .an-tile .value { font-size: 20px; }
  .stat-tile .label, .ac-label { font-size: 10.5px; letter-spacing: .08em; }


  /* ---------- a wide table becomes a stack of cards ----------
     Each row keeps its column headings, stamped onto the cells as data-label by
     js/pager.js, so nothing is lost in the change. The heading goes above its
     value rather than beside it: a cell can hold a face, a row of chips or a
     pair of buttons, and only a full-width value is certain to fit whatever
     turns up in it. */
  .table-wrap { overflow: visible; border: 0; border-radius: 0; background: none; }
  table.data { min-width: 0; display: block; }
  table.data thead { display: none; }
  table.data tbody, table.data tbody.pager-list { display: block; }
  table.data tr {
    display: block; margin-bottom: 9px; padding: 11px 13px;
    border: 1px solid var(--border-strong); border-radius: 16px;
    background: var(--panel-3);
  }
  table.data td {
    display: block; padding: 5px 0; border: 0;
    font-size: 13.8px; text-align: left; white-space: normal;
  }
  table.data td::before {
    content: attr(data-label); display: block; margin-bottom: 1px;
    color: var(--muted);
    font-size: 10px; font-weight: 800; text-transform: uppercase; letter-spacing: .1em;
  }
  table.data td:not([data-label])::before { display: none; }
  table.data td:empty { display: none; }
  /* the first cell names the row, so it is given the weight of a heading */
  table.data td:first-child {
    font-size: 15px; font-weight: 800;
    padding-top: 0; padding-bottom: 9px; margin-bottom: 5px;
    border-bottom: 1px dashed var(--border);
  }
  /* chips and buttons inside a cell wrap instead of running off the edge */
  table.data td .chip, table.data td .btn { margin: 2px 4px 2px 0; }
  table.data td .head-actions { width: 100%; }
  table.data td .head-actions > .btn { flex: 1 1 calc(50% - 4px); }

  /* ---------- search and paging ----------
     A row turned on its side is the one trap here: `flex: 1 1 260px` asks for
     width in a row and for HEIGHT in a column, which is how a search box ends
     up a quarter of the screen tall. Everything stacked below is pinned back to
     its natural height. */
  .page-head > *, .card-head > *, .pager-head > *, .dir-toolbar > *,
  .cal-top > *, .modal-foot > * { flex: 0 0 auto; }

  .pager-head { flex-direction: column; align-items: stretch; gap: 8px; }
  .pager-search-wrap, .dir-search { width: 100%; }
  .dir-search input { font-size: 16px; }
  .pager-count { align-self: flex-start; }
  .pager-foot { flex-wrap: wrap; justify-content: center; gap: 6px; }
  .pager-pages .btn { min-width: 38px; }
  .dir-toolbar {
    flex-direction: column; align-items: stretch; gap: 10px; padding: 12px;
    max-width: 100%;
  }
  /* the category chips scroll on their own rail; without a width limit the
     unwrapped row sets the width of the whole toolbar and the page slides */
  .dir-chips {
    flex-wrap: nowrap; overflow-x: auto; min-width: 0; max-width: 100%;
    padding-bottom: 4px; scrollbar-width: none;
  }
  .dir-chips::-webkit-scrollbar { display: none; }
  .dir-chip { flex: 0 0 auto; }
  .dir-count { min-width: 0; }


  /* ---------- the month grid becomes an agenda ----------
     Seven columns of empty squares tell you nothing on a phone, so
     only the days that can hold something are listed: the weekends
     clubs play on, and any day that already has an event. */
  .cal-grid { grid-template-columns: 1fr; gap: 8px; }
  .cal-dow { display: none; }
  .cal-cell { display: none; }
  .cal-cell.weekend, .cal-cell.has-events {
    display: grid; grid-template-columns: 74px minmax(0, 1fr);
    align-items: start; gap: 8px 10px;
    min-height: 0; padding: 11px 12px; border-radius: 16px;
  }
  .cal-cell.other { display: none; }
  .cal-cell > .flex.between {
    grid-column: 1; flex-direction: column; align-items: flex-start; gap: 6px;
  }
  .cal-cell > .cal-event-wrap { grid-column: 2; }
  /* a bare number is enough beneath a column heading; in a list it needs to
     say which day it is, which the cell already carries for its tooltip */
  .cal-date { font-size: 12.5px; line-height: 1.25; }
  .cal-date i { display: none; }
  .cal-date::before { content: attr(data-long); font-style: normal; }
  .cal-cell.weekend:not(.has-events) .cal-date::after {
    content: 'free'; display: block; color: var(--muted); font-weight: 600;
  }
  .cal-top { flex-direction: column; align-items: stretch; gap: 10px; }
  /* three month buttons belong on one line, not stacked in pairs */
  .cal-top .head-actions > .btn { flex: 1 1 auto; min-width: 0; }
  .cal-legend { font-size: 11.5px; }


  /* the points breakdown stacks rather than sitting beside the total */
  .pts-head { gap: 12px; }
  .pts-total { flex: 1 1 100%; }
  .pts-total .num { font-size: 32px; }
  .pts-breakdown { flex: 1 1 100%; }

  /* ---------- leaderboard ----------
     The podium puts second place on the left so first can stand raised in the
     middle. Stacked into one column that reads as 2, 1, 3, so the order is set
     straight and each place becomes a row: medal, face, name, score. */
  .podium { grid-template-columns: 1fr; gap: 9px; margin: 14px 0; }
  .podium-card {
    display: grid; align-items: center; gap: 2px 12px;
    grid-template-columns: auto auto minmax(0, 1fr) auto;
    grid-template-areas:
      'medal face name score'
      'medal face clubs score';
    text-align: left; padding: 12px 14px;
  }
  .podium-card.first { order: 1; }
  .podium-card.second { order: 2; }
  .podium-card.third { order: 3; }
  .podium-card.first, .podium-card.second, .podium-card.third {
    min-height: auto; transform: none;
  }
  .podium-card .medal { grid-area: medal; font-size: 24px; margin: 0; animation: none; }
  .podium-card .avatar { grid-area: face; width: 40px !important; height: 40px !important; font-size: 14px; }
  .podium-card h3 { grid-area: name; margin: 0 !important; font-size: 15px; }
  .podium-card .muted.small { grid-area: clubs; font-size: 12px; }
  .podium-card .points { grid-area: score; margin: 0; font-size: 22px; text-align: right; }
  .podium-card .tiny.muted { display: none; }   /* "points" beside a number is noise */


  /* ---------- chat: the room list and the thread take turns ----------
     Opening a room puts #/chat/<id> in the address, and that is what
     the shell records on #view — so on a phone the list steps aside
     and the conversation gets the whole screen. */
  .chat-wrap { gap: 12px; min-height: 0; }
  /* no room in the address: the rooms are the page. Pick one and the address
     gains its id, at which point the conversation takes the whole screen and
     the Chat tab at the bottom is the way back to the list. */
  #view[data-page="chat"][data-arg=""] .chat-pane { display: none; }
  #view[data-page="chat"][data-arg]:not([data-arg=""]) .chat-wrap > aside { display: none; }
  .chat-pane { padding: 12px !important; }
  .chat-msgs { max-height: none; min-height: 40vh; }
  /* the page title says nothing a reader of one conversation needs */
  #view[data-page="chat"][data-arg]:not([data-arg=""]) .page-head { display: none; }
  /* the box you type in follows you down the conversation instead of sitting
     at the far end of it */
  .chat-compose {
    position: sticky; bottom: calc(var(--mnav) + var(--sab) + 8px); z-index: 5;
    grid-template-columns: minmax(0, 1fr) auto; gap: 7px;
    margin: 10px -12px -12px; padding: 10px 12px calc(10px + var(--sab));
    background: var(--bg); border-top: 1px solid var(--border);
    border-radius: 0 0 18px 18px;
  }
  .chat-compose .btn { padding: 11px 14px; }
  .chat-item { padding: 11px; }
  .msg { max-width: 92%; }


  /* ---------- team building ---------- */
  .team-members { grid-template-columns: 1fr; }
  .pool-list { max-height: 320px; }
  .squad-card { padding: 13px; }


  /* ---------- a modal becomes a sheet that rises from the bottom ----------
     A centred box on a phone leaves a thin column of content with the
     keyboard covering half of it. A sheet starts at the bottom, where
     the thumb already is, and its buttons stay pinned in view. */
  .modal-root, .confirm-root { place-items: end stretch; padding: 0; }
  .modal, .confirm-box {
    width: 100% !important; max-width: 100% !important;
    max-height: 92vh;
    border-radius: 24px 24px 0 0;
    padding: 16px var(--gutter) calc(16px + var(--sab));
    animation: sheet-up .22s cubic-bezier(.22, .8, .3, 1);
  }
  @keyframes sheet-up { from { transform: translateY(26px); opacity: .6; } to { transform: none; opacity: 1; } }
  .modal.wide { width: 100% !important; }
  .modal-head h3 { font-size: 18px; }
  .modal-close { width: 40px; height: 40px; }
  .modal-foot { flex-direction: column-reverse; gap: 8px; margin-top: 14px; }
  .modal-foot .btn { width: 100%; }
  .modal-foot.stick {
    position: sticky; bottom: calc(-16px - var(--sab));
    padding-bottom: calc(10px + var(--sab));
    margin-left: calc(var(--gutter) * -1); margin-right: calc(var(--gutter) * -1);
    padding-left: var(--gutter); padding-right: var(--gutter);
  }
  /* a sheet is drawn over the bottom bar, not beside it */
  .modal-root, .confirm-root { z-index: 200; }


  /* ---------- toasts sit above the bottom bar ---------- */
  .toast-root {
    left: var(--gutter); right: var(--gutter);
    bottom: calc(var(--mnav) + var(--sab) + 12px);
    z-index: 150;
  }
  .toast { width: 100%; }


  /* ---------- the theme switch ----------
     A floating pill in the corner of a phone lands on top of whatever
     is underneath it. It becomes a round icon button tucked beside the
     top bar's avatar instead, and steps out of the way of a sheet. */
  /* the shell moves the button into the top bar on a phone, so all this has
     to do is stop it floating and make it round */
  .userbox .theme-toggle {
    position: static; order: -1;
    width: 34px; height: 34px; padding: 0; flex: 0 0 auto;
    border-radius: 50%; justify-content: center;
    font-size: 0;                                /* the words are on aria-label */
    box-shadow: none;
  }
  .theme-toggle .tt-dot { width: 12px; height: 12px; }
  body:has(#modal-root .modal-root) .theme-toggle,
  body:has(#confirm-root .confirm-root) .theme-toggle { display: none; }


  /* ---------- decoration that costs more than it gives ---------- */
  .sky-bg .pl-system, .sky-bg .pl-giant { display: none; }
  .hero-glow, .orb3d, .orb { display: none; }
  .hero { padding: 18px; }
  /* the club banner: the emblem and the name share the top line, and the
     description and chips get the full width instead of a narrow column */
  .club-banner { padding: 18px; border-radius: 24px; }
  .club-banner:after { display: none; }
  .banner-left { display: grid; grid-template-columns: 56px minmax(0, 1fr); gap: 12px; }
  .banner-icon {
    width: 56px; height: 56px; border-radius: 18px; font-size: 26px;
    transform: none; box-shadow: none;
    grid-row: 1 / span 2; align-self: center;   /* beside the name, not above it */
  }
  .banner-title { display: contents; }
  .banner-title .cr-sub, .banner-title h2 { grid-column: 2; }
  .banner-title h2 { font-size: 22px; }
  .banner-title p, .banner-meta { grid-column: 1 / -1; }
  .banner-title p { font-size: 13.5px; }
  .banner-meta { display: flex; flex-wrap: wrap; gap: 6px; }
  /* the spinning cube is 116px of decoration that overhangs the card edge */
  .directory-hero { flex-direction: column; align-items: flex-start; padding: 18px; gap: 12px; }
  .directory-hero .scene { display: none; }
  .hero h2 { font-size: 24px; }
  .club-stage { min-height: 178px; }
  .sc-marquee { display: none; }


  /* ---------- login ----------
     Somebody opening this on a phone came to sign in, so the form is the first
     thing on the screen and the description of the portal follows it. */
  .login-shell { grid-template-columns: 1fr; gap: 14px; }
  .login-card { order: -1; padding: 20px 16px; border-radius: 22px; }
  .login-body { padding: 14px; }
  .login-brand { padding: 18px; }
  .login-brand h1 { font-size: 30px; }
  .login-brand .scene { display: none; }
  .login-tagline { font-size: 13.5px; }
  .login-points { gap: 9px; font-size: 13px; }
  .brand-mark { width: 78px; }
  /* no top bar here to carry the switch, so it moves out of the form's way */
  .login-body .theme-toggle {
    left: auto; bottom: auto;
    right: 12px; top: calc(12px + env(safe-area-inset-top, 0px));
  }
}


/* ============================================================
   A phone held sideways

   There is barely any height to spend, so the bar at the bottom
   puts its label next to its icon instead of under it and the
   header gives back what it can.
   ============================================================ */
@media (max-width: 900px) and (max-height: 500px) {
  :root { --mnav: 44px; }
  .topbar { padding: 5px var(--gutter); }
  .nav { padding: 3px 4px calc(3px + var(--sab)); }
  .nav a { flex-direction: row; gap: 6px; padding: 5px 4px; font-size: 11px; }
  .nav .nav-ico { padding: 2px 7px; font-size: 15px; }
  .nav .badge { top: -2px; right: 4px; margin-right: 0; }
  .page { margin-top: 10px; }
  .page-head h1, .page h1 { font-size: 21px; }
  .modal, .confirm-box { max-height: 96vh; }
}


/* ============================================================
   Small phones — 380px and under
   ============================================================ */
@media (max-width: 380px) {
  :root { --gutter: 11px; }
  .page-head h1, .page h1 { font-size: 22px; }
  .card, .card.glass { padding: 13px; }
  .demo-grid, .admin-club-grid { grid-template-columns: 1fr; }
  .nav .nav-txt { font-size: 9.5px; }
  .nav .nav-ico { padding: 4px 9px; }
  table.data td { flex-direction: column; align-items: flex-start; gap: 2px; text-align: left; }
  table.data td::before { flex-basis: auto; }
}


/* ============================================================
   Touch screens of any size

   Hover effects that lift a card are stuck "on" after a tap on a
   touch screen, so they are dropped wherever there is no mouse.
   ============================================================ */
@media (hover: none) {
  .card:hover, .club-showcase:hover, .event-card:hover, .activity-card:hover,
  .member-card:hover, .highlight-card:hover, .tab:hover, .nav a:hover,
  .btn:hover, .theme-toggle:hover {
    transform: none;
  }
  /* a control you cannot hover has to be big enough to hit */
  .btn, .tab, .nav a, .chip[data-act], .modal-close { touch-action: manipulation; }
  /* the reschedule arrows on a calendar event are a 22px icon, which is a fine
     mouse target and too small for a thumb */
  .cal-move { min-width: 32px; min-height: 32px; }
}
