/* css/main/base-and-desktop-frame.css — part 2/30 of the app styles (was css/main.css; loaded in this order by index.html). */
      * {
        box-sizing: border-box;
        margin: 0;
        padding: 0;
        -webkit-tap-highlight-color: transparent;
      }
      /* ⛔ THE `hidden` ATTRIBUTE MUST ALWAYS WIN, and it's a fix at the root.
         The browser gives it `display: none` from its default sheet, so
         ANY rule of ours with `display:` overrides it — and then the element
         stays visible even though the JavaScript says `x.hidden = true`. **It gives no
         error**: the code is right, the attribute is set, and what
         shows is something else.
         It had already happened with `.drawer-item`, which was patched one by one; it happened
         again on 2026-08-25 with `.drawer-ident` (`display: flex`): a shooter
         got an empty strip with its separator line at the top of the
         menu, right where a club sees its role. The third time you fix the whole
         class, not the case.
         ⚠️ `!important` is essential here: without it it loses again against
         any later `display`. Guard: `tests/unit-hidden-gana.test.js`. */
      [hidden] { display: none !important; }
      /* Avoids the double-tap delay on interactive elements without blocking
         pinch zoom — compensates for what user-scalable=no used to do in the
         viewport (WCAG 1.4.4: zoom must be allowed). */
      button, a, .btn, .btn-primary, .btn-secondary, .btn-danger,
      .btn-icon, .btn-icon-secondary, .nav-btn, .fab, .fab-mini, .chip,
      [role="button"] {
        touch-action: manipulation;
        /* iOS sometimes interprets the first touch on the button text
           as a selection/callout attempt instead of a tap, and you have to
           tap twice or on the edge. This disables it. */
        -webkit-touch-callout: none;
        -webkit-user-select: none;
        user-select: none;
      }
      html {
        /* Prevents Safari from rescaling text on its own (readability
           heuristic) independently of the zoom the app applies,
           which on iOS leaves the lettering smaller than the rest of the UI. */
        -webkit-text-size-adjust: 100%;
        text-size-adjust: 100%;
      }
      html,
      body {
        height: calc(var(--app-h, 100dvh) / var(--tl-zoom, 1));
      }
      @supports not (height: 100dvh) {
        html, body { height: calc(var(--app-h, 100%) / var(--tl-zoom, 1)); }
      }
      body {
        font-family: "Inter", sans-serif;
        background: var(--bg);
        color: var(--text);
        max-width: 480px;
        margin: 0 auto;
        display: flex;
        flex-direction: column;
        overscroll-behavior-y: none;
      }
      html {
        overscroll-behavior-y: none;
        overscroll-behavior: none;
      }
      /* ═════════════════════════════════════════════════════════════════
         DESKTOP FRAME MODE — viewport ≥ 1024 px wide
         ─────────────────────────────────────────────────────────────────
         The app renders inside an 820 px "frame" (zoomed x≈1.71
         from the 480 px base design) centered in the window, with a
         neutral background at the sides. The JS (tabletScale in index.html) puts
         .tl-framed on body when entering this mode. The frame's height
         adapts to the window height up to a logical maximum equivalent
         to 1180 visual px.
         ═════════════════════════════════════════════════════════════════ */
      body.tl-framed {
        position: relative;
        /* contain:layout forces the body to be the containing block of
           ALL descendants with position:fixed (modals, drawer,
           toasts, photo-viewer, etc.). Without this the overlays escape to the
           viewport and cover the whole browser window, going outside
           the frame. */
        contain: layout;
        height: calc(min(1180px, 100vh - 60px) / var(--tl-zoom, 1));
        box-shadow: 0 24px 80px rgba(0, 0, 0, 0.6),
                    0 0 0 1px rgba(255, 255, 255, 0.05);
        border-radius: 14px;
        overflow: hidden;
      }
      @media (min-width: 821px) {
        html {
          background: #050505;
          min-height: 100vh;
        }
        :root[data-theme="light"] html {
          background: #d8d3c8;
        }
        :root[data-theme="light"] body.tl-framed {
          box-shadow: 0 24px 80px rgba(0, 0, 0, 0.35),
                      0 0 0 1px rgba(0, 0, 0, 0.06);
        }
      }
      /* Horizontal scrollbars visible in any mode with zoom
         (tl-zoomed covers tablet and framed desktop). On native mobile
         (≤480px, without tl-zoomed) they stay hidden so as not to take space. */
      body.tl-zoomed .nav,
      body.tl-zoomed .filter-bar,
      body.tl-zoomed .cv-link-bar-cats,
      body.tl-zoomed .bottom-nav,
      body.tl-zoomed .campo-dist-tablewrap {
        scrollbar-width: thin;
        scrollbar-color: var(--accent) transparent;
      }
      body.tl-zoomed .nav::-webkit-scrollbar,
      body.tl-zoomed .filter-bar::-webkit-scrollbar,
      body.tl-zoomed .cv-link-bar-cats::-webkit-scrollbar,
      body.tl-zoomed .bottom-nav::-webkit-scrollbar,
      body.tl-zoomed .campo-dist-tablewrap::-webkit-scrollbar {
        display: block !important;
        height: 6px;
        background: transparent;
      }
      body.tl-zoomed .nav::-webkit-scrollbar-thumb,
      body.tl-zoomed .filter-bar::-webkit-scrollbar-thumb,
      body.tl-zoomed .cv-link-bar-cats::-webkit-scrollbar-thumb,
      body.tl-zoomed .bottom-nav::-webkit-scrollbar-thumb,
      body.tl-zoomed .campo-dist-tablewrap::-webkit-scrollbar-thumb {
        background: var(--accent);
        border-radius: 6px;
        min-width: 30px;
      }
      body.tl-zoomed .nav::-webkit-scrollbar-track,
      body.tl-zoomed .filter-bar::-webkit-scrollbar-track,
      body.tl-zoomed .cv-link-bar-cats::-webkit-scrollbar-track,
      body.tl-zoomed .bottom-nav::-webkit-scrollbar-track,
      body.tl-zoomed .campo-dist-tablewrap::-webkit-scrollbar-track {
        background: transparent;
      }
      body:not(.tl-zoomed) .bottom-nav { scrollbar-width: none; }
      body:not(.tl-zoomed) .bottom-nav::-webkit-scrollbar { display: none; }
      /* Separates the horizontal scrollbar (6px) from the buttons when the UI
         is enlarged: without this it comes out stuck right below. */
      body.tl-zoomed .nav,
      body.tl-zoomed .filter-bar,
      body.tl-zoomed .cv-link-bar-cats,
      body.tl-zoomed .chip-row-tight,
      body.tl-zoomed .campo-dist-tablewrap {
        padding-bottom: 7px;
      }
      body.tl-zoomed .bottom-nav {
        padding-bottom: calc(env(safe-area-inset-bottom, 0px) + 7px);
      }
      .nav {
        background: var(--surface);
        border-bottom: 1px solid var(--border);
        display: flex;
        position: sticky;
        top: 0;
        z-index: 20;
        overflow-x: auto;
        padding: 0 2px;
      }
      body:not(.tl-zoomed) .nav {
        scrollbar-width: none;
      }
      body:not(.tl-zoomed) .nav::-webkit-scrollbar {
        display: none;
      }
      .nav-btn {
        flex: 0 0 auto;
        min-width: 73px;
        padding: 0 4px;
        height: 73px;
        background: none;
        border: none;
        color: var(--text);
        font-family: "Inter", sans-serif;
        font-size: 11px;
        font-weight: 600;
        letter-spacing: 0.5px;
        text-transform: uppercase;
        cursor: pointer;
        display: flex;
        flex-direction: column;
        align-items: center;
        justify-content: center;
        gap: 4px;
        transition: color 0.2s;
        white-space: nowrap;
      }
      .nav-btn .ni {
        width: 48px;
        height: 33px;
        display: flex;
        align-items: center;
        justify-content: center;
        border-radius: 14px;
        transition: background 0.2s;
      }
      .nav-btn .ni svg {
        width: 24px;
        height: 24px;
        display: block;
      }
      .nav-btn.active {
        color: var(--accent);
      }
      .nav-btn.active .ni {
        background: rgba(200, 168, 75, 0.2);
      }
      .content {
        flex: 1;
        overflow-y: auto;
        /* ⛔ THIS PADDING IS NEEDED BY WHOEVER STICKS TO THE TOP, and that's why it's a
           variable and not a loose 5. A `position: sticky; top: 0` block
           stays stuck to the edge of the content, that is 5 px BELOW the edge
           of the box that scrolls — and through that gap you see whatever is
           behind pass by. Santi saw it on 2026-08-27 in Search: *"when I scroll
           it shows up back there, it'll be 4 or 5 pixels, it looks ugly"*. Whoever sticks to the top
           compensates with `top: calc(-1 * var(--content-pt))`; written as a loose
           number, changing this padding would reopen the gap without anything
           warning. */
        --content-pt: 5px;
        padding-top: var(--content-pt);
        padding-bottom: 24px;
        overscroll-behavior-y: none;
      }
      body.has-modal-open .content {
        pointer-events: none;
      }
      .view {
        display: none;
      }
      .view.active {
        display: block;
      }
      /* ═══════════════════════════════════════════════════════════════
         THE SIDE MARGIN BELONGS TO THE CARD, NOT TO THE SCREEN (2026-08-27)

         ⛔ Where it comes from: *"the card's width takes the whole width and
         so that perception of a card is lost… the sides end up
         stuck to the side of the screen"* (Santi, looking at Search and the news
         channel on the phone). And it wasn't a design decision to revisit: it was
         that those screens were forgotten the wrapper.

         The house rule is `.section { padding: 12px 16px }`, and 32
         places in the index use it. But `.content` and `.view` have no side padding
         at all, so the screen that writes DIRECTLY into its `.view`
         —all those of the directory and the news reader— painted its cards
         flush with the glass. Half the app with margin and the other half without.

         ⭐ WHY `:has()` AND NOT A LIST OF IDENTIFIERS: so the NEW screen
         is born right without anyone remembering. Whoever wraps in `.section`
         already has its margin and this rule doesn't touch it; whoever writes bare
         gets it. Forgetting now fails to the good side, which was the
         goal.
         ⚠️ And if a browser didn't understand `:has()`, it discards the whole block and
         stays exactly as it was: without margin, not broken.

         ⛔ `.view-bleed` is the declared way out, for what goes edge to edge on
         purpose: the map, the counter's canvas, the calendar, the contact
         chat, the two legal texts (they are iframes) and the four screens that
         `tiradores.js` paints with its own centered 520 px column.

         ⛔⛔ AND THE MARGIN GOES ON THE CARD, NOT ON THE VIEW. The first version of
         this rule padded the whole `.view`, and Santi saw it as soon as it was
         published: *"it's as if that margin had been defined for the whole app…
         button bars that used to fit on one line go onto two"*. And he was right —
         padding the screen **shrinks everything inside by 32 px**, including
         the rows of chips and buttons, which need the full width and aren't
         cards. His words: *"it's fine for the cards to respect that margin,
         but the rest of the elements are different"*.

         So the margin is carried by **the four card families**, and only
         inside the screens that don't already have their wrapper. Everything else
         —filters, sticky headers, button bars, empty states, which already bring their
         own 16 px padding— keeps using the full width.
         ═══════════════════════════════════════════════════════════════ */
      .view:not(.view-bleed):not(:has(.section)) :is(.card, .cc-card, .hist-card, .hist-fila) {
        margin-left: 16px;
        margin-right: 16px;
        /* ⛔ THE WIDTH, IN ADDITION TO THE MARGIN, and it's not redundant: half a dozen of these
           cards are `<button>`s declared at 100 %, and over a fixed width the
           margin doesn't narrow — it PUSHES, and the card sticks out 16 px on the right.
           Setting `width: auto` doesn't work either: a button with automatic width
           shrinks to its text. This way it stays the same for the `<div>`s and for the
           buttons. */
        width: calc(100% - 32px);
      }
      /* In the history the card comes wrapped in `.hist-fila` —so that the
         «what happened» is a sibling and not a button inside another—, so the
         margin belongs to the wrapper or it would be added twice. In Honors and in Diplomas
         the card is loose and carries it itself. */
      .view:not(.view-bleed):not(:has(.section)) .hist-fila .hist-card {
        margin-left: 0;
        margin-right: 0;
        width: 100%;
      }
      #view-contador.active,
      #view-tiro-rapido.active,
      #view-calendario.active,
      #view-estadisticas.active,
      #view-backup.active,
      #view-contacto.active,
      #view-mis-datos.active,
      #view-mi-qr.active,
      #view-companeros.active,
      #view-debug.active,
      #view-privacidad.active,
      #view-legal.active,
      #view-condiciones.active,
      #view-licencias.active {
        display: flex;
        flex-direction: column;
        height: 100%;
        overflow: hidden;
      }
      #view-backup.active > .section,
      #view-contacto.active > .section {
        flex: 1;
        overflow-y: auto;
      }
