@import url(https://fonts.googleapis.com/css?family=Poppins:300,400,500,600,700);
@import url(/images/icons/simple-line-icons/css/simple-line-icons.css);
@import url(/images/icons/themify-icons/themify-icons.css);
/*
@import url(/images/icons/material-design-iconic-font/css/materialdesignicons.min.css);
@import url(/images/icons/weather-icons/css/weather-icons.min.css);
@import url(/images/icons/flag-icon-css/flag-icon.min.css);
*/

:root {
    --fs-theme-navigation-background: #F1F0F0;
    --fs-theme-text-color: #444444;

    --fs-primary-background: #F1F0F0;
    --fs-primary-text: #666666;
    --fs-primary-hover: #ced9e4;
    --fs-primary-active: #ced9e4;
    --fs-primary-focus: #ced9e4;
    --fs-primary-disabled: #edf1f5;

    --fs-secondary-background: #f8f9fa;
    --fs-secondary-text: #666666;
    --fs-secondary-hover: #e1e6ea;
    --fs-secondary-active: #e1e6ea;
    --fs-secondary-focus: #e1e6ea;
    --fs-secondary-disabled: #ffffff;

    --fs-info-background: #17a2b8;
    --fs-info-text: #fff;
    --fs-info-hover: #148c9f;
    --fs-info-active: #148c9f;
    --fs-info-focus: #148c9f;
    --fs-info-disabled: #4696a2;

    --fs-danger-background: #E57373;
    --fs-danger-text: #fff;
    --fs-danger-hover: #df5353;
    --fs-danger-active: #df5353;
    --fs-danger-focus: #df5353;
    --fs-danger-disabled: #efa9a9;


    --breakpoint-xs: 0;
    --breakpoint-sm: 576px;
    --breakpoint-md: 768px;
    --breakpoint-lg: 992px;
    --breakpoint-xl: 1200px;

    --fs-left-navigation-width: 250px;
    --fs-font-family: "Poppins", sans-serif;
}


/* Dynamic Sizing CSS */
/*
.fixed-layout .page-wrapper.xs {padding-top: 6.5rem;}
.fixed-layout .page-wrapper.sm {padding-top: 6.5rem;}
.fixed-layout .page-wrapper.md {padding-top: 6.5rem;}
.fixed-layout .page-wrapper.lg {padding-top: 6.5rem;}
.fixed-layout .page-wrapper.xl {padding-top: 6.5rem;}
 */



/*********************************************************
    HTML
 *********************************************************/
html {

}

body {
    font-family: var(--fs-font-family);
    font-size: 14px;
    font-weight: 300;
    line-height: 1.5;
    -webkit-text-size-adjust: 100%;
    -ms-text-size-adjust: 100%;
    -ms-overflow-style: scrollbar;
    -webkit-tap-highlight-color: rgba(0, 0, 0, 0)
}

* {
    font-family: var(--fs-font-family);
    font-size: 14px;
    font-weight: 300;
}

/*********************************************************
    LINKS
 *********************************************************/
a {
    color: var(--fs-theme-text-color);
    text-decoration: none;
    background-color: transparent;
    -webkit-text-decoration-skip: objects
}

a:hover {
    color: #1d6d86;
    text-decoration: none;
}



/*********************************************************
    HEADERS
 *********************************************************/
.h1, h1 {
    font-size: 1.5rem;
}

.h2, h2 {
    font-size: 1.4rem;
}

.h3, h3 {
    font-size: 1.3rem;
}

.h4, h4 {
    font-size: 1.2rem;
}

.h5, h5 {
    font-size: 1.1rem;
}

.h6, h6 {
    font-size: 1.0rem;
}


/*********************************************************
    DARK MODE
 *********************************************************/
.dark-mode, .dark-mode *:not(aside):not(aside *):not(.btn-info):not(.btn-info *):not(.bg-info):not(.bg-info *):not(select):not(select *):not(.btn-danger):not(.btn-danger *):not(.tag-delete):not(.tag-delete *):not(.ppg-box):not(.ppg-box *):not(.ppg-title-card):not(.ppg-title-card *) {
    background-color: #343434;
    color: white !important;
}

/* The wildcard above flattens every btn-check toggle-button pair (Color/
   Image, Dark Mode/After Dark, ...) to the exact same background whether
   selected or not, drowning out Bootstrap's own ".btn-check:checked +
   .btn" highlight - clicking one visibly did nothing, even though the
   underlying radio/checkbox state was changing correctly. Restores a
   clearly different, deliberate background instead. */
.dark-mode .btn-check:checked + .btn-outline-secondary {
    background-color: var(--fs-info-background) !important;
    border-color: var(--fs-info-background) !important;
    color: #fff !important;
}

.dark-mode .left-sidebar,
.dark-mode .offcanvas,
.dark-mode .offcanvas-body {
    background-color: #262626 !important;
}

.dark-mode .result-mini-card-view .card,
.dark-mode .result-shadow-card-view .card,
.dark-mode .result-boxes-view .card {
    border-width: 1px !important;
    border-color: #444 !important;
}

/* Boxes view: 25% thinner border than the default border-2 utility (2px -> 1.5px) */
.result-boxes-view .card {
    border-width: 1.5px !important;
}

.dark-mode .btn-close {
    background-color: white !important;
}

/* Phone-reported only: the left sidebar's close X (.nav-toggler.btn-close)
   showed a grey box around it in dark mode. Bootstrap's close button is a
   dark X icon drawn on a transparent background-image, with our white
   background-color sitting behind it and Bootstrap's own default 50%
   opacity applied to the whole thing - against a dark background that
   reads as a dingy grey square rather than a clean white X. Scoped to
   this specific mobile sidebar toggle only, inside the phone breakpoint -
   does not touch .dark-mode .btn-close above, which desktop (modals,
   etc.) still uses unchanged. */
@media (max-width: 767px) {
    .dark-mode .nav-toggler.btn-close {
        background-color: transparent !important;
        filter: invert(1) grayscale(100%) brightness(200%);
        opacity: 1 !important;
    }
}

.dark-mode .sidebar-nav ul li a.current,
.dark-mode .sidebar-nav ul li a.current i {
    background-color: #0d0d0d;
}

/* Keep modal containers transparent and backdrop semi-transparent so app content shows behind modals */
.dark-mode .modal,
.dark-mode .modal-dialog {
    background-color: transparent !important;
}

.dark-mode .modal-backdrop {
    background-color: #000;
    opacity: 0.5;
}

.dark-mode .card-body {
    border: 0.1px solid transparent;
}
.dark-mode .card {
    border: 0.1px solid grey;
}

/* Note cards on the bucket page, dark mode: a solid pastel-yellow fill
   reads as a jarring block against a dark page, same issue links' own
   hilite color had - swap to a thin yellow outline instead (still
   clearly marks it as a note), with light text since the background is
   no longer light. */
.dark-mode .note-card-body.border {
    background-color: transparent !important;
    border: 1.5px solid #f5d90a !important;
    color: #fff !important;
}

/* Note cards - classic sticky-note yellow in light mode (dark mode
   override is above, matching the more specific .note-card-body.border
   selector the real markup actually uses). */
.note-card-body {
    background-color: var(--note-color, #fffde8) !important;
    color: #333 !important;
}

/* "Color Off" on a note (see the Color modal) drops the sticky-note
   yellow entirely, back to a plain white card - the note equivalent of
   a link's bg_color 'N'. */
.note-card-body.color-off {
    background-color: #fff !important;
    color: #333 !important;
}

/* The swatch's actual color is per-user (each user's Site Colors
   "Color Each Link" value), so it's set as a CSS custom property
   inline rather than a plain inline background-color - that lets this
   rule (and the higher-specificity dark-mode override below it) keep
   re-applying the real color even where a broader rule would
   otherwise force a fixed background over it. */
#item-color-default-swatch {
    background-color: var(--item-color-default-swatch);
}

/* Overrides the generic ".dark-mode .btn:hover *" rule (turns
   everything inside a hovered button near-black) - the swatch keeps
   showing its actual color on hover instead. */
.dark-mode .btn:hover #item-color-default-swatch {
    background-color: var(--item-color-default-swatch) !important;
}

/* Lighter than Bootstrap's default btn-outline-secondary.active grey
   (#6c757d) - scoped to the Color modal's Off/Default/Custom picker
   only, not a sitewide button restyle. */
#item-color-mode-group .btn-outline-secondary {
    border-color: #6c757d;
}

#item-color-mode-group .btn-outline-secondary.active {
    background-color: #d8dadc !important;
    color: #212529 !important;
}

#item-color-mode-group .btn-outline-secondary:hover,
#item-color-mode-group .btn-outline-secondary:focus,
#item-color-mode-group .btn-outline-secondary:active,
#item-color-mode-group .btn-outline-secondary.active:hover,
#item-color-mode-group .btn-outline-secondary.active:focus {
    background-color: #e0e2e4 !important;
    color: #212529 !important;
}

/* Site Colors, Logo and Links tabs: a heading, the color preview and swatches centered with room around them,
   then the options set apart underneath. */
.site-colors-caption {
    margin-bottom: 0.5rem;
    font-size: 0.8rem;
    font-weight: 600;
    letter-spacing: 0.03em;
    text-transform: uppercase;
    color: #6c757d;
}

.site-colors-caption-options {
    margin-top: 1.25rem;
}

.site-colors-pick {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.75rem;
}

.site-colors-pick .ppg-swatch-grid {
    justify-content: center;
}

.site-colors-hint {
    margin: 0.75rem 0 0;
    font-size: 0.85rem;
    color: #6c757d;
}

.dark-mode .site-colors-caption,
.dark-mode .site-colors-hint {
    color: #adb5bd !important;
}

/* Public Sort Settings modal tabs (Profile/Layout/Background/Manage
   Boxes/Build Box) - Bootstrap's nav-tabs wraps onto a second line once
   5 tabs don't fit a phone's width, which pushed the active tab's
   underline out of alignment. Scroll horizontally on one line instead,
   phone only - desktop/tablet already fit all 5 without wrapping. */
@media (max-width: 767px) {
    #pps-tabs {
        flex-wrap: nowrap !important;
        overflow-x: auto;
        overflow-y: hidden;
        -webkit-overflow-scrolling: touch;
        scrollbar-width: none;
    }

    #pps-tabs::-webkit-scrollbar {
        display: none;
    }

    #pps-tabs .nav-link {
        white-space: nowrap;
        flex: 0 0 auto;
        /* 15% smaller than the normal tab text, to shrink how far each
           tab has to be scrolled past. Bold to stay readable at that
           smaller size. */
        font-size: 0.85rem;
        font-weight: 600;
    }
}

/* Admin User Defaults: pick the starting Start Page / Public Sort picture from the library. */
.default-image-thumb {
    width: 96px;
    height: 64px;
    padding: 0;
    object-fit: cover;
    border: 3px solid transparent;
    border-radius: 6px;
    cursor: pointer;
}

.default-image-thumb.selected {
    border-color: #17a2b8;
}

.default-image-none {
    display: flex;
    align-items: center;
    justify-content: center;
    background-color: #f1f3f5;
    border-color: #ced4da;
    color: #495057;
    font-size: 0.8rem;
}

.default-image-none.selected {
    border-color: #17a2b8;
}

.dark-mode .note-card-body.color-off {
    background-color: transparent !important;
    border-color: #6c757d !important;
    color: #fff !important;
}

/* A note with its own color set (see the "Color" option on the note's
   ellipsis menu) overrides the default sticky-note yellow above via the
   --note-color custom property set inline on this same element - dark
   mode still swaps to a thin outline instead of a solid fill, same
   reasoning as the default-yellow dark-mode rule above. */
.dark-mode .note-card-body.border[style*="--note-color"] {
    background-color: transparent !important;
    border: 1.5px solid var(--note-color) !important;
    color: #fff !important;
}

/* Note text was rendering at h4 heading size (~1.5rem) via its markup's
   .h4 class - much larger than a link's description text. Match that
   same 13.2px used for link descriptions (see .results-show-description
   .card-text) instead. */
.note-card-body .h4 {
    font-size: 13.2px;
}

.note-card-body h1 {
    margin-top: -0.5em;
}

/* Note ellipsis menu - hidden until the card is hovered, same pattern
   as the per-link ellipsis/checkbox controls elsewhere. */
.note-ellipsis {
    visibility: hidden;
}

.card:hover .note-ellipsis {
    visibility: visible;
}

.dark-mode .modal-content {
    background-color: #111 !important;
    border: none !important;
    box-shadow: none !important;
    outline: none !important;
}

/* Bootstrap's active nav-tab gets a bottom border color matching the
   page background (white), so the tab visually "merges" into the
   content below it - in dark mode that background is #111, not white,
   so the leftover white blend-border shows up as a stray bright line
   instead of disappearing. Match it to the actual dark background, and
   give the tab bar's own underline (under the inactive tabs) a visible
   dark-mode-appropriate color instead of the light-mode gray. */
.dark-mode .nav-tabs {
    border-bottom-color: #444 !important;
}

.dark-mode .nav-tabs .nav-link.active {
    background-color: #111 !important;
    border-color: #444 #444 #111 !important;
    color: #fff !important;
}

/* Each tab link's own border overlaps the tab bar's underline directly
   (Bootstrap positions them 1px on top of each other on purpose) - an
   inactive tab's border is transparent by default, which masks the
   line wherever that tab sits instead of just leaving it visible. */
.dark-mode .nav-tabs .nav-link:not(.active) {
    border-bottom-color: #444 !important;
}

.dark-mode .modal-header,
.dark-mode .modal-body,
.dark-mode .modal-footer {
    background-color: #111 !important;
    border: none !important;
}

.dark-mode .modal-content *:not(.btn-info):not(.btn-info *):not(.btn-danger):not(.btn-danger *):not(.btn-close):not(.dropdown-item):not(.dropdown-item *):not(#site-colors-logo-preview):not(.site-colors-save-btn):not(.tag-delete):not(.tag-delete *):not(.ppg-swatch):not(.ppg-swatch-custom):not(#item-color-default-swatch):not(#item-color-mode-group .active):not(.btn-check:checked + .btn-outline-secondary) {
    background-color: #111 !important;
}

/* Plain <select> dropdowns (e.g. "Your Links Look Like") get their
   background forced dark by the rule above like everything else in
   this modal, but text color is never part of that - native <select>
   text doesn't reliably inherit color the way normal text does,
   so it was defaulting to black-on-black. */
/* "Your page is live at..." callout - the modal-wide dark-mode rule
   above would otherwise force this to the same near-black as
   everything else, losing its green-means-good identity entirely.
   Light grey instead of trying to keep the green (which read poorly
   against a dark background at readable contrast). */
.dark-mode .ppg-live-page-callout {
    background: #e9ecef !important;
    border-color: #ced4da !important;
}

.dark-mode .ppg-live-page-callout-icon,
.dark-mode .ppg-live-page-callout-text {
    color: #212529 !important;
}

.dark-mode .ppg-live-page-callout-btn {
    color: #212529 !important;
    border-color: #495057 !important;
}

.dark-mode .modal-content select {
    color: #fff !important;
    /* Bootstrap's default chevron is a dark-gray SVG background-image -
       invisible against this modal's dark background, same reason the
       text needed its own color override above. White version of the
       same arrow. */
    background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23fff' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M2 5l6 6 6-6'/%3e%3c/svg%3e") !important;
    /* Drawn once at the right edge, like Bootstrap's own .form-select arrow. A select that only has
       .form-control (e.g. Create a Bucket's Parent Bucket, before it turns into a selectpicker)
       has none of those settings, so the arrow tiled across the whole box. */
    background-repeat: no-repeat;
    background-position: right 0.75rem center;
    background-size: 16px 12px;
}

.dark-mode .modal-content .dropdown-item,
.dark-mode .modal-content .dropdown-item * {
    background-color: #111 !important;
    color: white !important;
}

.dark-mode .modal-content .dropdown-item:hover,
.dark-mode .modal-content .dropdown-item:hover *,
.dark-mode .modal-content li.active > .dropdown-item,
.dark-mode .modal-content li.active > .dropdown-item * {
    background-color: #2a2a2a !important;
    color: white !important;
}

.dark-mode .modal-content .btn-close {
    filter: invert(1) !important;
    background-color: transparent !important;
    border: none !important;
    box-shadow: none !important;
}

/* Toggle switch circle - blue dot */
.dark-mode .modal-content .form-check-input[type="checkbox"],
.modal-content .form-check-input[type="checkbox"] {
    background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%230dcaf0'/%3e%3c/svg%3e") !important;
}

/* Toggle switch pill outline - thin (1pt) dark grey, same in both states.
   Per explicit request: only the knob should move/change on toggle - the
   track itself (background + outline) should look identical whether on
   or off, not fill with color when switched on. */
.modal-content .form-check-input[type="checkbox"],
.modal-content .form-check-input[type="checkbox"]:checked {
    border-width: 1px !important;
    border-color: #555 !important;
    background-color: #fff !important;
}

/* The "too thick" outline turned out to be Bootstrap's default blue
   focus ring (box-shadow on :focus), not the border - remove it in both
   states, since the switch already shows its state clearly via color. */
.modal-content .form-check-input[type="checkbox"]:focus {
    box-shadow: none !important;
}

/* Public Sort's own toggles (Hide this box, Widen this box, Manage
   Boxes visibility, etc.) - scoped to just these modals (id starts
   with "modal-public-") rather than changing the sitewide rule above,
   which was deliberately kept knob-position-only elsewhere. On/off
   was hard to tell apart here, so these fill with color when checked
   instead of only moving the knob. */
[id^="modal-public-"] .form-check-input[type="checkbox"]:checked {
    background-color: var(--fs-info-background) !important;
    border-color: var(--fs-info-background) !important;
}

[id^="modal-public-"] .form-check-input[type="checkbox"]:checked {
    background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%23fff'/%3e%3c/svg%3e") !important;
}

/* Site Colors' Reset/Match checkboxes and Add/Edit Link's "Also grab
   website description" are plain checkboxes (no .form-switch), not
   toggle switches - the rules above are meant for actual switches like
   Add Link's "Favorite?" and would otherwise make these look identical
   (a filled dot) whether checked or not. Restore normal Bootstrap
   checkbox appearance (empty box vs. filled checkmark) for these. */
#logo-color-reset-checkbox,
#logo-color-match-checkbox,
#button-color-reset-checkbox,
#frm_link_auto_fetch_description {
    background-image: none !important;
    border-width: 1px !important;
    border-color: #adb5bd !important;
    background-color: #fff !important;
}

#logo-color-reset-checkbox:checked,
#logo-color-match-checkbox:checked,
#button-color-reset-checkbox:checked,
#frm_link_auto_fetch_description:checked {
    background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3e%3cpath fill='none' stroke='%23fff' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='M6 10l3 3l6-6'/%3e%3c/svg%3e") !important;
    background-color: var(--fs-info-background) !important;
    border-color: var(--fs-info-background) !important;
}

/* Radio buttons - white ring unselected, teal when selected */
.dark-mode .modal-content .form-check-input[type="radio"] {
    background-color: transparent !important;
    border-color: white !important;
}

.dark-mode .modal-content .form-check-input[type="radio"]:checked {
    background-color: #0dcaf0 !important;
    border-color: #0dcaf0 !important;
}

.dark-mode .modal-content ::-webkit-scrollbar {
    width: 8px;
}

.dark-mode .modal-content ::-webkit-scrollbar-track {
    background: #111;
}

.dark-mode .modal-content ::-webkit-scrollbar-thumb {
    background-color: #555;
    border-radius: 4px;
}

.dark-mode .modal-content {
    scrollbar-color: #555 #111;
    scrollbar-width: thin;
}

.dark-mode .bootstrap-select .dropdown-menu,
.dark-mode .bootstrap-select .dropdown-menu .inner,
.dark-mode .bootstrap-select div.inner,
.dark-mode .bootstrap-select .dropdown-menu li,
.dark-mode .bootstrap-select .dropdown-menu li a,
.dark-mode .bootstrap-select .dropdown-menu li a span,
.dark-mode .bootstrap-select .dropdown-menu .dropdown-header {
    scrollbar-color: #2a2a2a #111 !important;
    scrollbar-width: thin !important;
    background-color: #111 !important;
    color: white !important;
}

.dark-mode .bootstrap-select .dropdown-menu::-webkit-scrollbar,
.dark-mode .bootstrap-select .dropdown-menu .inner::-webkit-scrollbar,
.dark-mode .bootstrap-select div.inner::-webkit-scrollbar,
.dark-mode .bootstrap-select .dropdown-menu *::-webkit-scrollbar {
    width: 8px !important;
}

.dark-mode .bootstrap-select .dropdown-menu::-webkit-scrollbar-track,
.dark-mode .bootstrap-select .dropdown-menu .inner::-webkit-scrollbar-track,
.dark-mode .bootstrap-select div.inner::-webkit-scrollbar-track,
.dark-mode .bootstrap-select .dropdown-menu *::-webkit-scrollbar-track {
    background: #111 !important;
}

.dark-mode .bootstrap-select .dropdown-menu::-webkit-scrollbar-thumb,
.dark-mode .bootstrap-select .dropdown-menu .inner::-webkit-scrollbar-thumb,
.dark-mode .bootstrap-select div.inner::-webkit-scrollbar-thumb,
.dark-mode .bootstrap-select .dropdown-menu *::-webkit-scrollbar-thumb {
    background-color: #2a2a2a !important;
    border-radius: 4px !important;
}

.dark-mode .modal-content .bootstrap-select .dropdown-menu li a:hover,
.dark-mode .modal-content .bootstrap-select .dropdown-menu li a:hover span,
.dark-mode .modal-content .bootstrap-select .dropdown-menu li.active a,
.dark-mode .modal-content .bootstrap-select .dropdown-menu li:hover a,
.dark-mode .bootstrap-select .dropdown-menu li a:hover,
.dark-mode .bootstrap-select .dropdown-menu li a:hover span,
.dark-mode .bootstrap-select .dropdown-menu li:hover a {
    background-color: #2a2a2a !important;
    color: white !important;
}

.dark-mode .result-icons-view * {
    border: none;
}

/* Auto-generated fallback icon (a link with no real favicon): a colored
   circle/square with the site's first letter in it. The outer div sets
   its own inline background-color (one of five accent colors), which
   correctly wins over dark mode's sitewide background override above -
   but the inner span holding just the letter has no background of its
   own to win with, so that sitewide rule paints a small dark box behind
   the letter instead of leaving it transparent against the real color. */
.dark-mode .link-display div[style*="background-color"] * {
    background-color: transparent !important;
}

/* SweetAlert dark mode */
.dark-mode .swal2-container {
    background-color: rgba(0, 0, 0, 0.5) !important;
}

.dark-mode .swal2-popup {
    background-color: #111 !important;
    border: none !important;
    box-shadow: none !important;
}

.dark-mode .swal2-popup *:not(.swal2-confirm):not(.swal2-cancel) {
    background-color: #111 !important;
    color: white !important;
}

.dark-mode .swal2-actions {
    background-color: transparent !important;
}

.bootstrap-select .dropdown-menu li.selected a,
.bootstrap-select .dropdown-menu li.selected a span,
.bootstrap-select .dropdown-menu li.active a,
.bootstrap-select .dropdown-menu li.active a span {
    background-color: white !important;
    color: #333 !important;
}

.dark-mode #fullsort_search_block *:not(.link-select) {
    background-color: #0d0d0d !important;
}

.dark-mode ::placeholder {
    color: white !important;
    opacity: 1 !important;
}

.dark-mode #toggleLock {
    color: white !important;
}

.dark-mode .btn:hover, .dark-mode .btn:hover * {
    background-color: #0d0d0d !important;
}

/* Inline-edit (x-editable) checkmark/X buttons - strip the default
   Bootstrap button chrome (border/background) so the checkmark floats
   the same way the plain-link X next to it does, instead of sitting
   in its own grey box. */
.editable-submit {
    background: transparent !important;
    border: none !important;
    box-shadow: none !important;
}

.dark-mode .editable-submit, .dark-mode .editable-submit * {
    background-color: transparent !important;
}

.dark-mode .dropdown-item:hover, .dark-mode .dropdown-item:hover * {
    background-color: #3a3a3a !important;
}

.dark-mode .dropdown-item:hover {
    background-color: #3a3a3a !important;
}

.dark-mode .change-all-color, .dark-mode .change-color-hilite {
    background-color: #0d0d0d !important;
}

.dark-mode .feedback_trigger_text,
.dark-mode .feedback_content * {
    color: black !important;
}

.dark-mode .link-select {
    background-color: #0d0d0d !important;
}

.dark-mode .link-select:hover, .dark-mode .link-select:hover * {
    background-color: #262626 !important;
}

.dark-mode .current,
.dark-mode .current *,
.dark-mode .sidebar-nav,
.dark-mode .sidebar-nav * {
    color: white !important;
    background-color: transparent !important;
}

.dark-mode .sidebar-nav ul li:hover {
    background-color: #0d0d0d !important;
}



/*********************************************************
    LEFT NAVIGATION
 *********************************************************/
.left-sidebar {
    background: var(--fs-theme-navigation-background);
    position: fixed;
    width: var(--fs-left-navigation-width);
    height: 100%;
    top: 0px;
    z-index: 50;
}

.left-sidebar.show-sidebar {
    display: block;
}


@media (max-width:991px) {
    .left-sidebar {
        display: none;
    }
    .left-sidebar.show-sidebar {
        display: block;
    }
}
@media (min-width:992px) {
    .left-sidebar {
        display: block;
    }
}

.offcanvas {
    width: var(--fs-left-navigation-width)!important;
}

.offcanvas-body::-webkit-scrollbar {
    display: none;
}

.sidebar-nav ul li {
    list-style: none
}

.sidebar-nav ul li a {
    color: var(--fs-theme-text-color);
    padding: 7px 15px 7px 15px;
    display: block;
}

.sidebar-nav ul li a.current,
.sidebar-nav ul li a:hover,
.sidebar-nav ul li a.current i,
.sidebar-nav ul li a:hover i {
    background-color: #e7e5e4;
}

.sidebar-nav>ul>li>a i,
.sidebar-nav>ul>li>a .emoji-icon {
    width: 25px;
    display: inline-block;
    vertical-align: middle;
}

/* The emoji icon's own <img> doesn't have a fixed width like the fa-*
   icon font glyphs do, so it wasn't centering inside the 25px slot
   above the way the shape/font icons do - text-align pulls it (and
   its fallback text-node, if the image 404s) to the middle instead of
   sitting flush left. A small extra nudge left/up on top of that to
   better match the other icons' optical center. */
.sidebar-nav>ul>li>a .emoji-icon {
    text-align: center;
    transform: translate(-6px, -5px);
}

/* Color swatches keep their own fixed circular/square size (width:height
   must stay 1:1 or the shape distorts) - match the FA/emoji gutter with
   margin instead of stretching the box width. */
.sidebar-nav>ul>li>a .bucket-icon-color,
.sidebar-nav>ul>li>a .bucket-icon-color-square,
.sidebar-nav>ul>li>a .bucket-icon-color-triangle,
.sidebar-nav>ul>li>a .bucket-icon-color-diamond,
.sidebar-nav>ul>li>a .bucket-icon-color-star,
.sidebar-nav>ul>li>a .bucket-icon-color-arrow,
.sidebar-nav>ul>li>a .bucket-icon-color-arrow-skinny,
.sidebar-nav>ul>li>a .bucket-icon-color-rectangle,
.sidebar-nav>ul>li>a .bucket-icon-color-hexagon,
.sidebar-nav>ul>li>a .bucket-icon-color-pentagon,
.sidebar-nav>ul>li>a .bucket-icon-color-heart,
.sidebar-nav>ul>li>a .bucket-icon-color-plus,
.sidebar-nav>ul>li>a .bucket-icon-color-bucket {
    margin-right: 9px;
    vertical-align: middle;
}

.sidebar-nav ul li ul li a {
    padding: 10px 15px 10px 15px;
}

.sidebar-nav .has-arrow {
    position: relative
}

.sidebar-nav .has-arrow:after {
    position: absolute;
    content: '';
    width: 7px;
    height: 7px;
    border-width: 1px 0 0 1px;
    border-style: solid;
    right: 20px;
    -webkit-transform: rotate(135deg) translate(0, -50%);
    -ms-transform: rotate(135deg) translate(0, -50%);
    -o-transform: rotate(135deg) translate(0, -50%);
    transform: rotate(135deg) translate(0, -50%);
    -webkit-transform-origin: top;
    -ms-transform-origin: top;
    -o-transform-origin: top;
    transform-origin: top;
    top: 15px;
    -webkit-transition: all .3s ease-out;
    -o-transition: all .3s ease-out;
    transition: all .3s ease-out
}

.sidebar-nav .has-arrow[aria-expanded=true]:after,
.sidebar-nav li>.has-arrow.active:after {
    -webkit-transform: rotate(-135deg) translate(0, -50%);
    -ms-transform: rotate(-135deg) translate(0, -50%);
    -o-transform: rotate(-135deg) translate(0, -50%);
    top: 42%;
    width: 7px;
    transform: rotate(-135deg) translate(0, -50%)
}

#left-nav-create-bucket {
    cursor: pointer;
}



/*********************************************************
    TEMPLATE THEME
 *********************************************************/
.skin-default {}

.row {margin-left: 0rem; margin-right: 0rem;}

.hide {
    display: none
}

.editable {
    border-bottom: none !important;
}

.hide-caret:after { content: none!important; }
.hide-caret:before { content: none!important; }

.dropdown-menu .dropdown-item {
    padding: 7px 1.5rem;
}

.dropdown:not(.no-hover):hover .dropdown-menu {
    display: block;
}

/* bootstrap-select (the Add Link bucket picker, etc.) also builds a
   .dropdown wrapper internally, so the sitewide hover-to-open rule
   above was catching it too - its own JS correctly starts closing the
   menu on selection, but the hover rule kept forcing it visibly open
   the whole time the mouse stayed over it. Making it conditional on
   :hover too (an earlier version of this fix) wasn't enough either -
   scrolling the list with the mouse wheel could momentarily drop the
   hover state, which made the menu disappear entirely mid-scroll since
   nothing else was keeping it visible at that instant. Unconditional
   instead: bootstrap-select's own dropdown is always governed purely by
   Bootstrap's .show class, never by hover, matching how it's supposed
   to work. Scoped to bootstrap-select only - every other dropdown in
   the app keeps the sitewide hover-to-open rule above untouched. */
.bootstrap-select.dropdown .dropdown-menu {
    display: none;
}

.bootstrap-select.dropdown .dropdown-menu.show {
    display: block;
}

.dropdown-menu .dropdown-item:hover {
    background-color: var(--fs-info-background);
    color: white;
}

/* Every link on a bucket/favorites/inbox page renders once per view
   style (Table, Cards, Mini, Boxes, etc. - ~13 total) in the same
   markup, all at once - result_change_view() in results-view.blade.php
   then hides the ~12 inactive ones and reveals the active one via
   jQuery on page load. Nothing previously hid the inactive ones by
   default, so on a fresh page load (before that JS runs) every view's
   copy of every link was visible simultaneously - with only a handful
   of real links, that flooded the page with repeats of those same few
   items across all their variants, each rendered in its own
   (uncompacted) size, for as long as JS took to catch up. jQuery's
   .show() still correctly reveals the active one over this. */
.link-display.result-balance-view,
.link-display.result-balanced-view,
.link-display.result-boxes-view,
.link-display.result-card-view,
.link-display.result-headline-view,
.link-display.result-icons-view,
.link-display.result-list-view,
.link-display.result-list2-view,
.link-display.result-masonry-view,
.link-display.result-mini-card-view,
.link-display.result-shadow-card-view,
.link-display.result-table-view,
.link-display.result-vintage-view {
    display: none;
}

.card {
    border: none;
    background-color: #fff;
    background-clip: border-box;
}

.card.hilite {
    background-color: var(--hilite-color, #fafaaf);
    background-clip: border-box;
}

/* On mobile, two color-highlighted cards stacked back-to-back can blend
   into what looks like one card since they share the same background.
   Targets the .link-display WRAPPER (not just the inner .card) since
   that's what actually controls vertical stacking/spacing between
   items — margin on the inner card alone had no visible effect. */
@media (max-width: 767px) {
    .link-display:has(> .card.hilite) {
        margin-top: 0.5em;
    }
}

/* Icons view only: shrink the persistent "Color" highlight so it hugs
   the icon and title instead of filling the whole grid cell. Other
   views keep the full-width highlight. */
.result-icons-view .card.hilite {
    background-color: transparent !important;
}

.result-icons-view .card.hilite .card-body {
    background-color: var(--hilite-color, #fafaaf) !important;
    border-radius: 6px;
    padding: 4px 2% !important;
    width: fit-content;
    margin: 0 auto;
}

/* In dark mode a solid fill of the (usually pastel) hilite color reads
   as a thick, jarring block rather than an accent. Swap the fill for a
   thin colored outline instead - still clearly marks the link as
   colored, just lighter-touch against a dark card. */
body.dark-mode .result-icons-view .card.hilite .card-body {
    background-color: transparent !important;
    border: 1.5px solid var(--hilite-color, #fafaaf);
    padding: 3px calc(2% - 1.5px) !important;
}

/* Every other card view (Mini, Boxes, Shadow, Vanilla, Masonry, etc.) -
   Icons view already gets its own colored-outline treatment above, so
   it's excluded here. Recolors whatever thin border the view's card
   already has (full border, or just border-bottom/border-end) to match
   the highlight color instead of leaving it the default grey. */
body.dark-mode .link-display:not(.result-icons-view) .card.hilite {
    border-color: var(--hilite-color, #fafaaf) !important;
}

/* Belt-and-suspenders for Vanilla/Masonry specifically: their cards use
   Bootstrap's .border utility, which also sets border-color via
   !important, so name these views explicitly to guarantee this wins
   regardless of selector-specificity ordering between the two. */
body.dark-mode .result-list-view .card.hilite,
body.dark-mode .result-masonry-view .card.hilite {
    border-color: var(--hilite-color, #fafaaf) !important;
}

.card-title {
    color:#444444;
    /* Every card view puts this inside a flex row alongside the icon
       (and the ellipsis menu in a sibling flex item) - a flex child's
       default min-width is its content's own natural one-line width,
       not 0, so without this the title never wraps at all and just
       pushes the whole card past the edge of the screen instead
       (visible as horizontal page-scroll on narrow phones/tablets). */
    min-width: 0;
}

.modal-title {
    color:#444444;
}

.card-footer, .modal-footer {
    background-color: inherit;
    border-top: none;
}
.dark-mode .card-footer {
    border-top: 1px solid transparent !important;
}

.line-clamp-2 {
    overflow: hidden;
    display: -webkit-box!important;
    -webkit-box-orient: vertical;
    /* truncate to 2 lines */
    -webkit-line-clamp: 2;
}

.line-clamp-1 {
    overflow: hidden;
    display: -webkit-box!important;
    -webkit-box-orient: vertical;
    /* truncate to 1 line */
    -webkit-line-clamp: 1;
}

/* The whole-card stretched-link overlay (see the card's own title anchor)
   otherwise sits above everything else in the card, including the
   description text below it - so a real mouse hover over the description
   never actually reaches it, silently breaking the hover-to-expand-full-
   description behavior. Lift the description above that overlay so hover
   events land on it directly again. */
.results-show-description {
    position: relative;
    z-index: 3;
}

/* Same stretched-link overlay problem as the description above - tags
   need to be clickable (opens the tag modal) instead of falling
   through to the whole-card link underneath. .tagRow already has
   Bootstrap's position-relative class; it just needs a z-index above
   the overlay's to actually receive the click. */
.tagRow.results-show-tags {
    z-index: 3;
}

.tt-dataset {
    margin-bottom: 20px;
}

.master-backdrop {
    position: fixed;
    top: 0;
    right: 0;
    bottom: 0;
    left: 0;
    z-index: 1060;
    background-color: #EAE7E6
}

.master-backdrop.fade {
    opacity: 0
}

.master-backdrop.show {
    opacity: 0.2
}

.card-background-shadow {
    background-color: #fbfbfb;
}


/*********************************************************
    HEADER
 *********************************************************/
.topbar {
    position: fixed;
    z-index: 50;
    width: 100%;
    background-color: #fff;
    max-height: 4.5rem;
}

@media (min-width:992px) {
    .topbar {padding-left: var(--fs-left-navigation-width); }
}

.input-group > .twitter-typeahead {
    flex: 1 1 auto;
    width: auto;
}

@media (max-width:991px) {
    #fullsort_search {padding-bottom: 0.5rem; padding-top: 0.5rem;}
    #fullsort_search_block {width: 100%;}
}
@media (min-width:992px) {
    #fullsort_search_block {width: 50%!important;}

    /* The 50% above assumes a sidebar is eating the other half of the
       topbar's width - Public Sort's topbar has no sidebar, so that
       same 50% left a large empty gap of bare background between the
       search box and the logo. Grow the search box to fill that gap
       instead, and stop the logo's own wrapper (normally flex-grow-1
       so a sidebar-having page's shorter search box doesn't leave the
       logo output stranded mid-row) from competing for the same
       space, so the logo keeps its natural size on the right. */
    .topbar-transparent #fullsort_search_block {width: auto!important; flex: 0 1 500px; max-width: 500px;}
}

#quick_search_string, #fullsort_search {
    height: 26.5px;
}


.twitter-typeahead .tt-menu .tt-suggestion {
    padding: 0.5rem 0.75rem 0.5rem 0.75rem;
}

.tt-suggestion:hover {
    background-color: var(--fs-info-background) !important;
}

/*********************************************************
    PAGE BODY
 *********************************************************/
.page-wrapper {
    padding-top: 4.5rem;
}

@media (min-width:992px) {
    .page-wrapper {
        margin-left: var(--fs-left-navigation-width)
    }
}

/* Mini and Boxes card views: split into N single-column lists side by
   side (see setupColumnSortable in results-view.blade.php) instead of
   one shared flex-wrap grid - jQuery UI Sortable handles a genuine
   single column correctly, unlike a wrapped multi-column row. Gap
   matches Bootstrap's usual 1.5rem row gutter so the grid looks the
   same as before. */
#split-columns {
    gap: 0 1.5rem;
}

.split-column {
    flex: 1 1 0;
    min-width: 0;
}

/* The item's own col-lg/col-md/col-sm classes set a fixed percentage
   width (e.g. col-lg-4 = width:33.3333%) meant for a 3-wide flex row -
   inside a single-item-wide column wrapper that leaves the card only a
   third as wide as its column, with a lot of blank space beside it.
   Override back to filling the column completely. */
.split-column .result-mini-card-view,
.split-column .result-boxes-view,
.split-column .result-list-view,
.split-column .result-balanced-view,
.split-column .result-balance-view {
    width: 100%;
    max-width: 100%;
    flex: none;
}

.link-sortable-placeholder {
    border: 2px dashed #aaa;
    height: 90px;
    width: 90px;
}

.bucket-sortable-placeholder {
    border: 2px dashed #aaa;
    height: 40px;
}

/* ============================================================
   LOCKED — hover/tap tint (day + dark mode). Confirmed final by
   user. DO NOT modify any rule in this block without asking the
   user first, even to "improve" or "simplify" it. See memory:
   feedback-hover-colors-locked.md
   ============================================================ */

/* card-overlay div disabled everywhere: hover/tap tint is applied directly
   to the card's own background-color instead of a layered semi-transparent
   div, so text/icons/favicon stay at full brightness (not dimmed). */
.card-overlay { display: none !important; }

/* Fix intermittent "second tap does nothing" on mobile: rapid taps on the
   same spot can be interpreted by the browser as a double-tap-to-zoom
   gesture, silently swallowing the second tap's click event before it
   ever reaches JS. touch-action:manipulation disables that disambiguation
   delay so consecutive taps register immediately and reliably. */
.link-display .card,
.link-display .list2-item,
.link-display .vintage-row,
.link-display .card a,
.link-display .list2-item a,
.link-display .vintage-row a {
    touch-action: manipulation;
}


/* Controls column sits above card content so ellipsis/checkbox stay visible.
   pointer-events:none on the column itself means blank padding within it
   doesn't block clicks meant for the card's stretched-link underneath —
   only the actual interactive children (re-enabled below) capture clicks.
   Matches both col-5 (Vanilla/Masonry's actions column before the Mini/
   Masonry title-widening change) and col-3 (Mini/Masonry after it) - the
   col-5-only version of this selector silently broke Mini/Masonry's
   ellipsis button when that column was narrowed. */
.link-display .card .col-5.position-relative,
.link-display .card .col-3.position-relative,
.link-display .list2-item .list2-actions { position: relative; z-index: 3; pointer-events: none; }
.link-display .card .col-5.position-relative > *,
.link-display .card .col-3.position-relative > *,
.link-display .list2-item .list2-actions > * { pointer-events: auto; }

/* When a card's menu is open (hover or touch-active), its controls must win
   the stacking fight against the NEXT card's controls, which share the same
   z-index and would otherwise paint over the open dropdown (same DOM tier,
   ties break by DOM order). Bump the active one way above everything else. */
.link-display .card:hover .col-5.position-relative,
.link-display .card:hover .col-3.position-relative,
.link-display .list2-item:hover .list2-actions,
.link-display .card.card-touch-active .col-5.position-relative,
.link-display .card.card-touch-active .col-3.position-relative,
.link-display .list2-item.card-touch-active .list2-actions { z-index: 1000; }

/* Hover/tap: light grey tint in day mode — DO NOT CHANGE, see memory */
.link-display .card:hover,
.link-display .list2-item:hover,
.link-display .vintage-row:hover,
.link-display .card.card-touch-active,
.link-display .list2-item.card-touch-active,
.link-display .vintage-row.card-touch-active {
    background-color: #f2f2f2 !important;
    border-color: rgba(0,0,0,0.5) !important;
}

/* Hover/tap: black tint in dark mode — covers every view type (card, list2, vintage) */
body.dark-mode .link-display .card:hover,
body.dark-mode .link-display .list2-item:hover,
body.dark-mode .link-display .vintage-row:hover,
body.dark-mode .link-display .card.card-touch-active,
body.dark-mode .link-display .list2-item.card-touch-active,
body.dark-mode .link-display .vintage-row.card-touch-active {
    background: #262626 !important;
    background-color: #262626 !important;
    border-color: #777 !important;
    box-shadow: inset 0 0 0 1px #777 !important;
}

/* ============================================================
   LOCKED — checkbox vertical position, confirmed exact by user
   ("perfect!!!!"). DO NOT change vertical-align/top without
   asking the user first, even for unrelated requests that touch
   nearby styles. See memory: feedback-hover-colors-locked.md
   ============================================================ */
.linkCheckbox {
    vertical-align: middle;
    position: relative;
    top: -3px;
}

/* Visibility for a CHECKED box must never depend only on JS mouseenter/
   mouseleave timing (app.blade.php) - that leaves a real window where a
   fast click can register as checked before the enter handler has set
   opacity, or a resize/re-render can leave it stuck invisible despite
   being checked. This guarantees a checked box is always visible
   regardless of hover state or event timing, while unchecked boxes still
   rely on hover/JS to stay hidden until interacted with. */
.linkCheckbox:checked {
    opacity: 1 !important;
}
/* ============================================================
   END LOCKED checkbox position
   ============================================================ */

/* Bulk-delete "Are you sure?" confirmation (delSelected in app.blade.php) -
   cherry red confirm button, white text, 10% darker on hover. */
.delete-confirm-swal .swal2-confirm {
    color: #fff !important;
}

.delete-confirm-swal .swal2-confirm:hover {
    background-color: #b01b34 !important;
}

/* Curated buckets admin "Are you sure?" confirmations - cherry red Cancel
   button, white text, 10% darker on hover. */
.curation-confirm-swal .swal2-cancel {
    color: #fff !important;
}

.curation-confirm-swal .swal2-cancel:hover {
    background-color: #b01b34 !important;
}

/* Every SweetAlert "Cancel" button sitewide (the public/private bucket
   lock toggle's confirmation, and any other "Are you sure?" dialog that
   didn't get its own scoped rule above) - cherry red, white text, 10%
   darker on hover. Unscoped on purpose so this covers every current and
   future swal cancel button without hunting each one down individually;
   the more specific .curation-confirm-swal rule above still applies the
   same colors, just redundantly now.
   EXCEPT .delete-confirm-swal: that dialog's Delete/Confirm button is
   already the cherry red destructive action (see above), so its Cancel
   stays the normal safe/info color - both buttons being cherry red on
   the same dialog was confusing about which one actually deletes. */
.swal2-cancel {
    background-color: #C41E3A !important;
    color: #fff !important;
}

.swal2-cancel:hover {
    background-color: #b01b34 !important;
}

.delete-confirm-swal .swal2-cancel {
    background-color: var(--fs-info-background) !important;
}

.delete-confirm-swal .swal2-cancel:hover {
    background-color: var(--fs-info-hover) !important;
}

/* Duplicate Detector's per-link delete buttons - cherry red, white
   text, 10% darker on hover. Scoped by its own class rather than the
   sitewide .btn-danger. */
.duplicate-delete-btn {
    background-color: #C41E3A !important;
    border-color: #C41E3A !important;
    color: #fff !important;
}

.duplicate-delete-btn:hover {
    background-color: #b01b34 !important;
    border-color: #b01b34 !important;
}

/* Tag modal delete buttons - same cherry red family but 15% lighter
   than the Duplicate Detector's, with hover kept the same 10%-darker-
   than-base relationship the original color had. */
.tag-delete {
    background-color: #9A3042 !important;
    border-color: #9A3042 !important;
    color: #fff !important;
}

.tag-delete:hover {
    background-color: #8B2B3B !important;
    border-color: #8B2B3B !important;
}

/* Tag modal: each tag in its own small bordered cell (25% of the
   original full-width input) with the delete button sitting just
   outside the cell instead of sharing its border. */
.tag-row {
    display: flex;
    align-items: center;
    margin-bottom: 0.55rem;
}

.tag-row-cell {
    display: flex;
    align-items: center;
    border: 1px solid #dee2e6;
    border-radius: 0;
    padding: 0.275rem 0.6rem;
    width: 207px;
}

.tag-row input.tag-row-input {
    border: none;
    background: transparent;
    padding: 0.25rem 0;
    width: 100%;
    min-width: 0;
}

.tag-row input.tag-row-input:focus {
    outline: none;
    box-shadow: none;
}

.tag-row .tag-delete {
    width: 31px;
    height: 31px;
    padding: 0;
    flex: 0 0 auto;
    margin-left: 0.5rem;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-radius: 4px;
    font-size: 0.9rem;
}

/* Change Password modal: same bordered-cell look as the tag modal
   inputs, full width instead of a fixed 180px. */
.password-modal-cell {
    display: flex;
    align-items: center;
    border: 1px solid #dee2e6;
    border-radius: 6px;
    padding: 0.25rem 0.6rem;
    width: 100%;
}

.password-modal-input {
    border: none;
    background: transparent;
    padding: 0.25rem 0;
    width: 100%;
    min-width: 0;
}

.password-modal-input:focus {
    outline: none;
    box-shadow: none;
}

/* Bucket Description and Add Note modals: a real bordered box instead
   of Bootstrap's .form-material underline-only look, matching the
   bordered-cell style used elsewhere (tags, change password). */
.bordered-cell-textarea {
    border: 1px solid #eef0f2 !important;
    border-radius: 6px !important;
    background-color: transparent !important;
    background-image: none !important;
    padding: 0.5rem 0.75rem !important;
}

.profile-pic-update-btn {
    font-size: 0.7rem;
    padding: 0.15rem 0.5rem;
}

.bordered-cell-textarea:focus {
    border-color: var(--fs-info-background) !important;
    box-shadow: none !important;
    background-image: none !important;
}

/* Edit Link modal's Delete button (#link-delete, add-link.blade.php) -
   same cherry red / white / 10%-darker-hover treatment, scoped to this
   specific button by id rather than .btn-danger so the other ~26
   .btn-danger buttons sitewide are untouched. */
#link-delete {
    background-color: #C41E3A !important;
    border-color: #C41E3A !important;
    color: #fff !important;
}

#link-delete:hover {
    background-color: #b01b34 !important;
    border-color: #b01b34 !important;
}

/* Bootstrap's checkbox has its own white box background by default —
   make it transparent so it blends into the black card instead of
   standing out as a separate light patch. */
body.dark-mode .link-display .card:hover .linkCheckbox,
body.dark-mode .link-display .list2-item:hover .linkCheckbox,
body.dark-mode .link-display .vintage-row:hover .linkCheckbox,
body.dark-mode .link-display .card.card-touch-active .linkCheckbox,
body.dark-mode .link-display .list2-item.card-touch-active .linkCheckbox,
body.dark-mode .link-display .vintage-row.card-touch-active .linkCheckbox {
    background-color: #262626 !important;
    border-color: #777 !important;
}

/* Ellipsis button: ensure no stray background of its own */
body.dark-mode .link-display .card:hover .dropdown-toggle,
body.dark-mode .link-display .list2-item:hover .dropdown-toggle,
body.dark-mode .link-display .vintage-row:hover .dropdown-toggle,
body.dark-mode .link-display .card.card-touch-active .dropdown-toggle,
body.dark-mode .link-display .list2-item.card-touch-active .dropdown-toggle,
body.dark-mode .link-display .vintage-row.card-touch-active .dropdown-toggle {
    background-color: transparent !important;
}

/* Force EVERY descendant within a hovered/touch-active card transparent.
   Root cause of the "patchy" look: a blanket dark-mode rule
   (".dark-mode *:not(...)") gives nearly every element its own #343434
   background, including the Bootstrap .row wrapping the title/controls.
   A wildcard here catches all of them, not just the few container
   classes we happened to name before. More specific overrides below
   (checkbox, dropdown-toggle) still win due to higher specificity. */
body.dark-mode .link-display .card:hover *,
body.dark-mode .link-display .card.card-touch-active *,
body.dark-mode .link-display .list2-item:hover *,
body.dark-mode .link-display .list2-item.card-touch-active *,
body.dark-mode .link-display .vintage-row:hover *,
body.dark-mode .link-display .vintage-row.card-touch-active * {
    background-color: transparent !important;
}
/* ============================================================
   END LOCKED hover/tap tint block
   ============================================================ */

/* Icons view only: shrink hover/tap highlight so it hugs the icon
   and title (plus a small margin) instead of filling the whole
   grid cell. Cancels the full-card tint above and re-applies the
   same colors to a fit-content box around the card body. Other
   views are untouched. */
.result-icons-view .card:hover,
.result-icons-view .card.card-touch-active {
    background-color: transparent !important;
    border-color: transparent !important;
}

.result-icons-view .card:hover .card-body,
.result-icons-view .card.card-touch-active .card-body {
    background-color: #f2f2f2 !important;
    border-radius: 6px;
    padding: 4px 2% !important;
    width: fit-content;
    margin: 0 auto;
}

body.dark-mode .result-icons-view .card:hover,
body.dark-mode .result-icons-view .card.card-touch-active {
    background: transparent !important;
    background-color: transparent !important;
    border-color: transparent !important;
    box-shadow: none !important;
}

body.dark-mode .result-icons-view .card:hover .card-body,
body.dark-mode .result-icons-view .card.card-touch-active .card-body {
    background: #262626 !important;
    background-color: #262626 !important;
    border-radius: 6px;
    padding: 4px 2% !important;
    width: fit-content;
    margin: 0 auto;
}

/* The "..." controls box sits invisibly (opacity:0) at the very top of
   every icon-view card, positioned absolute so it's removed from flow -
   but the blanket dark-mode rule still gives it a solid #343434
   background, which silently covers the top of the icon underneath in
   dark mode (only "uncovered" on hover, when a different rule makes
   every descendant transparent). transparent background alone wasn't
   enough to stop it visually intruding on the icon - go further and
   fully hide it from rendering except while actually hovered/touched,
   so nothing about it (background, border, any stray pixel) can ever
   sit on top of the icon underneath. */
body.dark-mode .result-icons-view .card .position-absolute.text-end,
body.dark-mode .result-icons-view .card .position-absolute.text-center {
    visibility: hidden;
    background-color: transparent !important;
}

body.dark-mode .result-icons-view .card:hover .position-absolute.text-end,
body.dark-mode .result-icons-view .card:hover .position-absolute.text-center,
body.dark-mode .result-icons-view .card.card-touch-active .position-absolute.text-end,
body.dark-mode .result-icons-view .card.card-touch-active .position-absolute.text-center {
    visibility: visible;
}

/* Icons view checkbox/ellipsis overlay: on phone and tablet it often lands
   in an inconsistent spot on top of the icon - it's position:absolute with
   no offset, so it falls back to wherever it would have sat in normal flow,
   which isn't reliable. Anchor it explicitly just outside the icon's
   top-right corner instead. left uses 50% + half the icon's width (40px/2)
   so it stays correct regardless of the card's actual pixel width (icon is
   centered in the card via mx-auto). Desktop/hover behavior is untouched. */
@media (max-width: 991px) {
    .result-icons-view .card-body .col-12.position-absolute.text-center {
        top: 2px !important;
        left: calc(50% + 14px) !important;
        right: auto !important;
        width: auto !important;
        text-align: left !important;
    }
}

/* ============================================================
   LOCKED — dropdown menu appearance inside hovered/touch-active
   cards (dark mode). Confirmed final by user. DO NOT modify
   without asking the user first. See memory:
   feedback-hover-colors-locked.md
   ============================================================ */

/* Exception to the locked wildcard above: the open dropdown menu itself
   must stay opaque even though it's a descendant of a hovered/touch-active
   card — otherwise card text bleeds through it. Higher specificity (6
   identifiers) than the wildcard (5) so this wins. */
body.dark-mode .link-display .card:hover .dropdown-menu,
body.dark-mode .link-display .card.card-touch-active .dropdown-menu,
body.dark-mode .link-display .list2-item:hover .dropdown-menu,
body.dark-mode .link-display .list2-item.card-touch-active .dropdown-menu,
body.dark-mode .link-display .vintage-row:hover .dropdown-menu,
body.dark-mode .link-display .vintage-row.card-touch-active .dropdown-menu,
body.dark-mode .table-row-item:hover .dropdown-menu {
    background-color: #111 !important;
}

/* Same exception for individual item hover — the wildcard was also killing
   this highlight for dropdown menus opened from inside a hovered card. */
body.dark-mode .link-display .card:hover .dropdown-item:hover,
body.dark-mode .link-display .card.card-touch-active .dropdown-item:hover,
body.dark-mode .link-display .list2-item:hover .dropdown-item:hover,
body.dark-mode .link-display .list2-item.card-touch-active .dropdown-item:hover,
body.dark-mode .link-display .vintage-row:hover .dropdown-item:hover,
body.dark-mode .link-display .vintage-row.card-touch-active .dropdown-item:hover,
body.dark-mode .link-display .card:hover .dropdown-item:hover *,
body.dark-mode .link-display .card.card-touch-active .dropdown-item:hover *,
body.dark-mode .link-display .list2-item:hover .dropdown-item:hover *,
body.dark-mode .link-display .list2-item.card-touch-active .dropdown-item:hover *,
body.dark-mode .link-display .vintage-row:hover .dropdown-item:hover *,
body.dark-mode .link-display .vintage-row.card-touch-active .dropdown-item:hover *,
body.dark-mode .table-row-item:hover .dropdown-item:hover,
body.dark-mode .table-row-item:hover .dropdown-item:hover * {
    background-color: #3a3a3a !important;
    color: #fff !important;
}
/* ============================================================
   END LOCKED dropdown-in-hovered-card block
   ============================================================ */

/* Dark mode: dropdown menus match modal background */
.dark-mode .dropdown-menu { background-color: #111 !important; border-color: #333 !important; }
.dark-mode .dropdown-menu * { color: #ddd !important; background-color: transparent !important; border-color: rgba(255,255,255,0.2) !important; }
.dark-mode .dropdown-menu .dropdown-item:hover,
.dark-mode .dropdown-menu .dropdown-item:hover * { background-color: #3a3a3a !important; color: #fff !important; }
.dark-mode .dropdown-menu .dropdown-divider {
    height: 0 !important;
    background-color: transparent !important;
    border: none !important;
    border-top: 1px solid rgba(255,255,255,0.12) !important;
    margin: 4px 0 !important;
    padding: 0 !important;
    opacity: 1 !important;
}

/* Plain view: hide inner card border. Vanilla (.result-list-view) used
   to be included here too, but that actually hid its grid lines
   (border-end/border-bottom) entirely, contradicting this comment's
   own "keep grid lines only" intent - removed so Vanilla's border
   shows again. */
.result-headline-view .card { border-color: transparent !important; }
.dark-mode .result-headline-view .card { border-color: transparent !important; }

/*********************************************************
    FOOTER
 *********************************************************/
.footer {
    bottom: 0;
    left: 0px;
    right: 0;
}



/* A Public Sort page whose wallpaper is an image (.ppg-image-bg on <body>,
   set from public-profile.blade.php): the footer sits straight on the
   picture, so it goes white like it already does in dark mode. The
   light shadow keeps it readable over a bright part of the image. */
.ppg-image-bg .footer,
.ppg-image-bg .footer a {
    color: #fff !important;
    text-shadow: 0 1px 3px rgba(0, 0, 0, 0.6);
}

/*********************************************************
    THEME PRELOADER
 *********************************************************/
.preloader {
    width: 100%;
    height: 100%;
    top: 0px;
    position: fixed;
    z-index: 99999;
    background: #fff
}

.preloader .cssload-speeding-wheel {
    position: absolute;
    top: calc(50% - 3.5px);
    left: calc(50% - 3.5px)
}

.loader,
.loader__figure {
    position: absolute;
    top: 50%;
    left: 50%;
    -webkit-transform: translate(-50%, -50%);
    -moz-transform: translate(-50%, -50%);
    -ms-transform: translate(-50%, -50%);
    -o-transform: translate(-50%, -50%);
    transform: translate(-50%, -50%)
}

.loader {
    overflow: visible;
    padding-top: 2em;
    height: 0;
    width: 2em
}

.loader__figure {
    height: 0;
    width: 0;
    -webkit-box-sizing: border-box;
    box-sizing: border-box;
    border: 0 solid #1976d2;
    border-radius: 50%;
    -webkit-animation: loader-figure 1.15s infinite cubic-bezier(0.215, 0.61, 0.355, 1);
    -moz-animation: loader-figure 1.15s infinite cubic-bezier(0.215, 0.61, 0.355, 1);
    animation: loader-figure 1.15s infinite cubic-bezier(0.215, 0.61, 0.355, 1)
}

.loader__label {
    float: left;
    margin-left: 50%;
    -webkit-transform: translateX(-50%);
    -moz-transform: translateX(-50%);
    -ms-transform: translateX(-50%);
    -o-transform: translateX(-50%);
    transform: translateX(-50%);
    margin: 0.5em 0 0 50%;
    font-size: 0.875em;
    letter-spacing: 0.1em;
    line-height: 1.5em;
    color: #1976d2;
    white-space: nowrap;
    -webkit-animation: loader-label 1.15s infinite cubic-bezier(0.215, 0.61, 0.355, 1);
    -moz-animation: loader-label 1.15s infinite cubic-bezier(0.215, 0.61, 0.355, 1);
    animation: loader-label 1.15s infinite cubic-bezier(0.215, 0.61, 0.355, 1)
}

@-webkit-keyframes loader-figure {
    0% {
        height: 0;
        width: 0;
        background-color: #1976d2
    }
    29% {
        background-color: #1976d2
    }
    30% {
        height: 2em;
        width: 2em;
        background-color: transparent;
        border-width: 1em;
        opacity: 1
    }
    to {
        height: 2em;
        width: 2em;
        border-width: 0;
        opacity: 0;
        background-color: transparent
    }
}

@-moz-keyframes loader-figure {
    0% {
        height: 0;
        width: 0;
        background-color: #1976d2
    }
    29% {
        background-color: #1976d2
    }
    30% {
        height: 2em;
        width: 2em;
        background-color: transparent;
        border-width: 1em;
        opacity: 1
    }
    to {
        height: 2em;
        width: 2em;
        border-width: 0;
        opacity: 0;
        background-color: transparent
    }
}

@keyframes loader-figure {
    0% {
        height: 0;
        width: 0;
        background-color: #1976d2
    }
    29% {
        background-color: #1976d2
    }
    30% {
        height: 2em;
        width: 2em;
        background-color: transparent;
        border-width: 1em;
        opacity: 1
    }
    to {
        height: 2em;
        width: 2em;
        border-width: 0;
        opacity: 0;
        background-color: transparent
    }
}

@-webkit-keyframes loader-label {
    0% {
        opacity: 0.25
    }
    30% {
        opacity: 1
    }
    to {
        opacity: 0.25
    }
}

@-moz-keyframes loader-label {
    0% {
        opacity: 0.25
    }
    30% {
        opacity: 1
    }
    to {
        opacity: 0.25
    }
}

@keyframes loader-label {
    0% {
        opacity: 0.25
    }
    30% {
        opacity: 1
    }
    to {
        opacity: 0.25
    }
}


/*********************************************************
    LOGIN
 *********************************************************/
.login-box {
    width: 400px;
    margin: 0 auto;
}

#recoverform {
    display: none; }



/*********************************************************
    BUTTONS
 *********************************************************/
@media (min-width: 992px) and (max-width: 1226px) {
    .btn-custom {
        display: block;
        font-size: 0.875rem;
    }
}

@media (min-width: 1226px) {
    .btn-custom {
        font-size: 0.875rem;
    }
}

.topView {
    border: none !important;
    outline: none !important;
    box-shadow: none !important;
}


.btn-block {
    display: block;
    width: 100%
}

.btn-primary, .btn-primary:active {
    color: var(--fs-primary-text)!important;
    background-color: var(--fs-primary-background)!important;
    border-color: var(--fs-primary-background)!important;
}

.btn-primary:hover {
    color: var(--fs-primary-text);
    background-color: var(--fs-primary-hover);
    border-color: var(--fs-primary-hover)
}

.btn-primary.focus,
.btn-primary:focus {
    -webkit-box-shadow: 0 0 0 0.2rem var(--fs-primary-focus);
    box-shadow: 0 0 0 0.2rem var(--fs-primary-focus);
}

.btn-primary.disabled,
.btn-primary:disabled {
    color: var(--fs-primary-text);
    background-color: var(--fs-primary-disabled);
    border-color: var(--fs-primary-disabled)
}

.btn-secondary {
    color: var(--fs-secondary-text);
    background-color: var(--fs-secondary-background);
    border-color: var(--fs-secondary-background);
}

.btn-secondary:hover {
    color: var(--fs-secondary-text);
    background-color: var(--fs-secondary-hover);
    border-color: var(--fs-secondary-hover);
}

.btn-secondary.focus,
.btn-secondary:focus {
    -webkit-box-shadow: 0 0 0 0.2rem var(--fs-secondary-focus);
    box-shadow: 0 0 0 0.2rem var(--fs-secondary-focus);
}

.btn-secondary.disabled,
.btn-secondary:disabled {
    color: var(--fs-secondary-text);
    background-color: var(--fs-secondary-disabled);
    border-color: var(--fs-secondary-disabled);
}

.btn-info {
    color: var(--fs-info-text);
    background-color: var(--fs-info-background);
    border-color: var(--fs-info-background)
}

.btn-info:hover {
    color: var(--fs-info-text);
    background-color: var(--fs-info-hover);
    border-color: var(--fs-info-hover);
}

.btn-info.focus,
.btn-info:focus {
    -webkit-box-shadow: 0 0 0 0.2rem var(--fs-info-focus);
    box-shadow: 0 0 0 0.2rem var(--fs-info-focus);
}

/* Bootstrap's own default active/open-dropdown color (a bright cyan, not
   our custom var) otherwise leaks through only on this state - e.g. the
   curated gallery "Bucket Options" button reverting to stock Bootstrap
   cyan the moment its dropdown opens, while every other state on that
   same button correctly follows the site's (possibly user-customized)
   info color. */
.btn-info:active,
.btn-info.active,
.btn-info.show,
.show > .btn-info.dropdown-toggle {
    color: var(--fs-info-text) !important;
    background-color: var(--fs-info-hover) !important;
    border-color: var(--fs-info-hover) !important;
}

.btn-info.disabled,
.btn-info:disabled {
    color: var(--fs-info-text);
    background-color: var(--fs-info-disabled);
    border-color: var(--fs-info-disabled)
}

.btn-danger {
    color: var(--fs-danger-text);
    background-color: var(--fs-danger-background);
    border-color: var(--fs-danger-background);
}

.btn-danger:hover {
    color: var(--fs-danger-text);
    background-color: var(--fs-danger-hover);
    border-color: var(--fs-danger-hover);
}

.btn-danger.focus,
.btn-danger:focus {
    -webkit-box-shadow: 0 0 0 0.2rem var(--fs-danger-focus);
    box-shadow: 0 0 0 0.2rem var(--fs-danger-focus);
}

.btn-danger.disabled,
.btn-danger:disabled {
    color: var(--fs-danger-text);
    background-color: var(--fs-danger-disabled);
    border-color: var(--fs-danger-disabled);
}

.btn-facebook, .btn-facebook:hover {
    color: #fff;
    background-color: #3b5998
}


.btn-twitter, .btn-twitter:hover {
    color: #fff;
    background-color: #55acee
}

.btn-linkedin, .btn-linkedin:hover {
    color: #fff;
    background-color: #007bb6
}

.btn-googleplus, .btn-googleplus:hover {
    color: #fff;
    background-color: #dd4b39
}


/*********************************************************
    VANILLA VIEW (result-list-view)
 *********************************************************/
.result-list-view .linkName {
    font-size: 14.3px;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* Phones only - title was truncating sooner than it needed to since
   the icon/ellipsis columns eat proportionally more of a narrow
   screen's width than they do on desktop/tablet. Give the title more
   of that room back, same technique used for Boxes. */
@media (max-width: 767px) {
    .result-list-view .col-7 {
        flex: 0 0 62.5%;
        max-width: 62.5%;
    }

    .result-list-view .col-5 {
        flex: 0 0 37.5%;
        max-width: 37.5%;
    }
}

.result-list-view .results-show-description .card-text {
    font-size: 13.2px;
}

/* Cards varied in height depending on whether a link had a description
   (and how many lines it clamped to) or a long title that wrapped -
   force a consistent minimum height and single-line title so every
   card in the list reads the same size regardless of content length. */
.result-list-view .card {
    min-height: 110px;
}

/* Cards were flush against each other (m-0, only a border line as a
   divider) and Bootstrap's py-3 padding made each row taller than
   needed - Bootstrap utility classes carry !important, so this needs
   it too to actually win. Shrinks padding and adds a small 3px gap
   between consecutive cards. */
.result-list-view .card {
    padding-top: 3px !important;
    padding-bottom: 3px !important;
    margin-bottom: 3px !important;
}

/* For links near the end of any view, the "..." menu (Favorite,
   Share, Color, Edit, Top, Bottom, Delete, Tags) can run past the
   bottom of the screen with no way to reach the last items - it uses
   fixed/static positioning (not Bootstrap's normal auto-flip-upward
   behavior) for a good reason (see git history: auto-flip used to
   randomly push the menu off the right edge on mobile instead).
   Simplest fix: reserve enough blank space below the last link for
   the tallest possible menu to always fit on open. */
#sortable_links,
#curated_links {
    padding-bottom: 120px;
}

/*********************************************************
    MASONRY VIEW (result-masonry-view)
 *********************************************************/
/* #sortable_links/#curated_links is one shared .row container reused by
   every view (individual .link-display items just toggle show/hide per
   active view) - CSS multi-column layout needs the container itself to
   not be a flex container, so this only applies when the JS view
   switcher has set data-view="masonry" on it, leaving every other view's
   shared-container layout untouched. */
#sortable_links[data-view="masonry"],
#curated_links[data-view="masonry"] {
    display: block !important;
    column-count: 1;
    column-gap: 1rem;
    padding-left: 5px;
    padding-right: 5px;
}

@media (min-width: 576px) {
    #sortable_links[data-view="masonry"],
    #curated_links[data-view="masonry"] {
        column-count: 2;
    }
}

/* At desktop width, column count follows the same 3-vs-4 preference
   as Mini/Boxes view (ellipsis menu) instead of being hardcoded -
   result_change_view() sets --masonry-columns from the user's actual
   saved setting. Falls back to the original 3/4 defaults if that
   variable is never set for some reason. */
@media (min-width: 992px) {
    #sortable_links[data-view="masonry"],
    #curated_links[data-view="masonry"] {
        column-count: var(--masonry-columns, 3);
    }
}

@media (min-width: 1400px) {
    #sortable_links[data-view="masonry"],
    #curated_links[data-view="masonry"] {
        column-count: var(--masonry-columns, 4);
    }
}

/* While the Start Page is showing, neither list belongs on the page. Bricks' !important
   above beats the inline hide the Start Page applies to the list, and the Retro list sits
   in its own box that the Start Page never hides - so with either as the chosen view its
   links showed under the Start Page boxes. */
body.start-boxes-mode #sortable_links,
body.start-boxes-mode #curated_links,
body.start-boxes-mode #vintage-bucket-list {
    display: none !important;
}

.result-masonry-view {
    display: inline-block;
    width: 100%;
    break-inside: avoid;
    -webkit-column-break-inside: avoid;
    margin-bottom: 1rem;
}

/* At certain widths (tablet held landscape, where this view's col-md-6
   drops it into a narrower 2-column layout) the ellipsis/checkbox/drag-
   handle icons - each their own d-inline-block sibling inside a narrow
   col-3 - wrap onto separate lines instead of staying in a row. Desktop
   and phone already have enough room and never wrap here anyway, so this
   is a no-op for them. Same fix applied to Mini/Balance, which share the
   identical col-3 controls markup and hit the same issue on tablet
   landscape (col-lg-N / col-md-6). */
.result-masonry-view .col-3,
.result-mini-card-view .col-3,
.result-balanced-view .col-3,
.result-balance-view .col-3 {
    white-space: nowrap;
}

/* Bricks/Mini/Balance: with wrapping now prevented, the nowrap
   controls group is wide enough to spill past the card's right edge at
   the narrower tablet-landscape column width. padding-right doesn't help
   here since overflowing nowrap content spills past padding regardless -
   use a transform instead, which actually shifts the rendered box (and
   its overflow) rather than reserving unused space.
   Scoped to landscape orientation in the tablet width range only - this
   was previously unconditional and wrongly shifted the controls in
   portrait/vertical view too, where there's no overflow to begin with. */
@media (min-width: 768px) and (max-width: 1199.98px) and (orientation: landscape) {
    .result-mini-card-view .col-3,
    .result-balanced-view .col-3,
    .result-balance-view .col-3 {
        transform: translateX(-1.5rem);
    }

    /* Bricks/Masonry's card is narrower than Mini/Balance at this
       breakpoint, so the same -1.5rem shift left too big a gap before
       the right edge - a smaller shift here. Also pulled up so the
       controls sit flush against the top-right corner instead of
       floating mid-card. */
    .result-masonry-view .col-3 {
        transform: translate(-0.75rem, -1.3rem);
    }
}

/* Bricks/Masonry in portrait/vertical tablet view - no horizontal
   overflow issue here (unlike landscape), but pull the controls up
   and right so they hug the top-right corner the same way as
   landscape, for a consistent look between orientations. */
@media (min-width: 768px) and (max-width: 1199.98px) and (orientation: portrait) {
    .result-masonry-view .col-3 {
        transform: translate(1.1rem, -1.3rem);
    }
}

.result-masonry-view .linkName {
    font-size: 14px;
}

.result-masonry-view .results-show-description .card-text {
    font-size: 13px;
}

/* News Feed modal (Start Page widget) */
.news-feed-list {
    display: flex;
    flex-direction: column;
}

.news-feed-item {
    display: flex;
    flex-direction: column;
    gap: 4px;
    padding: 12px 4px;
    border-bottom: 1px solid #eaecef;
    text-decoration: none;
    color: inherit;
    /* iOS Safari's default tap-highlight flash renders as a tight grey
       box around just the text content on this flex layout instead of
       the whole row - the site-wide reset on <body> isn't reaching
       content injected into the modal at runtime. Override directly. */
    -webkit-tap-highlight-color: transparent;
}

.news-feed-item-title,
.news-feed-item-source {
    -webkit-tap-highlight-color: transparent;
}

.news-feed-item:last-child {
    border-bottom: none;
}

.news-feed-item:hover {
    background-color: #f7f7f7;
    text-decoration: none;
}

.news-feed-item-title {
    font-size: 14px;
    font-weight: 600;
    color: #1a1d23;
    line-height: 1.4;
}

.news-feed-item-source {
    font-size: 11px;
    font-weight: 500;
    color: #8a8f9a;
    text-transform: uppercase;
    letter-spacing: 0.03em;
}

/* #modal-news-feed prefix (an ID) guarantees these beat the blanket
   dark-mode modal rule, which forces #111 backgrounds on nearly
   everything inside any modal and isn't aware of this new content. */
#modal-news-feed.dark-mode .news-feed-item,
.dark-mode #modal-news-feed .news-feed-item {
    border-bottom-color: rgba(255,255,255,0.12);
}

.dark-mode #modal-news-feed .news-feed-item:hover {
    background-color: #2a2a2a !important;
}

/* Same root cause fixed before elsewhere: the blanket dark-mode modal
   rule gives the title/source spans their own #111 background,
   painting over the row's hover color in patches instead of one
   solid fill. Force them transparent while their row is hovered. */
.dark-mode #modal-news-feed .news-feed-item:hover * {
    background-color: transparent !important;
}

.dark-mode #modal-news-feed .news-feed-item-title {
    color: #e8eaf0 !important;
}

.dark-mode #modal-news-feed .news-feed-item-source {
    color: #8a8f9a !important;
}

/*********************************************************
    CARDS-VIEW
 *********************************************************/
.card-img-container {
    height: 110px;
    padding-top: 1rem;
}

.fs-card-img {
    max-height: 90px;
    max-width: 100%;
    width: auto;
}

/*********************************************************
    ICONS-VIEW
 *********************************************************/
.icons-img {
    width: 20px;
    height: 20px;
}

.icons-bg {
    background-color: transparent;
}

/* Many favicons carry their own white square background baked into the
   image. That's invisible against the white page in light mode, but in
   dark mode it reads as a broken/cut-off white box around the icon.
   Rounding the image's own corners makes it read as a deliberate icon
   chip instead, in both modes. */
.result-icons-view .results-show-cover {
    overflow: hidden;
}

.result-icons-view .results-show-cover img {
    display: block;
    border-radius: 8px;
    width: 100%;
    height: 100%;
    object-fit: contain;
}

.icons-title {
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    max-width: 7em;
    font-size: 1rem;
    font-weight: 400;
}

@media (min-width:1400px) {
    .icons-title {
        max-width: 6em;
        font-size: .85rem;
        font-weight: 400;
    }
}

.result-icons-view {
    width: 16%;
}

@media (max-width: 768px) {
    .result-icons-view {
        width: 33%;
    }
}

/*********************************************************
    BACKGROUNDS
 *********************************************************/
.bg-primary {
    background-color: var(--fs-primary-background)!important;
}

.bg-secondary {
    background-color: var(--fs-secondary-background)!important;
}

.bg-info {
    background-color: var(--fs-info-background)!important;
}

.bg-warning {
    background-color: transparent!important;
}

/* bg-warning itself is overridden to transparent above, so admin-only
   badges that need an actual visible yellow (e.g. the "Pending Changes"
   badge on the PR Review index page) use this instead. */
.bg-warning-admin {
    background-color: #fff49b!important;
}

.bg-danger {
    background-color: var(--fs-danger-background)!important;
}



/*********************************************************
    FORMS
 *********************************************************/
.form-group {
    margin-bottom: 2.5rem;
}

@media (max-width:991px) {
    .form-group {
        margin-bottom: 2.0rem
    }
}

.form-control {
    min-height: 38px;
}

.form-control-sm {
    min-height: 20px!important;
}

.form-material .form-group {
    overflow: hidden
}

.form-material .form-control {
    background-color: rgba(0, 0, 0, 0);
    background-position: center bottom, center calc(100% - 1px);
    background-repeat: no-repeat;
    background-size: 0 2px, 100% 1px;
    padding: 5;
    -webkit-transition: background 0s ease-out 0s;
    -o-transition: background 0s ease-out 0s;
    transition: background 0s ease-out 0s
}

.form-material .form-control,
.form-material .form-control.focus,
.form-material .form-control:focus {
    background-image: -webkit-gradient(linear, left top, left bottom, from(var(--fs-theme-text-color)), to(var(--fs-theme-text-color))), -webkit-gradient(linear, left top, left bottom, from(#e9ecef), to(#e9ecef));
    background-image: -webkit-linear-gradient(var(--fs-theme-text-color), var(--fs-theme-text-color)), -webkit-linear-gradient(#e9ecef, #e9ecef);
    background-image: -o-linear-gradient(var(--fs-theme-text-color), var(--fs-theme-text-color)), -o-linear-gradient(#e9ecef, #e9ecef);
    background-image: linear-gradient(var(--fs-theme-text-color), var(--fs-theme-text-color)), linear-gradient(#e9ecef, #e9ecef);
    border: 0 none;
    border-radius: 0;
    -webkit-box-shadow: none;
    box-shadow: none;
    float: none
}

.form-material .form-control.focus,
.form-material .form-control:focus {
    background-size: 100% 2px, 100% 1px;
    outline: 0 none;
    -webkit-transition-duration: 0.3s;
    -o-transition-duration: 0.3s;
    transition-duration: 0.3s
}

.form-check-input:checked {
    background-color: #148c9f;
    border-color: #148c9f;
}

/* The "Delete this box's content"/"Delete this box for good" toggles
   (Public Sort's fixed/custom box edit modals) - a destructive action
   dressed as a switch for visual consistency with Hide/Widen above it,
   so it should never fill the same reassuring teal those do, checked
   or not. */
.ppg-box-content-delete-switch .form-check-input {
    border-color: #dc3545;
}

.ppg-box-content-delete-switch .form-check-input:checked {
    background-color: #dc3545;
    border-color: #dc3545;
}



/*********************************************************
    Nested Bucket Display
 *********************************************************/
.option-me-1 { margin-left: 1.25rem; }
.option-me-2 { margin-left: 2.5rem; }
.option-me-3 { margin-left: 3.75rem; }
.option-me-4 { margin-left: 5rem; }
.option-me-5 { margin-left: 6.25rem; }
.option-me-6 { margin-left: 7.5rem; }
.option-me-7 { margin-left: 8.75rem; }



/*********************************************************
    TABS
 *********************************************************/


/*********************************************************
    Vintage View
 *********************************************************/
.result-vintage-view {
    border: none !important;
}

#vintage-bucket-list {
    padding: 4px 8px;
    overflow-x: hidden;
}

.vintage-bucket-section {
    margin-bottom: 12px;
}

.vintage-bucket-name {
    font-weight: bold;
    font-size: 1.125rem;
    margin-bottom: 0.5em;
    margin-top: 4px;
    padding-left: 20px;
}

/* Same irradiation-effect compensation as .vintage-link — white bold
   text on dark backgrounds reads heavier than the same weight on light. */
.dark-mode .vintage-bucket-name {
    font-weight: 600;
}
.vintage-row {
    padding: 1px 8px 1px 20px;
    line-height: 1.4;
    position: relative;
}

/* Bucket-list Retro view only: hover should hug the text, not span the
   full row width. Scoped here so it doesn't affect the other Retro view
   (.vintage-row with d-flex/space-between for title+controls layout),
   which needs the full row width. */
#vintage-bucket-list .vintage-row {
    display: block;
    width: fit-content;
    max-width: 100%;
}

.vintage-row:hover .vintage-menu-btn {
    opacity: 1 !important;
}

/* Retro bucket-list hover — matches the same hover colors used elsewhere
   (day: light grey, dark: #262626). This view isn't wrapped in
   .link-display, so it needs its own rule separate from the locked
   .link-display .vintage-row hover block. */
#vintage-bucket-list .vintage-row:hover {
    background-color: #f2f2f2;
}
body.dark-mode #vintage-bucket-list .vintage-row:hover {
    background-color: #262626;
}

.vintage-link {
    color: #0000EE;
    text-decoration: underline;
    font-size: 1.125rem;
    font-weight: 500;
    word-break: break-word;
}

.vintage-link:visited {
    color: #551A8B;
}

.vintage-link:hover {
    color: #0000EE;
}

/* White text on a dark background reads as bolder than the same weight
   does on light (irradiation effect) — lighten it to compensate. */
.dark-mode .vintage-link {
    font-weight: 400;
}

/* List2 view */
.list2-item {
    display: flex;
    align-items: flex-start;
    gap: 14px;
    padding: 13px 20px 13px 0px;
    border-bottom: 1px solid #eaecef;
    background: #fff;
    position: relative;
}
.list2-thumb { flex-shrink: 0; width: 44px; height: 44px; border-radius: 6px; display: flex; align-items: center; justify-content: center; overflow: hidden; position: relative; z-index: 1; pointer-events: none; }
.list2-thumb a { pointer-events: auto; }
.list2-favicon { width: 24px; height: 24px; object-fit: contain; }
.list2-body { flex: 1 1 auto; min-width: 0; position: relative; z-index: 1; pointer-events: none; }
.list2-title a { pointer-events: auto; }
.list2-actions { flex-shrink: 0; display: flex; align-items: center; position: relative; z-index: 1; }
.list2-title { font-size: 14px; font-weight: 700; color: #1a1d23; line-height: 1.4; margin-bottom: 3px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.list2-title a { color: inherit; text-decoration: none; font-weight: 700; }
.list2-title a:hover { text-decoration: underline; }
.list2-desc { font-size: 12px; color: #1a1d23; line-height: 1.5; margin-bottom: 5px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.list2-meta { display: flex; align-items: center; gap: 6px; }

/* List's Bucket/Domain/Date + Tags line - same pipe-joined format and
   right-aligned/truncating Tags as Mini/Masonry (see the shared
   .mini-meta rules and JS separator logic). Replaces the old
   dot-marker bucket + always-visible domain/date styling now that all
   three are opt-in fields joined the same way everywhere. */
.result-list2-view .mini-meta {
    font-size: 11px;
    color: #8a8f9a;
}

.result-list2-view .mini-meta * {
    font-size: inherit !important;
}

.result-list2-view .tagRow {
    font-size: 11px;
}

.result-list2-view .tagRow * {
    font-size: inherit !important;
}

/* On phone, clamp the description to 3 lines with an ellipsis; tap
   it to expand the full text in place (card grows to fit). */
@media (max-width: 767px) {
    .list2-desc {
        white-space: normal;
        overflow: hidden;
        text-overflow: ellipsis;
        display: -webkit-box;
        -webkit-box-orient: vertical;
        -webkit-line-clamp: 3;
        pointer-events: auto;
        cursor: pointer;
    }
    .list2-desc.expanded {
        overflow: visible;
        display: block;
        -webkit-line-clamp: unset;
    }
}

.list2-item.hilite { background: var(--hilite-color, #fafaaf); }

.dark-mode .list2-item { background: #20242e; border-bottom: 1px solid rgba(255,255,255,0.12); }
.dark-mode .list2-item.hilite { background: var(--hilite-color, #fafaaf); }
.dark-mode .list2-title { color: #e8eaf0; }
.dark-mode .list2-desc { color: #9aa0b0; }
.dark-mode .list2-sep { color: #3a4050; }
.dark-mode .list2-domain { color: #5b9bd5; }
.dark-mode .list2-date { color: #5c6272; }

/* Table view (test) - dense spreadsheet-style rows */
.table-row-item {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 5px 16px;
    border-bottom: 1px solid #eaecef;
    background: #fff;
    position: relative;
    font-size: 12px;
    -webkit-user-select: none;
    user-select: none;
}

/* Each row has an invisible full-row <a class="stretched-link"> on top of
   it (so clicking anywhere on the row opens the link) - browsers treat any
   <a href> as natively draggable, so a drag gesture starting on the row was
   being picked up as the browser's own "drag this link" action instead of
   being handed to jQuery UI's sortable. user-select:none alone doesn't stop
   this since it's a separate browser behavior from text selection - that's
   why the gap/selection-highlight kept coming back even after that fix. */
.link-display .stretched-link {
    -webkit-user-drag: none;
    user-drag: none;
}

/* Every row is position:relative with no explicit z-index, so with
   auto stacking a LATER row in the list paints over an EARLIER row's
   open "..." menu (same stacking level - DOM order wins). Lift the
   whole row above its neighbors while its own menu is open, on both
   click (mobile) and hover (desktop). */
.table-row-item:has(.dropdown-menu.show) {
    z-index: 1000;
}
.table-row-icon { flex-shrink: 0; width: 18px; height: 18px; position: relative; z-index: 1; pointer-events: none; }
.table-row-favicon { width: 18px; height: 18px; object-fit: contain; border-radius: 3px; }
.table-row-title {
    flex: 1 1 260px;
    min-width: 0;
    font-weight: 500;
    color: #1a1d23;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    position: relative;
    z-index: 1;
    pointer-events: none;
}
.table-row-bucket {
    flex: 0 1 130px;
    min-width: 0;
    color: #8a8f9a;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.table-row-domain {
    flex: 0 1 160px;
    min-width: 0;
    color: #5b9bd5;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.table-row-date { flex: 0 0 92px; color: #a0aec0; text-align: right; white-space: nowrap; }
.table-row-tags {
    flex: 0 1 160px;
    min-width: 0;
    color: #8a8f9a;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* Bucket/Domain/Date/Tags at 90% of the title's size (they inherit
   the same 12px base as .table-row-title, so 0.9em lands there
   directly). Tags' own <span> tags need the inherit !important - the
   site's global "* { font-size: ... }" rule (near the top of this
   file) sets font-size directly on every element, so without this
   they'd ignore their parent's smaller size the same way Mini's
   Bucket/Domain/Date spans originally did. */
.table-row-bucket,
.table-row-domain,
.table-row-date,
.table-row-tags {
    font-size: 0.9em;
}

.table-row-tags * {
    font-size: inherit !important;
}

.table-row-tags span {
    text-decoration: underline;
}
.table-row-tags span:not(:last-child)::after {
    content: ", ";
    text-decoration: none;
}
.table-row-actions { flex-shrink: 0; position: relative; z-index: 1; pointer-events: none; }
.table-row-actions > * { pointer-events: auto; }
.table-row-actions .dropdown-menu {
    max-height: 70vh;
    overflow-y: auto;
    overscroll-behavior: contain;
}

/* Hover: same light grey tint as everywhere else, reveal the select
   checkbox (not the "..." menu - stays hidden), and let the whole row
   navigate (not just the domain text). */
.table-row-item:hover {
    background-color: #f2f2f2 !important;
}
body.dark-mode .table-row-item:hover {
    background: #262626 !important;
    background-color: #262626 !important;
}
body.dark-mode .table-row-item:hover * {
    background-color: transparent !important;
}
.table-row-item:hover .linkCheckbox,
.table-row-item:hover .dropdown-toggle {
    opacity: 1 !important;
}

@media (max-width: 991px) {
    /* Phone and tablet: drop bucket/domain/date/tags entirely rather
       than squeezing them in - gives the title room to breathe instead
       of fighting over limited width. */
    .table-row-bucket, .table-row-domain, .table-row-date, .table-row-tags { display: none; }
    .table-row-title { flex: 1 1 auto; }
    /* Pull the "..." button/checkbox out of the flex flow (overlaying the
       row instead) so they don't reserve layout width for a control
       that's invisible until tapped anyway. */
    .table-row-actions {
        position: absolute;
        right: 4px;
        top: 50%;
        transform: translateY(-50%);
    }
    .table-row-actions .btn.dropdown-toggle { padding: 4px; min-width: 0; }
    .table-row-actions .linkCheckbox { width: 16px; height: 16px; margin: 0; }
}
.table-row-item.hilite { background: var(--hilite-color, #fafaaf); }

/* Reorder Buckets modal - Save button always cherry red regardless of
   the site's theme color, 10% darker in dark mode. */
.manage-buckets-save {
    background-color: #C41E3A !important;
    border-color: #C41E3A !important;
    color: #fff !important;
}

/* Duplicate Detector's delete button - cherry red, 10% darker on
   hover (same treatment as Reorder Buckets' Save button). */
.duplicate-delete-btn {
    background-color: #C41E3A !important;
    border-color: #C41E3A !important;
}

.duplicate-delete-btn.btn-danger:hover {
    background-color: #B01B34 !important;
    border-color: #B01B34 !important;
    color: #fff !important;
}

.duplicate-delete-btn.btn-danger:hover * {
    background-color: transparent !important;
    color: #fff !important;
}

/* Add/Edit Link modal's delete button - same solid cherry-red button
   treatment as Duplicate Detector's. Shares the ".link-delete" class
   with the small icon-only "Delete" dropdown items below, so it's
   handled here separately by ID, and excluded from that icon-color
   rule (a red icon on this button's own red background would vanish). */
#link-delete.btn-danger {
    background-color: #C41E3A !important;
    border-color: #C41E3A !important;
}

#link-delete.btn-danger:hover {
    background-color: #B01B34 !important;
    border-color: #B01B34 !important;
    color: #fff !important;
}

#link-delete.btn-danger:hover * {
    background-color: transparent !important;
    color: #fff !important;
}

/* Small icon-only trash-can "Delete" options - cherry red icon in dark
   mode, 10% darker on hover. Link cards' own ellipsis "Delete"
   (.link-delete, used in every card view and Start Grid) and Delete
   Bucket are deliberately excluded. */
.dark-mode .delete-public-link i.fa-trash,
.dark-mode .delete-note i.fa-trash {
    color: #C41E3A !important;
}

.dark-mode .dropdown-item.delete-public-link:hover i.fa-trash,
.dark-mode .dropdown-item.delete-note:hover i.fa-trash {
    color: #B01B34 !important;
}

/* Tag modal delete button in dark mode - match Duplicate Detector's
   full button treatment (bright cherry red, white icon) instead of the
   lighter always-on red button it otherwise uses. */
.dark-mode .tag-delete {
    background-color: #B01B34 !important;
    border-color: #B01B34 !important;
    color: #fff !important;
}

.dark-mode .tag-delete:hover {
    background-color: #9E182F !important;
    border-color: #9E182F !important;
    color: #fff !important;
}

.dark-mode .tag-delete:hover * {
    background-color: transparent !important;
    color: #fff !important;
}

.dark-mode .manage-buckets-save {
    background-color: #B01B34 !important;
    border-color: #B01B34 !important;
}

/* Override the generic ".dark-mode .btn:hover" rule (turns everything
   near-black on hover) - this button hovers by darkening its OWN
   cherry red another 10%, in both themes, instead. */
.manage-buckets-save.btn-info:hover {
    background-color: #B01B34 !important;
    border-color: #B01B34 !important;
}

.dark-mode .manage-buckets-save.btn-info:hover {
    background-color: #9E182F !important;
    border-color: #9E182F !important;
}

.dark-mode .table-row-item { background: #20242e; border-bottom: 1px solid rgba(255,255,255,0.12); }
.dark-mode .table-row-item.hilite { background: var(--hilite-color, #fafaaf); }
.dark-mode .table-row-title { color: #e8eaf0; }
.dark-mode .table-row-bucket { color: #8a8f9a !important; }
.dark-mode .table-row-domain { color: #5b9bd5 !important; }
.dark-mode .table-row-date { color: #5c6272 !important; }
.dark-mode .table-row-tags { color: #8a8f9a !important; }

/* Start Grid view */
.start-grid-container {
    display: flex;
    align-items: flex-start;
    touch-action: pan-y;
    gap: 20px;
    padding: 10px 15px;
}

/* Desktop only: nudge the grid right, away from the sidebar edge */
@media (min-width: 992px) {
    .start-grid-container { padding-left: 35px; }
}

.start-grid-col {
    flex: 1;
    min-width: 0;
    /* jQuery UI Sortable can't accept a drop into a column with zero
       height - once the last category is dragged out, the empty column
       collapses and becomes permanently undroppable without this. */
    min-height: 40px;
}

@media (max-width: 800px)  { .start-grid-container { flex-wrap: wrap; } .start-grid-col { flex: 1 1 45%; } }
@media (max-width: 500px)  {
    .start-grid-col { flex: 1 1 100%; }
    /* Links were shrink-wrapping to their own text width (align-items:
       flex-start), leaving a big empty gap on the right on phone - the
       single column should use the full width it's given. */
    .start-grid-links { align-items: stretch !important; }
}

.start-grid-bucket {
    margin-bottom: 20px;
    background: transparent;
    border: none;
    border-radius: 0;
    overflow: visible;
}

.start-grid-bucket-header {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 2px 0 6px 4px; /* left padding matches .start-grid-link's 4px so the category icon lines up with link favicons below it */
    background: transparent;
    border-bottom: none;
    font-weight: 700;
    font-size: 0.95rem;
    color: #111;
}

.start-grid-bucket-icon {
    width: 16px;
    height: 16px;
    object-fit: contain;
}

.start-grid-bucket-icon-default {
    font-size: 14px;
    color: #666;
}

.start-grid-bucket-actions {
    flex-shrink: 0;
}

/* Drag handle for reordering whole Start Page categories - subtle
   until the header is hovered, same reveal pattern as the ellipsis
   menu below, so it doesn't clutter the header at rest. Given the
   same fixed-size flex box as the ellipsis button below so the two
   icons line up regardless of glyph metrics or what else is in the
   header (a bare <span><i>, with no box of its own, only lined up
   with the ellipsis <button> by coincidence). */
.start-grid-category-drag-handle {
    flex-shrink: 0;
    opacity: 0;
    color: #999;
    cursor: grab;
    font-size: 0.8rem;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 22px;
    height: 22px;
    margin-left: -6px; /* pulled closer to the ellipsis button, tighter than the header's default 8px gap */
}
.start-grid-bucket-header:hover .start-grid-category-drag-handle {
    opacity: 1;
}
.start-grid-category-drag-handle:active {
    cursor: grabbing;
}

/* Category drag-and-drop is desktop-only (see initStartGridCategorySortable()
   in dashboard.blade.php) - a tap can trigger :hover briefly on mobile
   browsers, surfacing a drag icon that doesn't actually do anything there
   and would just confuse users. Hide it outright below the breakpoint. */
@media (max-width: 767px) {
    .start-grid-category-drag-handle {
        display: none;
    }

    /* The ellipsis menu itself IS usable on mobile (Add Link, Edit Title,
       Change Icon, etc still work by tap) - it just relies on the same
       hover-only opacity, which mobile browsers don't reliably trigger.
       Show it outright here instead. */
    .start-grid-bucket-actions .dropdown-toggle {
        opacity: 1;
    }
}

/* Tablets too: dragging is off on any touch screen (see initStartGridCategorySortable()), so the
   grip handle is hidden there as well - the phone rule above only covers narrow screens, which
   left an icon on tablets that did nothing when touched. Mouse devices are unchanged. */
@media (pointer: coarse) {
    .start-grid-category-drag-handle {
        display: none;
    }
}

.start-grid-bucket-actions .dropdown-toggle {
    opacity: 0;
    padding: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 22px;
    height: 22px;
}

.start-grid-bucket-actions .dropdown-menu .dropdown-item {
    font-size: 0.9rem;
}

.start-grid-bucket-header:hover .start-grid-bucket-actions .dropdown-toggle {
    opacity: 1;
}

.start-grid-bucket-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
}

/* The global .twemoji-img size (20x20, see emoji-picker.css) overflows
   this 16x16 box and gets centered, shifting the visible glyph's left
   edge outward compared to a link's plain 16x16 favicon - constrain it
   to the box here so both line up on the same left edge. */
.start-grid-bucket-icon .twemoji-img {
    width: 16px;
    height: 16px;
}

/* Raw <select> elements are excluded from the broad ".dark-mode *"
   text-color rule (it skips select/select * so bootstrap-select's own
   dark-mode styling isn't fought with) - but this Start Category
   dropdown is a plain, non-bootstrap-select <select>, so without this
   it inherits a dark background from its parent while keeping
   Bootstrap's default dark-gray text color, making it unreadable. */
.dark-mode #frm_link_start_grid_bucket {
    color: #fff !important;
    background-color: #343434 !important;
}


.start-grid-menu-toggle {
    color: #888 !important;
}

.start-grid-bucket-name {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-weight: 600;
    font-size: 0.95rem;
    color: #111;
}

.start-grid-links {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    padding: 4px 0;
}

.start-grid-link {
    display: flex;
    align-items: center;
    position: relative;
    cursor: grab;
    gap: 6px;
    padding: 3px 4px;
    color: #333;
    touch-action: pan-y;
    text-decoration: none;
    font-size: 0.8rem;
    line-height: 1.3;
}

/* Same fix as Table view: every card is position:relative with no
   explicit z-index, so a LATER card in the list paints over an EARLIER
   card's open "..." menu (and moving the mouse onto that later card
   makes ITS ellipsis hover-reveal and intercept clicks meant for the
   open menu). Lift the whole card above its neighbors while its own
   menu is open. */
.start-grid-link:has(.dropdown-menu.show) {
    z-index: 1000;
}

.start-grid-link-actions {
    flex-shrink: 0;
    position: relative;
    z-index: 1;
    pointer-events: none;
}

.start-grid-link-actions > * {
    pointer-events: auto;
}

.start-grid-link-actions .dropdown-toggle {
    opacity: 0;
    padding: 2px 4px;
    pointer-events: auto;
}

.start-grid-link:hover .start-grid-link-actions .dropdown-toggle {
    opacity: 1;
}

/* Phones only - the link name has flex:1 (see .start-grid-link-name)
   so it stretches to fill the whole column width, pushing the ellipsis
   to the far right edge regardless of how short the actual link text
   is. Shrink the row to its own content instead, so the ellipsis sits
   right after the last word instead of stranded at the column edge. */
@media (max-width: 767px) {
    .start-grid-link {
        width: fit-content;
        max-width: 100%;
    }
    .start-grid-link-name {
        flex: 0 1 auto;
    }
    .start-grid-link-actions {
        margin-left: 5ch;
    }
}

.start-grid-link-actions .dropdown-item:hover,
.start-grid-link-actions .dropdown-item:active {
    background-color: var(--fs-info-background);
    color: #fff;
}

.start-grid-link-placeholder {
    border: 1px dashed #17a2b8;
    border-radius: 4px;
    margin: 2px 4px;
}

.start-grid-bucket-placeholder {
    border: 1px dashed #17a2b8;
    border-radius: 4px;
    margin-bottom: 1rem;
    margin-left: 12px;
    margin-right: 12px;
    box-sizing: border-box;
}

.dark-mode .start-grid-link-placeholder {
    border-color: #17a2b8;
}

.start-grid-link:hover {
    background: #f0f0f0;
    color: #000;
    text-decoration: none;
}

/* Bucket | Domain | Date line (Mini, Masonry, ...) - about 70% of the
   description text's size. Uses em (not a flat px/rem) so it scales
   along with the site's font-size setting instead of a fixed value
   that would look right at one text-size setting and wrong at
   others. The site's own "* { font-size: ... }" rule (near the top
   of this file) sets font-size directly on every element, including
   the spans inside .mini-meta - so setting this on the wrapping div
   alone doesn't reach them via inheritance. The child spans are
   explicitly set to "inherit" here so they pick up the div's already
   -scaled-down size instead of the global rule's own value. */
.result-mini-card-view .mini-meta {
    font-size: 0.8em !important;
}

.result-mini-card-view .mini-meta * {
    font-size: inherit !important;
}

/* Tags sit on the same line as Bucket/Domain/Date - matching that
   line's size (same reasoning/fix as .mini-meta above). */
.result-mini-card-view .tagRow {
    font-size: 0.8em !important;
}

.result-mini-card-view .tagRow * {
    font-size: inherit !important;
}

/* Bricks: bumped up one step from Mini's 0.8em, per explicit request,
   alongside the title/description size bump above - kept as its own
   rule since only Bricks' sizing changed here. */
.result-masonry-view .mini-meta {
    font-size: 0.88em !important;
}

.result-masonry-view .mini-meta * {
    font-size: inherit !important;
}

.result-masonry-view .tagRow {
    font-size: 0.88em !important;
}

.result-masonry-view .tagRow * {
    font-size: inherit !important;
}

/* Vanilla: same treatment, but 10% larger across the board (title,
   description, and this Bucket/Domain/Date/Tags line) per explicit
   request - kept as its own rule instead of joining Mini/Masonry's
   0.8em above since only Vanilla's sizing changed here. */
.result-list-view .mini-meta {
    font-size: 0.88em !important;
}

.result-list-view .mini-meta * {
    font-size: inherit !important;
}

.result-list-view .tagRow {
    font-size: 0.88em !important;
}

.result-list-view .tagRow * {
    font-size: inherit !important;
}

/* The Bucket/Domain/Date + Tags row otherwise sits right under the
   title/description, wherever that content happens to end - leaving a
   big empty gap below it on short cards, since .card-body itself
   isn't a flex container and nothing pushes this row down. Making it
   one and pinning this specific row to the bottom (margin-top: auto)
   keeps it flush with the card's bottom edge no matter how short the
   title/description above it is, or how tall the row's card-height
   neighbors force the card to be. */
.result-mini-card-view .card-body,
.result-list-view .card-body,
.result-masonry-view .card-body,
.result-balanced-view .card-body,
.result-balance-view .card-body {
    display: flex;
    flex-direction: column;
}

/* Mini only - card-body needs to actually fill the JS-set row height
   (not just size to its own content) so .mini-content-clip has real
   spare space to grow into and the meta line never gets clipped away
   (see the syncRowHeights re-run in results-view.blade.php). Scoped to
   just this view - adding it to the shared rule above also stretched
   Bricks/Masonry's card-body, which doesn't need it and only pushed
   its bottom meta line down with extra empty space above it. */
.result-balanced-view .card-body {
    height: 100%;
}

.result-mini-card-view .card-body > .row:last-child,
.result-list-view .card-body > .row:last-child,
.result-balance-view .card-body > .row:last-child {
    margin-top: auto;
}

/* Mini (.result-balanced-view) wraps its description + meta rows in
   .mini-content-clip (see link-display.blade.php) so long content can
   be clipped without also clipping the ellipsis dropdown menu in the
   row above it (overflow:hidden on the whole .card was clipping that
   dropdown too - see the note on .result-balanced-view .card below).
   Fills the remaining flex-column space after the icon/title row,
   clips anything past its own bounds, and keeps the meta row pinned to
   its own bottom edge exactly like the other views' pattern above. */
.result-balanced-view .mini-content-clip {
    display: flex;
    flex-direction: column;
    flex: 1 1 auto;
    min-height: 0;
    overflow: hidden;
}

.result-balanced-view .mini-content-clip > .row:last-child {
    margin-top: auto;
}

/*********************************************************
    MINI VIEW (result-balanced-view, renamed "Mini" in the View menu)
 *********************************************************/
/* Was forced to one fixed height for every card - switched to the same
   per-row height sync as Boxes (see syncRowHeights() in this file's
   script section) so each card auto-sizes to its own content, but every
   card in a given row still stretches to match that row's tallest one -
   matching production's original Mini look, with all rows staying
   uniform without a single global fixed height cutting off longer
   content. */

.result-balanced-view .mini-meta {
    font-size: 0.8em !important;
}

.result-balanced-view .mini-meta * {
    font-size: inherit !important;
}

.result-balanced-view .tagRow {
    font-size: 0.8em !important;
}

.result-balanced-view .tagRow * {
    font-size: inherit !important;
}

/*********************************************************
    BALANCE VIEW (result-balance-view)
 *********************************************************/
/* Restored as its own view, separate from Mini/Balanced above - same
   fixed-height-card technique, just its own independently-tunable
   height. */
.result-balance-view .card {
    /* Bootstrap's h-100 class (already on this card) carries !important,
       so a plain height here would silently lose to it - match that. */
    height: 132px !important;
    /* overflow:hidden was tried here but it also clips the ellipsis
       dropdown menu (a child of this same .card) - see the matching
       note on .result-balanced-view .card above. */
}

/* Phones only - Even's cards run 30% shorter than desktop/tablet. */
@media (max-width: 767px) {
    .result-balance-view .card {
        height: 92px !important;
    }
}

.result-balance-view .mini-meta {
    font-size: 0.8em !important;
}

.result-balance-view .mini-meta * {
    font-size: inherit !important;
}

.result-balance-view .tagRow {
    font-size: 0.8em !important;
}

.result-balance-view .tagRow * {
    font-size: inherit !important;
}

/* Bricks: Tags got split into its own row above Bucket/Domain/Date (was
   sharing a line with them), so the two are wrapped in one plain div to
   keep them moving down together as a unit - :last-child here targets
   that wrapper instead of a .row directly. */
.result-masonry-view .card-body > div:last-child {
    margin-top: auto;
}

/* DataTables pagination (admin tables) - the active page number
   defaults to Bootstrap's blue, which doesn't match the site's own
   teal "info" buttons (e.g. the "Bucket"/"Link" add buttons right
   above it). Match that color instead. */
.dataTables_wrapper .page-item.active .page-link {
    background-color: var(--fs-info-background) !important;
    border-color: var(--fs-info-background) !important;
}

/*********************************************************
    TOAST NOTIFICATIONS
 *********************************************************/
/* jquery.toast.css hardcodes a flat 250px width with no responsive
   handling at all - same width on a phone as a desktop monitor.
   Widened here instead of editing the vendor plugin file directly, so
   longer messages wrap less. On phones, scale to the viewport instead
   of a flat number so it can't get too close to (or past) the screen
   edges on a narrow/older phone. */
.jq-toast-wrap {
    width: 400px;
}

@media (max-width: 767px) {
    .jq-toast-wrap {
        width: calc(100vw - 40px);
        max-width: 400px;
    }
    .jq-toast-wrap.bottom-right,
    .jq-toast-wrap.top-right {
        right: 20px;
    }
    .jq-toast-wrap.bottom-left,
    .jq-toast-wrap.top-left {
        left: 20px;
    }
}

/* jquery.toast.css hardcodes success toasts to Bootstrap's bright blue
   (#0d6efd). Overridden here to a muted, darker teal instead of the
   site's full-saturation accent teal (#0dcaf0), which read as too
   bright/eye-catching for a routine "saved" notification. */
.jq-icon-success {
    background-color: #2b6e72;
    border-color: #2b6e72;
}

.start-grid-link.hilite {
    background: var(--hilite-color, #fafaaf);
    border-radius: 4px;
}

/* Same treatment as the Icons view's colored cards - a solid fill of the
   (usually pastel) hilite color reads too washed-out/bright against a
   dark card, so use a thin colored outline instead, same color used in
   light mode. */
.dark-mode .start-grid-link.hilite {
    background: transparent;
    border: 1.5px solid var(--hilite-color, #fafaaf);
}

.start-grid-favicon {
    width: 16px; /* matches .start-grid-bucket-icon so link and category icons line up on the same left edge */
    height: 16px;
    touch-action: pan-y;
    object-fit: contain;
    flex-shrink: 0;
    margin-left: -4px; /* nudged left - favicon artwork tends to have more built-in padding than the category icon, making it look indented at an identical box position */
}

.start-grid-favicon-default {
    font-size: 12px;
    color: #767676;
    flex-shrink: 0;
}

/* A link with no favicon (or one that fails to load): its first letter, white on
   a colored square, in the favicon's place - same look the other views use. */
.start-grid-favicon-letter {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-radius: 3px;
    color: #fff;
    font-size: 0.6rem;
    font-weight: 700;
    line-height: 1;
}

.start-grid-link-name {
    flex: 1 1 auto;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    touch-action: pan-y;
}

/* Dark mode */
.dark-mode .start-grid-bucket {
    background: transparent;
    border: none;
}

.dark-mode .start-grid-bucket-header {
    background: transparent;
    border: none;
    color: #fff;
}

.dark-mode .start-grid-link {
    color: #ddd;
}

/* Dark mode: top nav buttons hover — matches bucket menu/links/start grid hover */
.dark-mode .topLink:hover,
.dark-mode .topGear:hover,
.dark-mode .topView:hover,
.dark-mode .topEllip:hover,
.dark-mode .bucketButton:hover,
.dark-mode .topLink.btn-primary,
.dark-mode .topGear.btn-primary,
.dark-mode .topView.btn-primary,
.dark-mode .topEllip.btn-primary {
    background-color: #262626 !important;
    color: #fff !important;
    border-color: transparent !important;
    box-shadow: none !important;
}

/* Sidebar toggle button */
#sidebar-toggle {
    display: none;
    position: fixed;
    top: 82px;
    left: var(--fs-left-navigation-width);
    transform: translateX(-50%);
    z-index: 100;
    background-color: #e8e8e8;
    background-image: radial-gradient(circle, #aaa 1px, transparent 1px);
    background-size: 4px 4px;
    border: 1px solid #ccc;
    border-radius: 3px;
    width: 18px;
    height: 18px;
    font-size: 11px;
    line-height: 18px;
    cursor: pointer;
    padding: 0;
    color: #767676;
    transition: left 0.2s;
}
#sidebar-toggle:hover { background-color: #d0d0d0; background-image: radial-gradient(circle, #767676 1px, transparent 1px); background-size: 4px 4px; color: #555; }
.dark-mode #sidebar-toggle { background-color: #3a3a3a; background-image: radial-gradient(circle, rgba(255,255,255,0.5) 1px, transparent 1px); background-size: 4px 4px; border-color: #555; color: #bdbdbd; width: 18px; height: 18px; }
.dark-mode #sidebar-toggle:hover { background-color: #444; background-image: radial-gradient(circle, rgba(255,255,255,0.5) 1px, transparent 1px); background-size: 4px 4px; color: #fff; }

@media (min-width: 992px) {
    #sidebar-toggle { display: block; }
}

/* Collapsed sidebar state */
/* Only from 992px up, where the square that collapses the column exists. Below that, a "collapsed" choice
   made in landscape (kept in the browser) must not stop the hamburger from opening the column upright. */
@media (min-width: 992px) {
    #main-wrapper.sidebar-hidden .left-sidebar { display: none !important; }
}
#main-wrapper.sidebar-hidden .page-wrapper { margin-left: 0 !important; }
#main-wrapper.sidebar-hidden #sidebar-toggle { left: 10px; }

/*********************************************************
    CURATED GALLERY — hover matches other cards on the site
 *********************************************************/
.bucket-display .card:hover {
    background-color: #f2f2f2 !important;
    border-color: rgba(0,0,0,0.5) !important;
}
body.dark-mode .bucket-display .card:hover {
    background-color: #262626 !important;
    border-color: #777 !important;
}
/* Fill the whole box uniformly in dark mode — same wildcard-transparency
   approach used for link cards, so no child element shows its own patch
   of the old background color. */
body.dark-mode .bucket-display .card:hover * {
    background-color: transparent !important;
}
/* Exceptions: the open dropdown menu (Follow/Share/Copy) and its item
   hover must stay opaque, same as elsewhere on the site. */
body.dark-mode .bucket-display .card:hover .dropdown-menu {
    background-color: #111 !important;
}
body.dark-mode .bucket-display .card:hover .dropdown-item:hover,
body.dark-mode .bucket-display .card:hover .dropdown-item:hover * {
    background-color: #3a3a3a !important;
}
/* The "Bucket Options" dropdown-toggle button must also stay its normal
   teal, not go transparent (which let the darkened card background show
   through and looked black). */
body.dark-mode .bucket-display .card:hover .btn-info {
    background-color: var(--fs-info-background) !important;
    border-color: var(--fs-info-background) !important;
    color: var(--fs-info-text) !important;
}
body.dark-mode .bucket-display .card:hover .btn-info:hover {
    background-color: var(--fs-info-hover) !important;
    border-color: var(--fs-info-hover) !important;
    color: var(--fs-info-text) !important;
}

/* Curated gallery: hide the row-divider line (from .border-bottom on the
   grid wrapper) in dark mode — keep it in day mode. */
body.dark-mode .bucket-display.border-bottom {
    border-bottom-color: transparent !important;
}

/*********************************************************
    EMOJI BUCKET ICONS
 *********************************************************/
.emoji-icon {
    display: inline-block;
    font-size: 1.2em;
    line-height: 1;
    vertical-align: middle;
}

/* View menu: fixed-width icon slot so labels all line up regardless of
   whether the icon is an emoji, a font icon, or the custom box shape. */
.view-menu-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 20px;
    margin-right: 6px;
}

/* Bucket page title bar: select-all checkbox border 5% darker than
   Bootstrap's default */
.bucket-title-checkbox {
    border-color: rgba(0, 0, 0, 0.30) !important;
}

/* Favorites toolbar: 3/4-column layout switch icons turn white on hover */
.switch-columns:hover i {
    color: #fff;
}

/* Link Columns / Start Columns "3 | 4" numbers in the ellipsis menu: the
   row's hover background is the site's accent color, and the numbers'
   own link-hover color (a blue) blended into it - white instead, both
   when hovering a number and when hovering anywhere on the row. */
.layout-columns-item:hover .switch-columns,
.layout-columns-item:hover .switch-start-grid-columns,
.switch-columns:hover,
.switch-start-grid-columns:hover {
    color: #fff;
}

/* The number actually under the mouse gets underlined, so it's obvious
   whether 3 or 4 is about to be picked. */
.switch-columns:hover,
.switch-start-grid-columns:hover {
    text-decoration: underline;
}

/* View menu "Boxes" icon: colored hollow rectangle (no matching emoji exists) */
.view-menu-box-icon {
    display: inline-block;
    width: 14px;
    height: 11px;
    border: 2px solid #17a2b8;
    border-radius: 2px;
    vertical-align: middle;
}

/* Bookmark import modal: square radio buttons with a barely-visible black outline
   instead of Bootstrap's default filled circle */
#bookmark_import_form .form-check-input[type="radio"] {
    border-radius: 2px;
    border-color: rgba(0, 0, 0, 0.25);
}

/* Import modal's "how would you like your bookmarks organized" radios -
   follow the theme color when selected, same as the View menu Details
   checkboxes above and the Import/Export buttons (already themed via
   .btn-info). This was the one spot still using the old hardcoded teal
   from the sitewide .form-check-input:checked rule. */
#bookmark_import_form .form-check-input:checked {
    background-color: var(--fs-info-background) !important;
    border-color: var(--fs-info-background) !important;
}

/* Ellipsis menu's "Start Grid (On)/(Off)" status text - Bootstrap's
   .text-muted grey didn't match the "Start Grid" label next to it (white),
   making the on/off state look faded/disconnected from the rest of the
   item. */
#startGridStatus {
    color: #fff !important;
}

/* Icon picker (bucket icon selector): the library's hover highlight sets
   background:#fff with no !important, so the site's blanket dark-mode rule
   (background:#343434 !important on every element) swallows it - the
   hovered icon just blends into the dark modal background. Give it a
   visible highlight in dark mode. */
body.dark-mode #IconPickerModal .ip-icons-content .ip-icons-area > i:hover {
    background-color: #17a2b8 !important;
    color: #fff !important;
}

/* Admin > Manage Default Bucket/Links: "view links" modal rows */
#view-default-links {
    display: flex;
    flex-direction: column;
    gap: 4px;
    width: 100%;
}

.default-link-row {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 10px 4px;
    border-bottom: 1px solid #eaecef;
}

.default-link-row:last-child {
    border-bottom: none;
}

.default-link-favicon {
    width: 22px;
    height: 22px;
    object-fit: contain;
    border-radius: 4px;
    flex-shrink: 0;
}

.default-link-info {
    flex: 1 1 auto;
    min-width: 0;
}

.default-link-name {
    font-weight: 500;
    color: #1a1d23;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.default-link-favorite-star {
    color: #f5b301;
}

.default-link-url {
    font-size: 12px;
    color: #8a8f9a;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.default-link-description {
    font-size: 12px;
    color: #a0aec0;
    margin-top: 2px;
    overflow: hidden;
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 2;
}

.default-link-actions {
    flex-shrink: 0;
    display: flex;
}

.dark-mode .default-link-row {
    border-bottom-color: rgba(255, 255, 255, 0.12);
}

.dark-mode .default-link-name {
    color: #e8eaf0;
}

.dark-mode .default-link-url {
    color: #9aa0ab;
}

.dark-mode .default-link-description {
    color: #7a8290;
}

/* Start Grid dark mode hover - placed at the end of the file with extra
   specificity (matching the real .start-grid-link ancestor explicitly,
   not just relying on a shorter chain) to definitively beat any other
   dark-mode dropdown-item/card hover rule elsewhere in this file,
   regardless of source order. */
body.dark-mode .start-grid-link.start-grid-link:hover,
body.dark-mode .start-grid-link.start-grid-link:hover * {
    background-color: #454545 !important;
    color: #fff !important;
}

body.dark-mode .start-grid-link .start-grid-link-actions .dropdown-item:hover,
body.dark-mode .start-grid-link .start-grid-link-actions .dropdown-item:hover * {
    background-color: var(--fs-info-background) !important;
    color: #fff !important;
}

/* Search results: reveal an edit pencil on hover instead of the old
   "Edit Links" checkbox mode, so editing a link found via search doesn't
   require a separate toggle to remember is on/off. */
/* Always visible - hover-to-reveal meant tablet (no hover state)
   needed an extra tap on the row just to find the icon before tapping
   it for real. */
.tt-suggestion .search-edit-link {
    display: inline-block;
    float: right;
    margin-left: 1ch;
    margin-right: 1ch;
    shape-margin: 1ch;
    opacity: 1;
    cursor: pointer;
    color: #6c757d;
}
.tt-suggestion .search-edit-link:hover {
    color: #fff;
}

/* Mobile search: takes over the full screen while active instead of
   showing a cramped inline dropdown - close button on the right, results
   list fills the rest of the screen with larger touch-friendly rows. */
#mobile-search-close {
    display: none;
}
@media (max-width: 767px) {
    body.mobile-search-active {
        overflow: hidden;
    }
    body.mobile-search-active #fullsort_search_block {
        position: fixed;
        top: 0;
        left: 5%;
        width: 90% !important;
        box-sizing: border-box;
        bottom: 0;
        z-index: 2000;
        background-color: #fff;
        padding: 0.75rem;
        padding-right: 2.75rem;
        border: 1px solid rgba(0, 0, 0, 0.15);
    }
    body.dark-mode.mobile-search-active #fullsort_search_block {
        background-color: #0d0d0d;
        border-color: rgba(255, 255, 255, 0.2);
    }
    body.mobile-search-active #mobile-search-close {
        display: inline-flex;
        align-items: center;
        justify-content: center;
        color: #6c757d;
        font-size: 1.1rem;
        position: absolute;
        top: 0.15rem;
        left: auto;
        right: 0.25rem;
        z-index: 2001;
    }
    body.mobile-search-active .tt-menu {
        position: static !important;
        width: 100% !important;
        max-height: none !important;
        height: calc(100vh - 6rem) !important;
        overflow-y: auto !important;
        -webkit-overflow-scrolling: touch !important;
        margin-top: 3rem !important;
        border: 1px solid rgba(0, 0, 0, 0.15) !important;
        box-shadow: none !important;
        padding-top: 0.25rem !important;
        padding-bottom: 3rem !important;
        box-sizing: border-box;
    }
    body.dark-mode.mobile-search-active .tt-menu {
        border-color: rgba(255, 255, 255, 0.2) !important;
    }
    body.mobile-search-active .tt-suggestion {
        padding: 0.85rem 0.5rem !important;
        font-size: 1rem;
        border-bottom: 1px solid rgba(0, 0, 0, 0.1);
        position: relative;
    }
    body.dark-mode.mobile-search-active .tt-suggestion {
        border-bottom-color: rgba(255, 255, 255, 0.15);
    }
    body.mobile-search-active .tt-suggestion:last-child {
        border-bottom: none;
    }
    /* Flex here would split the icon, the highlighted match text, and
       the rest of a wrapping title into separate sibling flex items
       instead of one flowing block of inline text, causing overlapping
       lines on long titles - keep this as normal inline flow (icon is
       already an inline img) and just size it up a bit for touch. */
    body.mobile-search-active .link-select img,
    body.mobile-search-active .bucket-select img {
        vertical-align: middle;
    }
    /* The edit icon now comes BEFORE the title text in the HTML (see
       buildLinkSuggestionHtml) and floats right - a float only affects
       lines that come after it in the flow, so placing it first means
       every line of a wrapping title (not just the last) wraps around
       it natively, with a real gutter instead of touching it. */
    body.mobile-search-active .link-select,
    body.mobile-search-active .bucket-select {
        display: block;
    }
}

/* Gear/Settings dropdown: fixed-width icon slot so item labels all line up,
   since the mixed icon fonts/emoji used in that menu have different glyph
   widths and a plain margin-right doesn't equalize them. */
#fs-site-options-dropdown ~ .dropdown-menu .dropdown-item > i.me-1,
#fs-site-options-dropdown ~ .dropdown-menu .dropdown-item > span.me-1 {
    display: inline-block;
    width: 20px;
    margin-right: 0 !important;
    text-align: center;
}

/* Child bucket badges (buckets nested inside a bucket): darken slightly on
   hover so it reads as clickable, matching the hover language used
   elsewhere instead of a plain opacity fade (which reads as "disabled"). */
#child_buckets .badge.bg-info {
    transition: background-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;
}
#child_buckets .badge.bg-info:hover {
    background-color: var(--fs-info-hover) !important;
    box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
}

/* Feedback widget (bottom-left corner) Send button, dark mode: force
   white text and brighten the teal on hover, same treatment as the
   child bucket badges above. */
.dark-mode .feedback_submit {
    color: #fff !important;
}
.dark-mode .feedback_submit:hover {
    background-color: #1cb2c9 !important;
}

/* Guest sidebar (Home/Login/About Us) - darken from the default light
   link color for better contrast against the light sidebar background.
   Guests never get dark mode (that's a per-account setting), so this is
   plain day-mode-only text color. */
#sidebarnav-visitor li a {
    color: #222;
}
#sidebarnav-visitor li a:hover {
    color: #000;
    background-color: #f2f2f2 !important;
}
#sidebarnav-visitor li a.current {
    background-color: #ececec !important;
}

#demo_account_button,
.sidebar-nav ul li a#demo_account_button.current {
    color: #fff !important;
    background-color: var(--fs-info-background) !important;
    font-size: 1.15rem;
    font-weight: 600;
}
#demo_account_button:hover {
    background-color: var(--fs-info-hover) !important;
    border-color: var(--fs-info-hover) !important;
    color: #fff !important;
}

/* Dark mode: .btn-info buttons (curated gallery, Account Sign in, etc.)
   were getting caught by the generic ".dark-mode .btn:hover" rule
   turning them nearly black on hover - darken slightly from base
   instead, same value already used for .btn-info:hover in day mode. */
.dark-mode .btn-info:hover {
    background-color: var(--fs-info-hover) !important;
    border-color: var(--fs-info-hover) !important;
    color: var(--fs-info-text) !important;
}


/* View menu Details checkboxes (Icon/Title/Description/Bucket/Domain/Date/
   Tags) - follow the theme color when checked, same as buttons/scrollbar.
   Scoped to just this checkbox group, nothing else. */
#form-view-fields .form-check-input:checked {
    background-color: var(--fs-info-background) !important;
    border-color: var(--fs-info-background) !important;
}


/* jquery.toast's progress-bar loader sits at bottom:-3px by default -
   just past the toast box's own bottom edge, so it visually pokes out
   past the toast's background color (e.g. the navy "Link deleted, Undo"
   toast) instead of sitting inside it. Round the box's corners, clip
   anything that would spill past them, and pull the loader back inside
   the box so the background fully covers the whole toast including the
   loader strip. */
.jq-toast-single {
    border-radius: 6px;
    overflow: hidden;
}

.jq-toast-loader {
    bottom: 0 !important;
}

/* The sitewide dark-mode rule gives almost every element its own dark
   background (".dark-mode *") - that catches the toast's own links (like
   the "Undo" in the delete-link toast) too, painting a small dark patch
   behind just that text instead of letting the toast's own bgColor (e.g.
   navy) show through underneath it. */
body.dark-mode .jq-toast-single a,
body.dark-mode .jq-toast-single .close-jq-toast-single {
    background-color: transparent !important;
}

/* Boxed form fields (admin defaults modals) - each field is its own
   bordered block with the label stacked above the input, instead of
   the label-left/input-right row layout used elsewhere in the app. */
.form-field-box {
    border: 1px solid rgba(0, 0, 0, 0.125);
    border-radius: 6px;
    padding: 0.75rem 1rem;
    margin-bottom: 1rem;
}
.form-field-box label {
    display: block;
    font-weight: 600;
    font-size: 0.85rem;
    text-align: left;
    margin-bottom: 0.4rem;
}
.dark-mode .form-field-box {
    border-color: rgba(255, 255, 255, 0.15);
}

/* NOTE: keep this block above the ".info-toggle" @media (max-width: 767px)
   rule further down - that rule is missing its closing brace, so everything
   after it only applies on phone-width screens. */

/* Start Page tabs (up to 6 separate Start Pages). Desktop: a thin strip of vertical
   tabs on the left edge, exactly as wide as the sidebar dots button (18px) and
   starting just under it; "New tab" is always the last one. The tab you are on is
   pressed in. Each tab's color is set inline as --tab-color / --tab-text. */
#start-tabs {
    position: fixed;
    top: 106px;
    left: var(--fs-left-navigation-width);
    transform: translateX(-50%);
    z-index: 99;
    display: flex;
    flex-direction: column;
    align-items: stretch;
    gap: 4px;
    width: 18px;
}

#main-wrapper.sidebar-hidden #start-tabs {
    left: 10px;
}

#start-tabs .start-tab {
    display: block;
    width: 18px;
    padding: 8px 0;
    border-radius: 3px;
    /* Every tab is its solid color; the tab you are on is marked by bolder letters. */
    background: var(--tab-color, #6c757d);
    color: var(--tab-text, #fff);
    border: 1px solid rgba(0, 0, 0, 0.25);
    font-size: 11px;
    line-height: 16px;
    font-weight: 500;
    text-align: center;
    text-decoration: none;
    white-space: nowrap;
    opacity: 1;
    cursor: pointer;
}

#start-tabs .start-tab span {
    display: block;
    writing-mode: vertical-rl;
    transform: rotate(180deg);
    margin: 0 auto;
}

#start-tabs .start-tab:hover,
#start-tabs .start-tab.active {
    background: var(--tab-color, #6c757d);
}

#start-tabs .start-tab:hover {
    opacity: 1;
    text-decoration: none;
}

#start-tabs .start-tab.active {
    opacity: 1;
    font-weight: 700;
}

#start-tabs .start-tab-new,
#start-tabs .start-tab-new:hover,
.dark-mode #start-tabs .start-tab-new {
    opacity: 1;
    background: #17a2b8;
    /* Dark letters: on this teal they read better than white (the standard contrast rule). */
    color: #1c1f23;
    border: 1px solid rgba(0, 0, 0, 0.25);
    font-weight: 600;
}

/* Dark mode: the tab is just its color (no dimming that turns it muddy, no dark
   border) with white letters. The sitewide ".dark-mode *" wildcard gives every
   element a dark fill, including the box around the letters inside each tab, which
   showed as a black block with only a thin edge of color - so the letters' box is
   made transparent here. */
.dark-mode #start-tabs .start-tab {
    background: var(--tab-color, #6c757d);
    opacity: 1;
    border-color: transparent;
}

.dark-mode #start-tabs .start-tab span {
    background: transparent !important;
}

/* "New Tab" is always its own teal, in dark mode too - it never takes the logo color
   (the rule above gives every other tab its color, so this is more specific to win). */
.dark-mode #start-tabs .start-tab.start-tab-new,
.dark-mode #start-tabs .start-tab.start-tab-new:hover {
    background: #17a2b8;
}

/* The sitewide dark-mode rule forces white letters on everything; New Tab keeps its dark letters. */
.dark-mode #start-tabs .start-tab.start-tab-new,
.dark-mode #start-tabs .start-tab.start-tab-new span {
    color: #1c1f23 !important;
}

/* The "+" in the empty Start Page message: clickable, opens Add Category. */
.start-grid-empty-add {
    display: inline-block;
    color: #17a2b8;
    padding: 0 4px;
}

.start-grid-empty-add:hover {
    color: #117a8b;
}

/* Tablets and phones: the Start Page never scrolls sideways, so nothing can be dragged
   left or right (the message, the tabs row or a wide box can't push the page wider). */
@media (max-width: 991px), (pointer: coarse) {
    body.start-boxes-mode {
        overflow-x: hidden;
    }

    body.start-boxes-mode #start-grid-wrapper {
        max-width: 100%;
        overflow-x: clip;
    }
}

/* The empty-tab message is 12.5% larger than body text (1rem -> 1.125rem), on every screen size. */
.start-grid-container > p.text-muted {
    font-size: 1.125rem;
}

/* Desktop and tablet: the message stays on one line (the phone layout can wrap). It only takes
   the width it needs, so a widget box beside it isn't pushed off the right edge of the page. */
@media (min-width: 768px) {
    .start-grid-container > p.text-muted {
        white-space: nowrap;
        flex: 0 0 auto;
    }
}

/* With a Start Page background showing (a picture or a color), the empty-tab message sits
   on a white card with black text so it reads over anything; the "+" keeps its own
   color. Without a background it stays plain text. The card is only as wide as the
   message. (!important beats the sitewide dark-mode fill and the ps-2 padding.) */
body.start-bg-on .start-grid-container > p.text-muted {
    background: #fff !important;
    color: #000 !important;
    padding: 10px 18px !important;
    border-radius: 10px;
    flex: 0 0 auto;
    align-self: flex-start;
    width: fit-content;
    max-width: 100%;
}

/* Dark mode: the sitewide ".dark-mode *" rule forces white text on everything with a very
   specific selector, which left this card white with white words. Anchored on the Start
   Page's id so black text (and the teal "+") win. */
body.start-bg-on #start-grid-wrapper .start-grid-container > p.text-muted {
    color: #000 !important;
    background: #fff !important;
}

body.start-bg-on #start-grid-wrapper .start-grid-container > p.text-muted a.start-grid-empty-add,
body.start-bg-on #start-grid-wrapper .start-grid-container > p.text-muted a.start-grid-empty-add i {
    color: #17a2b8 !important;
    background: transparent !important;
}

/* The small outlined "Start" / "Favorites" buttons beside the page title (Start on
   Favorites, Favorites on the Start Page). The sitewide dark-mode wildcard forces white
   text and a dark fill on everything, so dark mode sets the teal text (by id, to
   outrank it) and a clear fill explicitly. */
.start-nav-pill {
    display: inline-block;
    color: var(--nav-pill-color, #17a2b8);
    background: transparent;
    border: 1px solid var(--nav-pill-color, #17a2b8);
    font-size: 9.3px;
    font-weight: 500;
    line-height: 1.3;
    /* "Start" and "Favorites" have no descenders, so even padding leaves the word sitting high. */
    padding: 2px 6.4px 0.8px;
    border-radius: 4.3px;
    vertical-align: middle;
}

a:hover .start-nav-pill {
    background: var(--nav-pill-color, #17a2b8);
    color: var(--nav-pill-text, #fff);
}

.dark-mode .start-nav-pill {
    background: transparent !important;
}

.dark-mode #favoritesStartGrid .start-nav-pill,
.dark-mode #startGridBackToFavorites .start-nav-pill {
    color: var(--nav-pill-color, #17a2b8) !important;
}

.dark-mode #favoritesStartGrid:hover .start-nav-pill,
.dark-mode #startGridBackToFavorites:hover .start-nav-pill {
    background: var(--nav-pill-color, #17a2b8) !important;
    color: var(--nav-pill-text, #fff) !important;
}

/* With a Start Page background showing, the outline would be hard to read over the
   picture or color, so the button is a solid fill in the logo color with white letters
   (light and dark mode alike). */
body.start-bg-on #favoritesStartGrid .start-nav-pill,
body.start-bg-on #startGridBackToFavorites .start-nav-pill,
body.dark-mode.start-bg-on #favoritesStartGrid .start-nav-pill,
body.dark-mode.start-bg-on #startGridBackToFavorites .start-nav-pill {
    background: var(--nav-pill-color, #17a2b8) !important;
    border-color: var(--nav-pill-color, #17a2b8) !important;
    color: var(--nav-pill-text, #fff) !important;
}

/* The "Start" button on the Favorites page is always a solid fill in the logo color (letters
   black or white by contrast); hovering it makes the button 10% darker. The "Favorites" button
   on the Start Page keeps its outline. Anchored on the button's id, with !important for dark mode. */
#favoritesStartGrid .start-nav-pill {
    background: var(--nav-pill-color, #17a2b8);
    color: var(--nav-pill-text, #fff);
    border-color: var(--nav-pill-color, #17a2b8);
}

#favoritesStartGrid:hover .start-nav-pill {
    background: var(--nav-pill-color, #17a2b8);
    color: var(--nav-pill-text, #fff);
    filter: brightness(0.9);
}

.dark-mode #favoritesStartGrid .start-nav-pill,
.dark-mode #favoritesStartGrid:hover .start-nav-pill {
    background: var(--nav-pill-color, #17a2b8) !important;
    color: var(--nav-pill-text, #fff) !important;
    border-color: var(--nav-pill-color, #17a2b8) !important;
}

.dark-mode #favoritesStartGrid:hover .start-nav-pill {
    filter: brightness(0.9);
}

/* The "Favorites" button on the Start Page also gets 10% darker when hovered (on top of its
   own hover fill, and over a background where it is already solid). */
#startGridBackToFavorites:hover .start-nav-pill {
    filter: brightness(0.9);
}

/* Admin-chosen alternatives to the colored Start / Favorites button (Manage Defaults): "outline"
   and "text". They have their own class, so none of the colored-button rules above apply to them;
   !important beats the sitewide dark-mode wildcard. */
.start-nav-alt {
    display: inline-block;
    vertical-align: middle;
    line-height: 1.3;
    background: transparent !important;
}

.start-nav-alt-outline {
    font-size: 9.3px;
    font-weight: 500;
    padding: 2px 6.4px 0.8px;
    border: 1px solid var(--nav-pill-color, #17a2b8);
    border-radius: 4.3px;
    color: var(--nav-pill-color, #17a2b8) !important;
}

a:hover .start-nav-alt-outline {
    background: var(--nav-pill-color, #17a2b8) !important;
    color: var(--nav-pill-text, #fff) !important;
}

.start-nav-alt-text {
    font-size: 12px;
    font-weight: 500;
    color: #1c1f23 !important;
}

a:hover .start-nav-alt-text {
    text-decoration: underline;
}

.dark-mode .start-nav-alt-text {
    color: #fff !important;
}

/* Manage Defaults: one selectable tile per Start / Favorites button style, previewing the real look. */
.start-nav-option {
    position: relative;
    display: block;
    height: 100%;
    padding: 18px 10px 12px;
    border: 1px solid #dee2e6;
    border-radius: 10px;
    text-align: center;
    cursor: pointer;
}

.start-nav-option:hover {
    border-color: #17a2b8;
}

.start-nav-option.selected {
    border-color: #17a2b8;
    box-shadow: 0 0 0 3px rgba(23, 162, 184, 0.25);
}

.start-nav-option .start-nav-style-radio {
    position: absolute;
    opacity: 0;
    pointer-events: none;
}

/* The colored button as it looks on Favorites (a solid fill), not the bare outline the pill starts from. */
.start-nav-option .start-nav-pill {
    background: var(--nav-pill-color, #17a2b8);
    color: var(--nav-pill-text, #fff);
}

.start-nav-option-preview {
    display: flex;
    align-items: center;
    justify-content: center;
    min-height: 44px;
    margin-bottom: 10px;
    font-size: 22px;
}

/* Over a Start Page picture or color the plain styles sit on a white card so they stay readable. */
body.start-bg-on .start-nav-alt {
    background: rgba(255, 255, 255, 0.88) !important;
    border-radius: 4.3px;
    padding: 2px 6.4px 0.8px;
}

body.start-bg-on .start-nav-alt-text {
    color: #1c1f23 !important;
}

/* The word that stands in for the Favorites button beside a Start-button icon takes the bar's own color instead of a white card. */
body.start-bg-on .start-nav-alt-follows-bar {
    background: transparent !important;
    padding: 0;
}

body.start-bg-on a:hover .start-nav-alt-outline {
    background: var(--nav-pill-color, #17a2b8) !important;
}

/* Every other icon button gets the same 10% darker on hover: the buttons at the top right
   (+, gear, view, ellipsis - including their faint box over a background picture) and the icons
   beside the page titles (Start Page: pencil, +, archive, dark-mode icon; Favorites and other
   pages: the icons in the title row). Only the button itself is filtered, never a menu. */
.topbar .topLink:hover,
.topbar .topGear:hover,
.topbar .topView:hover,
.topbar .topEllip:hover,
.start-grid-toolbar > a:not(.start-grid-icon-toggle):hover,
.titleText > a:not(.widget-start-grid):hover,
.favText ~ a:not(.start-grid-icon-toggle):not(.widget-start-grid):hover {
    filter: brightness(0.9);
}

@media (hover: hover) {
/* Light mode: the title icons get 25% brighter on hover (no grey highlight). */
body:not(.dark-mode) .start-grid-toolbar > a:not(.start-grid-icon-toggle):hover,
body:not(.dark-mode) .titleText > a:not(.widget-start-grid):hover,
body:not(.dark-mode) .favText ~ a:not(.start-grid-icon-toggle):not(.widget-start-grid):hover {
    filter: brightness(1.25);
}

/* Dark mode: a 10% filter is hard to see on the small icons beside the titles, so they get a
   soft light highlight behind them on hover (a ring of the same grey around the icon, so nothing
   moves). Anchored on the Start Page's id where it exists, with !important, so the see-through
   and dark-mode rules for the title row don't hide it. */
.dark-mode #start-grid-wrapper .start-grid-toolbar > a:not(.start-grid-icon-toggle):hover,
.dark-mode .titleText > a:not(.widget-start-grid):hover {
    border-radius: 6px;
    background: rgba(255, 255, 255, 0.16) !important;
    box-shadow: 0 0 0 4px rgba(255, 255, 255, 0.16);
}
}

/* The "Start tab different color than logo" switch in the Edit Tab window: the sitewide
   modal switches look the same on and off (only the knob moves), which made it hard to see
   that it was on. This one fills with the theme color and shows a white knob when on -
   scoped to this window only, like the Public Sort toggles. */
#modal-start-tab #st-dropdown:checked,
#modal-start-tab #st-diff-color:checked {
    background-color: var(--fs-info-background, #148c9f) !important;
    border-color: var(--fs-info-background, #148c9f) !important;
    background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%23fff'/%3e%3c/svg%3e") !important;
}

.start-tab-edit {
    color: #767676;
}

.start-tab-edit:hover {
    color: #17a2b8;
}

/* Phones and touch tablets: no room on the left edge, so the same tabs sit in a row
   above the boxes. */
@media (max-width: 991px), (pointer: coarse) {
    #start-tabs,
    #main-wrapper.sidebar-hidden #start-tabs {
        position: static;
        transform: none;
        flex-direction: row;
        flex-wrap: wrap;
        width: auto;
        gap: 6px;
        margin: 0 15px 0.75rem;
    }

    #start-tabs .start-tab {
        width: auto;
        padding: 0 12px;
        border-radius: 7px;
        line-height: 26px;
        font-size: 12px;
    }

    #start-tabs .start-tab span {
        writing-mode: horizontal-tb;
        transform: none;
    }
}

/* Phones and tablets: the tab buttons are replaced by a pull-down. The page title (the current
   tab's name) gets a little arrow and opens a list of the tabs, each with its color dot, the
   current one in bold, and "New Tab" at the bottom. The row of tab buttons is hidden. Desktop
   (mouse, wide) keeps the strip on the left and never shows the arrow or the list. */
.start-tab-caret {
    display: none;
}

.start-tab-menu {
    display: none;
}

@media (max-width: 991px), (pointer: coarse) {
    #start-tabs,
    #main-wrapper.sidebar-hidden #start-tabs {
        display: none !important;
    }

    #start-tab-title {
        cursor: pointer;
    }

    .start-tab-caret {
        display: inline-block;
        margin-left: 7px;
        font-size: 0.6em;
        vertical-align: middle;
    }

    .start-grid-toolbar {
        position: relative;
    }

    .start-tab-menu.open {
        display: block;
        position: absolute;
        top: 100%;
        left: 0;
        z-index: 200;
        min-width: 210px;
        margin-top: 6px;
        padding: 6px;
        background: #fff;
        border: 1px solid rgba(0, 0, 0, 0.15);
        border-radius: 8px;
        box-shadow: 0 6px 18px rgba(0, 0, 0, 0.18);
    }

    .start-tab-menu-item {
        display: flex;
        align-items: center;
        gap: 9px;
        padding: 10px 12px;
        border-radius: 6px;
        color: #1c1f23;
        font-size: 15px;
        line-height: 1.2;
        text-decoration: none;
    }

    .start-tab-menu-item.current {
        font-weight: 700;
        background: rgba(0, 0, 0, 0.06);
    }

    .start-tab-menu-new {
        margin-top: 4px;
        border-top: 1px solid rgba(0, 0, 0, 0.12);
        border-radius: 0 0 6px 6px;
        color: #0f6f80;
    }


    /* Solid, so the page never shows through the list. With a background on and After Dark, the
       Start Page turns everything inside the title row see-through, which left this list
       see-through too; anchoring on the Start Page's ids and using !important wins over it. */
    #start-grid-wrapper #start-tab-menu.open {
        background: #fff !important;
    }

    .dark-mode #start-grid-wrapper #start-tab-menu.open {
        background: #2a2a2a !important;
    }

    .dark-mode #start-grid-wrapper #start-tab-menu .start-tab-menu-item {
        background: transparent !important;
        color: #fff !important;
    }

    .dark-mode #start-grid-wrapper #start-tab-menu .start-tab-menu-item.current {
        background: #000 !important;
    }

    /* The colored dot and the "+" keep their colors over the see-through rules above (the dot's
       color comes from --dot, set on each item). */
    #start-grid-wrapper #start-tab-menu .start-tab-dot {
        background: var(--dot, #6c757d) !important;
    }

    #start-grid-wrapper #start-tab-menu .start-tab-menu-new i {
        color: inherit !important;
        background: transparent !important;
    }
    .start-tab-dot {
        flex: 0 0 auto;
        width: 12px;
        height: 12px;
        border-radius: 50%;
        border: 1px solid rgba(0, 0, 0, 0.25);
        background: var(--dot, #6c757d);
    }
}

/* "Show tabs as a drop-down" (Edit Tab window): the same title pull-down phones and tablets always
   use, on any screen - the side strip is hidden and the page title opens the tab list. The toolbar
   keeps its own position (on desktop it is fixed in the corner, which also anchors the list). */
#start-grid-wrapper.start-tabs-dropdown #start-tabs,
#main-wrapper.sidebar-hidden #start-grid-wrapper.start-tabs-dropdown #start-tabs {
    display: none !important;
}

#start-grid-wrapper.start-tabs-dropdown #start-tab-title {
    cursor: pointer;
}

#start-grid-wrapper.start-tabs-dropdown .start-tab-caret {
    display: inline-block;
    margin-left: 7px;
    font-size: 0.6em;
    vertical-align: middle;
}

#start-grid-wrapper.start-tabs-dropdown .start-tab-menu.open {
    display: block;
    position: absolute;
    top: 100%;
    left: 0;
    z-index: 200;
    min-width: 210px;
    margin-top: 6px;
    padding: 6px;
    background: #fff !important;
    border: 1px solid rgba(0, 0, 0, 0.15);
    border-radius: 8px;
    box-shadow: 0 6px 18px rgba(0, 0, 0, 0.18);
}

#start-grid-wrapper.start-tabs-dropdown .start-tab-menu-item {
    display: flex;
    align-items: center;
    gap: 9px;
    padding: 10px 12px;
    border-radius: 6px;
    color: #1c1f23;
    font-size: 15px;
    line-height: 1.2;
    text-decoration: none;
}

#start-grid-wrapper.start-tabs-dropdown .start-tab-menu-item.current {
    font-weight: 700;
    background: rgba(0, 0, 0, 0.06);
}

#start-grid-wrapper.start-tabs-dropdown .start-tab-menu-new {
    margin-top: 4px;
    border-top: 1px solid rgba(0, 0, 0, 0.12);
    border-radius: 0 0 6px 6px;
    color: #0f6f80;
}

#start-grid-wrapper.start-tabs-dropdown .start-tab-dot {
    flex: 0 0 auto;
    width: 12px;
    height: 12px;
    border-radius: 50%;
    border: 1px solid rgba(0, 0, 0, 0.25);
    background: var(--dot, #6c757d) !important;
}

#start-grid-wrapper.start-tabs-dropdown .start-tab-menu-new i {
    color: inherit !important;
    background: transparent !important;
}

.dark-mode #start-grid-wrapper.start-tabs-dropdown #start-tab-menu.open {
    background: #2a2a2a !important;
}

.dark-mode #start-grid-wrapper.start-tabs-dropdown #start-tab-menu .start-tab-menu-item {
    background: transparent !important;
    color: #fff !important;
}

.dark-mode #start-grid-wrapper.start-tabs-dropdown #start-tab-menu .start-tab-menu-item.current {
    background: #000 !important;
}

/* A soft grey highlight on the tab list's entries as the pointer (or a finger) moves over them - in
   the phone/tablet pull-down and the desktop drop-down alike. The current tab keeps its own
   stronger highlight. The dark-mode rules use the Start Page's ids so they win over the
   see-through and dark-fill rules above. */
#start-tab-menu .start-tab-menu-item:hover {
    background: rgba(0, 0, 0, 0.09);
}

#start-tab-menu .start-tab-menu-item.current:hover {
    background: rgba(0, 0, 0, 0.09);
}

.dark-mode #start-grid-wrapper #start-tab-menu .start-tab-menu-item:hover {
    background: #3d3d3d !important;
}

.dark-mode #start-grid-wrapper #start-tab-menu .start-tab-menu-item.current:hover {
    background: #000 !important;
}

/* Start Page (both styles), desktop/tablet: columns are only as wide as their
   longest link name (within a minimum and maximum; longer names cut off with
   "..." as before) instead of every column stretching to a quarter of the
   page, and the row of columns sits in the middle with the same space before
   the first column and after the last one.
   On a narrower screen (a tablet, or a desktop-mode iPad at about 980px) four
   full-size columns are wider than the screen, and a centered row that is too
   wide gets cut off on BOTH sides. So the columns may shrink (flex-shrink), the
   minimum width scales with the screen (never more than 328px), the side space
   grows with it, and "safe center" keeps the first column from being cut off if
   it still doesn't fit. Phones keep the normal full-width columns. */
@media (min-width: 801px) {
    .start-grid-container {
        justify-content: center;
        justify-content: safe center;
        padding-left: clamp(15px, 4vw, 60px);
        padding-right: clamp(15px, 4vw, 60px);
    }

    .start-grid-container .start-grid-col {
        flex: 0 1 auto;
        min-width: min(328px, 20vw);
        max-width: 530px;
    }
}


/* Boxes style, tablet/desktop: every column is the same width (328px, shrinking on a narrower screen)
   instead of growing to fit its longest content - a News box with long headlines used to make its
   whole column up to 530px wide. Long headlines wrap onto more lines instead. Lists style keeps the
   fit-to-content columns above. */
@media (min-width: 801px) {
    .start-grid-container.start-grid-boxes .start-grid-col {
        flex: 0 1 328px;
        max-width: 328px;
    }
}
/*********************************************************
    START PAGE "BOXES" STYLE
    (Start Style: Lists | Boxes in the dashboard's ellipsis menu)
 *********************************************************/

/* Each category becomes a box. Its color, when one is chosen (Color on the
   box's own menu), arrives as --box-color - same idea as a link card's
   --hilite-color. */
.start-grid-boxes .start-grid-bucket {
    background: #fff;
    border: 1px solid rgba(0, 0, 0, 0.12);
    border-radius: 8px;
    padding: 8px 10px 10px;
}

.start-grid-boxes .start-grid-bucket.start-box-colored {
    background: var(--box-color);
}

/* The box's "..." menu button and its move (drag) handle sit together in the
   top-right corner of the box instead of right after the title: the title takes
   the free space, which pushes the two buttons to the far end of the header. */
.start-grid-boxes .start-grid-bucket-name {
    flex: 1 1 auto;
    min-width: 0;
}

/* Start Widgets (Weather / Clock / News boxes): they are boxes like the categories,
   so the box options (transparency, white, hide) apply to them too; this only
   styles what is inside them. */
.start-widget-body {
    padding: 2px 4px 6px;
    font-size: 0.85rem;
}

/* Clock: the numbers are sized to the box (cqw = a percentage of the box's own
   width), so they fill it instead of leaving a wide empty strip. The date under it
   scales the same way. */
.start-widget-clock {
    container-type: inline-size;
    text-align: center;
}

.start-widget-clock-time {
    font-size: 1.9rem; /* fallback where container units aren't supported */
    font-size: clamp(1.6rem, 15cqw, 4.2rem);
    font-weight: 700;
    line-height: 1.1;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

.start-widget-clock-date {
    font-size: clamp(0.85rem, 5.5cqw, 1.3rem);
    opacity: 0.75;
    margin-top: 2px;
}

/* Weather: a big icon and temperature on the left, small "chips" (today's high/low,
   wind, sunrise, sunset) under them, then the 5-day forecast with a range bar per day. */
.start-widget-weather-hero {
    display: flex;
    align-items: center;
    gap: 14px;
}

.start-widget-weather-emoji {
    font-size: 3.4rem;
    line-height: 1;
    filter: drop-shadow(0 2px 4px rgba(0, 0, 0, 0.18));
}

.start-widget-weather-now {
    display: flex;
    flex-direction: column;
    min-width: 0;
}

.start-widget-weather-temp {
    font-size: 2.6rem;
    font-weight: 700;
    line-height: 1;
}

.start-widget-weather-words {
    font-weight: 600;
    font-size: 0.95rem;
    margin-top: 2px;
}

.start-widget-weather-city {
    font-size: 0.8rem;
}

.start-widget-chips {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    margin-top: 10px;
}

.start-widget-chip {
    background: rgba(128, 128, 128, 0.16);
    border-radius: 999px;
    padding: 2px 10px;
    font-size: 0.75rem;
    white-space: nowrap;
}

/* The News box's text (headlines and their source lines) is 20% smaller than the other boxes' on tablets and
   desktops (768px and wider); phones keep the normal size. */
@media (min-width: 768px) {
    .start-widget-news {
        font-size: 80%;
    }

    /* The page gives every element its own 14px (a "*" rule), so the smaller size above would only reach the
       box itself. Everything inside the News box takes its size from the box instead (the source line a
       little smaller than the headline). */
    .start-widget-news *:not(.start-widget-news-source) {
        font-size: inherit;
    }

    .start-widget-news .start-widget-news-source {
        font-size: 87.5%;
    }
}

.start-widget-news-list {
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.start-widget-news-item {
    display: flex;
    flex-direction: column;
    text-decoration: none;
    color: inherit;
    line-height: 1.25;
}

.start-widget-news-item:hover .start-widget-news-title {
    text-decoration: underline;
}

.start-widget-news-title {
    font-weight: 600;
}

/* The Notes box: the user's own quick notes, newest first. In light mode each note is filled with its
   own color (sticky-note yellow unless changed), with dark or light text picked for that color;
   "color off" leaves it plain. Dark mode keeps the full color too (see the dark-mode rules below).
   Edit / color / delete sit under each note. */
/* The + beside the "Notes" title opens the add-a-note editor. */
.start-widget-note-add {
    display: inline-block;
    margin-left: 6px;
    padding: 0 4px;
    color: inherit;
    text-decoration: none;
}

.start-widget-note-add:hover {
    opacity: 0.6;
}

.start-widget-notes-list {
    display: flex;
    flex-direction: column;
    gap: 10px;
}

.start-widget-note {
    position: relative;
    padding: 8px 10px 4px;
    border-radius: 6px;
    background: var(--note-color, transparent);
    color: var(--note-text, inherit);
}

.start-widget-note.color-off {
    border: 1px solid rgba(128, 128, 128, 0.45);
}

.start-widget-note-text {
    line-height: 1.3;
    white-space: pre-wrap;
    overflow-wrap: anywhere;
}

.start-widget-note-actions {
    display: flex;
    justify-content: flex-end;
    gap: 2px;
    margin-top: 2px;
}

.start-widget-note-actions a {
    padding: 2px 6px;
    color: inherit;
    text-decoration: none;
    opacity: 0.65;
}

.start-widget-note-actions a:hover {
    opacity: 1;
}

/* The edit / color / delete icons stay out of sight on every device until the note is pointed at (a
   mouse) or tapped (a phone or tablet - the script adds .actions-open, since a tap is not a reliable
   hover). Their row keeps its height, so nothing jumps, and hidden icons can't be tapped by accident. */
.start-widget-note-actions {
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.12s;
}

.start-widget-note:hover .start-widget-note-actions,
.start-widget-note:focus-within .start-widget-note-actions,
.start-widget-note.actions-open .start-widget-note-actions {
    opacity: 1;
    pointer-events: auto;
}

.start-widget-note-editor {
    display: flex;
    flex-direction: column;
    gap: 6px;
    margin-bottom: 8px;
}

.start-widget-note-editor-buttons {
    display: flex;
    gap: 6px;
}

/* Dark mode: the sitewide dark rule makes every element dark with white text, so a note is put back
   to its own full color here (with the dark or light text chosen for that color). The id selector is
   what lets this beat that rule. A note with its color off stays a plain, outlined note. */
.dark-mode #start-grid-wrapper .start-widget-note {
    background-color: var(--note-color, transparent) !important;
    color: var(--note-text, #fff) !important;
}

.dark-mode #start-grid-wrapper .start-widget-note *:not(.btn):not(textarea) {
    background-color: transparent !important;
    color: var(--note-text, #fff) !important;
}

.dark-mode #start-grid-wrapper .start-widget-note.color-off {
    background-color: transparent !important;
}


/* The 5-day forecast under today's weather: one row per day - day, icon, high / low. */
.start-widget-forecast {
    display: flex;
    flex-direction: column;
    gap: 4px;
    margin-top: 12px;
    padding-top: 8px;
    border-top: 1px solid rgba(128, 128, 128, 0.3);
}

/* day | icon | low | range bar | high */
.start-widget-forecast-row {
    display: grid;
    grid-template-columns: 2.9rem 1.7rem 2rem 1fr 2rem;
    align-items: center;
    gap: 4px;
}

.start-widget-forecast-day {
    font-weight: 600;
    font-size: 0.85rem;
}

.start-widget-forecast-emoji {
    font-size: 1.2rem;
    line-height: 1.3;
}

.start-widget-forecast-lo {
    text-align: right;
    font-variant-numeric: tabular-nums;
}

.start-widget-forecast-hi {
    text-align: left;
    font-variant-numeric: tabular-nums;
}

/* The bar sits in a faint track; its position and length show that day's low to high
   against the whole week's coldest and hottest. */
.start-widget-forecast-track {
    position: relative;
    height: 6px;
    border-radius: 3px;
    background: rgba(128, 128, 128, 0.22);
}

.start-widget-forecast-bar {
    position: absolute;
    top: 0;
    bottom: 0;
    border-radius: 3px;
    background: linear-gradient(90deg, #4aa3ff, #ffb347);
}

/* Small grey text inside a widget that stays readable on a colored or white box. */
.start-widget-muted {
    opacity: 0.65;
}

/* The plain dark-mode category rule above sets border: none, so the border
   has to be a full declaration here (color alone left it invisible), and the
   fill is a shade lighter than the page so the box actually reads. */
.dark-mode .start-grid-boxes .start-grid-bucket {
    background: #3f3f3f;
    border: 1px solid #5a5a5a;
}

/* Inside a box, every link row reserved room on its right for the "..." menu
   button (invisible until hover), which left a wide gap between the end of a
   link's text and the box's right edge. Here the button floats over the end of
   the row instead, so the space on the right matches the left. */
.start-grid-boxes .start-grid-link {
    padding-right: 4px;
}

.start-grid-boxes .start-grid-link-actions {
    position: absolute;
    right: 2px;
    top: 0;
    bottom: 0;
    display: flex;
    align-items: center;
}

/* Phones only: in a Start Page box the "..." button sat too close to the last letter of a
   link. The row gets two more spaces (2ch) of room on its right, which moves the button that
   far to the right without changing the link text. Tablets and desktop are untouched. */
@media (max-width: 767px) {
    .start-grid-boxes .start-grid-bucket:not(.start-grid-icons) .start-grid-link {
        padding-right: calc(4px + 2ch);
    }
}

/* List-style links (Lists, and Boxes with Box Links: List), desktop/tablet: the
   "..." menu button sits about two spaces after the last letter of the link
   instead of at the far end of the row, and the row is only as wide as its
   text so the clickable area matches. (Icon tiles keep their corner button.)
   Phones already have their own version of this above. */
@media (min-width: 768px) {
    .start-grid-bucket:not(.start-grid-icons) .start-grid-link {
        width: fit-content;
        max-width: 100%;
    }

    .start-grid-bucket:not(.start-grid-icons) .start-grid-link-name {
        flex: 0 1 auto;
    }

    .start-grid-bucket:not(.start-grid-icons) .start-grid-link-actions {
        position: relative;
        top: auto;
        right: auto;
        bottom: auto;
        display: block;
        margin-left: -3px; /* row gap (6px) + button padding (4px) - 3px = about two spaces of link text */
    }
}

/* Boxes > Box Links: Icons. Each link is its favicon at the same 40px the Icons
   view uses, with its title underneath (up to 2 lines, then "..."), 4 to a row
   inside the box; the "..." menu floats in the tile's corner. */
.start-grid-icons .start-grid-links {
    display: grid;
    grid-template-columns: repeat(4, minmax(0, 1fr));
    gap: 6px 4px;
    align-items: start;
    justify-items: center;
}

.start-grid-icons .start-grid-link {
    width: 100%;
    flex-direction: column;
    justify-content: flex-start;
    gap: 3px;
    padding: 6px 2px;
}

.start-grid-icons .start-grid-favicon {
    width: 40px;
    height: 40px;
}

.start-grid-icons .start-grid-favicon-letter {
    border-radius: 8px;
    font-size: 1.4rem;
}

.start-grid-icons .start-grid-link-name {
    flex: 0 0 auto;
    /* width 0 + min-width 100%: the title fills the tile but adds nothing to
       the column's own width, so long titles wrap inside the tile instead of
       stretching the whole column. */
    width: 0;
    min-width: 100%;
    max-width: 100%;
    text-align: center;
    font-size: 0.9rem;
    line-height: 1.2;
    white-space: normal;
    overflow-wrap: anywhere;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

.start-grid-icons .start-grid-link-actions {
    top: 0;
    bottom: auto;
    right: 0;
}


/* Tablets (and phones / touch screens): in dark mode the sitewide wildcard gives the invisible "..."
   button's wrapper its own dark fill, and in a narrow icon tile that little box sits over the
   top-right corner of the icon and cuts a piece out of it. The wrapper (and the button until it is
   shown) is see-through here; the open menu keeps its own background. */
@media (max-width: 991px), (pointer: coarse) {
    .dark-mode .start-grid-icons .start-grid-link-actions {
        background-color: transparent !important;
    }

    .dark-mode .start-grid-icons .start-grid-link-actions .dropdown-toggle:not(.show) {
        background-color: transparent !important;
    }
}

/* The menu that opens from an icon tile's "..." (Color / Edit / Remove Link):
   text half the normal size, with the row padding and the menu's minimum width
   scaled down to match so it stays a compact popup. */
.start-grid-icons .start-grid-link-actions .dropdown-menu {
    font-size: 0.5rem;
    min-width: 5rem;
}

.start-grid-icons .start-grid-link-actions .dropdown-menu .dropdown-item {
    padding: 3px 0.75rem;
}

.start-grid-icons .start-grid-empty-category-add-link {
    grid-column: 1 / -1;
    justify-self: start;
}

/* Icon tiles are never colored: a link marked with a highlight color keeps
   that setting (it still shows in the List view), but the tile itself stays
   plain in Icons - no fill in light mode, no colored outline in dark mode. */
.start-grid-icons .start-grid-link.hilite,
.dark-mode .start-grid-icons .start-grid-link.hilite {
    background: transparent;
    border: 0;
}

/* Start Page "..." menus (a box's, and a link's - Lists, Boxes list view and
   Boxes visual view) open on a click, like the "..." menus everywhere else on
   the site. The sitewide ".dropdown:hover .dropdown-menu" rule would open them
   just by resting the mouse on the button, so it is switched off here for these
   menus (an open menu, marked .show, is left alone). Bootstrap places the menu
   and flips it to whichever side has room. An open menu is lifted above the
   boxes and links that follow it. */
#start-grid-content .start-grid-bucket-actions:hover > .dropdown-menu:not(.show),
#start-grid-content .start-grid-link-actions:hover > .dropdown-menu:not(.show) {
    display: none;
}

#start-grid-content .start-grid-bucket:has(.dropdown-menu.show) {
    position: relative;
    z-index: 1000;
}

/* Dark mode and After Dark: a colored box (a category, or a Start Widget) keeps its full color, with
   dark or white text chosen for that color (--box-text, worked out where the box is drawn). The sitewide
   dark rule gives every element its own dark fill and white text, so the id selector and !important are
   what put the color back. Not while Make All Boxes White or Hide Boxes is on (they win), the open menus
   and colored link rows keep their own look, and a hovered link keeps the locked dark hover. Box
   Transparency still applies (the same --start-box-alpha the light-mode boxes use). */
.dark-mode:not(.start-white-boxes):not(.start-hide-boxes) #start-grid-wrapper .start-grid-boxes .start-grid-bucket.start-box-colored {
    background-color: color-mix(in srgb, var(--box-color) calc(var(--start-box-alpha, 1) * 100%), transparent) !important;
    border: 1px solid rgba(255, 255, 255, 0.15);
    color: var(--box-text, #fff) !important;
}

.dark-mode:not(.start-white-boxes):not(.start-hide-boxes) #start-grid-wrapper .start-grid-boxes .start-grid-bucket.start-box-colored *:not(.dropdown-menu):not(.dropdown-menu *):not(.hilite):not(.start-widget-note):not(.start-widget-note *):not(.start-widget-chip):not(.start-widget-forecast-track):not(.start-widget-forecast-bar):not(.start-grid-link:hover):not(.start-grid-link:hover *) {
    background-color: transparent !important;
    color: var(--box-text, #fff) !important;
}


/* A link with its own highlight color keeps its outline in dark mode (the Keep Link Colors in Dark Mode
   switch still decides whether the outline shows) - it is only the box that is filled. So inside a
   colored box the link row has no dark fill of its own, only the outline it had. */
.dark-mode:not(.start-white-boxes):not(.start-hide-boxes) #start-grid-wrapper .start-grid-boxes .start-grid-bucket.start-box-colored .start-grid-link.hilite:not(:hover),
.dark-mode:not(.start-white-boxes):not(.start-hide-boxes) #start-grid-wrapper .start-grid-boxes .start-grid-bucket.start-box-colored .start-grid-link.hilite:not(:hover) *:not(.dropdown-menu):not(.dropdown-menu *) {
    background-color: transparent !important;
    color: var(--box-text, #fff) !important;
}
/* Icons view inside a colored box, dark mode: a link that has a highlight color would otherwise show as
   a dark block behind its icon (icon tiles are never colored; the tile is meant to be plain). See-through
   here, with the box's own text color. A hovered tile keeps the locked hover. */
.dark-mode:not(.start-white-boxes):not(.start-hide-boxes) #start-grid-wrapper .start-grid-boxes .start-grid-bucket.start-box-colored.start-grid-icons .start-grid-link.hilite:not(:hover),
.dark-mode:not(.start-white-boxes):not(.start-hide-boxes) #start-grid-wrapper .start-grid-boxes .start-grid-bucket.start-box-colored.start-grid-icons .start-grid-link.hilite:not(:hover) *:not(.dropdown-menu):not(.dropdown-menu *) {
    background-color: transparent !important;
    border-color: transparent !important;
    color: var(--box-text, #fff) !important;
}

/* Start Page links, dark mode only (icon tiles and list rows alike): no hover effect - no dark highlight
   behind the link and no color change; light mode keeps its normal hover. The "..." button that appears on
   hover and its menu are left as they are. A link inside a colored box keeps that box's text color while
   hovered. This overrides the locked dark-mode row hover lower in this file, on purpose, on the Start Page only. */
body.dark-mode .start-grid-link.start-grid-link:hover,
body.dark-mode .start-grid-link.start-grid-link:hover *:not(.dropdown-menu):not(.dropdown-menu *) {
    background-color: transparent !important;
}

.dark-mode:not(.start-white-boxes):not(.start-hide-boxes) #start-grid-wrapper .start-grid-boxes .start-grid-bucket.start-box-colored .start-grid-link:hover,
.dark-mode:not(.start-white-boxes):not(.start-hide-boxes) #start-grid-wrapper .start-grid-boxes .start-grid-bucket.start-box-colored .start-grid-link:hover *:not(.dropdown-menu):not(.dropdown-menu *) {
    background-color: transparent !important;
    color: var(--box-text, #fff) !important;
}

/* Phones and touch tablets: the "Start Page" title in white while a picture is behind the page, with a
   soft shadow so it stays readable over a bright part of the picture. */
@media (max-width: 991px), (pointer: coarse) {
    body.start-bg-on.ppg-image-bg .start-grid-toolbar h2 {
        color: #fff !important;
        text-shadow: 0 1px 3px rgba(0, 0, 0, 0.6);
    }
}

/* No top bar while Start Page is in Boxes style (a desktop with a mouse): the
   bar's own background and the search box go away, but the Full Sort logo stays
   where it is and the icon row (+ , gear, ellipsis) just floats over the page.
   Phones and touch tablets keep the normal, solid top bar - a see-through bar let the boxes show
   through it as the page scrolled underneath. */
@media (min-width: 992px) and (pointer: fine) {
    body.start-boxes-mode .topbar {
        background: transparent !important;
        box-shadow: none !important;
        pointer-events: none;
    }

    body.start-boxes-mode .topbar .d-inline-flex,
    body.start-boxes-mode .topbar .nav-toggler,
    body.start-boxes-mode .topbar #fullsort_logo,
    body.start-boxes-mode .topbar #fullsort_search_block {
        pointer-events: auto;
    }
}

/* The top bar over a Start Background, on every device (phone, tablet and desktop): always a solid
   bar, so anything scrolling underneath goes out of sight behind it (no blur, no
   see-through). Over a plain-color background it is that same color; over a
   picture (or After Dark) it keeps its normal white or dark color. */
@media screen {
    body.start-bg-on.start-bg-color:not(.dark-mode) .topbar {
        background-color: var(--start-bg-color) !important;
    }

    /* Over a picture, the picture continues into the bar: the bar holds its own
       copy of the page picture (fixed to the screen and sized exactly like the
       page's, so the two line up with no seam) showing just the strip the bar
       covers. Behind the bar's buttons, on top of its solid color - so the bar
       stays opaque and nothing scrolling underneath shows through. The bar's
       height (--start-bar-h) is set by the page. */
    body.start-bg-on.ppg-image-bg:not(.dark-mode) .topbar::before,
    body.start-bg-on.ppg-after-dark.dark-mode .topbar::before {
        content: "";
        position: fixed;
        inset: 0;
        z-index: -1;
        pointer-events: none;
        background-image: var(--start-bg-image, none);
        background-size: cover;
        background-position: center;
        background-repeat: no-repeat;
        clip-path: inset(0 0 calc(100% - var(--start-bar-h, 90px)) 0);
    }

    /* The search box in the bar: fully white. The search input is see-through by
       design (a second, hint input shows through it), so it only looks white
       because the bar behind it is white - and with the picture (or the page color) in the bar the
       background showed through the box. A white fill on the box itself fixes that. */
    body.start-bg-on.ppg-image-bg:not(.dark-mode) .topbar #fullsort_search_block .input-group,
    body.start-bg-on.ppg-image-bg:not(.dark-mode) .topbar #fullsort_search_block .twitter-typeahead,
    body.start-bg-on.start-bg-color:not(.dark-mode) .topbar #fullsort_search_block .input-group,
    body.start-bg-on.start-bg-color:not(.dark-mode) .topbar #fullsort_search_block .twitter-typeahead {
        background-color: #fff !important;
        border-radius: 0.25rem;
    }

    /* After Dark dims the page picture to a quarter - the bar's strip too. */
    body.start-bg-on.ppg-after-dark.dark-mode .topbar::before {
        filter: brightness(0.25);
    }

    /* After Dark, phones and tablets: the picture in the bar (the ::before above) was hidden by
       the sitewide dark-mode wildcard, which gives every wrapper inside the bar its own opaque
       dark fill - the desktop rule further up clears them, but only for the see-through
       desktop bar. Here the bar itself stays a solid dark color (so anything scrolling
       underneath stays out of sight) and only what is inside it goes see-through, so the
       picture shows behind the buttons. The menus keep their own backgrounds, and the colored
       Full Sort logo (a masked block whose background IS the logo) is left alone. */
    body.start-bg-on.ppg-after-dark.dark-mode .topbar *:not(.dropdown-menu):not(.dropdown-menu *):not(#fullsort-logo-colored) {
        background-color: transparent !important;
    }
}

/* After Dark also raises the picture out of the background layer (z-index: auto,
   see .ppg-after-dark.dark-mode .ppg-page-background), so it paints over any
   content that isn't positioned. Public Sort's boxes are positioned; the Start
   Page's are not, so the Start Page area is lifted above the picture here -
   otherwise the picture would sit on top of the boxes. */
body.start-bg-on.ppg-after-dark.dark-mode #start-grid-wrapper {
    position: relative;
    z-index: 1;
}

/* Desktop and tablet: the "Start Page" title row is fixed in the top bar, so the wrapper
   above can't hold a layer of its own (the title row would be stuck under the top bar, which is now
   solid). Only the boxes get lifted above the picture here; the title row and the side tabs sit in
   the page's own layer, above the bar. */
@media (min-width: 768px) {
    body.start-bg-on.ppg-after-dark.dark-mode #start-grid-wrapper {
        position: static;
        z-index: auto;
    }

    body.start-bg-on.ppg-after-dark.dark-mode #start-grid-content {
        position: relative;
        z-index: 1;
    }
}

/* Box Transparency (Start Background window): the boxes fade so the picture
   shows through them. --start-box-alpha is 1 for solid down to 0 for fully clear
   (set from the saved percentage in applyStartGrid()); only applied while a
   background is showing and the slider is above 0%. Dark mode needs the
   important flags and the inner reset because the sitewide ".dark-mode *"
   wildcard gives the box and everything in it its own solid dark fill. */
body.start-box-fade .start-grid-boxes .start-grid-bucket {
    background-color: color-mix(in srgb, #fff calc(var(--start-box-alpha, 1) * 100%), transparent) !important;
}

body.start-box-fade .start-grid-boxes .start-grid-bucket.start-box-colored {
    background-color: color-mix(in srgb, var(--box-color) calc(var(--start-box-alpha, 1) * 100%), transparent) !important;
}

body.start-box-fade.dark-mode .start-grid-boxes .start-grid-bucket {
    background-color: color-mix(in srgb, #3f3f3f calc(var(--start-box-alpha, 1) * 100%), transparent) !important;
}

body.start-box-fade.dark-mode .start-grid-boxes .start-grid-bucket.start-box-colored {
    background-color: transparent !important;
}

body.start-box-fade.dark-mode .start-grid-boxes .start-grid-bucket *:not(.dropdown-menu):not(.dropdown-menu *):not(.hilite) {
    background-color: transparent !important;
}

/* Link colors in dark mode: a colored link normally shows a colored outline in
   dark mode. On the Start Page that is off unless the "Keep Link Colors in Dark
   Mode" switch (Start Background window) is on - the outline goes see-through
   (its width stays, so nothing shifts) and the link keeps its plain look. The
   color itself stays saved on the link and still shows in light mode. */
body.dark-mode:not(.start-dark-link-colors) .start-grid-link.hilite {
    background: transparent;
    border-color: transparent;
}

/* Link colors in light mode: a colored link normally shows its color as a fill. With
   the "Keep Link Colors in Light Mode" switch (Start Background window) turned off the
   fill goes away and the link keeps its plain look; the color stays saved on the link
   and still shows in dark mode (if that switch is on) and everywhere else. */
body:not(.dark-mode).start-hide-light-link-colors .start-grid-link.hilite {
    background: transparent;
}

/* Make All Boxes White (Start Background window): every box a solid white card
   with dark text, whatever its own color - a colored box's color is left saved
   (only shown as white while this is on). The doubled ".start-grid-bucket" only
   raises specificity so this beats the color, fade and dark-mode rules above.
   Text goes dark in dark mode too, or it would be white on white. Hide Boxes
   below wins over this. */
body.start-white-boxes:not(.start-hide-boxes) .start-grid-boxes .start-grid-bucket.start-grid-bucket {
    background-color: color-mix(in srgb, #fff calc(var(--start-box-alpha, 1) * 100%), transparent) !important;
    border: 1px solid rgba(0, 0, 0, 0.12) !important;
}

body.start-white-boxes:not(.start-hide-boxes).dark-mode .start-grid-boxes .start-grid-bucket.start-grid-bucket *:not(.dropdown-menu):not(.dropdown-menu *):not(.hilite) {
    background-color: transparent !important;
    color: #222 !important;
}

body.start-white-boxes:not(.start-hide-boxes).dark-mode .start-grid-boxes .start-grid-bucket.start-grid-bucket .start-grid-link.hilite {
    color: #222 !important;
}

/* Hide Boxes (Start Background window): the boxes themselves disappear - no fill,
   no border - while every link, title and menu stays, sitting straight on the
   background. Wins over Make All Boxes White and Box Transparency. */
body.start-hide-boxes .start-grid-boxes .start-grid-bucket.start-grid-bucket {
    background-color: transparent !important;
    border-color: transparent !important;
    box-shadow: none !important;
}

body.start-hide-boxes.dark-mode .start-grid-boxes .start-grid-bucket.start-grid-bucket *:not(.dropdown-menu):not(.dropdown-menu *):not(.hilite) {
    background-color: transparent !important;
}

/* The sitewide ".dark-mode *" wildcard also gives the Start Page area's own
   wrappers (and the title/icon strip) an opaque dark fill - with the area lifted
   above the picture, that fill would cover the picture everywhere but the header.
   See-through here so the picture shows behind the boxes and the footer, and the
   "Start Page" title and its icons sit straight on it with no box. The boxes
   themselves and the forecast panel keep their own backgrounds. */
body.start-bg-on.ppg-after-dark.dark-mode #start-grid-wrapper,
body.start-bg-on.ppg-after-dark.dark-mode #start-grid-content,
body.start-bg-on.ppg-after-dark.dark-mode .start-grid-container,
body.start-bg-on.ppg-after-dark.dark-mode .start-grid-col,
body.start-bg-on.ppg-after-dark.dark-mode .start-grid-toolbar,
body.start-bg-on.ppg-after-dark.dark-mode .start-grid-toolbar *:not(.weather-forecast-panel):not(.weather-forecast-panel *) {
    background-color: transparent !important;
}

/* With a Start Page background showing: how the title row (title, edit pencil, Favorites, +,
   archive, dark-mode icon) is drawn depends on the picture behind it, measured on the server
   (StartBackgroundController::look()) and passed in as body classes:
     - start-bg-busy      the strip behind the row is busy -> a faint whitish backing (barely-white,
                          slightly rounded corners) so the small icons stay readable, dark text
     - neither class      the strip is plain and light -> no backing, dark text and icons
     - start-bg-text-light  plain and dark (or dark mode) -> no backing, light text and icons
   The same on desktop, tablet and phone. Anchored on the Start Page's id so it also beats the
   sitewide dark-mode rule (white text, dark fills), which is why it uses !important. */
@media screen {
    body.start-bg-on.start-bg-busy #start-grid-wrapper .start-grid-toolbar {
        display: inline-block;
        width: fit-content;
        max-width: calc(100% - 30px);
        background: rgba(255, 255, 255, 0.63) !important;
        border-radius: 6px;
        padding: 6px 12px !important;
    }

    body.start-bg-on #start-grid-wrapper .start-grid-toolbar h2 {
        color: #1c1f23 !important;
        text-shadow: none !important;
        background: transparent !important;
    }

    body.start-bg-on #start-grid-wrapper .start-grid-toolbar a {
        background: transparent !important;
    }

    body.start-bg-on #start-grid-wrapper .start-grid-toolbar a i {
        color: #1c1f23 !important;
        background: transparent !important;
    }

    /* The light bulb / sun is an inline SVG (its own stroke color, a pale yellow sun in dark
       mode), so it gets a dark indigo on a light or backed row... */
    body.start-bg-on #start-grid-wrapper .start-grid-toolbar a.darkMode svg {
        stroke: #4b0082 !important;
        background: transparent !important;
    }

    /* ...and light text and icons (with a soft shadow) straight over a plain dark background. */
    body.start-bg-on.start-bg-text-light #start-grid-wrapper .start-grid-toolbar h2 {
        color: #fff !important;
        text-shadow: 0 1px 3px rgba(0, 0, 0, 0.45) !important;
    }

    body.start-bg-on.start-bg-text-light #start-grid-wrapper .start-grid-toolbar a i {
        color: #fff !important;
    }

    body.start-bg-on.start-bg-text-light #start-grid-wrapper .start-grid-toolbar a.darkMode svg {
        stroke: #fce88a !important;
    }

    /* The gear, view and ellipsis buttons at the top right get the same faint whitish box, over a
       busy background picture (which also means never over a solid color), with dark icons. They
       are matched by id so the sitewide dark-mode rule and the After Dark see-through rule for the
       top bar don't win. */
    body.start-bg-on.start-bg-busy #fs-site-options-dropdown,
    body.start-bg-on.start-bg-busy #dropdownMenuResultsViewButton,
    body.start-bg-on.start-bg-busy #fs-bucket-dropdown {
        background: rgba(255, 255, 255, 0.63) !important;
        border-radius: 6px;
        color: #1c1f23 !important;
        /* All three boxes the same, shorter height with only a sliver of grey above and below the icon. */
        display: inline-flex;
        align-items: center;
        justify-content: center;
        box-sizing: border-box;
        height: 28px;
        padding-top: 0 !important;
        padding-bottom: 0 !important;
        line-height: 1;
    }

    body.start-bg-on.start-bg-busy #fs-site-options-dropdown *,
    body.start-bg-on.start-bg-busy #dropdownMenuResultsViewButton *,
    body.start-bg-on.start-bg-busy #fs-bucket-dropdown * {
        color: #1c1f23 !important;
        background: transparent !important;
    }

    /* In dark mode with After Dark the header's inner boxes are made see-through (so the picture
       shows), which also wiped out the faint box behind these three buttons and left their dark
       icons invisible. The extra :not()s only raise the specificity enough to win back the box. */
    body.start-bg-on.start-bg-busy.ppg-after-dark.dark-mode #fs-site-options-dropdown:not(.x):not(.y):not(.z),
    body.start-bg-on.start-bg-busy.ppg-after-dark.dark-mode #dropdownMenuResultsViewButton:not(.x):not(.y):not(.z),
    body.start-bg-on.start-bg-busy.ppg-after-dark.dark-mode #fs-bucket-dropdown:not(.x):not(.y):not(.z) {
        background-color: rgba(255, 255, 255, 0.63) !important;
    }

    /* Regular dark mode with no busy Start Page background picture (none, a plain color, or a plain picture): no grey boxes behind the title icons or the
       gear / view / ellipsis buttons (the sitewide dark-mode rule paints them grey). Only while at
       rest - hover, the open menu and the highlights above still show. */
    body.dark-mode.start-boxes-mode:not(.start-bg-busy) #start-grid-wrapper .start-grid-toolbar,
    body.dark-mode.start-boxes-mode:not(.start-bg-busy) #start-grid-wrapper .start-grid-toolbar > a:not(.start-grid-icon-toggle):not(:hover),
    body.dark-mode.start-boxes-mode:not(.start-bg-busy) #fs-site-options-dropdown:not(:hover):not(.show),
    body.dark-mode.start-boxes-mode:not(.start-bg-busy) #dropdownMenuResultsViewButton:not(:hover):not(.show),
    body.dark-mode.start-boxes-mode:not(.start-bg-busy) #fs-bucket-dropdown:not(:hover):not(.show) {
        background-color: transparent !important;
    }
}


/* The "..." (ellipsis) menu, while the Start Page is showing: only Start Columns,
   Start Background, Start Widgets and the Start Page on/off switch. Everything else in it (Help,
   Display Size, Link Columns, the Sort Links list) is for the other views, and
   comes back as soon as the Start Page is turned off. */
body.start-boxes-mode #fs-bucket-dropdown ~ .dropdown-menu > *:not(#startPageColumnsMenuItem):not(#startBackgroundMenuItem):not(#startWidgetsMenuItem):not(#toggleStartGrid) {
    display: none !important;
}

/* The Start Page switch is normally nudged 8px left (to line up with the sort
   items above it, which are hidden here). With nothing above it to line up with,
   that nudge pushed its hover highlight out past the left edge of the menu. */
body.start-boxes-mode #toggleStartGrid {
    margin-left: 0;
}

/* The View menu's "Details" section (Icon, Title, Description, and so on) only
   applies to the other views' link cards, so it is left out while the Start Page
   is showing - the divider above it, its heading and its checkboxes. The list of
   views itself stays, and Details is back as soon as a view is picked. */
body.start-boxes-mode .dropdown-menu[aria-labelledby="dropdownMenuResultsViewButton"] > hr,
body.start-boxes-mode .dropdown-menu[aria-labelledby="dropdownMenuResultsViewButton"] > h4:nth-of-type(2),
body.start-boxes-mode .dropdown-menu[aria-labelledby="dropdownMenuResultsViewButton"] > #form-view-fields {
    display: none;
}

/* No "+" (add link) button in the top bar while the Start Page is showing - links
   are added from a box's own menu or its "Add a link", and the "+" beside the
   "Start Page" title (add category) stays. */
body.start-boxes-mode #template-add-link-button {
    display: none;
}

/* Phone and touch tablet, Start Page: one space (1rem) less between the logo row and the row
   of buttons under it (the button row's own top padding goes), and a space (1rem)
   more above the "Start Page" title - its wrapper is normally pulled up by 1.25rem,
   which left the title tight against the top bar. */
@media (max-width: 767px), (pointer: coarse) {
    body.start-boxes-mode .topbar .py-3.px-0.pe-md-3.float-end.d-inline-flex {
        padding-top: 0 !important;
    }

    body.start-boxes-mode #start-grid-wrapper {
        margin-top: -0.25rem !important;
    }
}

@media (min-width: 992px) and (pointer: fine) {
    /* The "Start Page" title and its icons move up into the corner where the
       search box would be, level with the logo. They live inside the Start
       Page area, so they show only while Start Page does - leaving it brings
       back the usual title of whichever view is picked. The left edge clears
       the sidebar when it is showing. */
    body.start-boxes-mode #start-grid-wrapper .start-grid-toolbar {
        position: fixed;
        top: 20px;
        left: 20px;
        z-index: 60;
        margin: 0 !important;
    }

    body.start-boxes-mode #main-wrapper:not(.sidebar-hidden) #start-grid-wrapper .start-grid-toolbar {
        left: calc(var(--fs-left-navigation-width) + 20px);
    }

    body.start-boxes-mode #start-grid-content {
        padding-top: 0.5rem;
    }
}

/* Tablet (touch or 768-991px wide), Start Page: the "Start Page" title row is pinned in the top bar
   like on desktop, so it stays put when the page scrolls instead of moving under the bar. The row lines up with the left edge of the boxes. */
@media (min-width: 768px) and (max-width: 991px), (min-width: 768px) and (pointer: coarse) {
    body.start-boxes-mode #start-grid-wrapper .start-grid-toolbar {
        position: fixed;
        top: 20px;
        left: var(--start-box-left, 64px);
        max-width: calc(100vw - var(--start-box-left, 64px) - 190px);
        z-index: 60;
        margin: 0 !important;
    }

    body.start-boxes-mode #start-grid-content {
        padding-top: 0.5rem;
    }
}

/* Portrait tablet (768-991px), Start Page: the pinned title row and search box sit above the left column's layer, so
   they showed through it when the hamburger opened it. While the column is open they drop below it. */
@media (min-width: 768px) and (max-width: 991px) {
    body.start-boxes-mode #main-wrapper:has(.left-sidebar.show-sidebar) #start-grid-wrapper .start-grid-toolbar,
    body.start-boxes-mode.start-search-fits #main-wrapper:has(.left-sidebar.show-sidebar) .topbar #fullsort_search_block {
        z-index: 40;
    }
}

/* Wide tablet (touch, 992px and up) with the sidebar open: the pinned title row starts at the
   left edge of the boxes, but never further left than the sidebar's right edge, so it can not
   be drawn on top of the sidebar even if the measured box position is out of date. */
@media (min-width: 992px) and (pointer: coarse) {
    body.start-boxes-mode #main-wrapper:not(.sidebar-hidden) #start-grid-wrapper .start-grid-toolbar {
        left: max(var(--start-box-left, 64px), calc(var(--fs-left-navigation-width) + 20px));
        max-width: calc(100vw - max(var(--start-box-left, 64px), calc(var(--fs-left-navigation-width) + 20px)) - 190px);
    }
}

/* Desktop and tablet, Start Page: the search box sits in the top bar's corner beside the logo, about as wide
   as the pinned title row (never wider than the room left between the two). Its width and right edge are measured by
   the page (setStartBarHeight); when there is no room for a usable box it stays hidden. */
@media (min-width: 768px) {
    body.start-boxes-mode .topbar #fullsort_search_block {
        display: none;
    }

    body.start-boxes-mode.start-search-fits .topbar #fullsort_search_block {
        display: block;
        position: fixed;
        top: 20px;
        right: var(--start-search-right, 190px);
        width: var(--start-search-w, 300px) !important;
        margin: 0 !important;
        z-index: 60;
    }
}

/* Edit Link modal info icons (Start Category, Start Page Title) - 30%
   bigger on phone only, easier to tap than the desktop size. */
@media (max-width: 767px) {
    .info-toggle i {
        font-size: 130%;
    }
}

/* "Sort Links" label above the ellipsis menu's 4 sort options - the
   default .dropdown-header is small/muted, easy to miss as a section
   label rather than just another line of text. */
.sort-menu-header {
    font-size: 0.95rem;
    font-weight: 700;
    margin-top: 0.5rem;
    margin-bottom: 0.35rem;
}

/* Link Columns / Start Columns row: label and "3 | 4" stay on one line,
   but "3 | 4" is grouped into its own inline-flex unit so the two
   numbers always share one baseline - without this, "4" (bold, tighter
   line-height than the label span) sat visibly lower than "3". */
.layout-columns-toggle {
    display: inline-flex;
    align-items: baseline;
    gap: 0.35rem;
}

/* "Easy Scroll" bucket browser (test, Add Link only) - built from real
   .dropdown-item rows so it matches the app's existing menu styling
   (incl. dark mode) automatically, just with a small expand/collapse
   chevron and per-depth indent added. */
.bucket-tree-toggle {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 16px;
    color: #888;
    flex-shrink: 0;
    margin-right: 8px;
}

/* Bumps the actual tappable area to ~44px (the standard minimum touch
   target) without changing the visible 16px icon or shifting
   surrounding layout - padding grows the hit box, the matching
   negative margin pulls the box back to its original footprint. Only
   applied on touch devices (pointer: coarse) - on desktop the enlarged
   hitbox overlapped into neighboring rows above/below, making the
   chevron unreliable to click with a mouse. */
@media (pointer: coarse) {
    .bucket-tree-toggle {
        padding: 14px;
        margin: -14px 8px -14px -14px;
    }
}

.dark-mode .bucket-tree-toggle {
    color: #aaa;
}

.bucket-tree-name {
    overflow: hidden;
    text-overflow: ellipsis;
}

/* Sort Links / Start Page items in the top-right ellipsis menu - nudge
   left evenly (icon + label together) by about half a character space. */
#alphaSort, #newSort, #oldSort, #customSort, #toggleStartGrid {
    margin-left: -8px;
}

/* Public profile page (fullsort.com/username) - a sectioned grid
   layout instead of one plain stacked list: the header/bio spans the
   full width, then Buckets (wide) and Elsewhere (narrow) sit side by
   side below it. Every box is deliberately always light, even in dark
   mode - each is a small, contained card rather than the page's own
   background, so it reads fine on a dark page the
   same way the sticky-note yellow note cards do; !important beats the
   sitewide dark-mode text/background override. */
.public-profile-grid {
    display: flex;
    flex-direction: column;
    gap: 1.5rem;
    margin-top: 4px;
}

/* Pulls just the header box up so it visually sits inside the topbar's
   own space (same left position it already had - only the vertical
   position changes) - simple CSS on the existing block, not a
   restructuring of the shared topbar itself.

   A flat pixel pull is only safe because .topbar.topbar-transparent
   above now guarantees a 150px-tall topbar for every viewer - it used
   to rely on the sitewide 4.5rem topbar height, which
   is 9rem for a logged-in viewer but only 4.5rem for a guest (see
   HomeController::css()), so the same pull either overshot above the
   page (guest) or didn't reach far enough (owner). Fixed height, fixed
   pull, same 21px gap either way now. */
.topbar-transparent ~ #page-wrapper .ppg-box-header {
    position: fixed;
    z-index: 51;
    top: -8px;
    left: 20px;
    right: 20px;
    /* This box's own plain background/text isn't interactive - only
       its photo and title-edit pencil are (re-enabled below) - so a
       click anywhere else on it falls through to whatever it happens
       to be overlapping instead of being swallowed here. Fixes the
       Back to Home / dark-mode buttons above it being unclickable on
       every screen size, without moving this box's position at all. */
    pointer-events: none;
}

.topbar-transparent ~ #page-wrapper .ppg-box-header a,
.topbar-transparent ~ #page-wrapper .ppg-box-header .ppg-zoomable {
    pointer-events: auto;
}

/* The pulled-up header box above sits on top of (and visually
   overlaps) the topbar's own Back to Home / dark-mode toggle -
   without this they render fine but can't actually be clicked,
   since the header box's higher z-index intercepts the click first.
   Scoped to .topbar-transparent (only this page ever sets that flag),
   so the shared topbar markup itself isn't touched. */
.topbar-transparent .py-3.px-0.pe-md-3.float-end.d-inline-flex {
    position: relative;
    z-index: 52;
}

/* Tablet/desktop: photo on the left, title beside it with its badges
   underneath. Long titles and badges wrap instead of overflowing. */
@media (min-width: 768px) {
    .ppg-box-header > .d-flex.align-items-center.flex-wrap.gap-3 {
        flex-wrap: nowrap !important;
        align-items: flex-start !important;
        gap: 0.5rem !important;
    }

    .ppg-photo-badges-row {
        order: 1;
        flex-shrink: 0;
    }

    .ppg-badges-phone {
        display: none !important;
    }

    .ppg-title-block {
        order: 2;
        min-width: 0;
    }

    .ppg-title-block h1,
    .ppg-badges-wide .ppg-badge {
        max-width: 100%;
        overflow-wrap: anywhere;
    }
}

@media (max-width: 767px) {
    .ppg-badges-wide {
        display: none !important;
    }
}

/* Phone-only: nudges the profile header box (photo/name/badges) down
   40px past its base -8px position above, for more breathing room
   under the crowded topbar - the logo and +/gear icons stay put.
   Must come after the base rule (same selector/specificity - later
   wins) to actually take effect at this width. */
@media (max-width: 767px) {
    .topbar-transparent ~ #page-wrapper .ppg-box-header {
        /* Was 32px (the original locked phone nudge) - not needed anymore now that
           title/badges/photo stack in one narrow column instead of sharing a row with
           the topbar icons, so it can sit much closer to the top like the desktop
           version does. */
        top: 4px;
    }
}

/* Phone-only: the profile picture and title used to share a row with the topbar's own
   icons, which don't all fit together on a narrow screen. Moves the picture out of that
   row entirely - shrunk to the same height as the Full Sort logo, into the top-left
   corner, which is otherwise empty on this page (the sidebar toggle it would normally
   hold is hidden here). That gives the title the row to itself; its own badges (work/
   relationship status) are hidden for now to keep the box short, and the title itself
   is sized down so it reliably fits on one line. Desktop/tablet untouched - they already
   have the room for all of this side by side. */
@media (max-width: 767px) {
    /* Title on its own line, then the photo and its badges side by side below it (the
       blade markup itself now puts the title-only block first and groups photo+badges
       into their own row, ppg-photo-badges-row, so this is just stacking those two
       top-level pieces - no reordering trickery needed). All hugging the left edge
       instead of centered, so this reads as one block in the corner. */
    .ppg-box-header > .d-flex.align-items-center.flex-wrap.gap-3 {
        flex-direction: column;
        align-items: flex-start !important;
    }

    .ppg-logo {
        /* !important beats the base .ppg-logo rule further down this file - same
           specificity, and CSS breaks same-specificity ties by source order, not by
           which media query matches. Square, not the base rule's rounder 12px corner
           (which reads as nearly circular at this small a size). */
        width: 30px !important;
        height: 30px !important;
        border-radius: 4px !important;
    }

    .ppg-zoom-icon {
        display: none;
    }

    /* Small nudge up, tighter under the title. */
    .ppg-photo-badges-row {
        margin-top: -6px;
    }

    /* Scaled down twice now - 20% off the base, then another 20% off that. */
    .ppg-availability-badges .ppg-badge {
        font-size: 0.52rem;
        padding: 0.12rem 0.4rem;
    }

    .ppg-title-card h1 {
        font-size: 1.05rem;
    }

    /* 20% smaller than the 32px Icon Boxes gives them by default - !important beats
       that rule the same way as .ppg-logo above (same specificity, source order). */
    .topbar-transparent a.ppg-home-icon,
    .topbar-transparent a.darkMode {
        width: 26px !important;
        height: 26px !important;
    }
}

/* .page-wrapper's own padding-top (sitewide, further up this file)
   still uses the shorter 4.5rem value directly - that
   now undershoots the topbar's real 150px height on this page, so
   the content below sits crammed right up against/behind it with no
   gap. Matches the topbar's own min-height above; wins on specificity
   (id + class beats .page-wrapper's plain class) without !important. */
.topbar-transparent ~ #page-wrapper {
    padding-top: 114px;
}

/* Opt-in only (see $transparentTopbar in public-profile.blade.php) -
   the shared site topbar (search bar + logo) is white by default
   everywhere else; on the Public Sort page this lets the chosen
   background color/image show through that top strip too, instead of
   a plain white bar sitting above it. Never applies unless that page
   explicitly sets the flag, so no other page is affected. */
/* min-height (not max-height) so this always wins over the sitewide
   .topbar max-height above, whichever one 4.5rem came
   out to (min-height beats a smaller max-height per spec) - the
   pulled-up header needs a topbar tall enough to actually contain it
   regardless of whether the viewer is logged in or a guest. */
.topbar.topbar-transparent {
    background-color: transparent !important;
    box-shadow: none !important;
    min-height: 140px;
    padding-bottom: 10px;
}

/* The top bar over a background picture is see-through, so content scrolling up under it used to show
   through. The page hands the bar its own copy of the picture (--ppg-bar-image, set on the bar by
   public-profile.blade.php), fixed to the screen and sized exactly like the page's own picture so the two
   line up with no seam, clipped to just the strip the bar covers (--ppg-bar-h, measured by the page).
   It sits behind the bar's buttons, so the bar is opaque and anything scrolling under it stays out of
   sight. After Dark dims the page picture, and the bar's strip with it. Only the picture case: a background
   color is already an opaque bar, and classic Dark Mode is a solid bar. */
.topbar-transparent[style*="--ppg-bar-image"]::before {
    content: "";
    position: fixed;
    inset: 0;
    z-index: -1;
    pointer-events: none;
    background-color: #343434;
    background-image: var(--ppg-bar-image);
    background-size: cover;
    background-position: center;
    background-repeat: no-repeat;
    clip-path: inset(0 0 calc(100% - var(--ppg-bar-h, 150px)) 0);
}

.ppg-after-dark.dark-mode .topbar-transparent[style*="--ppg-bar-image"]::before {
    filter: brightness(0.25);
}

/* Only relevant for "After Dark" (see the Background tab's Dark Mode
   Style choice) - classic Dark Mode wants the topbar solid, same as
   ever. Making .topbar itself transparent isn't enough on its own -
   the sitewide ".dark-mode *" wildcard (way up near the top of this
   file) still gives every one of its inner wrapper divs (logo,
   dark-mode toggle, home icon - none of them .ppg-box or a descendant
   of one, the wildcard's own exclusion) their own opaque #343434,
   covering most of the bar with solid color in small blocks and
   leaving only the gaps between them actually see-through. Blanket
   transparency on every descendant here instead, same idea as the
   .ppg-box exclusion already carved out of that wildcard. The colored Full Sort logo is left out: it is a
   masked block whose background-color IS the logo, so making it transparent made the logo disappear. */
.ppg-after-dark.dark-mode .topbar-transparent,
.ppg-after-dark.dark-mode .topbar-transparent *:not(#fullsort-logo-colored) {
    background-color: transparent !important;
}

/* Tablet/desktop only - phone's own spacing is locked separately
   (see the max-width:767px block above). Just the topbar's own
   height, nothing else touched. */
@media (min-width: 768px) {
    .topbar.topbar-transparent {
        min-height: 60px;
    }
}

/* Search doesn't belong on a public, guest-facing page - the owner
   viewing their own page is the only one who'd ever see it here
   anyway, and removing it lets the profile header sit closer to the
   top instead of leaving a tall, empty topbar above it. */
.topbar-transparent #fullsort_search_block {
    display: none !important;
}

/* Bootstrap's .input-group squares off the connecting side of an
   inner control that isn't the last element in the group - here
   that's the search input, next to the close button that's hidden
   outside mobile search. Invisible against the topbar's normal solid
   white, but a plain square corner stands out once the topbar itself
   goes transparent, so only rounded back here (not sitewide, since
   every other topbar is still solid and this was never visible there). */
.topbar-transparent #quick_search_string {
    border-top-right-radius: 0.25rem !important;
    border-bottom-right-radius: 0.25rem !important;
}

/* Typeahead overlays two inputs - the real (transparent) one on top,
   and an opaque white ".tt-hint" clone behind it that shows the
   autocomplete suggestion. #quick_search_string's own height rule
   below doesn't reach that clone (typeahead builds it before this CSS
   would apply, from the input's own un-styled height), leaving it a
   few pixels short - invisible against the topbar's normal solid
   white, but once the topbar goes transparent, that gap is exactly
   tall enough to show the topbar's own background color peeking
   through the bottom of the search box. */
.topbar-transparent .tt-hint {
    height: 26.5px !important;
}

/* Full-viewport wallpaper behind the whole page (color or uploaded
   image, set via the Background tab) - fixed so it stays in place
   while the page scrolls, negative z-index so it sits behind every
   box regardless of DOM order. */
.ppg-page-background {
    position: fixed;
    inset: 0;
    z-index: -1;
    background-size: cover;
    background-position: center;
    background-repeat: no-repeat;
}

/* Classic "Dark Mode" (the original, default behavior - see the
   Background tab's Dark Mode Style choice) always covers the full
   viewport regardless of dark mode, so wherever the page's own content
   is shorter than the viewport, the user's chosen light color/image
   was showing through below it. Dark mode just goes plain black here
   instead, same as everywhere else. Excluded when the owner has opted
   into "After Dark" (.ppg-after-dark on <body>), which wants the real
   background to show through instead - see that ruleset below. */
.dark-mode:not(.ppg-after-dark) .ppg-page-background {
    background-color: #343434 !important;
    background-image: none !important;
}

/* "After Dark" - the owner's opt-in alternative to classic Dark Mode
   (Background tab). Lets the real background image/color bleed
   through instead of switching to plain black, dimmed ~75% so it
   doesn't look out of place next to the rest of the page having gone
   dark. Two problems classic Dark Mode never had to deal with, since
   it just replaces everything with the same flat color regardless:

   1) z-index: auto (overriding the negative default above) - every
      wrapper between this div and <body> (page-wrapper, sidebar-hidden,
      container-fluid, .row, ...) is position: static, but in dark mode
      the sitewide ".dark-mode *" wildcard still gives each of them
      their own opaque background - painted, per normal stacking order,
      AFTER a negative-z-index descendant, which would otherwise hide
      this behind them entirely. Plain z-index: auto instead puts it in
      the same "positioned, z-index auto" paint step as those wrappers'
      own backgrounds - painted after those, so it's visible - while
      still painting BEFORE .ppg-box (position: relative, later in DOM
      order) so real content still stacks on top.
   2) The dimming filter itself. */
.ppg-after-dark.dark-mode .ppg-page-background {
    z-index: auto;
    filter: brightness(0.25);
}

/* Same reason as the z-index: auto above - the footer is not
   positioned, so the wallpaper (now painted in the positioned layer)
   covered it completely. Positioning it puts it back on top; its color
   is already white via .ppg-image-bg. */
.ppg-after-dark.dark-mode .footer {
    position: relative;
}

/* The sitewide ".dark-mode *" wildcard paints the footer a solid dark
   band - see-through here so the wallpaper continues right down to the
   bottom of the page. */
.ppg-after-dark.dark-mode .footer,
.ppg-after-dark.dark-mode .footer * {
    background-color: transparent !important;
}


/* Fixed-column layout (like start.me) - each box lives in exactly one
   column, full width of it, stacked in order. A column's width comes
   from an equal share of the row (see the size classes below), not from
   the box - so a box can never overlap another the way the earlier
   free-form drag-anywhere system could. Height stays automatic from
   content. */
.ppg-columns {
    /* Gap below the topbar, independent of the header's own position -
       page-wrapper's padding-top affects both the header and this row
       together, so tuning it to fix a gap here kept dragging the
       header out of position too. This only touches the space above
       the box grid itself. */
    margin-top: 35px;
    display: flex;
    /* stretch (not flex-start) so every column fills the full row
       height, matching the tallest one - otherwise a short column's
       actual droppable area silently ended where its own content
       ended, well above where it visually looked like it should
       still extend to alongside a taller neighbor. That's what made
       dragging a box into a shorter column fail unpredictably,
       depending on exactly where the mouse was released. */
    align-items: stretch;
    gap: 20px;
    justify-content: center;
    justify-content: safe center;
    margin-bottom: 50px;
}

.ppg-column {
    display: flex;
    flex-direction: column;
    min-width: 0;
    /* An empty column (more columns chosen than there are boxes to
       fill them) would otherwise collapse to zero height as a flex
       container with no children - nothing to actually drag a box
       onto. This keeps every column a real drop target regardless of
       how many boxes are in it. */
    min-height: 80px;
}

/* An empty column (no boxes in it) gets a faint outline so the drop
   target itself is visible instead of just blank space - pure CSS
   (:empty), no JS/DOM manipulation, so there's nothing that can get
   left behind and block a later drag into it. No label text - just
   the outline. */
.ppg-column:empty {
    border: 2px dashed #ced4da;
    border-radius: 5px;
}
/* Every column is the same width (328px, the Start Page's column width, shrinking on a narrower screen),
   whatever size class it carries (the old Small / Medium / Large / XL per-column setting no longer changes
   anything). The row of columns is centered, so the space left of the first column and right of the last
   is the same, and the same as the Start Page's for the same number of columns. */
.ppg-column-size-s,
.ppg-column-size-m,
.ppg-column-size-l,
.ppg-column-size-x {
    flex: 0 1 328px;
    max-width: 328px;
}

.ppg-box {
    position: relative;
    color: #212529 !important;
    border-radius: 5px;
    padding: 1.75rem;
    box-shadow: 0 1px 4px rgba(0, 0, 0, 0.08);
}

/* Hover state, mouse-only (see the (hover: hover) query below) - a
   thin black overlay darkens whatever the box's own background color
   happens to be by about 5%, same idea as the link-card hover tint but
   working for any of the boxes' different pastel colors (including a
   fully custom one) without needing a per-color override. Sits behind
   the box's own z-index:auto content (text, icons, photos) via the
   negative z-index below, so it reads as the box itself darkening
   rather than a layer painted over the content. */
.ppg-box::after {
    content: '';
    position: absolute;
    inset: 0;
    z-index: -1;
    border-radius: inherit;
    background-color: rgba(0, 0, 0, 0.05);
    opacity: 0;
    transition: opacity 0.15s ease;
    pointer-events: none;
}

@media (hover: hover) {
    .ppg-box:hover::after {
        opacity: 1;
    }

    /* Edit/hide/drag controls only ever exist in the DOM for the
       profile's own owner (see ppg-box-content.blade.php) - hiding them
       until hover keeps a box's normal content free of clutter, same
       as the buckets/links hover-to-reveal pattern elsewhere. Scoped to
       real hover (not touch) since a touchscreen has no hover state to
       reveal them with - they stay visible there like before. */
    .ppg-box .ppg-box-edit,
    .ppg-box .ppg-box-hide,
    .ppg-box .ppg-drag-handle {
        opacity: 0;
        transition: opacity 0.15s ease;
    }

    .ppg-box:hover .ppg-box-edit,
    .ppg-box:hover .ppg-box-hide,
    .ppg-box:hover .ppg-drag-handle {
        opacity: 1;
    }
}

/* Phones and tablets (any touch screen, and a narrow window): the same hide-until-you-point-at-it as
   desktop. Touch has no hover, so tapping a box (the page script adds .ppg-controls-open) shows its edit /
   hide / drag icons, and tapping it again or another box hides them. Hidden icons can't be tapped by
   accident. */
@media (max-width: 991px), (pointer: coarse) {
    .ppg-box .ppg-box-edit,
    .ppg-box .ppg-box-hide,
    .ppg-box .ppg-drag-handle {
        opacity: 0;
        pointer-events: none;
        transition: opacity 0.15s ease;
    }

    .ppg-box:hover .ppg-box-edit,
    .ppg-box:hover .ppg-box-hide,
    .ppg-box:hover .ppg-drag-handle,
    .ppg-box.ppg-controls-open .ppg-box-edit,
    .ppg-box.ppg-controls-open .ppg-box-hide,
    .ppg-box.ppg-controls-open .ppg-drag-handle {
        opacity: 1;
        pointer-events: auto;
    }
}

/* Real margin instead of the column's old flex `gap` - a flex `gap` is
   blank space owned by no element, so jQuery UI Sortable (which only
   recalculates drop position while the pointer is over an actual item)
   would silently ignore the cursor while it sat in that gap between
   two boxes. Margin keeps that space part of the box above it, so
   hovering there still counts as hovering the box. */
.ppg-column > .ppg-box:not(:last-child),
.ppg-column > .ppg-drag-placeholder:not(:last-child) {
    margin-bottom: 1.5rem;
}

/* --ppg-box-alpha comes from the Background tab's Box Transparency
   slider (set inline on .public-profile-grid, 1 = fully solid) - lets
   the page background (color or uploaded image) show through every
   box by the same amount, default fully opaque when unset. */
/* Always fully transparent (not affected by Box Transparency) so it
   blends into the page background/image instead of reading as a
   separate white card sitting on top of it - unlike the other boxes,
   this one has no tint of its own to fade. */
/* Unlike every other box, this one has no light background of its
   own (transparent, see below) - it sits directly on the topbar,
   which goes black in dark mode, so its own text/icons need to stay
   white there instead of following the other boxes' "always dark
   text" rule. The title card is the exception to the exception - it
   has its own white background (see .ppg-title-card, already fully
   excluded from dark mode above), so its own text stays normal dark. */
.dark-mode .ppg-box-header,
.dark-mode .ppg-box-header *:not(.ppg-badge):not(.ppg-badge *):not(.ppg-title-card):not(.ppg-title-card *) {
    color: #fff !important;
}

.ppg-box-header {
    background-color: transparent !important;
    box-shadow: none !important;
    /* No visible card on this box, so its left edge should line up
       with the other boxes' outer edge below it, not sit indented by
       the normal box padding. */
    padding-left: 0;
}

.ppg-box-buckets {
    background-color: color-mix(in srgb, #eaf6f3 calc(var(--ppg-box-alpha, 1) * 100%), transparent) !important;
}

.ppg-box-links {
    background-color: color-mix(in srgb, #f3effc calc(var(--ppg-box-alpha, 1) * 100%), transparent) !important;
}

.ppg-box-photos {
    background-color: color-mix(in srgb, #eaf1fb calc(var(--ppg-box-alpha, 1) * 100%), transparent) !important;
}

.ppg-box-photos > *:last-child {
    margin-bottom: 10px;
}

.ppg-box-social {
    background-color: color-mix(in srgb, #fdf1e8 calc(var(--ppg-box-alpha, 1) * 100%), transparent) !important;
}

.ppg-box-description {
    background-color: color-mix(in srgb, #fefbea calc(var(--ppg-box-alpha, 1) * 100%), transparent) !important;
}

@media (max-width: 767px) {
    /* A phone can't fit multiple columns side by side - stack them into one, full
       width. Tablets (768px and wider) keep the columns side by side, equal width
       (see the tablet rule below the phone block). */
    .ppg-columns {
        flex-direction: column;
    }

    /* The size classes' flex-grow (1/2/3/4) is meant to divide up
       WIDTH when columns sit side by side - once the container above
       switches to column-direction, those same values fight over
       HEIGHT instead, since flex-grow follows whatever the main axis
       currently is. That made stacked columns overlap/compress rather
       than size to their own content. Reset to a plain block-like
       flex-basis here so each one just takes the height its content
       needs. */
    .ppg-column {
        flex: 1 1 auto;
        max-width: none;
    }

    /* Stacking columns turns .ppg-columns' side-by-side gap into
       vertical space between them - the same dead zone problem the
       flex `gap` inside a column had (see .ppg-column > .ppg-box
       above): blank space owned by no element, so Sortable's
       drop-position tracking (which only updates while the pointer is
       over an actual item) ignored the cursor while it sat in that
       gap between the bottom of one stacked column and the top of the
       next. Margin on the column container itself wouldn't fix this -
       Sortable only tracks the mouse against item elements, not their
       container - so instead give the last box of every column that
       trailing margin, making the boundary part of a real item. */
    .ppg-columns {
        gap: 0;
    }

    .ppg-column > .ppg-box:last-child,
    .ppg-column > .ppg-drag-placeholder:last-child {
        margin-bottom: 1.5rem;
    }
}


/* Phones and tablets (and any touch screen): the Public Sort page never scrolls sideways. Only this page has
   .topbar-transparent, so nothing else is affected. Clipping the page wrapper (and hiding the page's own
   sideways scroll) keeps a wide row of columns, the fixed header box or a long unbroken word in a box
   from adding a horizontal scrollbar or letting the page be dragged left and right. */
@media (max-width: 991px), (pointer: coarse) {
    body:has(.topbar-transparent) {
        overflow-x: hidden;
    }

    .topbar-transparent ~ #page-wrapper {
        overflow-x: clip;
    }

    .ppg-box {
        overflow-wrap: anywhere;
    }
}
/* Side space on every screen size so the grid never runs edge to edge: the same amount on the left of
   the first column and the right of the last one, growing with the screen (15px up to 60px), the same as the Start Page. */
.public-profile-grid {
    padding: 0 clamp(15px, 4vw, 60px);
}

/* Owner-only drag-to-reorder/move-between-columns affordance - see the
   inline script on the public profile page for the jQuery UI
   sortable() setup. */
/* Back to Home icon on the Public Sort page - same 18x18 size and
   line-icon style as the dark-mode lightbulb next to it. Black in
   light mode; the sitewide dark-mode override (this link isn't a
   .ppg-box, so it's not excluded from that) already turns it white
   automatically. */
.ppg-home-icon {
    color: #000;
}

/* The owner's four header icons (pause, dark mode, add a box, home): a faint whitish box behind each
   one with dark icons, like the Start Page's, so they stay readable over the page background. Two ways
   to earn it - the older After-Dark-over-a-picture case (kept as-is), and the Icon Boxes setting on the
   Background tab (.ppg-icon-box-on, Auto/On/Off - see $iconBoxOn in public-profile.blade.php), which
   applies in every mode. The doubled body classes are what let either beat the rule that makes
   everything in the header see-through. */
.ppg-after-dark.dark-mode.ppg-image-bg .topbar-transparent a.ppg-home-icon:not(#fullsort-logo-colored),
.ppg-after-dark.dark-mode.ppg-image-bg .topbar-transparent a.darkMode:not(#fullsort-logo-colored),
.ppg-icon-box-on .topbar-transparent a.ppg-home-icon:not(#fullsort-logo-colored),
.ppg-icon-box-on .topbar-transparent a.darkMode:not(#fullsort-logo-colored) {
    display: inline-flex !important;
    align-items: center;
    justify-content: center;
    box-sizing: border-box;
    width: 32px;
    height: 32px;
    padding: 0;
    border-radius: 6px;
    background-color: rgba(255, 255, 255, 0.63) !important;
    color: #1c1f23 !important;
}

.ppg-after-dark.dark-mode.ppg-image-bg .topbar-transparent a.ppg-home-icon:not(#fullsort-logo-colored) *,
.ppg-after-dark.dark-mode.ppg-image-bg .topbar-transparent a.darkMode:not(#fullsort-logo-colored) *,
.ppg-icon-box-on .topbar-transparent a.ppg-home-icon:not(#fullsort-logo-colored) *,
.ppg-icon-box-on .topbar-transparent a.darkMode:not(#fullsort-logo-colored) * {
    color: #1c1f23 !important;
}

/* Dark Mode paints a dark square behind everything inside the top bar, which showed as a dark
   square inside each light icon box. After Dark already clears these (see above). */
.dark-mode.ppg-icon-box-on .topbar-transparent a.ppg-home-icon:not(#fullsort-logo-colored) *,
.dark-mode.ppg-icon-box-on .topbar-transparent a.darkMode:not(#fullsort-logo-colored) * {
    background-color: transparent !important;
}

/* The dark-mode sun is pale yellow (invisible on the whitish box) - same indigo the Start Page uses. */
.ppg-after-dark.dark-mode.ppg-image-bg .topbar-transparent a.darkMode:not(#fullsort-logo-colored) svg,
.ppg-icon-box-on .topbar-transparent a.darkMode:not(#fullsort-logo-colored) svg {
    stroke: #4b0082 !important;
}

@media (hover: hover) {
    .ppg-after-dark.dark-mode.ppg-image-bg .topbar-transparent a.ppg-home-icon:not(#fullsort-logo-colored):hover,
    .ppg-after-dark.dark-mode.ppg-image-bg .topbar-transparent a.darkMode:not(#fullsort-logo-colored):hover,
    .ppg-icon-box-on .topbar-transparent a.ppg-home-icon:not(#fullsort-logo-colored):hover,
    .ppg-icon-box-on .topbar-transparent a.darkMode:not(#fullsort-logo-colored):hover {
        filter: brightness(0.9);
    }
}

/* "See what your visitors see" - outlined so it reads as a utility
   control, not a call-to-action competing with the page's own
   content. Sits left of the feedback widget's tab (bottom-right) so
   the two never overlap. */
.ppg-preview-as-visitor {
    position: fixed;
    right: 90px;
    bottom: 20px;
    z-index: 40;
    padding: 0.5rem 1rem;
    border: 1px solid #6c757d;
    border-radius: 5px;
    background-color: rgba(255, 255, 255, 0.9);
    color: #495057;
    font-size: 0.85rem;
    text-decoration: none;
}

.ppg-preview-as-visitor:hover {
    background-color: #fff;
    color: #212529;
    border-color: #495057;
}

.dark-mode .ppg-preview-as-visitor {
    background-color: rgba(52, 52, 52, 0.9);
    border-color: #adb5bd;
    color: #fff;
}

.dark-mode .ppg-preview-as-visitor:hover {
    background-color: #343434;
    border-color: #fff;
}

/* Public Page window: whichever button of a toggle pair is chosen (Dark Mode / After Dark, Color / Image,
   and the others) is filled solid like the window's other buttons (Upload Image) - the theme button color
   with the theme button text - in light mode and in dark mode. In dark mode the window's own dark rule
   (every element inside a modal gets a #111 fill) used to turn the chosen button black; it now skips a
   chosen toggle button (see that rule), and this anchors the look on the window's id. */
#modal-public-page .btn-check:checked + .btn-outline-secondary {
    background-color: var(--fs-info-background) !important;
    border-color: var(--fs-info-background) !important;
    color: var(--fs-info-text, #fff) !important;
}

.ppg-drag-handle {
    cursor: move;
    color: #adb5bd;
    font-size: 0.85rem;
}

/* A box's edit, hide (custom boxes) and drag controls sit together in the top-right corner of the box
   header, in that order with the drag handle outermost, instead of the edit / hide icons sitting next to
   the title. The header is a flex row: the first control takes the free space (margin-left: auto) and the
   drag handle no longer does (its own ms-auto is switched off), or the space would be split between them. */
.ppg-section-heading .ppg-box-edit {
    margin-left: auto;
}

.ppg-section-heading .ppg-drag-handle {
    margin-left: 0 !important;
}

.ppg-drag-placeholder {
    border: 2px dashed #adb5bd;
    border-radius: 5px;
}

/* Replaces the native <input type="color"> everywhere in Public Sort
   (box colors, background color, per-link icon colors) - restricted
   to light colors since every swatch sits behind dark text, and a
   native color wheel can't be limited to a palette itself. */
.ppg-swatch-grid {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    max-width: 220px;
}

.ppg-swatch {
    width: 24px;
    height: 24px;
    border-radius: 6px;
    border: 1px solid rgba(0, 0, 0, 0.15);
    cursor: pointer;
    box-sizing: border-box;
}

.ppg-swatch:hover {
    border-color: rgba(0, 0, 0, 0.35);
}

.ppg-swatch-selected {
    border: 2px solid #495057;
    box-shadow: 0 0 0 2px #fff inset;
}

/* "Custom color" swatch appended to every light-swatch grid - opens
   the real native <input type="color"> (kept in the DOM, just
   visually hidden below, not display:none - a display:none input
   can't open its picker even via a scripted .click()) so a user isn't
   limited to the light palette above. */
.ppg-swatch-custom {
    position: relative;
    background: conic-gradient(from 180deg, #ff5252, #ffca28, #66bb6a, #26c6da, #5c6bc0, #ab47bc, #ff5252);
}

.ppg-swatch-custom::after {
    pointer-events: none;
    content: '+';
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    color: #fff;
    font-weight: 700;
    font-size: 14px;
    text-shadow: 0 1px 2px rgba(0, 0, 0, 0.6);
}

/* Large box showing the color currently chosen in a Public Sort color picker, so the pick is
   obvious on a phone or tablet where the small swatches are hard to see. */
.ppg-color-preview {
    position: relative;
    display: inline-block;
    vertical-align: middle;
    flex: 0 0 auto;
    width: 44px;
    height: 44px;
    border-radius: 8px;
    border: 2px solid rgba(0, 0, 0, 0.25);
    box-sizing: border-box;
    background-color: #ffffff;
    cursor: pointer;
}

/* Color window (link, note and Start Page box colors): the color in use as a large box, the swatches
   below it, then the Off / Default / Custom choice set apart from them. */
#modal-item-color .ppg-color-preview {
    display: block;
    width: 56px;
    height: 56px;
    margin: 0 auto 0.75rem;
}

/* Off: an empty box with a diagonal line, so "no color" reads as no color. */
#modal-item-color .ppg-color-preview.ppg-color-preview-off {
    background-image: linear-gradient(to top right, transparent calc(50% - 1px), rgba(0, 0, 0, 0.35) 50%, transparent calc(50% + 1px));
}

#modal-item-color .ppg-swatch-grid {
    justify-content: center;
    margin: 0 auto;
}

.item-color-caption {
    margin-bottom: 0.5rem;
    font-size: 0.8rem;
    font-weight: 600;
    letter-spacing: 0.03em;
    text-transform: uppercase;
    color: #6c757d;
}

.item-color-caption-or {
    margin-top: 1.25rem;
}

.item-color-hint {
    min-height: 1.25rem;
    margin: 0.75rem 0 0;
    font-size: 0.85rem;
    color: #6c757d;
}

.dark-mode .item-color-caption,
.dark-mode .item-color-hint {
    color: #adb5bd !important;
}

.dark-mode #modal-item-color .ppg-color-preview.ppg-color-preview-off {
    background-image: linear-gradient(to top right, transparent calc(50% - 1px), rgba(255, 255, 255, 0.5) 50%, transparent calc(50% + 1px));
}

/* The real <input type="color"> sits inside the big preview box, stretched
   invisibly over it (the "+" is a label for the same input), so a tap is a tap on the input itself - phones and
   tablets won't open the picker from a scripted click. */
.ppg-color-input-visually-hidden {
    position: absolute;
    top: 0;
    left: 0;
    width: 100% !important;
    height: 100% !important;
    margin: 0;
    padding: 0;
    border: 0;
    opacity: 0;
    cursor: pointer;
}

/* "Widen Box" - a box rendered full width instead of in its normal
   column (see UserController::public_profile()'s $wideBoxes and
   partials/ppg-box-content.blade.php). Same vertical rhythm as boxes
   stacked inside a column. */
.ppg-box-wide-wrapper:not(:last-child) {
    margin-bottom: 1.5rem;
}

.ppg-logo {
    height: 64px;
    width: 64px;
    object-fit: cover;
    border-radius: 12px;
    cursor: zoom-in;
}

/* Wraps any click-to-enlarge image (logo or a Photos thumbnail) - a
   magnifying glass fades in on hover/focus and the image darkens
   slightly underneath so the white icon stays legible on any photo. */
.ppg-zoomable {
    position: relative;
    display: inline-block;
}

.ppg-zoomable:hover img,
.ppg-zoomable:focus-within img {
    filter: brightness(0.7);
}

.ppg-zoom-icon {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    color: #fff;
    font-size: 1.1rem;
    text-shadow: 0 1px 3px rgba(0, 0, 0, 0.6);
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.15s ease;
}

.ppg-zoomable:hover .ppg-zoom-icon,
.ppg-zoomable:focus-within .ppg-zoom-icon {
    opacity: 1;
}

/* Wraps just the page title + its edit pencil in its own small white
   card - display:inline-flex (not the plain d-flex/block it also
   carries) so the card hugs exactly as wide as the title text, never
   stretching to fill the row. */
/* Inline-editable page title (owner only) - contenteditable has no
   native placeholder, so this fakes one only while genuinely empty
   (not mid-edit with real content). A dashed underline on focus is
   the only visual cue it's editable otherwise - deliberately subtle,
   since this sits right next to the actual "Edit your Public Sort"
   pencil which already signals editability. */
.ppg-title-editable {
    outline: none;
    cursor: text;
    min-width: 1ch;
}

.ppg-title-editable:focus {
    text-decoration: underline;
    text-decoration-style: dashed;
    text-underline-offset: 4px;
}

.ppg-title-editable:empty::before {
    content: attr(data-placeholder);
    opacity: 0.6;
}

/* Text edited right on the box - About Me / My Business / My Expertise
   and a quick_edit custom box. Same "click to edit, save on blur"
   pattern as the title above, with the floating toolbar below for
   formatting. Only editable once the JS in public-profile.blade.php has
   set contenteditable (mouse-type pointers only), so nothing here
   changes how it looks on a phone, where the pencil/modal is used. */
.ppg-inline-rich {
    min-height: 1.5em;
}

.ppg-inline-rich:empty::before {
    content: attr(data-empty-text);
    opacity: 0.6;
}

.ppg-inline-rich[contenteditable="true"] {
    outline: none;
    cursor: text;
    border-radius: 6px;
    margin: -0.25rem -0.4rem;
    padding: 0.25rem 0.4rem;
    transition: background-color 0.15s ease;
}

.ppg-inline-rich[contenteditable="true"]:hover {
    background-color: rgba(0, 0, 0, 0.05);
}

.ppg-inline-rich[contenteditable="true"]:focus {
    background-color: rgba(0, 0, 0, 0.05);
    outline: 1px dashed rgba(0, 0, 0, 0.3);
    outline-offset: 2px;
}

.ppg-inline-rich[contenteditable="true"]:empty::before {
    content: attr(data-placeholder);
}

/* The editor's own paragraphs shouldn't add a gap under the last line. */
.ppg-custom-box-content p:last-child {
    margin-bottom: 0;
}

/* Floating toolbar shown above the text being edited. Colors are
   !important since the sitewide ".dark-mode *" rule paints every
   element's background and would otherwise flatten the buttons. */
.ppg-inline-toolbar {
    position: fixed;
    z-index: 2000;
    display: flex;
    gap: 2px;
    padding: 4px;
    border-radius: 8px;
    background: #212529 !important;
    box-shadow: 0 4px 14px rgba(0, 0, 0, 0.3);
}

.ppg-inline-toolbar button {
    width: 30px;
    height: 30px;
    padding: 0;
    border: 0;
    border-radius: 6px;
    line-height: 1;
    font-size: 0.85rem;
    cursor: pointer;
    background: transparent !important;
    color: #fff !important;
}

.ppg-inline-toolbar button:hover {
    background: rgba(255, 255, 255, 0.18) !important;
}

.ppg-inline-toolbar button.active {
    background: #148c9f !important;
}

.ppg-inline-toolbar-sep {
    width: 1px;
    margin: 4px 3px;
    background: rgba(255, 255, 255, 0.25) !important;
}

.ppg-title-card {
    display: inline-flex !important;
    border-radius: 5px;
    padding: 0.5rem;
    box-shadow: 0 1px 4px rgba(0, 0, 0, 0.08);
    color: #212529;
}

.ppg-section-heading {
    font-size: 1.1rem;
    margin-bottom: 1.25rem;
}

/* The icon to the left of a box title (a Font Awesome / Tabler / Phosphor icon, an emoji or a color shape,
   the same kinds a Start Page category icon can be). The owner's is clickable and opens the icon picker. */
.ppg-box-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex: 0 0 auto;
    font-size: 0.95rem;
    line-height: 1;
}

.ppg-box-icon img {
    width: 1em;
    height: 1em;
}

.ppg-box-icon-editable {
    cursor: pointer;
}

.ppg-box-icon-editable:hover {
    opacity: 0.65;
}

/* Boxes sized and positioned like the Start Page's: the heading a little smaller and sitting higher (much
   less padding above it and around it, a smaller gap under it), and the bucket / link lists in the same
   small size as the Start Page's link rows. The header box at the top (avatar, title) is left alone - its
   position is locked. */
.ppg-box:not(.ppg-box-header) {
    padding: 10px 12px 12px;
}

.ppg-box:not(.ppg-box-header) .ppg-section-heading {
    font-size: 0.95rem;
    margin-bottom: 0.6rem;
}

.ppg-item,
.ppg-item * {
    font-size: 0.85rem;
}

/* No width cap: text fills its box, whatever the box's width. It used to
   stop at 65ch for readability, which left a box in a wide column (a
   widened box, or few columns) filled only halfway. */
.ppg-bio {
    color: #495057 !important;
}

/* The rich text editors in Public Sort's box modals (About Me, My
   Business, My Expertise, and a custom box's content). The editor is an
   iframe that copies its height from its textarea when it starts, so the
   height is set here on the textarea - the default 4 rows left only
   three or four lines visible, far too little to write in. */
textarea.ppg-rich-text,
#custom-box-content,
#new-custom-box-content {
    height: 300px;
}

/* A sitewide reset flattens <b>/<strong> to normal weight - Build Box
   content (the only place on this page with real rich text) needs
   its own bold to actually look bold, so it's restored just here
   rather than touching that reset everywhere else it's relied on. */
.ppg-custom-box-content b,
.ppg-custom-box-content strong {
    font-weight: 700 !important;
}

.ppg-custom-box-content ul,
.ppg-custom-box-content ol {
    padding-left: 1.25rem;
    margin-bottom: 0;
}

.ppg-custom-box-content a {
    color: inherit;
    text-decoration: underline;
}

/* Manage Boxes tab (modal-public-page) - one row per box with an
   on/off switch, instead of the old "only shows up once you've
   already hidden it" unhide-link list. */
.ppg-manage-boxes-list {
    border: 1px solid #eef0f2;
    border-radius: 10px;
    overflow: hidden;
}

.ppg-manage-box-row {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    padding: 0.65rem 0.9rem;
    background-color: #fff;
}

.ppg-manage-box-row:not(:last-child) {
    border-bottom: 1px solid #eef0f2;
}

.ppg-manage-box-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 28px;
    height: 28px;
    border-radius: 8px;
    background-color: #f4f6f8;
    color: #6c757d;
    font-size: 0.8rem;
    flex-shrink: 0;
}

.ppg-manage-box-name {
    font-size: 0.9rem;
    font-weight: 600;
}

.ppg-badge {
    display: inline-flex;
    align-items: center;
    font-size: 0.8rem;
    font-weight: 600;
    padding: 0.2rem 0.65rem;
    /* Same corner rounding as the boxes below them (.ppg-box), not a
       full pill. */
    border-radius: 5px;
}

.ppg-badge-open {
    background-color: #e7f7ee !important;
    color: #1b7f4c !important;
}

.ppg-badge-closed {
    background-color: #f1f0f0 !important;
    color: #6c757d !important;
}

.ppg-badge-neutral {
    background-color: #fbe9ef !important;
    color: #b3436a !important;
}

/* Buckets/links float directly on the section's tinted background
   instead of sitting in their own white card - just a subtle hover
   fill (a black wash works on any tint, unlike a fixed hover color)
   so it's still obvious they're clickable. */
.ppg-item {
    /* No left padding, unlike the other three sides - a bucket/link's
       icon should start flush with the box's own padding, same as
       Social's icons and every other box's plain text content, not
       inset further right by this hover target's own padding. The
       hover fill still covers the icon (padding-left: 0 just moves its
       left edge, not its top/right/bottom reach). */
    padding: 0.65rem 0.9rem 0.65rem 0;
    border-radius: 10px;
    color: inherit !important;
}

/* Bucket icons come from a free-text emoji/icon picker (any width),
   so without a fixed slot the bucket name after it lands at a
   different x-position on every row. Centers each icon in the same
   width slot instead, so every bucket's name starts at the same
   spot regardless of which icon it has. */
.ppg-bucket-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1.5em;
    flex-shrink: 0;
}

.ppg-item:hover {
    background-color: rgba(0, 0, 0, 0.05);
}

/* "Serious" mood (class name kept as -business internally) - every section renders in the same neutral light
   grey instead of the colorful mint/lavender default, for a more
   professional/toned-down look. */
.ppg-mood-business .ppg-box-buckets,
.ppg-mood-business .ppg-box-links,
.ppg-mood-business .ppg-box-photos,
.ppg-mood-business .ppg-box-social,
.ppg-mood-business .ppg-box-description {
    background-color: color-mix(in srgb, #f1f3f5 calc(var(--ppg-box-alpha, 1) * 100%), transparent) !important;
}

.ppg-social-icons {
    display: flex;
    flex-wrap: wrap;
    gap: 0.75rem;
}

/* Grid-style Buckets list - flex + gap instead of Bootstrap's .row/.col
   (see the matching comment in ppg-box-content.blade.php), same
   technique as .ppg-social-icons above so both line up flush with the
   box's own left padding. flex-basis approximates the old 3-per-row
   (col-md-4) / 2-per-row (col-sm-6) breakpoints without the grid's
   negative-margin side effect. */
.ppg-bucket-grid {
    display: flex;
    flex-wrap: wrap;
    gap: 0.75rem 1rem;
}

.ppg-bucket-grid-item {
    flex: 1 1 calc(33.333% - 0.75rem);
    min-width: 140px;
}

@media (max-width: 575px) {
    .ppg-bucket-grid-item {
        flex: 1 1 calc(50% - 0.5rem);
    }
}

.ppg-social-icon {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 44px;
    height: 44px;
    border-radius: 50%;
    background-color: rgba(0, 0, 0, 0.06);
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.15);
    transition: transform 0.15s ease, box-shadow 0.15s ease;
}

.ppg-social-icon:hover {
    transform: translateY(-2px);
    box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
}

/* The real brand logo (self-hosted SVG, see ppg-box-content.blade.php) - a plain black
   shape, recolored here since an <img> can't pick up `color` like a font icon could.
   White on every colored circle except Snapchat's bright yellow one, which needs a dark
   icon to stay legible (its own override further down, same as before this changed). */
.ppg-social-icon-img {
    width: 24px;
    height: 24px;
    filter: brightness(0) invert(1);
}

@media (prefers-reduced-motion: reduce) {
    .ppg-social-icon:hover {
        transform: none;
    }
}

/* Each platform's own brand color, white logo on top (see .ppg-social-icon-img's
   filter) - color: #fff/#000 here is now only a fallback for the brief instant before
   the logo image loads. Snapchat is the one exception (its brand yellow needs a dark
   icon to stay legible, not white - the matching filter override is just below). */
.ppg-social-icon-facebook { background-color: #1877f2; color: #fff; }
.ppg-social-icon-instagram { background-color: #e4405f; color: #fff; }
.ppg-social-icon-x { background-color: #000; color: #fff; }
.ppg-social-icon-snapchat { background-color: #fffc00; color: #000; }
.ppg-social-icon-linkedin { background-color: #0a66c2; color: #fff; }
.ppg-social-icon-pinterest { background-color: #e60023; color: #fff; }
.ppg-social-icon-tiktok { background-color: #000; color: #fff; }
.ppg-social-icon-youtube { background-color: #ff0000; color: #fff; }
.ppg-social-icon-threads { background-color: #000; color: #fff; }

.ppg-social-icon-snapchat .ppg-social-icon-img {
    filter: brightness(0);
}

.ppg-social-icon-facebook:hover { background-color: #0d5dc7; color: #fff; }
.ppg-social-icon-instagram:hover { background-color: #c32b4b; color: #fff; }
.ppg-social-icon-x:hover { background-color: #2a2a2a; color: #fff; }
.ppg-social-icon-snapchat:hover { background-color: #e6e200; color: #000; }
.ppg-social-icon-linkedin:hover { background-color: #08508f; color: #fff; }
.ppg-social-icon-pinterest:hover { background-color: #b8001c; color: #fff; }
.ppg-social-icon-tiktok:hover { background-color: #2a2a2a; color: #fff; }
.ppg-social-icon-youtube:hover { background-color: #cc0000; color: #fff; }
.ppg-social-icon-threads:hover { background-color: #2a2a2a; color: #fff; }

/* Displayed at 80px - twice the small 40px profile logo/photo, per
   the Photos box's own request. */
.ppg-photo-grid {
    display: flex;
    flex-wrap: wrap;
    gap: 0.75rem;
}

.ppg-photo-thumb {
    width: 80px;
    height: 80px;
    object-fit: cover;
    border-radius: 8px;
}

/* Thumbnails in the settings modal's "Your Photos" manager, not the
   public page itself - smaller, with a remove button overlaid on the
   corner. */
.profile-photo-thumb-wrap {
    width: 70px;
    height: 70px;
}

.profile-photo-thumb {
    width: 70px;
    height: 70px;
    object-fit: cover;
    border-radius: 6px;
}

.profile-photo-delete {
    position: absolute;
    top: -8px;
    right: -8px;
    width: 22px;
    height: 22px;
    padding: 0;
    line-height: 1;
    border-radius: 50%;
}


/* Start Background: make the chosen picture obvious - a strong outline on it, the other pictures dimmed, and a
   highlighted line under the preview while the choice still needs Save. */
#modal-start-background .sb-thumb.sb-picked {
    border-color: #17a2b8;
    box-shadow: 0 0 0 3px #17a2b8;
}

#modal-start-background .sb-has-pick .sb-thumb:not(.sb-picked) {
    opacity: 0.55;
}

#modal-start-background #sb-image-status.sb-pending {
    color: #17a2b8;
}

/* Manage Default Buckets / Links, dark mode: the generic ".dark-mode .btn:hover *" rule paints a near-black
   box behind the icon inside a hovered button; keep the icon's own background clear on this page only. */
.dark-mode #bucket_defaults .btn:hover *,
.dark-mode .default-link-actions .btn:hover *,
.dark-mode #create-defaults-bucket:hover * {
    background-color: transparent !important;
}
