
        /* ---- Edit tab: add form vs. "Moje prezenty" list ----
           Desktop (>768px): the form is its own light-green bounded card at
           the top, the list has a heading + count and a divider.
           Mobile (<=768px): the form becomes a thumb-zone composer fixed
           just above the bottom tab bar. Collapsed it is a single tappable
           "Dodaj prezent…" row with a decorative cue; in add mode the
           same row grows a title, a close button, the chevron that reveals
           the optional description and the round add button.
           formularz.js keeps --quick-add-bottom (where it sits) and
           --quick-add-reserve (how much room the page keeps free for it) in
           sync with the tab bar, the on-screen keyboard and the row's
           height. */
        .quick-add-section {
            background: #f3faf4;
            border: 1px solid rgba(30, 126, 52, 0.28);
            border-left: 4px solid #28a745;
            border-radius: 16px;
            padding: 16px;
            margin-bottom: 28px;
            box-shadow: 0 2px 10px rgba(0, 0, 0, 0.06);
        }

        .quick-add-composer {
            position: relative;
            display: grid;
            grid-template-columns: minmax(0, 1fr) auto;
            grid-template-areas:
                "heading heading"
                "name    name"
                "desc    desc"
                "msg     submit";
            gap: 10px;
            align-items: center;
            margin: 0;
        }

        .quick-add-head {
            grid-area: heading;
            display: flex;
            align-items: center;
            justify-content: space-between;
            gap: 8px;
        }

        .quick-add-heading {
            margin: 0;
            color: #1b5e20;
            font-size: 1rem;
            font-weight: 700;
        }

        .quick-add-toggle { display: none; }
        /* Desktop: the form is a permanent inline card, so there is
           nothing to close (the mobile rules switch it on), and there is no
           collapsed state either - so the compact bar's decorative cue is
           not rendered at all */
        .quick-add-close { display: none; }
        .quick-add-cue { display: none; }
        .quick-add-name { grid-area: name; min-width: 0; }
        .quick-add-desc { grid-area: desc; min-width: 0; }
        .quick-add-desc textarea { resize: vertical; }

        /* Short, motivating helper above the optional description */
        .quick-add-hint {
            margin: 0 0 6px;
            color: #2f5d34;
            font-size: 0.875rem;
            font-weight: 600;
            line-height: 1.3;
        }

        /* "+ Dodaj szczegóły" nudge on presents without a description */
        #myPresentsList .my-present-add-details {
            position: relative;
            display: flex;
            width: fit-content;
            max-width: 100%;
            align-items: center;
            gap: 6px;
            min-height: 32px;
            margin: 4px 0 8px;
            padding: 4px 12px;
            border: 1.5px dashed #c99700;
            border-radius: 999px;
            background: #fff8e1;
            color: #664d03;
            font-size: 0.875rem;
            font-weight: 600;
            line-height: 1.2;
            cursor: pointer;
            transition: background-color 0.15s ease, border-color 0.15s ease;
        }

        /* Invisible hit area: 44px tall tap target around the 32px pill */
        #myPresentsList .my-present-add-details::after {
            content: "";
            position: absolute;
            inset: -6px -4px;
        }

        #myPresentsList .my-present-add-details i { font-size: 0.75rem; }

        #myPresentsList .my-present-add-details:hover {
            background: #ffefb3;
            border-style: solid;
        }

        #myPresentsList .my-present-add-details:focus-visible {
            outline: 3px solid #1a56db;
            outline-offset: 2px;
            border-style: solid;
        }

        @media (prefers-reduced-motion: reduce) {
            #myPresentsList .my-present-add-details { transition: none; }
        }

        .quick-add-submit {
            grid-area: submit;
            justify-self: end;
            display: inline-flex;
            align-items: center;
            justify-content: center;
            gap: 0.5rem;
            min-height: 48px;
            min-width: 48px;
            border-radius: 999px;
            /* Darker than .btn-green so the white label clears 4.5:1 */
            background: linear-gradient(135deg, #1e7e34 0%, #19692c 100%) !important;
            border-color: #19692c !important;
        }

        .quick-add-message {
            grid-area: msg;
            margin: 0;
            padding: 0.5rem 0.75rem;
            font-size: 0.9rem;
        }

        /* Opaque status colours (the theme makes alerts translucent, which
           is unreadable when the pill floats over the list on mobile) */
        .quick-add-message.alert-success {
            background: #d1e7dd !important;
            border: 1px solid #a3cfbb !important;
            color: #0a3622 !important;
        }

        .quick-add-message.alert-danger {
            background: #f8d7da !important;
            border: 1px solid #f1aeb5 !important;
            color: #58151c !important;
        }

        .quick-add-toggle:focus-visible,
        .quick-add-close:focus-visible,
        .quick-add-submit:focus-visible {
            outline: 3px solid #1a56db;
            outline-offset: 2px;
        }

        .my-presents-header {
            display: flex;
            align-items: center;
            justify-content: space-between;
            gap: 12px;
            padding-bottom: 10px;
            margin-bottom: 14px;
            border-bottom: 2px solid rgba(0, 0, 0, 0.1);
        }

        .my-presents-heading {
            margin: 0;
            color: #1a1a1a;
            font-size: 1.05rem;
            font-weight: 700;
        }

        .my-presents-heading i { color: #c8202f; }

        .my-presents-count {
            flex: 0 0 auto;
            padding: 3px 10px;
            border-radius: 999px;
            background: #fff3cd;
            border: 1px solid #ffda6a;
            color: #664d03;
            font-size: 0.85rem;
            font-weight: 700;
            white-space: nowrap;
        }

        /* Newly added present: brief yellow flash + green ring.
           (The item background is !important, so the flash is an overlay.) */
        #myPresentsList .my-present-item.is-new {
            position: relative;
            animation: myPresentNewRing 2.4s ease-out;
        }

        #myPresentsList .my-present-item.is-new::before {
            content: "";
            position: absolute;
            inset: 0;
            border-radius: inherit;
            background: rgba(255, 193, 7, 0.28);
            pointer-events: none;
            animation: myPresentNewFlash 2.4s ease-out forwards;
        }

        @keyframes myPresentNewRing {
            0%, 60% { box-shadow: 0 0 0 3px rgba(30, 126, 52, 0.7), 0 2px 8px rgba(0, 0, 0, 0.1); }
            100% { box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); }
        }

        @keyframes myPresentNewFlash {
            0%, 50% { opacity: 1; }
            100% { opacity: 0; }
        }

        /* Desktop (>768px): no scrim. The add form is already a bounded
           green card at the top of the page with nothing competing for
           attention, and there is no keyboard or thumb-reach problem to
           solve there - a full-page dim would only feel heavy-handed.
           (The mobile rules below switch it on.) */
        .quick-add-scrim {
            display: none;
        }

        @media (max-width: 768px) {
            /* A backdrop-filter on the card would turn it into the containing
               block for the fixed composer - drop it on mobile and make the
               card a little more opaque instead. */
            #editTab .main-card,
            #editTab .main-card:hover {
                backdrop-filter: none !important;
                -webkit-backdrop-filter: none !important;
                background: rgba(255, 255, 255, 0.94) !important;
                /* Same reason: no hover lift transform / filter on mobile */
                transform: none !important;
                filter: none !important;
                will-change: auto !important;
            }

            #editTab .card-body {
                padding: 1.25rem 1rem;
            }

            .quick-add-section {
                background: none;
                border: 0;
                padding: 0;
                margin: 0;
                box-shadow: none;
            }

            .quick-add-composer {
                position: fixed;
                left: 12px;
                right: 12px;
                bottom: var(--quick-add-bottom, calc(max(12px, env(safe-area-inset-bottom, 0px)) + 90px));
                z-index: 999; /* under the tab bar (1000) and its menus */
                grid-template-columns: 48px minmax(0, 1fr) 52px;
                /* The head and desc rows are always there but collapse to
                   0 height (row-gap 0; each open row adds its own margin) */
                grid-template-areas:
                    "head   head head"
                    "toggle name submit"
                    "desc   desc submit";
                column-gap: 8px;
                row-gap: 0;
                padding: 8px;
                background: rgba(255, 255, 255, 0.98);
                border: 1px solid rgba(0, 0, 0, 0.08);
                border-top: 3px solid #28a745;
                border-radius: 20px;
                box-shadow: 0 8px 28px rgba(0, 0, 0, 0.28);
                /* `bottom` handles the add-mode / on-screen-keyboard moves;
                   `transform` handles hide-on-scroll. Disjoint triggers, and
                   the one overlap (entering add mode while the dock is
                   scroll-hidden) is handled by the add-mode rule below.
                   Nothing here animates the grid: the collapsed and the
                   add-mode row use the SAME grid-template-columns (only the
                   name field's column span differs, see below), so no
                   engine-dependent column interpolation is involved. */
                transition: bottom 0.25s ease,
                    transform 0.3s cubic-bezier(0.4, 0, 0.2, 1);
            }

            /* ---- Hide-on-scroll: the composer and the dock are ONE unit ----
               Same flag (body.dock-hidden, written only by
               initTabBarAutoHide in tab-bar-functions.js), same property
               (transform), same distance (--dock-hide-shift, set by
               formularz.js to exactly dockRestOffset() - dockFloor()), same
               0.3s cubic-bezier as bottom-tab-bar.css. So the 28px between
               the composer and the dock is preserved for the whole travel
               and no gap can open between them. Nothing here changes the
               page's reserved bottom padding, so document.scrollHeight
               cannot move mid-gesture. */
            body.dock-hidden:not(.quick-add-active) .quick-add-composer {
                transform: translateY(var(--dock-hide-shift, 98px));
            }

            /* PRECEDENCE: add mode wins. formularz.js also removes
               `dock-hidden` on entry, so this is a belt-and-braces guard
               against a stale class; the composer must sit at its add-mode
               `bottom` and nowhere else.
               The two properties must UNWIND TOGETHER. Entering add mode
               from a scroll-hidden dock changes both at once: `bottom` goes
               110 -> 12 (which moves the box DOWN 98px) while the hide
               `translateY(98px)` goes back to 0 (which moves it UP 98px).
               They cancel exactly - the rendered bottom edge stays at 12px
               for the whole 250ms - but only while both use the SAME
               duration and the SAME easing. Dropping `transform` from this
               list (or giving it a different curve) is what made the
               composer snap ~98px up and glide back on every "scroll down
               the list, tap the bar" entry. */
            body.quick-add-active .quick-add-composer {
                transform: none;
                transition: bottom 0.25s ease, transform 0.25s ease;
            }

            /* The whole compact row is the "start adding" affordance */
            body:not(.quick-add-active) .quick-add-composer {
                cursor: pointer;
            }

            /* Collapsed: the name field takes the submit column too, so the
               bordered input runs to the same 8px inset on the right as the
               chevron circle has on the left (the submit button is
               visibility:hidden here, and its column used to be left empty,
               which made the bar look lopsided). Only the column span
               changes - never the row - so the field's LEFT edge and its
               vertical position are the same in both states; the right edge
               moves in the instant the submit button comes back in add mode.
               This is a plain grid placement, not a grid-template-columns
               change, so there is nothing for WebKit to interpolate. */
            body:not(.quick-add-active) .quick-add-name {
                grid-column: 2 / 4;
            }

            body:not(.quick-add-active) .quick-add-composer:active {
                background: #f4f8f5;
            }

            /* Heading stays for screen readers (aria-labelledby) */
            .quick-add-heading,
            .quick-add-submit-label {
                position: absolute !important;
                width: 1px !important;
                height: 1px !important;
                padding: 0 !important;
                margin: -1px !important;
                overflow: hidden !important;
                clip: rect(0, 0, 0, 0) !important;
                white-space: nowrap !important;
                border: 0 !important;
            }

            /* Head row (title + close): collapsed to nothing in the compact
               state so the bar keeps its slim height, revealed in add mode.
               The heading itself stays visibility:visible throughout (only
               clipped by the visually-hidden rule above) so the section's
               aria-labelledby name never disappears. */
            .quick-add-head {
                grid-area: head;
                max-height: 0;
                margin-bottom: 0;
                overflow: hidden;
                transition: max-height 0.2s ease, margin-bottom 0.2s ease;
            }

            body.quick-add-active .quick-add-head {
                max-height: 56px;
                margin-bottom: 6px;
            }

            /* In add mode the title becomes visible - it is the same node,
               so there is no duplicated string and no empty accname */
            body.quick-add-active .quick-add-heading {
                position: static !important;
                width: auto !important;
                height: auto !important;
                margin: 0 !important;
                overflow: visible !important;
                clip: auto !important;
                white-space: normal !important;
                font-size: 0.9rem;
            }

            /* Explicit close control. 44x44 and in the tab order, but only
               while there is something to close: visibility:hidden (not just
               the parent's overflow clip) keeps it out of the tab order and
               the accessibility tree in the compact state. A rounded square
               with an x - deliberately unlike the round chevron below it. */
            .quick-add-close {
                display: inline-flex;
                align-items: center;
                justify-content: center;
                flex: 0 0 auto;
                width: 44px;
                height: 44px;
                padding: 0;
                border: 1px solid #cbd2d9;
                border-radius: 12px;
                background: #eef1f4;
                color: #44515e;
                font-size: 1.1rem;
                visibility: hidden;
            }

            body.quick-add-active .quick-add-close { visibility: visible; }

            /* The chevron is a details toggle, so it exists only where there
               are details to toggle: add mode. In the compact bar it would
               be a control that, when pressed, first opens the form (which
               opens the description) and then collapses the very row the
               user was reaching for - and its label would still read
               "Dodaj opis (opcjonalnie)" at that moment. visibility:hidden
               (not just opacity) takes it out of the tab order AND the
               accessibility tree, so that sequence is now unreachable
               rather than merely discouraged. Its 48px grid column stays
               reserved, so the name field's box does not move between the
               two states; the decorative .quick-add-cue below takes over
               the cell visually. */
            .quick-add-toggle {
                grid-area: toggle;
                display: inline-flex;
                align-items: center;
                justify-content: center;
                width: 48px;
                height: 48px;
                padding: 0;
                border: 1px solid #cbd2d9;
                border-radius: 50%;
                background: #eef1f4;
                color: #2d3748;
                font-size: 1rem;
                visibility: hidden;
                pointer-events: none;
            }

            body.quick-add-active .quick-add-toggle {
                visibility: visible;
                pointer-events: auto;
            }

            .quick-add-toggle i { transition: transform 0.2s ease; }
            .quick-add-toggle[aria-expanded="true"] { background: #e3f2e6; border-color: #28a745; color: #1b5e20; }
            .quick-add-toggle[aria-expanded="true"] i { transform: rotate(180deg); }

            /* ---- The compact bar's leading chevron ----
               A purely visual twin of the real .quick-add-toggle above, in
               its collapsed look: same cell, 48x48 box, 1px border, fill,
               colour and icon size, with the same chevron-up icon. It is
               decorative only (aria-hidden, pointer-events: none, no tab
               stop, no accessible name): a tap on it falls through to the
               row-level click handler that enters add mode. The real toggle
               is visibility:hidden here and takes over this exact cell in
               add mode, so the two never exist at the same time and the
               keyboard/press races the real chevron had in the compact bar
               stay unreachable. */
            .quick-add-cue {
                grid-area: toggle;
                display: inline-flex;
                align-items: center;
                justify-content: center;
                width: 48px;
                height: 48px;
                padding: 0;
                border: 1px solid #cbd2d9;
                border-radius: 50%;
                background: #eef1f4;
                color: #2d3748;
                font-size: 1rem;
                pointer-events: none;
            }

            body.quick-add-active .quick-add-cue { visibility: hidden; }

            .quick-add-name .form-control {
                height: 48px;
                padding: 0.5rem 0.875rem;
                border-radius: 14px;
                font-size: 16px; /* >=16px: no iOS zoom on focus */
            }

            /* Collapsed: zero height, hidden from tab order / AT. Opens
               upward (the composer is anchored at the bottom) with a short
               height + fade transition. */
            .quick-add-desc {
                max-height: 0;
                margin-top: 0;
                opacity: 0;
                overflow: hidden;
                visibility: hidden;
                transition: max-height 0.2s ease, margin-top 0.2s ease,
                    opacity 0.15s ease, visibility 0s linear 0.2s;
            }

            .quick-add-composer.is-expanded .quick-add-desc {
                max-height: calc(30vh + 40px);
                margin-top: 8px;
                opacity: 1;
                visibility: visible;
                transition: max-height 0.2s ease, margin-top 0.2s ease,
                    opacity 0.15s ease 0.05s, visibility 0s;
            }

            .quick-add-hint {
                margin: 0 4px 4px;
                font-size: 0.8125rem;
            }

            .quick-add-desc .form-control {
                font-size: 16px;
                padding: 0.5rem 0.875rem;
                border-radius: 14px;
                max-height: 30vh;
            }

            /* The "+" is the real submit control, so it exists only where
               there is something to submit: add mode. In the compact state
               the row has no submit affordance at all - it was a second
               green "add" button sitting ~44px above the dock's own green
               "Dodaj" tab, and with an empty field it could not submit
               anything. visibility:hidden takes it out of the tab order and
               the accessibility tree, and its 52px grid column stays in the
               template: while collapsed the name field spans that column
               (see .quick-add-name above), in add mode it gives it back.
               The field's left edge never moves, and nothing depends on an
               engine interpolating grid-template-columns (WebKit/iOS does
               not).
               The explicit transition is required: .btn-green sets
               `transition: all 0.3s ease`, and `visibility` is a
               transitionable discrete property, so inheriting that would
               delay the flip by ~150ms+. */
            .quick-add-submit {
                align-self: end;
                width: 52px;
                height: 52px;
                min-height: 52px;
                padding: 0;
                margin-bottom: -2px;
                font-size: 1.25rem;
                visibility: hidden;
                pointer-events: none;
                transition: visibility 0s, background-color 0.18s ease,
                    box-shadow 0.18s ease;
            }

            body.quick-add-active .quick-add-submit {
                visibility: visible;
                pointer-events: auto;
            }

            /* Collapsed, the name field stays a clearly visible, bordered
               input (the user asked for the form to remain visible when the
               bar is closed). It used to be painted transparent here. Only
               colours are set, never width or size, so the box is identical
               to add mode's height and nothing shifts vertically when add
               mode starts; the row reads as [chevron] [ input ]. */
            body:not(.quick-add-active) .quick-add-name .form-control {
                background: #ffffff;
                border-color: #8a96a3;
            }

            /* Status pill floats just above the composer */
            .quick-add-message {
                position: absolute;
                left: 0;
                right: 0;
                bottom: calc(100% + 8px);
                box-shadow: 0 4px 14px rgba(0, 0, 0, 0.2);
                border-radius: 12px;
            }

            /* Reserve room so the composer + tab bar never cover the last
               present or the "Dodaj dla kogoś innego" button */
            body.has-tab-bar.quick-add-docked {
                /* --quick-add-reserve is where the composer sits plus how
                   tall it is, as one number, written by formularz.js. One
                   number and not a pair, because the page's scroll height
                   depends on their SUM: while the form opens, the offset
                   drops in one write and the height grows over 0.2s, so a
                   live pair dips ~98px for a few frames and clamps a reader
                   pinned to the bottom of the page. */
                padding-bottom: calc(var(--quick-add-reserve, 172px) + 20px) !important;
                /* Entering add mode grows this padding (the composer gets
                   taller faster than it drops), which can never move the
                   scroll position. Leaving shrinks it, and a reader pinned
                   to the very bottom of the page then gets clamped upwards
                   by the difference - matching the composer's own
                   `bottom` transition spreads that over the same 0.25s, so
                   it settles instead of snapping. */
                transition: padding-bottom 0.25s ease;
            }

            /* ---- Attention scrim ----
               While the composer is active (name/description focused or
               being typed into) everything behind it is dimmed so the
               bright composer is the obvious place to look. Decorative
               only: aria-hidden, not focusable, no role="dialog", no focus
               trap and no scroll lock - a tap dismisses it, a drag still
               scrolls the list. No backdrop-filter: the page background is
               a photo, so a blur here costs frames for a muddy result. */
            .quick-add-scrim {
                display: block;
                position: fixed;
                inset: 0;
                /* Above all page content (header, list, "Dodaj dla kogoś
                   innego"), below the composer (999) and the bottom tab
                   bar (1000), so the bar stays bright and clickable */
                z-index: 998;
                background: rgba(0, 0, 0, 0.45);
                opacity: 0;
                visibility: hidden;
                pointer-events: none;
                -webkit-tap-highlight-color: transparent;
                transition: opacity 0.18s ease, visibility 0s linear 0.18s;
            }

            body.quick-add-active .quick-add-scrim {
                opacity: 1;
                visibility: visible;
                pointer-events: auto;
                transition: opacity 0.18s ease, visibility 0s;
            }

            /* Lift the composer off the dimmed page: a deeper shadow and a
               fully opaque surface (at 0.98 the dimmed list underneath
               showed through just enough to be noticeable) */
            body.quick-add-active .quick-add-composer {
                background: #ffffff;
                box-shadow: 0 10px 36px rgba(0, 0, 0, 0.45);
            }

            /* ---- Add mode owns the thumb zone ----
               The dock (and the red FAB poking out of it) slide out while a
               present is being typed, so the composer can sit at the very
               bottom. visibility:hidden - not just a transform - so the bar
               leaves the accessibility tree AND the tab order while hidden;
               formularz.js additionally sets inert/aria-hidden on it. The
               composer drops to the dock's own inset (see tabBarOffset in
               formularz.js); the page's bottom padding is sized for the
               dock-shown state and only ever changes with add mode, never
               with scrolling, so nothing is clipped.
               PRECEDENCE is enforced in JS, not by cascade order:
               `quick-add-active` and `dock-hidden` are mutually exclusive -
               entering add mode removes `dock-hidden` and the scroll
               handler returns early while add mode is on, and leaving calls
               window.resetDockAutoHide() to hand the dock back shown. This
               rule is therefore the only one that ever touches visibility /
               inert / aria-hidden on the dock; hide-on-scroll only ever
               touches transform / opacity / pointer-events. */
            body.quick-add-active .bottom-tab-bar {
                /* +56px clears the FAB, which pokes ~18px above the bar's
                   own box - so the whole dock ends up below the fold */
                transform: translateY(calc(100% + 56px));
                opacity: 0;
                visibility: hidden;
                pointer-events: none;
                transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1),
                    opacity 0.3s ease, visibility 0s linear 0.3s;
            }
        }



        @media (prefers-reduced-motion: reduce) {
            .quick-add-composer,
            body.dock-hidden:not(.quick-add-active) .quick-add-composer,
            body.quick-add-active .quick-add-composer,
            .quick-add-toggle i,
            .quick-add-desc,
            .quick-add-composer.is-expanded .quick-add-desc,
            .quick-add-scrim,
            body.quick-add-active .quick-add-scrim,
            .quick-add-head,
            body.quick-add-active .quick-add-head,
            body.has-tab-bar.quick-add-docked,
            /* Both directions: the base slide-back transition lives in
               bottom-tab-bar.css, which is shared, so it is neutralised
               here (page-local, no cross-page cache churn) */
            .bottom-tab-bar,
            body.quick-add-active .bottom-tab-bar {
                transition: none !important;
            }

            #myPresentsList .my-present-item.is-new {
                animation: none;
                box-shadow: 0 0 0 3px rgba(30, 126, 52, 0.7), 0 2px 8px rgba(0, 0, 0, 0.1);
            }

            #myPresentsList .my-present-item.is-new::before {
                animation: none;
                opacity: 1;
            }
        }
    