/* ================================================================
   app-components.css — shared design tokens and utility classes
   Loaded globally. Used by json-node, sg-editor, and all
   future components that need consistent inputs, buttons, etc.
================================================================ */

/* ── Design tokens ─────────────────────────────────────────── */
:root {
    --app-accent:     #0a5dc2;
    --app-accent-lt:  #e8f0fb;
    --app-accent-bd:  #bfd4f5;
    --app-border:     #dee2e6;
    --app-bg:         #ffffff;
    --app-bg-subtle:  #f8f9fa;
    --app-text:       #212529;
    --app-text-muted: #6c757d;
    --app-success:    #198754;
    --app-warning:    #fd7e14;
    --app-danger:     #dc3545;
    --app-radius-sm:  4px;
    --app-radius:     6px;
    --app-radius-lg:  10px;
    --app-shadow:     0 1px 4px rgba(0,0,0,.08);
    --app-shadow-lg:  0 8px 32px rgba(0,0,0,.14);

    /* ── Fluid type scale ── */
    --text-xxs:   clamp(7px, 0.45vw, 9px);
    --text-xs:   clamp(11px, 0.65vw, 12px);
    --text-sm:   clamp(13px, 0.85vw, 14px);
    --text-base: clamp(14px, 0.95vw, 15px);
    --text-md:   clamp(15px, 1.05vw, 17px);
    /*
      ⚠️ These MUST match src/design-scale.scss in categories-web, and did not.
      This file said --text-lg: clamp(17px,...) and --text-xl: clamp(24px,...);
      design-scale.scss, approot.css and the table in CLAUDE.md all say 22px and
      38px. Same token name, two values, and which one you got depended on which
      stylesheet happened to load last — app-components.css here, design-scale
      there. Measured, that made a heading 17px in the WebApp and 22px in the
      Angular app at the same width, and --text-xl 24px against 38px.

      Reconciled onto the DOCUMENTED values. Desktop is unchanged for --text-lg
      (both resolve to 23.4px at 1300px); what moves is below ~1222px, where the
      floor now holds at 22px instead of sagging to 17px.
    */
    --text-lg:   clamp(22px, 1.8vw,  28px);
    --text-xl:   clamp(38px, 3.2vw,  40px);
}

/* ── Font-size utility classes ─────────────────────────────── */
.font-xs   { font-size: var(--text-xs);   }
.font-sm   { font-size: var(--text-sm);   }
.font-base { font-size: var(--text-base); }
.font-md   { font-size: var(--text-md);   }
.font-lg   { font-size: var(--text-lg);   }
.font-xl   { font-size: var(--text-xl);   }

/* ── Buttons ───────────────────────────────────────────────── */
.app-btn {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    padding: 4px 10px;
    border-radius: var(--app-radius-sm);
    /*border: 1px solid var(--app-border);*/
    border:none;
    background: inherit;
    
    
    font-weight: 500;
    cursor: pointer;
    /*transition: background .12s, border-color .12s, color .12s;*/
    white-space: nowrap;
    line-height: 1.4;
}
/*.app-btn:hover            { background: var(--app-bg-subtle); border-color: #adb5bd; }
.app-btn-primary          { color: var(--app-accent); border-color: var(--app-accent-bd); background: var(--app-accent-lt); }
.app-btn-primary:hover    { background: #d0e4ff; border-color: var(--app-accent); }
.app-btn-success          { color: var(--app-success); border-color: #a3cfbb; background: #d1e7dd; }
.app-btn-success:hover    { background: #badbcc; }
.app-btn-danger           { color: var(--app-danger); border-color: #f1aeb5; background: #f8d7da; }
.app-btn-danger:hover     { background: #f1aeb5; }*/
.app-btn-sm {
    padding: 2px 7px;
    font-size: var(--text-sm)
}
.app-btn-md {
    padding: 2px 7px;
    font-size: var(--text-md)
}
.app-btn-lg {
    padding: 2px 7px;
    font-size: var(--text-lg)
}
.app-btn-icon             { padding: 3px 6px; font-size: var(--text-md); line-height: 1; }

/* ── Status / alert bar ────────────────────────────────────── */
.app-status {
    padding: 7px 16px;
    font-size: var(--text-base);
    font-weight: 500;
    display: flex;
    align-items: center;
    gap: 8px;
    border-bottom: 1px solid transparent;
}
.app-status-info    { background: var(--app-accent-lt); color: var(--app-accent);  border-color: var(--app-accent-bd); }
.app-status-success { background: #d1e7dd; color: var(--app-success); border-color: #a3cfbb; }
.app-status-warning { background: #fff3cd; color: #7c4e00; border-color: #ffc107; }
.app-status-error   { background: #f8d7da; color: var(--app-danger); border-color: #f1aeb5; }
.app-status-close {
    margin-left: auto;
    background: none;
    border: none;
    cursor: pointer;
    font-size: var(--text-md);
    opacity: .6;
    padding: 0 2px;
}
.app-status-close:hover { opacity: 1; }

/* ── Overlay backdrop ──────────────────────────────────────── */
.app-overlay {
    position: fixed;
    inset: 0;
    background: rgba(0,0,0,.45);
    display: flex;
    align-items: center;
    justify-content: center;
    z-index: 10500;
    padding: 20px;
    backdrop-filter: blur(3px);
}

/* ── Dialog / modal shell ──────────────────────────────────── */
.app-dialog {
    background: var(--app-bg);
    border-radius: var(--app-radius-lg);
    box-shadow: var(--app-shadow-lg);
    width: 100%;
    max-width: 480px;
    display: flex;
    flex-direction: column;
    overflow: hidden;
}
.app-dialog-lg { max-width: 860px; max-height: 88vh; }

.app-dialog-header {
    padding: 14px 20px;
    border-bottom: 1px solid var(--app-border);
    display: flex;
    align-items: center;
    justify-content: space-between;
    background: var(--app-bg-subtle);
}
.app-dialog-title  { font-weight: 600; font-size: var(--text-md); color: var(--app-text); display: flex; align-items: center; gap: 8px; }
.app-dialog-close  { background: none; border: none; font-size: var(--text-lg); cursor: pointer; color: var(--app-text-muted); line-height: 1; padding: 0 4px; }
.app-dialog-close:hover { color: var(--app-text); }
.app-dialog-body   { padding: 20px; flex: 1; overflow-y: auto; }
.app-dialog-footer { padding: 12px 20px; border-top: 1px solid var(--app-border); display: flex; gap: 8px; justify-content: flex-end; background: var(--app-bg-subtle); }

.app-dialog-label { font-size: var(--text-md); font-weight: 500; color: var(--app-text); }
.app-dialog-input {
    width: 100%;
    border: 1px solid var(--app-border);
    border-radius: var(--app-radius-sm);
    padding: 8px 10px;
    font-size: var(--text-md);
    outline: none;
    margin-top: 8px;
    transition: border-color .12s;
    font-family: inherit;
}
.app-dialog-input:focus { border-color: var(--app-accent); }

/* ── Template grid (ds-tmpl-*) ─────────────────────────────── */
/* Shared by browser and any feature that renders a template picker */
.ds-tmpl-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(clamp(120px, 30%, 160px), 1fr));
    gap: clamp(8px, 1.5vw, 12px);
    padding: clamp(10px, 2vw, 16px);
}

.ds-tmpl-card {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 6px;
    padding: clamp(10px, 2vw, 14px) 8px;
    border: 1px solid var(--bs-border-color);
    border-radius: 10px;
    cursor: pointer;
    transition: border-color .15s, box-shadow .15s;
    text-align: center;
}
.ds-tmpl-card:hover {
    border-color: var(--bs-primary);
    box-shadow: 0 2px 8px rgba(var(--bs-primary-rgb), .12);
}

/* Extends .emoji-icon — add this class alongside emoji-icon in HTML */
.ds-tmpl-icon {
    border-radius: 50%;
    background: rgba(var(--bs-primary-rgb), .1);
    color: var(--bs-primary);
    flex-shrink: 0;
}

.ds-tmpl-name {
    font-size: var(--text-md);
    font-weight: 600;
    line-height: 1.2;
}

.ds-tmpl-desc {
    font-size: var(--text-sm);
    color: var(--bs-secondary-color);
    line-height: 1.3;
}

/* ── Template view toolbar ── */
.ds-tmpl-toolbar-wrap {
    display: flex;
    flex-direction: column;
    flex-shrink: 0;
}
.ds-tmpl-toolbar-row {
    display: flex;
    align-items: center;
    padding: .4rem .6rem;
    gap: 6px;
    min-height: 0;
}

/* Category filter — horizontal scroll area (base shared styles) */
.ds-tmpl-cat-filter {
    flex: 1;
    min-width: 0;
    border-radius: 10px;
    padding: 6px;
    overflow-x: scroll;
}

.ds-tmpl-cat-filter-inner {
    display: flex;
    align-items: center;
    gap: 4px;
    flex-wrap: nowrap;
    overflow-x: auto;
    overflow-y: hidden;
    -webkit-overflow-scrolling: touch;
    scroll-snap-type: x proximity;
    padding: .3rem .6rem .5rem .3rem;
    scrollbar-width: thin;
    scrollbar-color: var(--border2) transparent;
}
.ds-tmpl-cat-filter-inner::-webkit-scrollbar        { height: 5px; }
.ds-tmpl-cat-filter-inner::-webkit-scrollbar-track  { background: transparent; }
.ds-tmpl-cat-filter-inner::-webkit-scrollbar-thumb  { background: var(--border2); border-radius: 999px; }

/* Desktop: inline filter visible, mobile row hidden */
.ds-tmpl-cat-filter--desktop { display: flex; }
.ds-tmpl-cat-filter--mobile  { display: none; padding: 0; width: 100%; }

/* Mobile step navigation */
.ds-tmpl-mobile-nav { display: none; }

@media (max-width: 767px) {
    .ds-tmpl-cat-filter--desktop { display: none !important; }
    .ds-tmpl-cat-filter--mobile  { display: flex !important; }

    /* Mobile: full-width vertical list with scroll */
    .ds-tmpl-cat-filter--mobile {
        width: 100% !important;
        flex: 1 1 auto;
        min-height: 0;
        overflow: hidden;
    }
    .ds-tmpl-cat-filter--mobile .ds-tmpl-cat-filter-inner {
        flex-direction: column;
        overflow-x: visible;
        overflow-y: auto;
        /*max-height: 60vh;*/
        padding-bottom: .5rem;
        gap: .25rem;
        width:100%;
    }

    /* Head row: "All" chip + toolbar inline */
    .ds-tmpl-cat-filter-head {
        display: flex;
        align-items: center;
        width: 100%;
        gap: .5rem;
    }
    .ds-tmpl-cat-filter-head > .ds-tmpl-cat-chip {
        flex-shrink: 0;
        display: inline-flex;
        width: auto;
    }
    .ds-tmpl-toolbar-row--inline {
        display: flex;
        align-items: center;
        gap: 6px;
        margin-left: auto;
        padding: 0;
    }

    /* Hide the desktop toolbar row on mobile */
    .ds-tmpl-toolbar-wrap > .ds-tmpl-toolbar-row {
        display: none !important;
    }

    /* Category chips — full width in mobile list */
    .ds-tmpl-cat-filter--mobile > .ds-tmpl-cat-filter-inner .ds-tmpl-cat-chip {
        display: flex;
        justify-content: flex-start;
        width: 100%;
        border-radius: 7px;
        font-size: var(--text-lg);
        padding: .6rem 1rem;
    }
    .ds-tmpl-cat-filter--mobile .ds-tmpl-cat-chip--active::after {
        content: '✓';
        margin-left: auto;
        font-size: var(--text-sm);
        color: var(--active-link);
        font-weight: 700;
    }

    /* Mobile step nav */
    .ds-tmpl-mobile-nav {
        display: flex;
        flex-direction: column;
        margin-bottom: .375rem;
    }
    .ds-tmpl-mobile-nav__bar {
        display: flex;
        align-items: center;
        gap: .5rem;
        padding-bottom: .5rem;
        border-bottom: 1px solid var(--border2);
        margin-bottom: .625rem;
    }
    .ds-tmpl-mobile-nav__title {
        display: inline-flex;
        align-items: center;
        gap: .3rem;
        font-size: var(--text-base);
        font-weight: 600;
    }
    .ds-tmpl-mobile-nav__count {
        display: inline-flex;
        align-items: center;
        justify-content: center;
        min-width: 18px;
        height: 18px;
        padding: 0 .3rem;
        border: 1px solid var(--border2);
        font-size: var(--text-xs);
        font-weight: 700;
        border-radius: 999px;
        line-height: 1;
        flex-shrink: 0;
    }
    .ds-tmpl-mobile-nav__action {
        display: inline-flex;
        align-items: center;
        gap: .2rem;
        margin-left: auto;
        padding: .275rem .75rem;
        border: 1px solid var(--active-link);
        border-radius: 999px;
        background: transparent;
        font-size: var(--text-sm);
        font-weight: 600;
        color: var(--active-link);
        cursor: pointer;
        transition: background .22s ease;
    }
    .ds-tmpl-mobile-nav__action:hover { background: rgba(221, 163, 97, .10); }

    /* Step visibility */
    .ds-tmpl-toolbar-wrap:not(.ds-tmpl--browse) .ds-tmpl-grid,
    .ds-tmpl-toolbar-wrap:not(.ds-tmpl--browse) .ds-tmpl-list { }
    .ds-tmpl-toolbar-wrap.ds-tmpl--browse .ds-tmpl-cat-filter--mobile { display: none !important; }
    .ds-tmpl-toolbar-wrap.ds-tmpl--browse .ds-tmpl-mobile-nav__bar--filters { display: none; }
}

/* Category chip — border only, no backgrounds */
.ds-tmpl-cat-chip {
    display: inline-flex;
    align-items: center;
    padding: .6rem 1rem;
    font-size: var(--text-md);
    font-weight: 500;
    white-space: nowrap;
    border: 1px solid var(--border2);
    border-radius: 999px;
    background: transparent;
    cursor: pointer;
    transition: color .15s, border-color .15s;
    flex-shrink: 0;
    scroll-snap-align: start;
    line-height: 1.25;
}
.ds-tmpl-cat-chip:active {
    transform: scale(.94);
    background: var(--dark-opq-50);
}
.ds-tmpl-cat-chip:hover {
    border-color: var(--active-link);
}
.ds-tmpl-cat-chip--active {
    border-color: var(--active-link);
    color: var(--active-link);
    font-weight: 600;
}

/* Paging — pinned right */
.ds-tmpl-paging {
    display: flex;
    align-items: center;
    gap: 6px;
    margin-left: auto;
    font-size: var(--text-xs);
    color: var(--bs-secondary-color);
    flex-shrink: 0;
}

/* ── Template preview grid — flex row with responsive columns ── */
.ds-subtab-body .ds-tmpl-grid {
    display: flex;
    flex-wrap: wrap;
    gap: 12px;
    padding: 12px;
    overflow-y: auto;
    align-content: flex-start;
}

/* ── Template preview cards (lightweight field layout) ── */
.ds-tmpl-preview-card {
    display: flex;
    flex-direction: column;
    border: 1px solid var(--bs-border-color);
    border-radius: .6rem;
    overflow: hidden;
    cursor: pointer;
    transition: border-color .15s, box-shadow .15s;
    display: block;
    height: 320px;
}
.ds-tmpl-preview-card:hover {
    border-color: var(--bs-primary);
    box-shadow: 0 2px 10px rgba(var(--bs-primary-rgb), .12);
}
.ds-tmpl-preview-card--active {
    border-color: var(--bs-primary);
    box-shadow: 0 0 0 2px rgba(var(--bs-primary-rgb), .15);
}
/*
@media (min-width: 576px)  { .ds-tmpl-preview-card { width: 100%; display:block; border:1px solid red} }
@media (min-width: 992px)  { .ds-tmpl-preview-card { width: 300px; } }*/

/* Mobile: always visible above col-main */
@media (max-width: 767.98px) {
    .ds-tmpl-preview-card {
        width: 100%;
        display: block;
    }
}

/* Desktop: fixed column to the right */
@media (min-width: 768px) {
    .ds-tmpl-preview-card {
        width: 300px;
    } 
}

/* fnc-browser preview container */
.ds-tmpl-preview-browser {
    flex: 1 1 auto;
    min-height: 0;
    height: 250px;
    max-height: 250px;
    overflow: hidden;
    pointer-events: none;
}
.ds-tmpl-preview-browser fnc-browser {
    display: block;
    height: 100%;
    overflow: hidden;
}

/* Footer */
.ds-tmpl-preview-footer {
    display: flex;
    align-items: center;
    gap: .4rem;
    padding: .4rem .6rem;
    border-top: 1px solid var(--bs-border-color);
}
.ds-tmpl-preview-name {
    flex: 1;
    font-size: var(--text-sm);
    font-weight: 600;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.ds-tmpl-preview-count {
    font-size: var(--text-xs);
    color: var(--bs-secondary-color);
    flex-shrink: 0;
}
.ds-tmpl-preview-count::after {
    content: ' fields';
}

/* ── fnc-browser entrance animations ── */
@keyframes fncFadeUp {
    from { opacity: 0; transform: translateY(12px); }
    to   { opacity: 1; transform: translateY(0); }
}
@keyframes fncFadeIn {
    from { opacity: 0; }
    to   { opacity: 1; }
}
@keyframes fncScaleIn {
    from { opacity: 0; transform: scale(.96); }
    to   { opacity: 1; transform: scale(1); }
}
.fnc-animate-fade-up  { animation: fncFadeUp  .35s ease both; }
.fnc-animate-fade-in  { animation: fncFadeIn  .3s ease both; }
.fnc-animate-scale-in { animation: fncScaleIn .3s ease both; }

/* Staggered animation now handled by ff-stagger directive */

/* ══════════════════════════════════════════════════════════════
   MASTER MENU — site-wide floating toggle (MasterMenuService)
   Every collapsible dock/footer in the app (n1-dock, wv-dock--catalog,
   wv-dock--workspace, each <fnc-browser>'s footer) starts hidden and is
   driven by this one registry. No background colors per theme rules —
   just a blurred, low-opacity glass circle so it never competes with
   page content. ══════════════════════════════════════════════════ */
.mm-toggle-wrap {
    position: fixed;
    right: 16px;
    /* Clears the bottom-fixed page docks (n1-dock / wv-dock--catalog /
       wv-dock--workspace, all bottom:0 and ~44-60px tall) instead of
       sitting flush against the very edge and overlapping them — still
       unmistakably the bottom-right corner, just enough headroom that it
       never visually collides with (or reads as hidden behind) dock
       chrome on pages like service-platform.html that actually show one. */
    bottom: calc(72px + env(safe-area-inset-bottom, 0px));
    /* Highest z-index anywhere else in the app is 1050 (n1-dock/wv-dock) —
       comfortable headroom above that so this can never end up under a
       dock or menu on any page. */
    z-index: 1200;
    /* <master-menu-toggle> starts as an empty custom element in the
       server-rendered HTML — Angular injects this wrap div asynchronously
       after bootstrap, i.e. after the first paint. Mobile Safari has a
       long-documented bug where a position:fixed element added/restyled
       post-paint like this doesn't get composited as fixed until the next
       scroll forces a recompute — it renders wherever it would sit in
       normal flow (off past the bottom of the viewport, on a page tall
       enough) until you scroll once, which "fixes" it. Forcing its own
       GPU compositing layer immediately sidesteps that entirely. */
    transform: translateZ(0);
    will-change: transform;
}

.mm-toggle-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 46px;
    height: 46px;
    border-radius: 50%;
    border: 1px solid rgba(128, 128, 128, 0.28);
    background: transparent;
    color: inherit;
    opacity: 0.5;
    cursor: grab;
    /* Own touch handling (press/hold/drag) — stop the browser's default
       pan/scroll from fighting the drag gesture. */
    touch-action: none;
    -webkit-user-select: none;
    user-select: none;
    transition: opacity 0.2s ease, transform 0.15s ease, border-color 0.2s ease, color 0.2s ease;
}

/* Blur only — no tint, so the button stays genuinely transparent and
   just softens whatever's behind it. */
@supports (backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px)) {
    .mm-toggle-btn {
        -webkit-backdrop-filter: blur(14px);
        backdrop-filter: blur(14px);
    }
}

.mm-toggle-btn:hover {
    opacity: 0.9;
    transform: scale(1.06);
}

.mm-toggle-btn:active {
    cursor: grabbing;
    transform: scale(0.94);
}

.mm-toggle-btn--active {
    opacity: 1;
    border-color: rgba(10, 93, 194, 0.55);
    color: var(--app-accent, #0a5dc2);
}

/* Held still (left mouse or touch) for ~3s to tuck the button away — only
   the faint nub remains as the way back, per the "hide the master button"
   requirement. */
.mm-toggle-nub {
    display: none;
    width: 14px;
    height: 40px;
    border: none;
    border-radius: 8px 0 0 8px;
    background: rgba(128, 128, 128, 0.18);
    opacity: 0.35;
    cursor: pointer;
    transition: opacity 0.2s ease, width 0.2s ease;
}

.mm-toggle-nub:hover {
    opacity: 0.8;
    width: 18px;
}

.mm-toggle-wrap--hidden .mm-toggle-btn {
    display: none;
}

.mm-toggle-wrap--hidden .mm-toggle-nub {
    display: block;
}

/* ── Reusable "handle" for any dock/footer registered with
   MasterMenuService — a thin grabber bar shown only while its region
   is collapsed, so the collapsed state costs almost no vertical space
   yet always leaves a way back in without hunting for the floating
   toggle. Fixed variant for page-edge docks (n1-dock / wv-dock); the
   inline variant (.mm-dock-handle--inline) is for chrome embedded in
   normal flow, like a <fnc-browser> footer. */
.mm-dock-handle {
    position: fixed;
    left: 50%;
    bottom: 0;
    transform: translateX(-50%);
    z-index: 1040;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 56px;
    height: 14px;
    padding: 0;
    border: none;
    border-radius: 8px 8px 0 0;
    background: transparent;
    cursor: pointer;
    opacity: 0.3;
    transition: opacity 0.15s ease, height 0.15s ease;
}

.mm-dock-handle:hover {
    opacity: 0.75;
    height: 18px;
}

.mm-dock-handle::before {
    content: '';
    width: 32px;
    height: 3px;
    border-radius: 3px;
    background: currentColor;
}

.mm-dock-handle--inline {
    position: static;
    transform: none;
    width: 100%;
    height: 10px;
    border-radius: 0;
}

.mm-dock-handle--inline:hover {
    height: 14px;
}

